1fee10bd2SNaga Sureshkumar Relli // SPDX-License-Identifier: GPL-2.0 2fee10bd2SNaga Sureshkumar Relli /* 3fee10bd2SNaga Sureshkumar Relli * ARM PL353 SMC driver 4fee10bd2SNaga Sureshkumar Relli * 5fee10bd2SNaga Sureshkumar Relli * Copyright (C) 2012 - 2018 Xilinx, Inc 6fee10bd2SNaga Sureshkumar Relli * Author: Punnaiah Choudary Kalluri <punnaiah@xilinx.com> 7fee10bd2SNaga Sureshkumar Relli * Author: Naga Sureshkumar Relli <nagasure@xilinx.com> 8fee10bd2SNaga Sureshkumar Relli */ 9fee10bd2SNaga Sureshkumar Relli 10fee10bd2SNaga Sureshkumar Relli #include <linux/clk.h> 11fee10bd2SNaga Sureshkumar Relli #include <linux/io.h> 12fee10bd2SNaga Sureshkumar Relli #include <linux/kernel.h> 13fee10bd2SNaga Sureshkumar Relli #include <linux/module.h> 14fee10bd2SNaga Sureshkumar Relli #include <linux/of_platform.h> 15fee10bd2SNaga Sureshkumar Relli #include <linux/platform_device.h> 16fee10bd2SNaga Sureshkumar Relli #include <linux/slab.h> 17fee10bd2SNaga Sureshkumar Relli #include <linux/pl353-smc.h> 18fee10bd2SNaga Sureshkumar Relli #include <linux/amba/bus.h> 19fee10bd2SNaga Sureshkumar Relli 20fee10bd2SNaga Sureshkumar Relli /* Register definitions */ 21fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_MEMC_STATUS_OFFS 0 /* Controller status reg, RO */ 22fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_CFG_CLR_OFFS 0xC /* Clear config reg, WO */ 23fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_DIRECT_CMD_OFFS 0x10 /* Direct command reg, WO */ 24fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_OFFS 0x14 /* Set cycles register, WO */ 25fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_OPMODE_OFFS 0x18 /* Set opmode register, WO */ 26fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_STATUS_OFFS 0x400 /* ECC status register */ 27fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_MEMCFG_OFFS 0x404 /* ECC mem config reg */ 28fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_MEMCMD1_OFFS 0x408 /* ECC mem cmd1 reg */ 29fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_MEMCMD2_OFFS 0x40C /* ECC mem cmd2 reg */ 30fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_VALUE0_OFFS 0x418 /* ECC value 0 reg */ 31fee10bd2SNaga Sureshkumar Relli 32fee10bd2SNaga Sureshkumar Relli /* Controller status register specific constants */ 33fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_MEMC_STATUS_RAW_INT_1_SHIFT 6 34fee10bd2SNaga Sureshkumar Relli 35fee10bd2SNaga Sureshkumar Relli /* Clear configuration register specific constants */ 36fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_CFG_CLR_INT_CLR_1 0x10 37fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_CFG_CLR_ECC_INT_DIS_1 0x40 38fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_CFG_CLR_INT_DIS_1 0x2 39fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_CFG_CLR_DEFAULT_MASK (PL353_SMC_CFG_CLR_INT_CLR_1 | \ 40fee10bd2SNaga Sureshkumar Relli PL353_SMC_CFG_CLR_ECC_INT_DIS_1 | \ 41fee10bd2SNaga Sureshkumar Relli PL353_SMC_CFG_CLR_INT_DIS_1) 42fee10bd2SNaga Sureshkumar Relli 43fee10bd2SNaga Sureshkumar Relli /* Set cycles register specific constants */ 44fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T0_MASK 0xF 45fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T0_SHIFT 0 46fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T1_MASK 0xF 47fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T1_SHIFT 4 48fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T2_MASK 0x7 49fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T2_SHIFT 8 50fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T3_MASK 0x7 51fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T3_SHIFT 11 52fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T4_MASK 0x7 53fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T4_SHIFT 14 54fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T5_MASK 0x7 55fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T5_SHIFT 17 56fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T6_MASK 0xF 57fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_SET_CYCLES_T6_SHIFT 20 58fee10bd2SNaga Sureshkumar Relli 59fee10bd2SNaga Sureshkumar Relli /* ECC status register specific constants */ 60fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_STATUS_BUSY BIT(6) 61fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_REG_SIZE_OFFS 4 62fee10bd2SNaga Sureshkumar Relli 63fee10bd2SNaga Sureshkumar Relli /* ECC memory config register specific constants */ 64fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_MEMCFG_MODE_MASK 0xC 65fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_ECC_MEMCFG_MODE_SHIFT 2 6625dcca7fSgexueyuan #define PL353_SMC_ECC_MEMCFG_PGSIZE_MASK 0x3 67fee10bd2SNaga Sureshkumar Relli 68fee10bd2SNaga Sureshkumar Relli #define PL353_SMC_DC_UPT_NAND_REGS ((4 << 23) | /* CS: NAND chip */ \ 69fee10bd2SNaga Sureshkumar Relli (2 << 21)) /* UpdateRegs operation */ 70fee10bd2SNaga Sureshkumar Relli 71fee10bd2SNaga Sureshkumar Relli #define PL353_NAND_ECC_CMD1 ((0x80) | /* Write command */ \ 72fee10bd2SNaga Sureshkumar Relli (0 << 8) | /* Read command */ \ 73fee10bd2SNaga Sureshkumar Relli (0x30 << 16) | /* Read End command */ \ 74fee10bd2SNaga Sureshkumar Relli (1 << 24)) /* Read End command calid */ 75fee10bd2SNaga Sureshkumar Relli 76fee10bd2SNaga Sureshkumar Relli #define PL353_NAND_ECC_CMD2 ((0x85) | /* Write col change cmd */ \ 77fee10bd2SNaga Sureshkumar Relli (5 << 8) | /* Read col change cmd */ \ 78fee10bd2SNaga Sureshkumar Relli (0xE0 << 16) | /* Read col change end cmd */ \ 79fee10bd2SNaga Sureshkumar Relli (1 << 24)) /* Read col change end cmd valid */ 80fee10bd2SNaga Sureshkumar Relli #define PL353_NAND_ECC_BUSY_TIMEOUT (1 * HZ) 81fee10bd2SNaga Sureshkumar Relli /** 82fee10bd2SNaga Sureshkumar Relli * struct pl353_smc_data - Private smc driver structure 83fee10bd2SNaga Sureshkumar Relli * @memclk: Pointer to the peripheral clock 84fee10bd2SNaga Sureshkumar Relli * @aclk: Pointer to the APER clock 85fee10bd2SNaga Sureshkumar Relli */ 86fee10bd2SNaga Sureshkumar Relli struct pl353_smc_data { 87fee10bd2SNaga Sureshkumar Relli struct clk *memclk; 88fee10bd2SNaga Sureshkumar Relli struct clk *aclk; 89fee10bd2SNaga Sureshkumar Relli }; 90fee10bd2SNaga Sureshkumar Relli 91fee10bd2SNaga Sureshkumar Relli /* SMC virtual register base */ 92fee10bd2SNaga Sureshkumar Relli static void __iomem *pl353_smc_base; 93fee10bd2SNaga Sureshkumar Relli 94fee10bd2SNaga Sureshkumar Relli /** 95fee10bd2SNaga Sureshkumar Relli * pl353_smc_set_buswidth - Set memory buswidth 96fee10bd2SNaga Sureshkumar Relli * @bw: Memory buswidth (8 | 16) 97fee10bd2SNaga Sureshkumar Relli * Return: 0 on success or negative errno. 98fee10bd2SNaga Sureshkumar Relli */ 99fee10bd2SNaga Sureshkumar Relli int pl353_smc_set_buswidth(unsigned int bw) 100fee10bd2SNaga Sureshkumar Relli { 101fee10bd2SNaga Sureshkumar Relli if (bw != PL353_SMC_MEM_WIDTH_8 && bw != PL353_SMC_MEM_WIDTH_16) 102fee10bd2SNaga Sureshkumar Relli return -EINVAL; 103fee10bd2SNaga Sureshkumar Relli 104fee10bd2SNaga Sureshkumar Relli writel(bw, pl353_smc_base + PL353_SMC_SET_OPMODE_OFFS); 105fee10bd2SNaga Sureshkumar Relli writel(PL353_SMC_DC_UPT_NAND_REGS, pl353_smc_base + 106fee10bd2SNaga Sureshkumar Relli PL353_SMC_DIRECT_CMD_OFFS); 107fee10bd2SNaga Sureshkumar Relli 108fee10bd2SNaga Sureshkumar Relli return 0; 109fee10bd2SNaga Sureshkumar Relli } 110fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_set_buswidth); 111fee10bd2SNaga Sureshkumar Relli 112fee10bd2SNaga Sureshkumar Relli /** 113fee10bd2SNaga Sureshkumar Relli * pl353_smc_set_cycles - Set memory timing parameters 114fee10bd2SNaga Sureshkumar Relli * @timings: NAND controller timing parameters 115fee10bd2SNaga Sureshkumar Relli * 116fee10bd2SNaga Sureshkumar Relli * Sets NAND chip specific timing parameters. 117fee10bd2SNaga Sureshkumar Relli */ 118fee10bd2SNaga Sureshkumar Relli void pl353_smc_set_cycles(u32 timings[]) 119fee10bd2SNaga Sureshkumar Relli { 120fee10bd2SNaga Sureshkumar Relli /* 121fee10bd2SNaga Sureshkumar Relli * Set write pulse timing. This one is easy to extract: 122fee10bd2SNaga Sureshkumar Relli * 123fee10bd2SNaga Sureshkumar Relli * NWE_PULSE = tWP 124fee10bd2SNaga Sureshkumar Relli */ 125fee10bd2SNaga Sureshkumar Relli timings[0] &= PL353_SMC_SET_CYCLES_T0_MASK; 126fee10bd2SNaga Sureshkumar Relli timings[1] = (timings[1] & PL353_SMC_SET_CYCLES_T1_MASK) << 127fee10bd2SNaga Sureshkumar Relli PL353_SMC_SET_CYCLES_T1_SHIFT; 128fee10bd2SNaga Sureshkumar Relli timings[2] = (timings[2] & PL353_SMC_SET_CYCLES_T2_MASK) << 129fee10bd2SNaga Sureshkumar Relli PL353_SMC_SET_CYCLES_T2_SHIFT; 130fee10bd2SNaga Sureshkumar Relli timings[3] = (timings[3] & PL353_SMC_SET_CYCLES_T3_MASK) << 131fee10bd2SNaga Sureshkumar Relli PL353_SMC_SET_CYCLES_T3_SHIFT; 132fee10bd2SNaga Sureshkumar Relli timings[4] = (timings[4] & PL353_SMC_SET_CYCLES_T4_MASK) << 133fee10bd2SNaga Sureshkumar Relli PL353_SMC_SET_CYCLES_T4_SHIFT; 134fee10bd2SNaga Sureshkumar Relli timings[5] = (timings[5] & PL353_SMC_SET_CYCLES_T5_MASK) << 135fee10bd2SNaga Sureshkumar Relli PL353_SMC_SET_CYCLES_T5_SHIFT; 136fee10bd2SNaga Sureshkumar Relli timings[6] = (timings[6] & PL353_SMC_SET_CYCLES_T6_MASK) << 137fee10bd2SNaga Sureshkumar Relli PL353_SMC_SET_CYCLES_T6_SHIFT; 138fee10bd2SNaga Sureshkumar Relli timings[0] |= timings[1] | timings[2] | timings[3] | 139fee10bd2SNaga Sureshkumar Relli timings[4] | timings[5] | timings[6]; 140fee10bd2SNaga Sureshkumar Relli 141fee10bd2SNaga Sureshkumar Relli writel(timings[0], pl353_smc_base + PL353_SMC_SET_CYCLES_OFFS); 142fee10bd2SNaga Sureshkumar Relli writel(PL353_SMC_DC_UPT_NAND_REGS, pl353_smc_base + 143fee10bd2SNaga Sureshkumar Relli PL353_SMC_DIRECT_CMD_OFFS); 144fee10bd2SNaga Sureshkumar Relli } 145fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_set_cycles); 146fee10bd2SNaga Sureshkumar Relli 147fee10bd2SNaga Sureshkumar Relli /** 148fee10bd2SNaga Sureshkumar Relli * pl353_smc_ecc_is_busy - Read ecc busy flag 149fee10bd2SNaga Sureshkumar Relli * Return: the ecc_status bit from the ecc_status register. 1 = busy, 0 = idle 150fee10bd2SNaga Sureshkumar Relli */ 151fee10bd2SNaga Sureshkumar Relli bool pl353_smc_ecc_is_busy(void) 152fee10bd2SNaga Sureshkumar Relli { 153fee10bd2SNaga Sureshkumar Relli return ((readl(pl353_smc_base + PL353_SMC_ECC_STATUS_OFFS) & 154fee10bd2SNaga Sureshkumar Relli PL353_SMC_ECC_STATUS_BUSY) == PL353_SMC_ECC_STATUS_BUSY); 155fee10bd2SNaga Sureshkumar Relli } 156fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_ecc_is_busy); 157fee10bd2SNaga Sureshkumar Relli 158fee10bd2SNaga Sureshkumar Relli /** 159fee10bd2SNaga Sureshkumar Relli * pl353_smc_get_ecc_val - Read ecc_valueN registers 160fee10bd2SNaga Sureshkumar Relli * @ecc_reg: Index of the ecc_value reg (0..3) 161fee10bd2SNaga Sureshkumar Relli * Return: the content of the requested ecc_value register. 162fee10bd2SNaga Sureshkumar Relli * 163fee10bd2SNaga Sureshkumar Relli * There are four valid ecc_value registers. The argument is truncated to stay 164fee10bd2SNaga Sureshkumar Relli * within this valid boundary. 165fee10bd2SNaga Sureshkumar Relli */ 166fee10bd2SNaga Sureshkumar Relli u32 pl353_smc_get_ecc_val(int ecc_reg) 167fee10bd2SNaga Sureshkumar Relli { 168fee10bd2SNaga Sureshkumar Relli u32 addr, reg; 169fee10bd2SNaga Sureshkumar Relli 170fee10bd2SNaga Sureshkumar Relli addr = PL353_SMC_ECC_VALUE0_OFFS + 171fee10bd2SNaga Sureshkumar Relli (ecc_reg * PL353_SMC_ECC_REG_SIZE_OFFS); 172fee10bd2SNaga Sureshkumar Relli reg = readl(pl353_smc_base + addr); 173fee10bd2SNaga Sureshkumar Relli 174fee10bd2SNaga Sureshkumar Relli return reg; 175fee10bd2SNaga Sureshkumar Relli } 176fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_get_ecc_val); 177fee10bd2SNaga Sureshkumar Relli 178fee10bd2SNaga Sureshkumar Relli /** 179fee10bd2SNaga Sureshkumar Relli * pl353_smc_get_nand_int_status_raw - Get NAND interrupt status bit 180fee10bd2SNaga Sureshkumar Relli * Return: the raw_int_status1 bit from the memc_status register 181fee10bd2SNaga Sureshkumar Relli */ 182fee10bd2SNaga Sureshkumar Relli int pl353_smc_get_nand_int_status_raw(void) 183fee10bd2SNaga Sureshkumar Relli { 184fee10bd2SNaga Sureshkumar Relli u32 reg; 185fee10bd2SNaga Sureshkumar Relli 186fee10bd2SNaga Sureshkumar Relli reg = readl(pl353_smc_base + PL353_SMC_MEMC_STATUS_OFFS); 187fee10bd2SNaga Sureshkumar Relli reg >>= PL353_SMC_MEMC_STATUS_RAW_INT_1_SHIFT; 188fee10bd2SNaga Sureshkumar Relli reg &= 1; 189fee10bd2SNaga Sureshkumar Relli 190fee10bd2SNaga Sureshkumar Relli return reg; 191fee10bd2SNaga Sureshkumar Relli } 192fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_get_nand_int_status_raw); 193fee10bd2SNaga Sureshkumar Relli 194fee10bd2SNaga Sureshkumar Relli /** 195fee10bd2SNaga Sureshkumar Relli * pl353_smc_clr_nand_int - Clear NAND interrupt 196fee10bd2SNaga Sureshkumar Relli */ 197fee10bd2SNaga Sureshkumar Relli void pl353_smc_clr_nand_int(void) 198fee10bd2SNaga Sureshkumar Relli { 199fee10bd2SNaga Sureshkumar Relli writel(PL353_SMC_CFG_CLR_INT_CLR_1, 200fee10bd2SNaga Sureshkumar Relli pl353_smc_base + PL353_SMC_CFG_CLR_OFFS); 201fee10bd2SNaga Sureshkumar Relli } 202fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_clr_nand_int); 203fee10bd2SNaga Sureshkumar Relli 204fee10bd2SNaga Sureshkumar Relli /** 205fee10bd2SNaga Sureshkumar Relli * pl353_smc_set_ecc_mode - Set SMC ECC mode 206fee10bd2SNaga Sureshkumar Relli * @mode: ECC mode (BYPASS, APB, MEM) 207fee10bd2SNaga Sureshkumar Relli * Return: 0 on success or negative errno. 208fee10bd2SNaga Sureshkumar Relli */ 209fee10bd2SNaga Sureshkumar Relli int pl353_smc_set_ecc_mode(enum pl353_smc_ecc_mode mode) 210fee10bd2SNaga Sureshkumar Relli { 211fee10bd2SNaga Sureshkumar Relli u32 reg; 212fee10bd2SNaga Sureshkumar Relli int ret = 0; 213fee10bd2SNaga Sureshkumar Relli 214fee10bd2SNaga Sureshkumar Relli switch (mode) { 215fee10bd2SNaga Sureshkumar Relli case PL353_SMC_ECCMODE_BYPASS: 216fee10bd2SNaga Sureshkumar Relli case PL353_SMC_ECCMODE_APB: 217fee10bd2SNaga Sureshkumar Relli case PL353_SMC_ECCMODE_MEM: 218fee10bd2SNaga Sureshkumar Relli 219fee10bd2SNaga Sureshkumar Relli reg = readl(pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS); 220fee10bd2SNaga Sureshkumar Relli reg &= ~PL353_SMC_ECC_MEMCFG_MODE_MASK; 221fee10bd2SNaga Sureshkumar Relli reg |= mode << PL353_SMC_ECC_MEMCFG_MODE_SHIFT; 222fee10bd2SNaga Sureshkumar Relli writel(reg, pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS); 223fee10bd2SNaga Sureshkumar Relli 224fee10bd2SNaga Sureshkumar Relli break; 225fee10bd2SNaga Sureshkumar Relli default: 226fee10bd2SNaga Sureshkumar Relli ret = -EINVAL; 227fee10bd2SNaga Sureshkumar Relli } 228fee10bd2SNaga Sureshkumar Relli 229fee10bd2SNaga Sureshkumar Relli return ret; 230fee10bd2SNaga Sureshkumar Relli } 231fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_set_ecc_mode); 232fee10bd2SNaga Sureshkumar Relli 233fee10bd2SNaga Sureshkumar Relli /** 234fee10bd2SNaga Sureshkumar Relli * pl353_smc_set_ecc_pg_size - Set SMC ECC page size 235fee10bd2SNaga Sureshkumar Relli * @pg_sz: ECC page size 236fee10bd2SNaga Sureshkumar Relli * Return: 0 on success or negative errno. 237fee10bd2SNaga Sureshkumar Relli */ 238fee10bd2SNaga Sureshkumar Relli int pl353_smc_set_ecc_pg_size(unsigned int pg_sz) 239fee10bd2SNaga Sureshkumar Relli { 240fee10bd2SNaga Sureshkumar Relli u32 reg, sz; 241fee10bd2SNaga Sureshkumar Relli 242fee10bd2SNaga Sureshkumar Relli switch (pg_sz) { 243fee10bd2SNaga Sureshkumar Relli case 0: 244fee10bd2SNaga Sureshkumar Relli sz = 0; 245fee10bd2SNaga Sureshkumar Relli break; 246fee10bd2SNaga Sureshkumar Relli case SZ_512: 247fee10bd2SNaga Sureshkumar Relli sz = 1; 248fee10bd2SNaga Sureshkumar Relli break; 249fee10bd2SNaga Sureshkumar Relli case SZ_1K: 250fee10bd2SNaga Sureshkumar Relli sz = 2; 251fee10bd2SNaga Sureshkumar Relli break; 252fee10bd2SNaga Sureshkumar Relli case SZ_2K: 253fee10bd2SNaga Sureshkumar Relli sz = 3; 254fee10bd2SNaga Sureshkumar Relli break; 255fee10bd2SNaga Sureshkumar Relli default: 256fee10bd2SNaga Sureshkumar Relli return -EINVAL; 257fee10bd2SNaga Sureshkumar Relli } 258fee10bd2SNaga Sureshkumar Relli 259fee10bd2SNaga Sureshkumar Relli reg = readl(pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS); 260fee10bd2SNaga Sureshkumar Relli reg &= ~PL353_SMC_ECC_MEMCFG_PGSIZE_MASK; 261fee10bd2SNaga Sureshkumar Relli reg |= sz; 262fee10bd2SNaga Sureshkumar Relli writel(reg, pl353_smc_base + PL353_SMC_ECC_MEMCFG_OFFS); 263fee10bd2SNaga Sureshkumar Relli 264fee10bd2SNaga Sureshkumar Relli return 0; 265fee10bd2SNaga Sureshkumar Relli } 266fee10bd2SNaga Sureshkumar Relli EXPORT_SYMBOL_GPL(pl353_smc_set_ecc_pg_size); 267fee10bd2SNaga Sureshkumar Relli 268fee10bd2SNaga Sureshkumar Relli static int __maybe_unused pl353_smc_suspend(struct device *dev) 269fee10bd2SNaga Sureshkumar Relli { 270fee10bd2SNaga Sureshkumar Relli struct pl353_smc_data *pl353_smc = dev_get_drvdata(dev); 271fee10bd2SNaga Sureshkumar Relli 272fee10bd2SNaga Sureshkumar Relli clk_disable(pl353_smc->memclk); 273fee10bd2SNaga Sureshkumar Relli clk_disable(pl353_smc->aclk); 274fee10bd2SNaga Sureshkumar Relli 275fee10bd2SNaga Sureshkumar Relli return 0; 276fee10bd2SNaga Sureshkumar Relli } 277fee10bd2SNaga Sureshkumar Relli 278fee10bd2SNaga Sureshkumar Relli static int __maybe_unused pl353_smc_resume(struct device *dev) 279fee10bd2SNaga Sureshkumar Relli { 280fee10bd2SNaga Sureshkumar Relli int ret; 281fee10bd2SNaga Sureshkumar Relli struct pl353_smc_data *pl353_smc = dev_get_drvdata(dev); 282fee10bd2SNaga Sureshkumar Relli 283fee10bd2SNaga Sureshkumar Relli ret = clk_enable(pl353_smc->aclk); 284fee10bd2SNaga Sureshkumar Relli if (ret) { 285fee10bd2SNaga Sureshkumar Relli dev_err(dev, "Cannot enable axi domain clock.\n"); 286fee10bd2SNaga Sureshkumar Relli return ret; 287fee10bd2SNaga Sureshkumar Relli } 288fee10bd2SNaga Sureshkumar Relli 289fee10bd2SNaga Sureshkumar Relli ret = clk_enable(pl353_smc->memclk); 290fee10bd2SNaga Sureshkumar Relli if (ret) { 291fee10bd2SNaga Sureshkumar Relli dev_err(dev, "Cannot enable memory clock.\n"); 292fee10bd2SNaga Sureshkumar Relli clk_disable(pl353_smc->aclk); 293fee10bd2SNaga Sureshkumar Relli return ret; 294fee10bd2SNaga Sureshkumar Relli } 295fee10bd2SNaga Sureshkumar Relli 296fee10bd2SNaga Sureshkumar Relli return ret; 297fee10bd2SNaga Sureshkumar Relli } 298fee10bd2SNaga Sureshkumar Relli 299fee10bd2SNaga Sureshkumar Relli static struct amba_driver pl353_smc_driver; 300fee10bd2SNaga Sureshkumar Relli 301fee10bd2SNaga Sureshkumar Relli static SIMPLE_DEV_PM_OPS(pl353_smc_dev_pm_ops, pl353_smc_suspend, 302fee10bd2SNaga Sureshkumar Relli pl353_smc_resume); 303fee10bd2SNaga Sureshkumar Relli 304fee10bd2SNaga Sureshkumar Relli /** 305fee10bd2SNaga Sureshkumar Relli * pl353_smc_init_nand_interface - Initialize the NAND interface 306fee10bd2SNaga Sureshkumar Relli * @adev: Pointer to the amba_device struct 307fee10bd2SNaga Sureshkumar Relli * @nand_node: Pointer to the pl353_nand device_node struct 308fee10bd2SNaga Sureshkumar Relli */ 309fee10bd2SNaga Sureshkumar Relli static void pl353_smc_init_nand_interface(struct amba_device *adev, 310fee10bd2SNaga Sureshkumar Relli struct device_node *nand_node) 311fee10bd2SNaga Sureshkumar Relli { 312fee10bd2SNaga Sureshkumar Relli unsigned long timeout; 313fee10bd2SNaga Sureshkumar Relli 314fee10bd2SNaga Sureshkumar Relli pl353_smc_set_buswidth(PL353_SMC_MEM_WIDTH_8); 315fee10bd2SNaga Sureshkumar Relli writel(PL353_SMC_CFG_CLR_INT_CLR_1, 316fee10bd2SNaga Sureshkumar Relli pl353_smc_base + PL353_SMC_CFG_CLR_OFFS); 317fee10bd2SNaga Sureshkumar Relli writel(PL353_SMC_DC_UPT_NAND_REGS, pl353_smc_base + 318fee10bd2SNaga Sureshkumar Relli PL353_SMC_DIRECT_CMD_OFFS); 319fee10bd2SNaga Sureshkumar Relli 320fee10bd2SNaga Sureshkumar Relli timeout = jiffies + PL353_NAND_ECC_BUSY_TIMEOUT; 321fee10bd2SNaga Sureshkumar Relli /* Wait till the ECC operation is complete */ 322fee10bd2SNaga Sureshkumar Relli do { 323fee10bd2SNaga Sureshkumar Relli if (pl353_smc_ecc_is_busy()) 324fee10bd2SNaga Sureshkumar Relli cpu_relax(); 325fee10bd2SNaga Sureshkumar Relli else 326fee10bd2SNaga Sureshkumar Relli break; 327fee10bd2SNaga Sureshkumar Relli } while (!time_after_eq(jiffies, timeout)); 328fee10bd2SNaga Sureshkumar Relli 329fee10bd2SNaga Sureshkumar Relli if (time_after_eq(jiffies, timeout)) 330fee10bd2SNaga Sureshkumar Relli return; 331fee10bd2SNaga Sureshkumar Relli 332fee10bd2SNaga Sureshkumar Relli writel(PL353_NAND_ECC_CMD1, 333fee10bd2SNaga Sureshkumar Relli pl353_smc_base + PL353_SMC_ECC_MEMCMD1_OFFS); 334fee10bd2SNaga Sureshkumar Relli writel(PL353_NAND_ECC_CMD2, 335fee10bd2SNaga Sureshkumar Relli pl353_smc_base + PL353_SMC_ECC_MEMCMD2_OFFS); 336fee10bd2SNaga Sureshkumar Relli } 337fee10bd2SNaga Sureshkumar Relli 338fee10bd2SNaga Sureshkumar Relli static const struct of_device_id pl353_smc_supported_children[] = { 339fee10bd2SNaga Sureshkumar Relli { 340fee10bd2SNaga Sureshkumar Relli .compatible = "cfi-flash" 341fee10bd2SNaga Sureshkumar Relli }, 342fee10bd2SNaga Sureshkumar Relli { 343fee10bd2SNaga Sureshkumar Relli .compatible = "arm,pl353-nand-r2p1", 344fee10bd2SNaga Sureshkumar Relli .data = pl353_smc_init_nand_interface 345fee10bd2SNaga Sureshkumar Relli }, 346fee10bd2SNaga Sureshkumar Relli {} 347fee10bd2SNaga Sureshkumar Relli }; 348fee10bd2SNaga Sureshkumar Relli 349fee10bd2SNaga Sureshkumar Relli static int pl353_smc_probe(struct amba_device *adev, const struct amba_id *id) 350fee10bd2SNaga Sureshkumar Relli { 351fee10bd2SNaga Sureshkumar Relli struct pl353_smc_data *pl353_smc; 352fee10bd2SNaga Sureshkumar Relli struct device_node *child; 353fee10bd2SNaga Sureshkumar Relli struct resource *res; 354fee10bd2SNaga Sureshkumar Relli int err; 355fee10bd2SNaga Sureshkumar Relli struct device_node *of_node = adev->dev.of_node; 356fee10bd2SNaga Sureshkumar Relli static void (*init)(struct amba_device *adev, 357fee10bd2SNaga Sureshkumar Relli struct device_node *nand_node); 358fee10bd2SNaga Sureshkumar Relli const struct of_device_id *match = NULL; 359fee10bd2SNaga Sureshkumar Relli 360fee10bd2SNaga Sureshkumar Relli pl353_smc = devm_kzalloc(&adev->dev, sizeof(*pl353_smc), GFP_KERNEL); 361fee10bd2SNaga Sureshkumar Relli if (!pl353_smc) 362fee10bd2SNaga Sureshkumar Relli return -ENOMEM; 363fee10bd2SNaga Sureshkumar Relli 364fee10bd2SNaga Sureshkumar Relli /* Get the NAND controller virtual address */ 365fee10bd2SNaga Sureshkumar Relli res = &adev->res; 366fee10bd2SNaga Sureshkumar Relli pl353_smc_base = devm_ioremap_resource(&adev->dev, res); 367fee10bd2SNaga Sureshkumar Relli if (IS_ERR(pl353_smc_base)) 368fee10bd2SNaga Sureshkumar Relli return PTR_ERR(pl353_smc_base); 369fee10bd2SNaga Sureshkumar Relli 370fee10bd2SNaga Sureshkumar Relli pl353_smc->aclk = devm_clk_get(&adev->dev, "apb_pclk"); 371fee10bd2SNaga Sureshkumar Relli if (IS_ERR(pl353_smc->aclk)) { 372fee10bd2SNaga Sureshkumar Relli dev_err(&adev->dev, "aclk clock not found.\n"); 373fee10bd2SNaga Sureshkumar Relli return PTR_ERR(pl353_smc->aclk); 374fee10bd2SNaga Sureshkumar Relli } 375fee10bd2SNaga Sureshkumar Relli 376fee10bd2SNaga Sureshkumar Relli pl353_smc->memclk = devm_clk_get(&adev->dev, "memclk"); 377fee10bd2SNaga Sureshkumar Relli if (IS_ERR(pl353_smc->memclk)) { 378fee10bd2SNaga Sureshkumar Relli dev_err(&adev->dev, "memclk clock not found.\n"); 379fee10bd2SNaga Sureshkumar Relli return PTR_ERR(pl353_smc->memclk); 380fee10bd2SNaga Sureshkumar Relli } 381fee10bd2SNaga Sureshkumar Relli 382fee10bd2SNaga Sureshkumar Relli err = clk_prepare_enable(pl353_smc->aclk); 383fee10bd2SNaga Sureshkumar Relli if (err) { 384fee10bd2SNaga Sureshkumar Relli dev_err(&adev->dev, "Unable to enable AXI clock.\n"); 385fee10bd2SNaga Sureshkumar Relli return err; 386fee10bd2SNaga Sureshkumar Relli } 387fee10bd2SNaga Sureshkumar Relli 388fee10bd2SNaga Sureshkumar Relli err = clk_prepare_enable(pl353_smc->memclk); 389fee10bd2SNaga Sureshkumar Relli if (err) { 390fee10bd2SNaga Sureshkumar Relli dev_err(&adev->dev, "Unable to enable memory clock.\n"); 391fee10bd2SNaga Sureshkumar Relli goto out_clk_dis_aper; 392fee10bd2SNaga Sureshkumar Relli } 393fee10bd2SNaga Sureshkumar Relli 394fee10bd2SNaga Sureshkumar Relli amba_set_drvdata(adev, pl353_smc); 395fee10bd2SNaga Sureshkumar Relli 396fee10bd2SNaga Sureshkumar Relli /* clear interrupts */ 397fee10bd2SNaga Sureshkumar Relli writel(PL353_SMC_CFG_CLR_DEFAULT_MASK, 398fee10bd2SNaga Sureshkumar Relli pl353_smc_base + PL353_SMC_CFG_CLR_OFFS); 399fee10bd2SNaga Sureshkumar Relli 400fee10bd2SNaga Sureshkumar Relli /* Find compatible children. Only a single child is supported */ 401fee10bd2SNaga Sureshkumar Relli for_each_available_child_of_node(of_node, child) { 402fee10bd2SNaga Sureshkumar Relli match = of_match_node(pl353_smc_supported_children, child); 403fee10bd2SNaga Sureshkumar Relli if (!match) { 404fee10bd2SNaga Sureshkumar Relli dev_warn(&adev->dev, "unsupported child node\n"); 405fee10bd2SNaga Sureshkumar Relli continue; 406fee10bd2SNaga Sureshkumar Relli } 407fee10bd2SNaga Sureshkumar Relli break; 408fee10bd2SNaga Sureshkumar Relli } 409fee10bd2SNaga Sureshkumar Relli if (!match) { 410*76e5624fSZhen Lei err = -ENODEV; 411fee10bd2SNaga Sureshkumar Relli dev_err(&adev->dev, "no matching children\n"); 412fee10bd2SNaga Sureshkumar Relli goto out_clk_disable; 413fee10bd2SNaga Sureshkumar Relli } 414fee10bd2SNaga Sureshkumar Relli 415fee10bd2SNaga Sureshkumar Relli init = match->data; 416fee10bd2SNaga Sureshkumar Relli if (init) 417fee10bd2SNaga Sureshkumar Relli init(adev, child); 418fee10bd2SNaga Sureshkumar Relli of_platform_device_create(child, NULL, &adev->dev); 419fee10bd2SNaga Sureshkumar Relli 420fee10bd2SNaga Sureshkumar Relli return 0; 421fee10bd2SNaga Sureshkumar Relli 422fee10bd2SNaga Sureshkumar Relli out_clk_disable: 423fee10bd2SNaga Sureshkumar Relli clk_disable_unprepare(pl353_smc->memclk); 424fee10bd2SNaga Sureshkumar Relli out_clk_dis_aper: 425fee10bd2SNaga Sureshkumar Relli clk_disable_unprepare(pl353_smc->aclk); 426fee10bd2SNaga Sureshkumar Relli 427fee10bd2SNaga Sureshkumar Relli return err; 428fee10bd2SNaga Sureshkumar Relli } 429fee10bd2SNaga Sureshkumar Relli 4303fd269e7SUwe Kleine-König static void pl353_smc_remove(struct amba_device *adev) 431fee10bd2SNaga Sureshkumar Relli { 432fee10bd2SNaga Sureshkumar Relli struct pl353_smc_data *pl353_smc = amba_get_drvdata(adev); 433fee10bd2SNaga Sureshkumar Relli 434fee10bd2SNaga Sureshkumar Relli clk_disable_unprepare(pl353_smc->memclk); 435fee10bd2SNaga Sureshkumar Relli clk_disable_unprepare(pl353_smc->aclk); 436fee10bd2SNaga Sureshkumar Relli } 437fee10bd2SNaga Sureshkumar Relli 438fee10bd2SNaga Sureshkumar Relli static const struct amba_id pl353_ids[] = { 439fee10bd2SNaga Sureshkumar Relli { 440fee10bd2SNaga Sureshkumar Relli .id = 0x00041353, 441fee10bd2SNaga Sureshkumar Relli .mask = 0x000fffff, 442fee10bd2SNaga Sureshkumar Relli }, 443fee10bd2SNaga Sureshkumar Relli { 0, 0 }, 444fee10bd2SNaga Sureshkumar Relli }; 445fee10bd2SNaga Sureshkumar Relli MODULE_DEVICE_TABLE(amba, pl353_ids); 446fee10bd2SNaga Sureshkumar Relli 447fee10bd2SNaga Sureshkumar Relli static struct amba_driver pl353_smc_driver = { 448fee10bd2SNaga Sureshkumar Relli .drv = { 449fee10bd2SNaga Sureshkumar Relli .owner = THIS_MODULE, 450fee10bd2SNaga Sureshkumar Relli .name = "pl353-smc", 451fee10bd2SNaga Sureshkumar Relli .pm = &pl353_smc_dev_pm_ops, 452fee10bd2SNaga Sureshkumar Relli }, 453fee10bd2SNaga Sureshkumar Relli .id_table = pl353_ids, 454fee10bd2SNaga Sureshkumar Relli .probe = pl353_smc_probe, 455fee10bd2SNaga Sureshkumar Relli .remove = pl353_smc_remove, 456fee10bd2SNaga Sureshkumar Relli }; 457fee10bd2SNaga Sureshkumar Relli 458fee10bd2SNaga Sureshkumar Relli module_amba_driver(pl353_smc_driver); 459fee10bd2SNaga Sureshkumar Relli 460fee10bd2SNaga Sureshkumar Relli MODULE_AUTHOR("Xilinx, Inc."); 461fee10bd2SNaga Sureshkumar Relli MODULE_DESCRIPTION("ARM PL353 SMC Driver"); 462fee10bd2SNaga Sureshkumar Relli MODULE_LICENSE("GPL"); 463