diff options
Diffstat (limited to 'include/soc/imx')
-rw-r--r-- | include/soc/imx/clk-fracn-gppll.h | 144 | ||||
-rw-r--r-- | include/soc/imx/ddr.h | 171 | ||||
-rw-r--r-- | include/soc/imx/gpmi-nand.h | 147 | ||||
-rw-r--r-- | include/soc/imx/imx-nand-bcb.h | 13 |
4 files changed, 475 insertions, 0 deletions
diff --git a/include/soc/imx/clk-fracn-gppll.h b/include/soc/imx/clk-fracn-gppll.h new file mode 100644 index 0000000000..15ab9e67ec --- /dev/null +++ b/include/soc/imx/clk-fracn-gppll.h @@ -0,0 +1,144 @@ +#ifndef __SOC_IMX_CLK_FRACN_GPGPPLL_H +#define __SOC_IMX_CLK_FRACN_GPGPPLL_H + +#include <linux/bitfield.h> +#include <linux/iopoll.h> + +#define GPPLL_CTRL 0x0 +#define HW_CTRL_SEL BIT(16) +#define CLKMUX_BYPASS BIT(2) +#define CLKMUX_EN BIT(1) +#define POWERUP_MASK BIT(0) + +#define GPPLL_ANA_PRG 0x10 +#define GPPLL_SPREAD_SPECTRUM 0x30 + +#define GPPLL_NUMERATOR 0x40 +#define GPPLL_MFN_MASK GENMASK(31, 2) + +#define GPPLL_DENOMINATOR 0x50 +#define GPPLL_MFD_MASK GENMASK(29, 0) + +#define GPPLL_DIV 0x60 +#define GPPLL_MFI_MASK GENMASK(24, 16) +#define GPPLL_RDIV_MASK GENMASK(15, 13) +#define GPPLL_ODIV_MASK GENMASK(7, 0) + +#define GPPLL_DFS_CTRL(x) (0x70 + (x) * 0x10) + +#define GPPLL_STATUS 0xF0 +#define GPPLL_LOCK_STATUS BIT(0) + +#define GPPLL_DFS_STATUS 0xF4 + +#define GPPLL_LOCK_TIMEOUT_US 200 + +#define CLK_FRACN_GPPLL_INTEGER BIT(0) +#define CLK_FRACN_GPPLL_FRACN BIT(1) + +/* NOTE: Rate table should be kept sorted in descending order. */ +struct imx_fracn_gppll_rate_table { + unsigned int rate; + unsigned int mfi; + unsigned int mfn; + unsigned int mfd; + unsigned int rdiv; + unsigned int odiv; +}; + +struct imx_fracn_gppll_clk { + const struct imx_fracn_gppll_rate_table *rate_table; + int rate_count; + int flags; +}; + +struct clk *imx_clk_fracn_gppll(const char *name, const char *parent_name, void __iomem *base, + const struct imx_fracn_gppll_clk *pll_clk); +struct clk *imx_clk_fracn_gppll_integer(const char *name, const char *parent_name, + void __iomem *base, + const struct imx_fracn_gppll_clk *pll_clk); + +extern struct imx_fracn_gppll_clk imx_fracn_gppll; +extern struct imx_fracn_gppll_clk imx_fracn_gppll_integer; + +static inline int fracn_gppll_wait_lock(void __iomem *base) +{ + u32 val; + + return readl_poll_timeout(base + GPPLL_STATUS, val, + val & GPPLL_LOCK_STATUS, GPPLL_LOCK_TIMEOUT_US); +} + +static inline const struct imx_fracn_gppll_rate_table *imx_get_gppll_settings( + const struct imx_fracn_gppll_rate_table *rate_table, int n_table, unsigned long rate) +{ + int i; + + for (i = 0; i < n_table; i++) + if (rate == rate_table[i].rate) + return &rate_table[i]; + + return NULL; +} + +static inline int fracn_gppll_set_rate(void __iomem *base, unsigned int flags, + const struct imx_fracn_gppll_rate_table *table, int n_table, + unsigned long drate) +{ + const struct imx_fracn_gppll_rate_table *rate; + u32 tmp, pll_div, ana_mfn; + int ret; + + rate = imx_get_gppll_settings(table, n_table, drate); + + /* Hardware control select disable. PLL is control by register */ + tmp = readl_relaxed(base + GPPLL_CTRL); + tmp &= ~HW_CTRL_SEL; + writel_relaxed(tmp, base + GPPLL_CTRL); + + /* Disable output */ + tmp = readl_relaxed(base + GPPLL_CTRL); + tmp &= ~CLKMUX_EN; + writel_relaxed(tmp, base + GPPLL_CTRL); + + /* Power Down */ + tmp &= ~POWERUP_MASK; + writel_relaxed(tmp, base + GPPLL_CTRL); + + /* Disable BYPASS */ + tmp &= ~CLKMUX_BYPASS; + writel_relaxed(tmp, base + GPPLL_CTRL); + + pll_div = FIELD_PREP(GPPLL_RDIV_MASK, rate->rdiv) | rate->odiv | + FIELD_PREP(GPPLL_MFI_MASK, rate->mfi); + writel_relaxed(pll_div, base + GPPLL_DIV); + if (flags & CLK_FRACN_GPPLL_FRACN) { + writel_relaxed(rate->mfd, base + GPPLL_DENOMINATOR); + writel_relaxed(FIELD_PREP(GPPLL_MFN_MASK, rate->mfn), base + GPPLL_NUMERATOR); + } + + /* Wait for 5us according to fracn mode pll doc */ + udelay(5); + + /* Enable Powerup */ + tmp |= POWERUP_MASK; + writel_relaxed(tmp, base + GPPLL_CTRL); + + /* Wait Lock */ + ret = fracn_gppll_wait_lock(base); + if (ret) + return ret; + + /* Enable output */ + tmp |= CLKMUX_EN; + writel_relaxed(tmp, base + GPPLL_CTRL); + + ana_mfn = readl_relaxed(base + GPPLL_STATUS); + ana_mfn = FIELD_GET(GPPLL_MFN_MASK, ana_mfn); + + WARN(ana_mfn != rate->mfn, "ana_mfn != rate->mfn\n"); + + return 0; +} + +#endif /* __SOC_IMX_CLK_FRACN_GPGPPLL_H */ diff --git a/include/soc/imx/ddr.h b/include/soc/imx/ddr.h new file mode 100644 index 0000000000..0225ac0e03 --- /dev/null +++ b/include/soc/imx/ddr.h @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2017 NXP + */ + +#ifndef __SOC_IMX_DDR_H +#define __SOC_IMX_DDR_H + +/* user data type */ +enum fw_type { + FW_1D_IMAGE, + FW_2D_IMAGE, +}; + +enum dram_type { +#define DRAM_TYPE_MASK 0x00ff + DRAM_TYPE_LPDDR4 = 0 << 0, + DRAM_TYPE_DDR4 = 1 << 0, +}; + +static inline enum dram_type get_dram_type(unsigned type) +{ + return type & DRAM_TYPE_MASK; +} + +enum ddrc_type { +#define DDRC_TYPE_MASK 0xff00 + DDRC_TYPE_MM = 0 << 8, + DDRC_TYPE_MN = 1 << 8, + DDRC_TYPE_MQ = 2 << 8, + DDRC_TYPE_MP = 3 << 8, +}; + +static inline enum ddrc_type get_ddrc_type(unsigned type) +{ + return type & DDRC_TYPE_MASK; +} + +struct dram_cfg_param { + unsigned int reg; + unsigned int val; +}; + +struct dram_fsp_cfg { + struct dram_cfg_param ddrc_cfg[20]; + struct dram_cfg_param mr_cfg[10]; + unsigned int bypass; +}; + +struct dram_fsp_msg { + unsigned int drate; + enum fw_type fw_type; + struct dram_cfg_param *fsp_cfg; + unsigned int fsp_cfg_num; +}; + +#define __deprecated_dram_timing_info \ + __attribute__((deprecated("board-specific data here is ignored in favor of the defaults." \ + " You can probably remove the array"))) + +struct dram_timing_info { + /* umctl2 config */ + struct dram_cfg_param *ddrc_cfg; + unsigned int ddrc_cfg_num; + /* fsp config */ + struct dram_fsp_cfg *fsp_cfg; + unsigned int fsp_cfg_num; + /* ddrphy config */ + struct dram_cfg_param *ddrphy_cfg; + unsigned int ddrphy_cfg_num; + /* ddr fsp train info */ + struct dram_fsp_msg *fsp_msg; + unsigned int fsp_msg_num; + /* ddr phy trained CSR */ + struct dram_cfg_param *ddrphy_trained_csr __deprecated_dram_timing_info; + unsigned int ddrphy_trained_csr_num __deprecated_dram_timing_info; + /* ddr phy PIE */ + struct dram_cfg_param *ddrphy_pie; + unsigned int ddrphy_pie_num; + /* initialized drate table */ + unsigned int fsp_table[4]; +}; + +struct dram_controller { + enum ddrc_type ddrc_type; + enum dram_type dram_type; + void __iomem *phy_base; + u32 (*phy_remap)(u32 paddr_apb_from_ctlr); + void (*get_trained_CDD)(struct dram_controller *dram, u32 fsp); + void (*set_dfi_clk)(struct dram_controller *dram, unsigned int drate_mhz); + bool imx8m_ddr_old_spreadsheet; +}; + +void ddr_get_firmware_lpddr4(void); +void ddr_get_firmware_ddr(void); + +static inline void ddr_get_firmware(enum dram_type dram_type) +{ + if (dram_type == DRAM_TYPE_LPDDR4) + ddr_get_firmware_lpddr4(); + else + ddr_get_firmware_ddr(); +} + +int ddr_cfg_phy(struct dram_controller *dram, struct dram_timing_info *timing_info); +void ddrphy_trained_csr_save(struct dram_controller *dram, struct dram_cfg_param *param, + unsigned int num); +void *dram_config_save(struct dram_controller *dram, struct dram_timing_info *info, + unsigned long base); + +/* utils function for ddr phy training */ +int wait_ddrphy_training_complete(struct dram_controller *dram); + +#define reg32_write(a, v) writel(v, a) +#define reg32_read(a) readl(a) + +static inline void reg32setbit(unsigned long addr, u32 bit) +{ + setbits_le32(addr, (1 << bit)); +} + +static inline void *dwc_ddrphy_apb_addr(struct dram_controller *dram, unsigned int addr) +{ + if (dram->phy_remap) + addr = dram->phy_remap(addr); + else + addr *= 4; + + return dram->phy_base + addr; +} + +static inline void dwc_ddrphy_apb_wr(struct dram_controller *dram, unsigned int addr, u32 data) +{ + reg32_write(dwc_ddrphy_apb_addr(dram, addr), data); +} + +static inline u32 dwc_ddrphy_apb_rd(struct dram_controller *dram, unsigned int addr) +{ + return reg32_read(dwc_ddrphy_apb_addr(dram, addr)); +} + +extern struct dram_cfg_param ddrphy_trained_csr[]; +extern uint32_t ddrphy_trained_csr_num; + +enum ddrc_phy_firmware_offset { + DDRC_PHY_IMEM = 0x00050000U, + DDRC_PHY_DMEM = 0x00054000U, +}; + +void ddr_load_train_code(struct dram_controller *dram, enum dram_type dram_type, + enum fw_type fw_type); + +void ddrc_phy_load_firmware(struct dram_controller *dram, + enum ddrc_phy_firmware_offset, + const u16 *, size_t); + +static inline bool dram_is_lpddr4(enum dram_type dram_type) +{ + return IS_ENABLED(CONFIG_FIRMWARE_IMX_LPDDR4_PMU_TRAIN) && + dram_type == DRAM_TYPE_LPDDR4; +} + +static inline bool dram_is_ddr4(enum dram_type dram_type) +{ + return IS_ENABLED(CONFIG_FIRMWARE_IMX_DDR4_PMU_TRAIN) && + dram_type == DRAM_TYPE_DDR4; +} + +#define DDRC_PHY_REG(x) ((x) * 4) + +#endif /* __SOC_IMX_DDR_H */ diff --git a/include/soc/imx/gpmi-nand.h b/include/soc/imx/gpmi-nand.h new file mode 100644 index 0000000000..a552513e0d --- /dev/null +++ b/include/soc/imx/gpmi-nand.h @@ -0,0 +1,147 @@ +#ifndef __SOC_IMX_GPMI_NAND_H +#define __SOC_IMX_GPMI_NAND_H + +#include <linux/bitfield.h> + +#define GPMI_CTRL0 0x00000000 +#define GPMI_CTRL0_SFTRST BIT(31) +#define GPMI_CTRL0_RUN BIT(29) +#define GPMI_CTRL0_DEV_IRQ_EN BIT(28) +#define GPMI_CTRL0_UDMA BIT(26) +#define GPMI_CTRL0_COMMAND_MODE GENMASK(25, 24) +#define GPMI_CTRL0_COMMAND_MODE_WRITE (0x0 << 24) +#define GPMI_CTRL0_COMMAND_MODE_READ (0x1 << 24) +#define GPMI_CTRL0_COMMAND_MODE_READ_AND_COMPARE (0x2 << 24) +#define GPMI_CTRL0_COMMAND_MODE_WAIT_FOR_READY (0x3 << 24) +#define GPMI_CTRL0_WORD_LENGTH (1 << 23) +#define GPMI_CTRL0_CS GENMASK(22, 20) +#define GPMI_CTRL0_ADDRESS GENMASK(19, 17) +#define GPMI_CTRL0_ADDRESS_NAND_DATA (0x0 << 17) +#define GPMI_CTRL0_ADDRESS_NAND_CLE (0x1 << 17) +#define GPMI_CTRL0_ADDRESS_NAND_ALE (0x2 << 17) +#define GPMI_CTRL0_ADDRESS_INCREMENT BIT(16) +#define GPMI_CTRL0_XFER_COUNT GENMASK(15, 0) + +#define GPMI_CTRL1 0x00000060 +#define GPMI_CTRL1_SET 0x00000064 +#define GPMI_CTRL1_CLR 0x00000068 +#define GPMI_CTRL1_DECOUPLE_CS BIT(24) +#define GPMI_CTRL1_WRN_DLY(d) (((d) & 0x3) << 22) +#define GPMI_CTRL1_TIMEOUT_IRQ_EN BIT(20) +#define GPMI_CTRL1_GANGED_RDYBUSY BIT(19) +#define GPMI_CTRL1_BCH_MODE BIT(18) +#define GPMI_CTRL1_DLL_ENABLE BIT(17) +#define GPMI_CTRL1_HALF_PERIOD BIT(16) +#define GPMI_CTRL1_RDN_DELAY(d) (((d) & 0xf) << 12) +#define GPMI_CTRL1_DMA2ECC_MODE BIT(11) +#define GPMI_CTRL1_DEV_IRQ BIT(10) +#define GPMI_CTRL1_TIMEOUT_IRQ BIT(9) +#define GPMI_CTRL1_BURST_EN BIT(8) +#define GPMI_CTRL1_ABORT_WAIT_REQUEST BIT(7) +#define GPMI_CTRL1_ABORT_WAIT_FOR_READY GENMASK(6, 4) +#define GPMI_CTRL1_DEV_RESET BIT(3) +#define GPMI_CTRL1_ATA_IRQRDY_POLARITY BIT(2) +#define GPMI_CTRL1_CAMERA_MODE BIT(1) +#define GPMI_CTRL1_GPMI_MODE BIT(0) + +#define BV_GPMI_CTRL1_WRN_DLY_SEL_4_TO_8NS 0x0 +#define BV_GPMI_CTRL1_WRN_DLY_SEL_6_TO_10NS 0x1 +#define BV_GPMI_CTRL1_WRN_DLY_SEL_7_TO_12NS 0x2 +#define BV_GPMI_CTRL1_WRN_DLY_SEL_NO_DELAY 0x3 + +#define GPMI_TIMING0 0x00000070 + +#define GPMI_TIMING0_ADDRESS_SETUP(d) (((d) & 0xff) << 16) +#define GPMI_TIMING0_DATA_HOLD(d) (((d) & 0xff) << 8) +#define GPMI_TIMING0_DATA_SETUP(d) (((d) & 0xff) << 0) + +#define GPMI_TIMING1 0x00000080 +#define GPMI_TIMING1_BUSY_TIMEOUT(d) (((d) & 0xffff) << 16) + +#define GPMI_ECCCTRL_HANDLE GENMASK(31, 16) +#define GPMI_ECCCTRL_ECC_CMD GENMASK(14, 13) +#define GPMI_ECCCTRL_ECC_CMD_DECODE (0x0 << 13) +#define GPMI_ECCCTRL_ECC_CMD_ENCODE (0x1 << 13) +#define GPMI_ECCCTRL_RANDOMIZER_ENABLE BIT(11) +#define GPMI_ECCCTRL_RANDOMIZER_TYPE0 0 +#define GPMI_ECCCTRL_RANDOMIZER_TYPE1 (1 << 9) +#define GPMI_ECCCTRL_RANDOMIZER_TYPE2 (2 << 9) +#define GPMI_ECCCTRL_ENABLE_ECC BIT(12) +#define GPMI_ECCCTRL_BUFFER_MASK GENMASK(8, 0) +#define GPMI_ECCCTRL_BUFFER_MASK_BCH_AUXONLY 0x100 +#define GPMI_ECCCTRL_BUFFER_MASK_BCH_PAGE 0x1ff + +#define GPMI_STAT 0x000000b0 +#define GPMI_STAT_READY_BUSY_OFFSET 24 + +#define GPMI_DEBUG 0x000000c0 +#define GPMI_DEBUG_READY0_OFFSET 28 + +#define GPMI_VERSION 0x000000d0 +#define GPMI_VERSION_MINOR_OFFSET 16 +#define GPMI_VERSION_TYPE_MX23 0x0300 + +#define BCH_CTRL 0x00000000 +#define BCH_CTRL_COMPLETE_IRQ BIT(0) +#define BCH_CTRL_COMPLETE_IRQ_EN BIT(8) + +#define BCH_LAYOUTSELECT 0x00000070 + +#define BCH_FLASH0LAYOUT0 0x00000080 +#define BCH_FLASHLAYOUT0_NBLOCKS GENMASK(31, 24) +#define BCH_FLASHLAYOUT0_META_SIZE GENMASK(23, 16) +#define BCH_FLASHLAYOUT0_ECC0 GENMASK(15, 12) +#define IMX6_BCH_FLASHLAYOUT0_ECC0 GENMASK(15, 11) +#define BCH_FLASHLAYOUT0_DATA0_SIZE GENMASK(9, 0) +#define BCH_FLASHLAYOUT0_GF13_0_GF14_1 BIT(10) + +#define BCH_FLASH0LAYOUT1 0x00000090 +#define BCH_FLASHLAYOUT1_PAGE_SIZE GENMASK(31, 16) +#define BCH_FLASHLAYOUT1_ECCN GENMASK(15, 12) +#define IMX6_BCH_FLASHLAYOUT1_ECCN GENMASK(15, 11) +#define BCH_FLASHLAYOUT1_GF13_0_GF14_1 BIT(10) +#define BCH_FLASHLAYOUT1_DATAN_SIZE GENMASK(9, 0) + +#define MXS_NAND_DMA_DESCRIPTOR_COUNT 4 + +#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE 512 +#define MXS_NAND_METADATA_SIZE 10 + +#define MXS_NAND_COMMAND_BUFFER_SIZE 32 + +#define MXS_NAND_BCH_TIMEOUT 10000 + +#define BCH62_WRITESIZE 1024 +#define BCH62_OOBSIZE 838 +#define BCH62_PAGESIZE (BCH62_WRITESIZE + BCH62_OOBSIZE) + +/* + * Some SoCs like the i.MX7 use a special layout in the FCB block. + * We can read/write that by adjusting the BCH engine to that layout. + * Particularly we have pages consisting of 8 chunks with 128 bytes + * of data and 100.75 bytes of ECC data each. + */ +static void mxs_nand_mode_fcb_62bit(void __iomem *bch_regs) +{ + u32 fl0, fl1; + + /* 8 ecc_chunks */ + fl0 = FIELD_PREP(BCH_FLASHLAYOUT0_NBLOCKS, 7); + /* 32 bytes for metadata */ + fl0 |= FIELD_PREP(BCH_FLASHLAYOUT0_META_SIZE, 32); + /* using ECC62 level to be performed */ + fl0 |= FIELD_PREP(IMX6_BCH_FLASHLAYOUT0_ECC0, 0x1f); + /* 0x20 * 4 bytes of the data0 block */ + fl0 |= FIELD_PREP(BCH_FLASHLAYOUT0_DATA0_SIZE, 0x20); + writel(fl0, bch_regs + BCH_FLASH0LAYOUT0); + + /* 1024 for data + 838 for OOB */ + fl1 = FIELD_PREP(BCH_FLASHLAYOUT1_PAGE_SIZE, BCH62_PAGESIZE); + /* using ECC62 level to be performed */ + fl1 |= FIELD_PREP(IMX6_BCH_FLASHLAYOUT1_ECCN, 0x1f); + /* 0x20 * 4 bytes of the data0 block */ + fl1 |= FIELD_PREP(BCH_FLASHLAYOUT1_DATAN_SIZE, 0x20); + writel(fl1, bch_regs + BCH_FLASH0LAYOUT1); +} + +#endif /* __SOC_IMX_GPMI_NAND_H */ diff --git a/include/soc/imx/imx-nand-bcb.h b/include/soc/imx/imx-nand-bcb.h index b60205bd59..c5481e602e 100644 --- a/include/soc/imx/imx-nand-bcb.h +++ b/include/soc/imx/imx-nand-bcb.h @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + #ifndef __MACH_IMX_NAND_BCB_H #define __MACH_IMX_NAND_BCB_H @@ -75,6 +77,17 @@ struct fcb_block { uint32_t DISBBM; /* the flag to enable (1)/disable(0) bi swap */ uint32_t BBMarkerPhysicalOffsetInSpareData; /* The swap position of main area in spare area */ + + /* iMX7 only */ + uint32_t onfi_sync_enable; /* enable Onfi nand sync support */ + uint32_t onfi_sync_speed; /* Speed for Onfi nand sync mode */ + uint32_t onfi_sync_nand_data; /* parameters for Onfi nand sync mode timing */ + uint32_t reserved[6]; + uint32_t disbbm_search; /* disable bad block search function when reading the firmware, only using DBBT */ + uint32_t disbbm_search_limit; /* ???randomizer type 2 enable ???*/ + uint32_t reserved1[15]; /* reserved for future use */ + uint32_t read_retry_enable; /* enable read retry for DBBT and firmware */ + uint32_t reserved2[1]; /*reserved, keep at 0 */ }; #endif /* __MACH_IMX_NAND_BCB_H */ |