| /* |
| * Copyright (c) 2022 Nordic Semiconductor ASA. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <errno.h> |
| #include <zephyr/init.h> |
| #include <zephyr/drivers/pinctrl.h> |
| #include <nrfx_qspi.h> |
| #include <hal/nrf_clock.h> |
| |
| #define QSPI_STD_CMD_WRSR 0x01 |
| #define QSPI_STD_CMD_RSTEN 0x66 |
| #define QSPI_STD_CMD_RST 0x99 |
| |
| #define QSPI_NODE DT_NODELABEL(qspi) |
| |
| static int qspi_ext_mem_init(const struct device *dev) |
| { |
| ARG_UNUSED(dev); |
| |
| static const nrfx_qspi_config_t qspi_config = { |
| .prot_if = { |
| .readoc = NRF_QSPI_READOC_READ4IO, |
| .writeoc = NRF_QSPI_WRITEOC_PP4IO, |
| .addrmode = NRF_QSPI_ADDRMODE_24BIT, |
| }, |
| .phy_if = { |
| /* Frequency = PCLK192M / 2 * (sck_freq + 1) -> 32 MHz. |
| * 33 MHz is the maximum for WRSR, even in the High |
| * Performance mode. |
| */ |
| .sck_freq = 2, |
| .sck_delay = 0x05, |
| .spi_mode = NRF_QSPI_MODE_0, |
| }, |
| .skip_gpio_cfg = true, |
| .skip_psel_cfg = true, |
| }; |
| static const nrf_qspi_phy_conf_t qspi_phy_48mhz = { |
| /* After sending WRSR, use 48 MHz (96 MHz cannot be used, |
| * as 80 MHz is the maximum for the MX25R6435F chip). |
| */ |
| .sck_freq = 1, |
| .sck_delay = 0x05, |
| .spi_mode = NRF_QSPI_MODE_0, |
| }; |
| nrf_qspi_cinstr_conf_t cinstr_cfg = { |
| .opcode = QSPI_STD_CMD_RSTEN, |
| .length = NRF_QSPI_CINSTR_LEN_1B, |
| .io2_level = true, |
| .io3_level = true, |
| .wipwait = true, |
| }; |
| static const uint8_t flash_chip_cfg[] = { |
| /* QE (Quad Enable) bit = 1 */ |
| BIT(6), |
| 0x00, |
| /* L/H Switch bit = 1 -> High Performance mode */ |
| BIT(1), |
| }; |
| nrfx_err_t err; |
| int ret; |
| |
| PINCTRL_DT_DEFINE(QSPI_NODE); |
| |
| ret = pinctrl_apply_state(PINCTRL_DT_DEV_CONFIG_GET(QSPI_NODE), |
| PINCTRL_STATE_DEFAULT); |
| if (ret < 0) { |
| return ret; |
| } |
| |
| err = nrfx_qspi_init(&qspi_config, NULL, NULL); |
| if (err != NRFX_SUCCESS) { |
| return -EIO; |
| } |
| |
| nrf_clock_hfclk192m_div_set(NRF_CLOCK, NRF_CLOCK_HFCLK_DIV_1); |
| |
| /* Send reset enable */ |
| nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL); |
| |
| /* Send reset command */ |
| cinstr_cfg.opcode = QSPI_STD_CMD_RST; |
| nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL); |
| |
| /* Switch to Quad I/O and High Performance mode */ |
| cinstr_cfg.opcode = QSPI_STD_CMD_WRSR; |
| cinstr_cfg.wren = true; |
| cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_4B; |
| nrfx_qspi_cinstr_xfer(&cinstr_cfg, &flash_chip_cfg, NULL); |
| |
| nrf_qspi_ifconfig1_set(NRF_QSPI, &qspi_phy_48mhz); |
| |
| /* Enable XiP */ |
| nrf_qspi_xip_set(NRF_QSPI, true); |
| |
| return 0; |
| } |
| |
| SYS_INIT(qspi_ext_mem_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS); |