18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (c) 2019 Nuvoton Technology corporation. 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/bits.h> 58c2ecf20Sopenharmony_ci#include <linux/init.h> 68c2ecf20Sopenharmony_ci#include <linux/kernel.h> 78c2ecf20Sopenharmony_ci#include <linux/device.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/ioport.h> 108c2ecf20Sopenharmony_ci#include <linux/clk.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/io.h> 138c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 148c2ecf20Sopenharmony_ci#include <linux/regmap.h> 158c2ecf20Sopenharmony_ci#include <linux/of_device.h> 168c2ecf20Sopenharmony_ci#include <linux/spi/spi-mem.h> 178c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* NPCM7xx GCR module */ 208c2ecf20Sopenharmony_ci#define NPCM7XX_INTCR3_OFFSET 0x9C 218c2ecf20Sopenharmony_ci#define NPCM7XX_INTCR3_FIU_FIX BIT(6) 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Flash Interface Unit (FIU) Registers */ 248c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_CFG 0x00 258c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_CFG 0x04 268c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG 0x08 278c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CTS 0x0C 288c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CMD 0x10 298c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_ADDR 0x14 308c2ecf20Sopenharmony_ci#define NPCM_FIU_PRT_CFG 0x18 318c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW0 0x20 328c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW1 0x24 338c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW2 0x28 348c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW3 0x2C 358c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR0 0x30 368c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR1 0x34 378c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR2 0x38 388c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR3 0x3C 398c2ecf20Sopenharmony_ci#define NPCM_FIU_MAX_REG_LIMIT 0x80 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* FIU Direct Read Configuration Register */ 428c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_CFG_LCK BIT(31) 438c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_CFG_R_BURST GENMASK(25, 24) 448c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_CFG_ADDSIZ GENMASK(17, 16) 458c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_CFG_DBW GENMASK(13, 12) 468c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_CFG_ACCTYPE GENMASK(9, 8) 478c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_CFG_RDCMD GENMASK(7, 0) 488c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_ADDSIZ_SHIFT 16 498c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_DBW_SHIFT 12 508c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_ACCTYPE_SHIFT 8 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* FIU Direct Write Configuration Register */ 538c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_CFG_LCK BIT(31) 548c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_CFG_W_BURST GENMASK(25, 24) 558c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_CFG_ADDSIZ GENMASK(17, 16) 568c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_CFG_ABPCK GENMASK(11, 10) 578c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_CFG_DBPCK GENMASK(9, 8) 588c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_CFG_WRCMD GENMASK(7, 0) 598c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_ADDSIZ_SHIFT 16 608c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_ABPCK_SHIFT 10 618c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_DBPCK_SHIFT 8 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* FIU UMA Configuration Register */ 648c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_LCK BIT(31) 658c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_CMMLCK BIT(30) 668c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_RDATSIZ GENMASK(28, 24) 678c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_DBSIZ GENMASK(23, 21) 688c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_WDATSIZ GENMASK(20, 16) 698c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_ADDSIZ GENMASK(13, 11) 708c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_CMDSIZ BIT(10) 718c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_RDBPCK GENMASK(9, 8) 728c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_DBPCK GENMASK(7, 6) 738c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_WDBPCK GENMASK(5, 4) 748c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_ADBPCK GENMASK(3, 2) 758c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_CMBPCK GENMASK(1, 0) 768c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_ADBPCK_SHIFT 2 778c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_WDBPCK_SHIFT 4 788c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_DBPCK_SHIFT 6 798c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_RDBPCK_SHIFT 8 808c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT 11 818c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_WDATSIZ_SHIFT 16 828c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_DBSIZ_SHIFT 21 838c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CFG_RDATSIZ_SHIFT 24 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* FIU UMA Control and Status Register */ 868c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CTS_RDYIE BIT(25) 878c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CTS_RDYST BIT(24) 888c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CTS_SW_CS BIT(16) 898c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CTS_DEV_NUM GENMASK(9, 8) 908c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CTS_EXEC_DONE BIT(0) 918c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT 8 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* FIU UMA Command Register */ 948c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CMD_DUM3 GENMASK(31, 24) 958c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CMD_DUM2 GENMASK(23, 16) 968c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CMD_DUM1 GENMASK(15, 8) 978c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_CMD_CMD GENMASK(7, 0) 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* FIU UMA Address Register */ 1008c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_ADDR_UMA_ADDR GENMASK(31, 0) 1018c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_ADDR_AB3 GENMASK(31, 24) 1028c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_ADDR_AB2 GENMASK(23, 16) 1038c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_ADDR_AB1 GENMASK(15, 8) 1048c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_ADDR_AB0 GENMASK(7, 0) 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* FIU UMA Write Data Bytes 0-3 Register */ 1078c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW0_WB3 GENMASK(31, 24) 1088c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW0_WB2 GENMASK(23, 16) 1098c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW0_WB1 GENMASK(15, 8) 1108c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW0_WB0 GENMASK(7, 0) 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* FIU UMA Write Data Bytes 4-7 Register */ 1138c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW1_WB7 GENMASK(31, 24) 1148c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW1_WB6 GENMASK(23, 16) 1158c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW1_WB5 GENMASK(15, 8) 1168c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW1_WB4 GENMASK(7, 0) 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* FIU UMA Write Data Bytes 8-11 Register */ 1198c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW2_WB11 GENMASK(31, 24) 1208c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW2_WB10 GENMASK(23, 16) 1218c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW2_WB9 GENMASK(15, 8) 1228c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW2_WB8 GENMASK(7, 0) 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* FIU UMA Write Data Bytes 12-15 Register */ 1258c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW3_WB15 GENMASK(31, 24) 1268c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW3_WB14 GENMASK(23, 16) 1278c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW3_WB13 GENMASK(15, 8) 1288c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DW3_WB12 GENMASK(7, 0) 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* FIU UMA Read Data Bytes 0-3 Register */ 1318c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR0_RB3 GENMASK(31, 24) 1328c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR0_RB2 GENMASK(23, 16) 1338c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR0_RB1 GENMASK(15, 8) 1348c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR0_RB0 GENMASK(7, 0) 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* FIU UMA Read Data Bytes 4-7 Register */ 1378c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR1_RB15 GENMASK(31, 24) 1388c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR1_RB14 GENMASK(23, 16) 1398c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR1_RB13 GENMASK(15, 8) 1408c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR1_RB12 GENMASK(7, 0) 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci/* FIU UMA Read Data Bytes 8-11 Register */ 1438c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR2_RB15 GENMASK(31, 24) 1448c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR2_RB14 GENMASK(23, 16) 1458c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR2_RB13 GENMASK(15, 8) 1468c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR2_RB12 GENMASK(7, 0) 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci/* FIU UMA Read Data Bytes 12-15 Register */ 1498c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR3_RB15 GENMASK(31, 24) 1508c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR3_RB14 GENMASK(23, 16) 1518c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR3_RB13 GENMASK(15, 8) 1528c2ecf20Sopenharmony_ci#define NPCM_FIU_UMA_DR3_RB12 GENMASK(7, 0) 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci/* FIU Read Mode */ 1558c2ecf20Sopenharmony_cienum { 1568c2ecf20Sopenharmony_ci DRD_SINGLE_WIRE_MODE = 0, 1578c2ecf20Sopenharmony_ci DRD_DUAL_IO_MODE = 1, 1588c2ecf20Sopenharmony_ci DRD_QUAD_IO_MODE = 2, 1598c2ecf20Sopenharmony_ci DRD_SPI_X_MODE = 3, 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cienum { 1638c2ecf20Sopenharmony_ci DWR_ABPCK_BIT_PER_CLK = 0, 1648c2ecf20Sopenharmony_ci DWR_ABPCK_2_BIT_PER_CLK = 1, 1658c2ecf20Sopenharmony_ci DWR_ABPCK_4_BIT_PER_CLK = 2, 1668c2ecf20Sopenharmony_ci}; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cienum { 1698c2ecf20Sopenharmony_ci DWR_DBPCK_BIT_PER_CLK = 0, 1708c2ecf20Sopenharmony_ci DWR_DBPCK_2_BIT_PER_CLK = 1, 1718c2ecf20Sopenharmony_ci DWR_DBPCK_4_BIT_PER_CLK = 2, 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci#define NPCM_FIU_DRD_16_BYTE_BURST 0x3000000 1758c2ecf20Sopenharmony_ci#define NPCM_FIU_DWR_16_BYTE_BURST 0x3000000 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci#define MAP_SIZE_128MB 0x8000000 1788c2ecf20Sopenharmony_ci#define MAP_SIZE_16MB 0x1000000 1798c2ecf20Sopenharmony_ci#define MAP_SIZE_8MB 0x800000 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci#define FIU_DRD_MAX_DUMMY_NUMBER 3 1828c2ecf20Sopenharmony_ci#define NPCM_MAX_CHIP_NUM 4 1838c2ecf20Sopenharmony_ci#define CHUNK_SIZE 16 1848c2ecf20Sopenharmony_ci#define UMA_MICRO_SEC_TIMEOUT 150 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cienum { 1878c2ecf20Sopenharmony_ci FIU0 = 0, 1888c2ecf20Sopenharmony_ci FIU3, 1898c2ecf20Sopenharmony_ci FIUX, 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistruct npcm_fiu_info { 1938c2ecf20Sopenharmony_ci char *name; 1948c2ecf20Sopenharmony_ci u32 fiu_id; 1958c2ecf20Sopenharmony_ci u32 max_map_size; 1968c2ecf20Sopenharmony_ci u32 max_cs; 1978c2ecf20Sopenharmony_ci}; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistruct fiu_data { 2008c2ecf20Sopenharmony_ci const struct npcm_fiu_info *npcm_fiu_data_info; 2018c2ecf20Sopenharmony_ci int fiu_max; 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic const struct npcm_fiu_info npxm7xx_fiu_info[] = { 2058c2ecf20Sopenharmony_ci {.name = "FIU0", .fiu_id = FIU0, 2068c2ecf20Sopenharmony_ci .max_map_size = MAP_SIZE_128MB, .max_cs = 2}, 2078c2ecf20Sopenharmony_ci {.name = "FIU3", .fiu_id = FIU3, 2088c2ecf20Sopenharmony_ci .max_map_size = MAP_SIZE_128MB, .max_cs = 4}, 2098c2ecf20Sopenharmony_ci {.name = "FIUX", .fiu_id = FIUX, 2108c2ecf20Sopenharmony_ci .max_map_size = MAP_SIZE_16MB, .max_cs = 2} }; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic const struct fiu_data npxm7xx_fiu_data = { 2138c2ecf20Sopenharmony_ci .npcm_fiu_data_info = npxm7xx_fiu_info, 2148c2ecf20Sopenharmony_ci .fiu_max = 3, 2158c2ecf20Sopenharmony_ci}; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistruct npcm_fiu_spi; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistruct npcm_fiu_chip { 2208c2ecf20Sopenharmony_ci void __iomem *flash_region_mapped_ptr; 2218c2ecf20Sopenharmony_ci struct npcm_fiu_spi *fiu; 2228c2ecf20Sopenharmony_ci unsigned long clkrate; 2238c2ecf20Sopenharmony_ci u32 chipselect; 2248c2ecf20Sopenharmony_ci}; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistruct npcm_fiu_spi { 2278c2ecf20Sopenharmony_ci struct npcm_fiu_chip chip[NPCM_MAX_CHIP_NUM]; 2288c2ecf20Sopenharmony_ci const struct npcm_fiu_info *info; 2298c2ecf20Sopenharmony_ci struct spi_mem_op drd_op; 2308c2ecf20Sopenharmony_ci struct resource *res_mem; 2318c2ecf20Sopenharmony_ci struct regmap *regmap; 2328c2ecf20Sopenharmony_ci unsigned long clkrate; 2338c2ecf20Sopenharmony_ci struct device *dev; 2348c2ecf20Sopenharmony_ci struct clk *clk; 2358c2ecf20Sopenharmony_ci bool spix_mode; 2368c2ecf20Sopenharmony_ci}; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic const struct regmap_config npcm_mtd_regmap_config = { 2398c2ecf20Sopenharmony_ci .reg_bits = 32, 2408c2ecf20Sopenharmony_ci .val_bits = 32, 2418c2ecf20Sopenharmony_ci .reg_stride = 4, 2428c2ecf20Sopenharmony_ci .max_register = NPCM_FIU_MAX_REG_LIMIT, 2438c2ecf20Sopenharmony_ci}; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic void npcm_fiu_set_drd(struct npcm_fiu_spi *fiu, 2468c2ecf20Sopenharmony_ci const struct spi_mem_op *op) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG, 2498c2ecf20Sopenharmony_ci NPCM_FIU_DRD_CFG_ACCTYPE, 2508c2ecf20Sopenharmony_ci ilog2(op->addr.buswidth) << 2518c2ecf20Sopenharmony_ci NPCM_FIU_DRD_ACCTYPE_SHIFT); 2528c2ecf20Sopenharmony_ci fiu->drd_op.addr.buswidth = op->addr.buswidth; 2538c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG, 2548c2ecf20Sopenharmony_ci NPCM_FIU_DRD_CFG_DBW, 2558c2ecf20Sopenharmony_ci ((op->dummy.nbytes * ilog2(op->addr.buswidth)) / BITS_PER_BYTE) 2568c2ecf20Sopenharmony_ci << NPCM_FIU_DRD_DBW_SHIFT); 2578c2ecf20Sopenharmony_ci fiu->drd_op.dummy.nbytes = op->dummy.nbytes; 2588c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG, 2598c2ecf20Sopenharmony_ci NPCM_FIU_DRD_CFG_RDCMD, op->cmd.opcode); 2608c2ecf20Sopenharmony_ci fiu->drd_op.cmd.opcode = op->cmd.opcode; 2618c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG, 2628c2ecf20Sopenharmony_ci NPCM_FIU_DRD_CFG_ADDSIZ, 2638c2ecf20Sopenharmony_ci (op->addr.nbytes - 3) << NPCM_FIU_DRD_ADDSIZ_SHIFT); 2648c2ecf20Sopenharmony_ci fiu->drd_op.addr.nbytes = op->addr.nbytes; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic ssize_t npcm_fiu_direct_read(struct spi_mem_dirmap_desc *desc, 2688c2ecf20Sopenharmony_ci u64 offs, size_t len, void *buf) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci struct npcm_fiu_spi *fiu = 2718c2ecf20Sopenharmony_ci spi_controller_get_devdata(desc->mem->spi->master); 2728c2ecf20Sopenharmony_ci struct npcm_fiu_chip *chip = &fiu->chip[desc->mem->spi->chip_select]; 2738c2ecf20Sopenharmony_ci void __iomem *src = (void __iomem *)(chip->flash_region_mapped_ptr + 2748c2ecf20Sopenharmony_ci offs); 2758c2ecf20Sopenharmony_ci u8 *buf_rx = buf; 2768c2ecf20Sopenharmony_ci u32 i; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (fiu->spix_mode) { 2798c2ecf20Sopenharmony_ci for (i = 0 ; i < len ; i++) 2808c2ecf20Sopenharmony_ci *(buf_rx + i) = ioread8(src + i); 2818c2ecf20Sopenharmony_ci } else { 2828c2ecf20Sopenharmony_ci if (desc->info.op_tmpl.addr.buswidth != fiu->drd_op.addr.buswidth || 2838c2ecf20Sopenharmony_ci desc->info.op_tmpl.dummy.nbytes != fiu->drd_op.dummy.nbytes || 2848c2ecf20Sopenharmony_ci desc->info.op_tmpl.cmd.opcode != fiu->drd_op.cmd.opcode || 2858c2ecf20Sopenharmony_ci desc->info.op_tmpl.addr.nbytes != fiu->drd_op.addr.nbytes) 2868c2ecf20Sopenharmony_ci npcm_fiu_set_drd(fiu, &desc->info.op_tmpl); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci memcpy_fromio(buf_rx, src, len); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return len; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic ssize_t npcm_fiu_direct_write(struct spi_mem_dirmap_desc *desc, 2958c2ecf20Sopenharmony_ci u64 offs, size_t len, const void *buf) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct npcm_fiu_spi *fiu = 2988c2ecf20Sopenharmony_ci spi_controller_get_devdata(desc->mem->spi->master); 2998c2ecf20Sopenharmony_ci struct npcm_fiu_chip *chip = &fiu->chip[desc->mem->spi->chip_select]; 3008c2ecf20Sopenharmony_ci void __iomem *dst = (void __iomem *)(chip->flash_region_mapped_ptr + 3018c2ecf20Sopenharmony_ci offs); 3028c2ecf20Sopenharmony_ci const u8 *buf_tx = buf; 3038c2ecf20Sopenharmony_ci u32 i; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (fiu->spix_mode) 3068c2ecf20Sopenharmony_ci for (i = 0 ; i < len ; i++) 3078c2ecf20Sopenharmony_ci iowrite8(*(buf_tx + i), dst + i); 3088c2ecf20Sopenharmony_ci else 3098c2ecf20Sopenharmony_ci memcpy_toio(dst, buf_tx, len); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return len; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int npcm_fiu_uma_read(struct spi_mem *mem, 3158c2ecf20Sopenharmony_ci const struct spi_mem_op *op, u32 addr, 3168c2ecf20Sopenharmony_ci bool is_address_size, u8 *data, u32 data_size) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct npcm_fiu_spi *fiu = 3198c2ecf20Sopenharmony_ci spi_controller_get_devdata(mem->spi->master); 3208c2ecf20Sopenharmony_ci u32 uma_cfg = BIT(10); 3218c2ecf20Sopenharmony_ci u32 data_reg[4]; 3228c2ecf20Sopenharmony_ci int ret; 3238c2ecf20Sopenharmony_ci u32 val; 3248c2ecf20Sopenharmony_ci u32 i; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS, 3278c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CTS_DEV_NUM, 3288c2ecf20Sopenharmony_ci (mem->spi->chip_select << 3298c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT)); 3308c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CMD, 3318c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CMD_CMD, op->cmd.opcode); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (is_address_size) { 3348c2ecf20Sopenharmony_ci uma_cfg |= ilog2(op->cmd.buswidth); 3358c2ecf20Sopenharmony_ci uma_cfg |= ilog2(op->addr.buswidth) 3368c2ecf20Sopenharmony_ci << NPCM_FIU_UMA_CFG_ADBPCK_SHIFT; 3378c2ecf20Sopenharmony_ci if (op->dummy.nbytes) 3388c2ecf20Sopenharmony_ci uma_cfg |= ilog2(op->dummy.buswidth) 3398c2ecf20Sopenharmony_ci << NPCM_FIU_UMA_CFG_DBPCK_SHIFT; 3408c2ecf20Sopenharmony_ci uma_cfg |= ilog2(op->data.buswidth) 3418c2ecf20Sopenharmony_ci << NPCM_FIU_UMA_CFG_RDBPCK_SHIFT; 3428c2ecf20Sopenharmony_ci uma_cfg |= op->dummy.nbytes << NPCM_FIU_UMA_CFG_DBSIZ_SHIFT; 3438c2ecf20Sopenharmony_ci uma_cfg |= op->addr.nbytes << NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT; 3448c2ecf20Sopenharmony_ci regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, addr); 3458c2ecf20Sopenharmony_ci } else { 3468c2ecf20Sopenharmony_ci regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, 0x0); 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci uma_cfg |= data_size << NPCM_FIU_UMA_CFG_RDATSIZ_SHIFT; 3508c2ecf20Sopenharmony_ci regmap_write(fiu->regmap, NPCM_FIU_UMA_CFG, uma_cfg); 3518c2ecf20Sopenharmony_ci regmap_write_bits(fiu->regmap, NPCM_FIU_UMA_CTS, 3528c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CTS_EXEC_DONE, 3538c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CTS_EXEC_DONE); 3548c2ecf20Sopenharmony_ci ret = regmap_read_poll_timeout(fiu->regmap, NPCM_FIU_UMA_CTS, val, 3558c2ecf20Sopenharmony_ci (!(val & NPCM_FIU_UMA_CTS_EXEC_DONE)), 0, 3568c2ecf20Sopenharmony_ci UMA_MICRO_SEC_TIMEOUT); 3578c2ecf20Sopenharmony_ci if (ret) 3588c2ecf20Sopenharmony_ci return ret; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (data_size) { 3618c2ecf20Sopenharmony_ci for (i = 0; i < DIV_ROUND_UP(data_size, 4); i++) 3628c2ecf20Sopenharmony_ci regmap_read(fiu->regmap, NPCM_FIU_UMA_DR0 + (i * 4), 3638c2ecf20Sopenharmony_ci &data_reg[i]); 3648c2ecf20Sopenharmony_ci memcpy(data, data_reg, data_size); 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int npcm_fiu_uma_write(struct spi_mem *mem, 3718c2ecf20Sopenharmony_ci const struct spi_mem_op *op, u8 cmd, 3728c2ecf20Sopenharmony_ci bool is_address_size, u8 *data, u32 data_size) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct npcm_fiu_spi *fiu = 3758c2ecf20Sopenharmony_ci spi_controller_get_devdata(mem->spi->master); 3768c2ecf20Sopenharmony_ci u32 uma_cfg = BIT(10); 3778c2ecf20Sopenharmony_ci u32 data_reg[4] = {0}; 3788c2ecf20Sopenharmony_ci u32 val; 3798c2ecf20Sopenharmony_ci u32 i; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS, 3828c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CTS_DEV_NUM, 3838c2ecf20Sopenharmony_ci (mem->spi->chip_select << 3848c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT)); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CMD, 3878c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CMD_CMD, cmd); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (data_size) { 3908c2ecf20Sopenharmony_ci memcpy(data_reg, data, data_size); 3918c2ecf20Sopenharmony_ci for (i = 0; i < DIV_ROUND_UP(data_size, 4); i++) 3928c2ecf20Sopenharmony_ci regmap_write(fiu->regmap, NPCM_FIU_UMA_DW0 + (i * 4), 3938c2ecf20Sopenharmony_ci data_reg[i]); 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (is_address_size) { 3978c2ecf20Sopenharmony_ci uma_cfg |= ilog2(op->cmd.buswidth); 3988c2ecf20Sopenharmony_ci uma_cfg |= ilog2(op->addr.buswidth) << 3998c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CFG_ADBPCK_SHIFT; 4008c2ecf20Sopenharmony_ci uma_cfg |= ilog2(op->data.buswidth) << 4018c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CFG_WDBPCK_SHIFT; 4028c2ecf20Sopenharmony_ci uma_cfg |= op->addr.nbytes << NPCM_FIU_UMA_CFG_ADDSIZ_SHIFT; 4038c2ecf20Sopenharmony_ci regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, op->addr.val); 4048c2ecf20Sopenharmony_ci } else { 4058c2ecf20Sopenharmony_ci regmap_write(fiu->regmap, NPCM_FIU_UMA_ADDR, 0x0); 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci uma_cfg |= (data_size << NPCM_FIU_UMA_CFG_WDATSIZ_SHIFT); 4098c2ecf20Sopenharmony_ci regmap_write(fiu->regmap, NPCM_FIU_UMA_CFG, uma_cfg); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci regmap_write_bits(fiu->regmap, NPCM_FIU_UMA_CTS, 4128c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CTS_EXEC_DONE, 4138c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CTS_EXEC_DONE); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci return regmap_read_poll_timeout(fiu->regmap, NPCM_FIU_UMA_CTS, val, 4168c2ecf20Sopenharmony_ci (!(val & NPCM_FIU_UMA_CTS_EXEC_DONE)), 0, 4178c2ecf20Sopenharmony_ci UMA_MICRO_SEC_TIMEOUT); 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic int npcm_fiu_manualwrite(struct spi_mem *mem, 4218c2ecf20Sopenharmony_ci const struct spi_mem_op *op) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci struct npcm_fiu_spi *fiu = 4248c2ecf20Sopenharmony_ci spi_controller_get_devdata(mem->spi->master); 4258c2ecf20Sopenharmony_ci u8 *data = (u8 *)op->data.buf.out; 4268c2ecf20Sopenharmony_ci u32 num_data_chunks; 4278c2ecf20Sopenharmony_ci u32 remain_data; 4288c2ecf20Sopenharmony_ci u32 idx = 0; 4298c2ecf20Sopenharmony_ci int ret; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci num_data_chunks = op->data.nbytes / CHUNK_SIZE; 4328c2ecf20Sopenharmony_ci remain_data = op->data.nbytes % CHUNK_SIZE; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS, 4358c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CTS_DEV_NUM, 4368c2ecf20Sopenharmony_ci (mem->spi->chip_select << 4378c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT)); 4388c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS, 4398c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CTS_SW_CS, 0); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, true, NULL, 0); 4428c2ecf20Sopenharmony_ci if (ret) 4438c2ecf20Sopenharmony_ci return ret; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* Starting the data writing loop in multiples of 8 */ 4468c2ecf20Sopenharmony_ci for (idx = 0; idx < num_data_chunks; ++idx) { 4478c2ecf20Sopenharmony_ci ret = npcm_fiu_uma_write(mem, op, data[0], false, 4488c2ecf20Sopenharmony_ci &data[1], CHUNK_SIZE - 1); 4498c2ecf20Sopenharmony_ci if (ret) 4508c2ecf20Sopenharmony_ci return ret; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci data += CHUNK_SIZE; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci /* Handling chunk remains */ 4568c2ecf20Sopenharmony_ci if (remain_data > 0) { 4578c2ecf20Sopenharmony_ci ret = npcm_fiu_uma_write(mem, op, data[0], false, 4588c2ecf20Sopenharmony_ci &data[1], remain_data - 1); 4598c2ecf20Sopenharmony_ci if (ret) 4608c2ecf20Sopenharmony_ci return ret; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CTS, 4648c2ecf20Sopenharmony_ci NPCM_FIU_UMA_CTS_SW_CS, NPCM_FIU_UMA_CTS_SW_CS); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci return 0; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic int npcm_fiu_read(struct spi_mem *mem, const struct spi_mem_op *op) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci u8 *data = op->data.buf.in; 4728c2ecf20Sopenharmony_ci int i, readlen, currlen; 4738c2ecf20Sopenharmony_ci u8 *buf_ptr; 4748c2ecf20Sopenharmony_ci u32 addr; 4758c2ecf20Sopenharmony_ci int ret; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci i = 0; 4788c2ecf20Sopenharmony_ci currlen = op->data.nbytes; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci do { 4818c2ecf20Sopenharmony_ci addr = ((u32)op->addr.val + i); 4828c2ecf20Sopenharmony_ci if (currlen < 16) 4838c2ecf20Sopenharmony_ci readlen = currlen; 4848c2ecf20Sopenharmony_ci else 4858c2ecf20Sopenharmony_ci readlen = 16; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci buf_ptr = data + i; 4888c2ecf20Sopenharmony_ci ret = npcm_fiu_uma_read(mem, op, addr, true, buf_ptr, 4898c2ecf20Sopenharmony_ci readlen); 4908c2ecf20Sopenharmony_ci if (ret) 4918c2ecf20Sopenharmony_ci return ret; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci i += readlen; 4948c2ecf20Sopenharmony_ci currlen -= 16; 4958c2ecf20Sopenharmony_ci } while (currlen > 0); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return 0; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic void npcm_fiux_set_direct_wr(struct npcm_fiu_spi *fiu) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci regmap_write(fiu->regmap, NPCM_FIU_DWR_CFG, 5038c2ecf20Sopenharmony_ci NPCM_FIU_DWR_16_BYTE_BURST); 5048c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_DWR_CFG, 5058c2ecf20Sopenharmony_ci NPCM_FIU_DWR_CFG_ABPCK, 5068c2ecf20Sopenharmony_ci DWR_ABPCK_4_BIT_PER_CLK << NPCM_FIU_DWR_ABPCK_SHIFT); 5078c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_DWR_CFG, 5088c2ecf20Sopenharmony_ci NPCM_FIU_DWR_CFG_DBPCK, 5098c2ecf20Sopenharmony_ci DWR_DBPCK_4_BIT_PER_CLK << NPCM_FIU_DWR_DBPCK_SHIFT); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic void npcm_fiux_set_direct_rd(struct npcm_fiu_spi *fiu) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci u32 rx_dummy = 0; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci regmap_write(fiu->regmap, NPCM_FIU_DRD_CFG, 5178c2ecf20Sopenharmony_ci NPCM_FIU_DRD_16_BYTE_BURST); 5188c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG, 5198c2ecf20Sopenharmony_ci NPCM_FIU_DRD_CFG_ACCTYPE, 5208c2ecf20Sopenharmony_ci DRD_SPI_X_MODE << NPCM_FIU_DRD_ACCTYPE_SHIFT); 5218c2ecf20Sopenharmony_ci regmap_update_bits(fiu->regmap, NPCM_FIU_DRD_CFG, 5228c2ecf20Sopenharmony_ci NPCM_FIU_DRD_CFG_DBW, 5238c2ecf20Sopenharmony_ci rx_dummy << NPCM_FIU_DRD_DBW_SHIFT); 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic int npcm_fiu_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct npcm_fiu_spi *fiu = 5298c2ecf20Sopenharmony_ci spi_controller_get_devdata(mem->spi->master); 5308c2ecf20Sopenharmony_ci struct npcm_fiu_chip *chip = &fiu->chip[mem->spi->chip_select]; 5318c2ecf20Sopenharmony_ci int ret = 0; 5328c2ecf20Sopenharmony_ci u8 *buf; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci dev_dbg(fiu->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n", 5358c2ecf20Sopenharmony_ci op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, 5368c2ecf20Sopenharmony_ci op->dummy.buswidth, op->data.buswidth, op->addr.val, 5378c2ecf20Sopenharmony_ci op->data.nbytes); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (fiu->spix_mode || op->addr.nbytes > 4) 5408c2ecf20Sopenharmony_ci return -ENOTSUPP; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (fiu->clkrate != chip->clkrate) { 5438c2ecf20Sopenharmony_ci ret = clk_set_rate(fiu->clk, chip->clkrate); 5448c2ecf20Sopenharmony_ci if (ret < 0) 5458c2ecf20Sopenharmony_ci dev_warn(fiu->dev, "Failed setting %lu frequency, stay at %lu frequency\n", 5468c2ecf20Sopenharmony_ci chip->clkrate, fiu->clkrate); 5478c2ecf20Sopenharmony_ci else 5488c2ecf20Sopenharmony_ci fiu->clkrate = chip->clkrate; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (op->data.dir == SPI_MEM_DATA_IN) { 5528c2ecf20Sopenharmony_ci if (!op->addr.nbytes) { 5538c2ecf20Sopenharmony_ci buf = op->data.buf.in; 5548c2ecf20Sopenharmony_ci ret = npcm_fiu_uma_read(mem, op, op->addr.val, false, 5558c2ecf20Sopenharmony_ci buf, op->data.nbytes); 5568c2ecf20Sopenharmony_ci } else { 5578c2ecf20Sopenharmony_ci ret = npcm_fiu_read(mem, op); 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci } else { 5608c2ecf20Sopenharmony_ci if (!op->addr.nbytes && !op->data.nbytes) 5618c2ecf20Sopenharmony_ci ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false, 5628c2ecf20Sopenharmony_ci NULL, 0); 5638c2ecf20Sopenharmony_ci if (op->addr.nbytes && !op->data.nbytes) { 5648c2ecf20Sopenharmony_ci int i; 5658c2ecf20Sopenharmony_ci u8 buf_addr[4]; 5668c2ecf20Sopenharmony_ci u32 addr = op->addr.val; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci for (i = op->addr.nbytes - 1; i >= 0; i--) { 5698c2ecf20Sopenharmony_ci buf_addr[i] = addr & 0xff; 5708c2ecf20Sopenharmony_ci addr >>= 8; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false, 5738c2ecf20Sopenharmony_ci buf_addr, op->addr.nbytes); 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci if (!op->addr.nbytes && op->data.nbytes) 5768c2ecf20Sopenharmony_ci ret = npcm_fiu_uma_write(mem, op, op->cmd.opcode, false, 5778c2ecf20Sopenharmony_ci (u8 *)op->data.buf.out, 5788c2ecf20Sopenharmony_ci op->data.nbytes); 5798c2ecf20Sopenharmony_ci if (op->addr.nbytes && op->data.nbytes) 5808c2ecf20Sopenharmony_ci ret = npcm_fiu_manualwrite(mem, op); 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return ret; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic int npcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct npcm_fiu_spi *fiu = 5898c2ecf20Sopenharmony_ci spi_controller_get_devdata(desc->mem->spi->master); 5908c2ecf20Sopenharmony_ci struct npcm_fiu_chip *chip = &fiu->chip[desc->mem->spi->chip_select]; 5918c2ecf20Sopenharmony_ci struct regmap *gcr_regmap; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (!fiu->res_mem) { 5948c2ecf20Sopenharmony_ci dev_warn(fiu->dev, "Reserved memory not defined, direct read disabled\n"); 5958c2ecf20Sopenharmony_ci desc->nodirmap = true; 5968c2ecf20Sopenharmony_ci return 0; 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (!fiu->spix_mode && 6008c2ecf20Sopenharmony_ci desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) { 6018c2ecf20Sopenharmony_ci desc->nodirmap = true; 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (!chip->flash_region_mapped_ptr) { 6068c2ecf20Sopenharmony_ci chip->flash_region_mapped_ptr = 6078c2ecf20Sopenharmony_ci devm_ioremap(fiu->dev, (fiu->res_mem->start + 6088c2ecf20Sopenharmony_ci (fiu->info->max_map_size * 6098c2ecf20Sopenharmony_ci desc->mem->spi->chip_select)), 6108c2ecf20Sopenharmony_ci (u32)desc->info.length); 6118c2ecf20Sopenharmony_ci if (!chip->flash_region_mapped_ptr) { 6128c2ecf20Sopenharmony_ci dev_warn(fiu->dev, "Error mapping memory region, direct read disabled\n"); 6138c2ecf20Sopenharmony_ci desc->nodirmap = true; 6148c2ecf20Sopenharmony_ci return 0; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (of_device_is_compatible(fiu->dev->of_node, "nuvoton,npcm750-fiu")) { 6198c2ecf20Sopenharmony_ci gcr_regmap = 6208c2ecf20Sopenharmony_ci syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr"); 6218c2ecf20Sopenharmony_ci if (IS_ERR(gcr_regmap)) { 6228c2ecf20Sopenharmony_ci dev_warn(fiu->dev, "Didn't find nuvoton,npcm750-gcr, direct read disabled\n"); 6238c2ecf20Sopenharmony_ci desc->nodirmap = true; 6248c2ecf20Sopenharmony_ci return 0; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci regmap_update_bits(gcr_regmap, NPCM7XX_INTCR3_OFFSET, 6278c2ecf20Sopenharmony_ci NPCM7XX_INTCR3_FIU_FIX, 6288c2ecf20Sopenharmony_ci NPCM7XX_INTCR3_FIU_FIX); 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) { 6328c2ecf20Sopenharmony_ci if (!fiu->spix_mode) 6338c2ecf20Sopenharmony_ci npcm_fiu_set_drd(fiu, &desc->info.op_tmpl); 6348c2ecf20Sopenharmony_ci else 6358c2ecf20Sopenharmony_ci npcm_fiux_set_direct_rd(fiu); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci } else { 6388c2ecf20Sopenharmony_ci npcm_fiux_set_direct_wr(fiu); 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic int npcm_fiu_setup(struct spi_device *spi) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci struct spi_controller *ctrl = spi->master; 6478c2ecf20Sopenharmony_ci struct npcm_fiu_spi *fiu = spi_controller_get_devdata(ctrl); 6488c2ecf20Sopenharmony_ci struct npcm_fiu_chip *chip; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci chip = &fiu->chip[spi->chip_select]; 6518c2ecf20Sopenharmony_ci chip->fiu = fiu; 6528c2ecf20Sopenharmony_ci chip->chipselect = spi->chip_select; 6538c2ecf20Sopenharmony_ci chip->clkrate = spi->max_speed_hz; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci fiu->clkrate = clk_get_rate(fiu->clk); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci return 0; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic const struct spi_controller_mem_ops npcm_fiu_mem_ops = { 6618c2ecf20Sopenharmony_ci .exec_op = npcm_fiu_exec_op, 6628c2ecf20Sopenharmony_ci .dirmap_create = npcm_fiu_dirmap_create, 6638c2ecf20Sopenharmony_ci .dirmap_read = npcm_fiu_direct_read, 6648c2ecf20Sopenharmony_ci .dirmap_write = npcm_fiu_direct_write, 6658c2ecf20Sopenharmony_ci}; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic const struct of_device_id npcm_fiu_dt_ids[] = { 6688c2ecf20Sopenharmony_ci { .compatible = "nuvoton,npcm750-fiu", .data = &npxm7xx_fiu_data }, 6698c2ecf20Sopenharmony_ci { /* sentinel */ } 6708c2ecf20Sopenharmony_ci}; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic int npcm_fiu_probe(struct platform_device *pdev) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci const struct fiu_data *fiu_data_match; 6758c2ecf20Sopenharmony_ci const struct of_device_id *match; 6768c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 6778c2ecf20Sopenharmony_ci struct spi_controller *ctrl; 6788c2ecf20Sopenharmony_ci struct npcm_fiu_spi *fiu; 6798c2ecf20Sopenharmony_ci void __iomem *regbase; 6808c2ecf20Sopenharmony_ci struct resource *res; 6818c2ecf20Sopenharmony_ci int id, ret; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci ctrl = devm_spi_alloc_master(dev, sizeof(*fiu)); 6848c2ecf20Sopenharmony_ci if (!ctrl) 6858c2ecf20Sopenharmony_ci return -ENOMEM; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci fiu = spi_controller_get_devdata(ctrl); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci match = of_match_device(npcm_fiu_dt_ids, dev); 6908c2ecf20Sopenharmony_ci if (!match || !match->data) { 6918c2ecf20Sopenharmony_ci dev_err(dev, "No compatible OF match\n"); 6928c2ecf20Sopenharmony_ci return -ENODEV; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci fiu_data_match = match->data; 6968c2ecf20Sopenharmony_ci id = of_alias_get_id(dev->of_node, "fiu"); 6978c2ecf20Sopenharmony_ci if (id < 0 || id >= fiu_data_match->fiu_max) { 6988c2ecf20Sopenharmony_ci dev_err(dev, "Invalid platform device id: %d\n", id); 6998c2ecf20Sopenharmony_ci return -EINVAL; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci fiu->info = &fiu_data_match->npcm_fiu_data_info[id]; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, fiu); 7058c2ecf20Sopenharmony_ci fiu->dev = dev; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control"); 7088c2ecf20Sopenharmony_ci regbase = devm_ioremap_resource(dev, res); 7098c2ecf20Sopenharmony_ci if (IS_ERR(regbase)) 7108c2ecf20Sopenharmony_ci return PTR_ERR(regbase); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci fiu->regmap = devm_regmap_init_mmio(dev, regbase, 7138c2ecf20Sopenharmony_ci &npcm_mtd_regmap_config); 7148c2ecf20Sopenharmony_ci if (IS_ERR(fiu->regmap)) { 7158c2ecf20Sopenharmony_ci dev_err(dev, "Failed to create regmap\n"); 7168c2ecf20Sopenharmony_ci return PTR_ERR(fiu->regmap); 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci fiu->res_mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, 7208c2ecf20Sopenharmony_ci "memory"); 7218c2ecf20Sopenharmony_ci fiu->clk = devm_clk_get(dev, NULL); 7228c2ecf20Sopenharmony_ci if (IS_ERR(fiu->clk)) 7238c2ecf20Sopenharmony_ci return PTR_ERR(fiu->clk); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci fiu->spix_mode = of_property_read_bool(dev->of_node, 7268c2ecf20Sopenharmony_ci "nuvoton,spix-mode"); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, fiu); 7298c2ecf20Sopenharmony_ci clk_prepare_enable(fiu->clk); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD 7328c2ecf20Sopenharmony_ci | SPI_TX_DUAL | SPI_TX_QUAD; 7338c2ecf20Sopenharmony_ci ctrl->setup = npcm_fiu_setup; 7348c2ecf20Sopenharmony_ci ctrl->bus_num = -1; 7358c2ecf20Sopenharmony_ci ctrl->mem_ops = &npcm_fiu_mem_ops; 7368c2ecf20Sopenharmony_ci ctrl->num_chipselect = fiu->info->max_cs; 7378c2ecf20Sopenharmony_ci ctrl->dev.of_node = dev->of_node; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci ret = devm_spi_register_master(dev, ctrl); 7408c2ecf20Sopenharmony_ci if (ret) 7418c2ecf20Sopenharmony_ci clk_disable_unprepare(fiu->clk); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci return ret; 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_cistatic int npcm_fiu_remove(struct platform_device *pdev) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci struct npcm_fiu_spi *fiu = platform_get_drvdata(pdev); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci clk_disable_unprepare(fiu->clk); 7518c2ecf20Sopenharmony_ci return 0; 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, npcm_fiu_dt_ids); 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic struct platform_driver npcm_fiu_driver = { 7578c2ecf20Sopenharmony_ci .driver = { 7588c2ecf20Sopenharmony_ci .name = "NPCM-FIU", 7598c2ecf20Sopenharmony_ci .bus = &platform_bus_type, 7608c2ecf20Sopenharmony_ci .of_match_table = npcm_fiu_dt_ids, 7618c2ecf20Sopenharmony_ci }, 7628c2ecf20Sopenharmony_ci .probe = npcm_fiu_probe, 7638c2ecf20Sopenharmony_ci .remove = npcm_fiu_remove, 7648c2ecf20Sopenharmony_ci}; 7658c2ecf20Sopenharmony_cimodule_platform_driver(npcm_fiu_driver); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Nuvoton FLASH Interface Unit SPI Controller Driver"); 7688c2ecf20Sopenharmony_ciMODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>"); 7698c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 770