diff options
Diffstat (limited to 'drivers')
341 files changed, 20841 insertions, 9313 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 0b0c610e629..fe35e07b124 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -162,6 +162,7 @@ source "drivers/xen/Kconfig" config PHYS_TO_BUS bool "Custom physical to bus address mapping" + depends on !COMPILE_TEST help Some SoCs use a different address map for CPU physical addresses and peripheral DMA master accesses. If yours does, select this option in diff --git a/drivers/Makefile b/drivers/Makefile index 7560008a842..77fc66eb8ba 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_MULTIPLEXER) += mux/ obj-$(CONFIG_$(PHASE_)ETH) += net/ obj-$(CONFIG_$(PHASE_)PCH) += pch/ obj-$(CONFIG_$(PHASE_)PCI) += pci/ +obj-$(CONFIG_$(PHASE_)PCI_ENDPOINT) += pci_endpoint/ obj-$(CONFIG_$(PHASE_)PHY) += phy/ obj-$(CONFIG_$(PHASE_)PINCTRL) += pinctrl/ obj-$(CONFIG_$(PHASE_)POWER) += power/ diff --git a/drivers/adc/meson-saradc.c b/drivers/adc/meson-saradc.c index 60e348968fb..0144ff828c5 100644 --- a/drivers/adc/meson-saradc.c +++ b/drivers/adc/meson-saradc.c @@ -205,9 +205,9 @@ static int meson_saradc_lock(struct meson_saradc_priv *priv) do { udelay(1); regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val); - } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--); + } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && --timeout); - if (timeout < 0) { + if (!timeout) { printf("Timeout while waiting for BL30 unlock\n"); return -ETIMEDOUT; } @@ -256,9 +256,9 @@ static int meson_saradc_wait_busy_clear(struct meson_saradc_priv *priv) do { udelay(1); regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val); - } while (FIELD_GET(MESON_SAR_ADC_REG0_BUSY_MASK, regval) && timeout--); + } while (FIELD_GET(MESON_SAR_ADC_REG0_BUSY_MASK, regval) && --timeout); - if (timeout < 0) + if (!timeout) return -ETIMEDOUT; return 0; diff --git a/drivers/adc/stm32-adc-core.c b/drivers/adc/stm32-adc-core.c index af340b8b273..3446e34fa46 100644 --- a/drivers/adc/stm32-adc-core.c +++ b/drivers/adc/stm32-adc-core.c @@ -200,6 +200,7 @@ err_aclk_disable: static const struct udevice_id stm32_adc_core_ids[] = { { .compatible = "st,stm32h7-adc-core" }, { .compatible = "st,stm32mp1-adc-core" }, + { .compatible = "st,stm32mp13-adc-core" }, {} }; diff --git a/drivers/adc/stm32-adc.c b/drivers/adc/stm32-adc.c index d50f00f1233..b11f771b71c 100644 --- a/drivers/adc/stm32-adc.c +++ b/drivers/adc/stm32-adc.c @@ -49,29 +49,68 @@ /* STM32H7_ADC_SQR1 - bit fields */ #define STM32H7_SQ1_SHIFT 6 +/* STM32H7_ADC_DIFSEL - bit fields */ +#define STM32H7_DIFSEL_SHIFT 0 +#define STM32H7_DIFSEL_MASK GENMASK(19, 0) + /* BOOST bit must be set on STM32H7 when ADC clock is above 20MHz */ #define STM32H7_BOOST_CLKRATE 20000000UL +/* STM32MP13 - Registers for each ADC instance */ +#define STM32MP13_ADC_DIFSEL 0xB0 + +/* STM32MP13_ADC_CFGR specific bit fields */ +#define STM32MP13_DMAEN BIT(0) +#define STM32MP13_DMACFG BIT(1) + +/* STM32MP13_ADC_DIFSEL - bit fields */ +#define STM32MP13_DIFSEL_SHIFT 0 +#define STM32MP13_DIFSEL_MASK GENMASK(18, 0) + #define STM32_ADC_CH_MAX 20 /* max number of channels */ #define STM32_ADC_TIMEOUT_US 100000 +struct stm32_adc { + void __iomem *regs; + int active_channel; + const struct stm32_adc_cfg *cfg; +}; + +struct stm32_adc_regs { + int reg; + int mask; + int shift; +}; + +struct stm32_adc_regspec { + const struct stm32_adc_regs difsel; +}; + struct stm32_adc_cfg { + const struct stm32_adc_regspec *regs; unsigned int max_channels; unsigned int num_bits; bool has_vregready; + bool has_boostmode; + bool has_linearcal; + bool has_presel; }; -struct stm32_adc { - void __iomem *regs; - int active_channel; - const struct stm32_adc_cfg *cfg; +static const struct stm32_adc_regspec stm32h7_adc_regspec = { + .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK }, +}; + +static const struct stm32_adc_regspec stm32mp13_adc_regspec = { + .difsel = { STM32MP13_ADC_DIFSEL, STM32MP13_DIFSEL_MASK }, }; static void stm32_adc_enter_pwr_down(struct udevice *dev) { struct stm32_adc *adc = dev_get_priv(dev); - clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST); + if (adc->cfg->has_boostmode) + clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST); + /* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */ setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD); } @@ -90,8 +129,7 @@ static int stm32_adc_exit_pwr_down(struct udevice *dev) /* Exit deep power down, then enable ADC voltage regulator */ clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD); setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADVREGEN); - - if (common->rate > STM32H7_BOOST_CLKRATE) + if (adc->cfg->has_boostmode && common->rate > STM32H7_BOOST_CLKRATE) setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST); /* Wait for startup time */ @@ -134,7 +172,7 @@ static int stm32_adc_start_channel(struct udevice *dev, int channel) return ret; /* Only use single ended channels */ - writel(0, adc->regs + STM32H7_ADC_DIFSEL); + clrbits_le32(adc->regs + adc->cfg->regs->difsel.reg, adc->cfg->regs->difsel.mask); /* Enable ADC, Poll for ADRDY to be set (after adc startup time) */ setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADEN); @@ -147,7 +185,8 @@ static int stm32_adc_start_channel(struct udevice *dev, int channel) } /* Preselect channels */ - writel(uc_pdata->channel_mask, adc->regs + STM32H7_ADC_PCSEL); + if (adc->cfg->has_presel) + writel(uc_pdata->channel_mask, adc->regs + STM32H7_ADC_PCSEL); /* Set sampling time to max value by default */ writel(0xffffffff, adc->regs + STM32H7_ADC_SMPR1); @@ -156,9 +195,11 @@ static int stm32_adc_start_channel(struct udevice *dev, int channel) /* Program regular sequence: chan in SQ1 & len = 0 for one channel */ writel(channel << STM32H7_SQ1_SHIFT, adc->regs + STM32H7_ADC_SQR1); - /* Trigger detection disabled (conversion can be launched in SW) */ - clrbits_le32(adc->regs + STM32H7_ADC_CFGR, STM32H7_EXTEN | - STM32H7_DMNGT); + /* + * Trigger detection disabled (conversion can be launched in SW) + * STM32H7_DMNGT is equivalent to STM32MP13_DMAEN & STM32MP13_DMACFG + */ + clrbits_le32(adc->regs + STM32H7_ADC_CFGR, STM32H7_EXTEN | STM32H7_DMNGT); adc->active_channel = channel; return 0; @@ -206,7 +247,7 @@ static int stm32_adc_selfcalib(struct udevice *dev) { struct stm32_adc *adc = dev_get_priv(dev); int ret; - u32 val; + u32 val, mask; /* * Select calibration mode: @@ -231,7 +272,10 @@ static int stm32_adc_selfcalib(struct udevice *dev) * - Linearity calibration (needs to be done only once for single/diff) * will run simultaneously with offset calibration. */ - setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCALDIF | STM32H7_ADCALLIN); + mask = STM32H7_ADCALDIF; + if (adc->cfg->has_linearcal) + mask |= STM32H7_ADCALLIN; + setbits_le32(adc->regs + STM32H7_ADC_CR, mask); /* Start calibration, then wait for completion */ setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCAL); @@ -394,14 +438,28 @@ static const struct adc_ops stm32_adc_ops = { }; static const struct stm32_adc_cfg stm32h7_adc_cfg = { + .regs = &stm32h7_adc_regspec, .num_bits = 16, .max_channels = STM32_ADC_CH_MAX, + .has_boostmode = true, + .has_linearcal = true, + .has_presel = true, }; static const struct stm32_adc_cfg stm32mp1_adc_cfg = { + .regs = &stm32h7_adc_regspec, .num_bits = 16, .max_channels = STM32_ADC_CH_MAX, .has_vregready = true, + .has_boostmode = true, + .has_linearcal = true, + .has_presel = true, +}; + +static const struct stm32_adc_cfg stm32mp13_adc_cfg = { + .regs = &stm32mp13_adc_regspec, + .num_bits = 12, + .max_channels = STM32_ADC_CH_MAX - 1, }; static const struct udevice_id stm32_adc_ids[] = { @@ -409,6 +467,8 @@ static const struct udevice_id stm32_adc_ids[] = { .data = (ulong)&stm32h7_adc_cfg }, { .compatible = "st,stm32mp1-adc", .data = (ulong)&stm32mp1_adc_cfg }, + { .compatible = "st,stm32mp13-adc", + .data = (ulong)&stm32mp13_adc_cfg }, {} }; diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index ac78760a33e..b8c73b4a9dd 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -363,7 +363,7 @@ static int mv_start_edma_engine(struct udevice *dev, int port) return 0; } -static int mv_reset_channel(struct udevice *dev, int port) +static void mv_reset_channel(struct udevice *dev, int port) { struct mv_priv *priv = dev_get_plat(dev); @@ -374,8 +374,6 @@ static int mv_reset_channel(struct udevice *dev, int port) udelay(25); /* allow reset propagation */ out_le32(priv->regbase + EDMA_CMD, 0); mdelay(10); - - return 0; } static void mv_reset_port(struct udevice *dev, int port) @@ -578,9 +576,9 @@ static void process_responses(struct udevice *dev, int port) } } -static int mv_ata_exec_ata_cmd(struct udevice *dev, int port, - struct sata_fis_h2d *cfis, - u8 *buffer, u32 len, u32 iswrite) +static void mv_ata_exec_ata_cmd(struct udevice *dev, int port, + struct sata_fis_h2d *cfis, + u8 *buffer, lbaint_t len, u32 iswrite) { struct mv_priv *priv = dev_get_plat(dev); struct crqb *req; @@ -589,7 +587,7 @@ static int mv_ata_exec_ata_cmd(struct udevice *dev, int port, if (len >= 64 * 1024) { printf("We only support <64K transfers for now\n"); - return -1; + return; } /* Initialize request */ @@ -653,7 +651,7 @@ static int mv_ata_exec_ata_cmd(struct udevice *dev, int port, /* Wait for completion */ if (wait_dma_completion(dev, port, slot, 10000)) { printf("ATA operation timed out\n"); - return -1; + return; } process_responses(dev, port); @@ -664,16 +662,13 @@ static int mv_ata_exec_ata_cmd(struct udevice *dev, int port, invalidate_dcache_range(start, start + ALIGN(len, ARCH_DMA_MINALIGN)); } - - return len; } -static u32 mv_sata_rw_cmd_ext(struct udevice *dev, int port, lbaint_t start, - u32 blkcnt, - u8 *buffer, int is_write) +static void mv_sata_rw_cmd_ext(struct udevice *dev, int port, lbaint_t start, + lbaint_t blkcnt, + u8 *buffer, int is_write) { struct sata_fis_h2d cfis; - u32 res; u64 block; block = (u64)start; @@ -693,18 +688,15 @@ static u32 mv_sata_rw_cmd_ext(struct udevice *dev, int port, lbaint_t start, cfis.sector_count_exp = (blkcnt >> 8) & 0xff; cfis.sector_count = blkcnt & 0xff; - res = mv_ata_exec_ata_cmd(dev, port, &cfis, buffer, - ATA_SECT_SIZE * blkcnt, is_write); - - return res >= 0 ? blkcnt : res; + mv_ata_exec_ata_cmd(dev, port, &cfis, buffer, + ATA_SECT_SIZE * blkcnt, is_write); } -static u32 mv_sata_rw_cmd(struct udevice *dev, int port, lbaint_t start, - u32 blkcnt, u8 *buffer, int is_write) +static void mv_sata_rw_cmd(struct udevice *dev, int port, lbaint_t start, + lbaint_t blkcnt, u8 *buffer, int is_write) { struct sata_fis_h2d cfis; lbaint_t block; - u32 res; block = start; @@ -720,19 +712,16 @@ static u32 mv_sata_rw_cmd(struct udevice *dev, int port, lbaint_t start, cfis.lba_low = block & 0xff; cfis.sector_count = (u8)(blkcnt & 0xff); - res = mv_ata_exec_ata_cmd(dev, port, &cfis, buffer, - ATA_SECT_SIZE * blkcnt, is_write); - - return res >= 0 ? blkcnt : res; + mv_ata_exec_ata_cmd(dev, port, &cfis, buffer, + ATA_SECT_SIZE * blkcnt, is_write); } static u32 ata_low_level_rw(struct udevice *dev, int port, lbaint_t blknr, lbaint_t blkcnt, void *buffer, int is_write) { struct blk_desc *desc = dev_get_uclass_plat(dev); - lbaint_t start, blks; + lbaint_t start, blks, max_blks; u8 *addr; - int max_blks; debug("%s: " LBAFU " " LBAFU "\n", __func__, blknr, blkcnt); diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index c6c148ebd17..185da2b5cfc 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -137,6 +137,7 @@ endif # EFI_MEDIA config IDE bool "Support IDE controllers" + depends on !COMPILE_TEST select BLK help Enables support for IDE (Integrated Drive Electronics) hard drives. diff --git a/drivers/block/efi_blk.c b/drivers/block/efi_blk.c index 9766cd6f832..f3ae70290e7 100644 --- a/drivers/block/efi_blk.c +++ b/drivers/block/efi_blk.c @@ -49,7 +49,7 @@ static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, * Write to block device * * @dev: device - * @blknr: first block to be write + * @blknr: first block to write * @blkcnt: number of blocks to write * @buffer: input buffer * Return: number of blocks transferred diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index e60aa722b97..a786fe430e4 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -14,6 +14,7 @@ config TI_PWMSS config TI_SYSC bool "TI sysc interconnect target module driver" depends on DM && ARCH_OMAP2PLUS + select CLK help Generic driver for Texas Instruments interconnect target module found on many TI SoCs. diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index e6483ddc88b..b884a02bdeb 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -131,7 +131,7 @@ config CLK_BOSTON config CLK_CDCE9XX bool "Enable CDCD9XX clock driver" - depends on CLK + depends on CLK && ARCH_OMAP2PLUS help Enable the clock synthesizer driver for CDCE913/925/937/949 series of chips. @@ -169,7 +169,7 @@ config CLK_K210_SET_RATE config CLK_MPC83XX bool "Enable MPC83xx clock driver" - depends on CLK + depends on CLK && MPC83xx help Support for the clock driver of the MPC83xx series of SoCs. diff --git a/drivers/clk/airoha/clk-airoha.c b/drivers/clk/airoha/clk-airoha.c index 1b2c4c98de5..49dbca82135 100644 --- a/drivers/clk/airoha/clk-airoha.c +++ b/drivers/clk/airoha/clk-airoha.c @@ -16,7 +16,7 @@ #include <dm/device_compat.h> #include <dm/lists.h> #include <regmap.h> -#include <syscon.h> +#include <asm/arch/scu-regmap.h> #include <dt-bindings/clock/en7523-clk.h> @@ -26,6 +26,7 @@ #define REG_SPI_CLK_DIV_SEL 0x1c4 #define REG_SPI_CLK_FREQ_SEL 0x1c8 #define REG_NPU_CLK_DIV_SEL 0x1fc +#define REG_CRYPTO_CLKSRC 0x200 #define REG_NP_SCU_PCIC 0x88 #define REG_NP_SCU_SSTR 0x9c @@ -33,6 +34,7 @@ #define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11) #define REG_CRYPTO_CLKSRC2 0x20c +#define EN7523_MAX_CLKS 8 #define EN7581_MAX_CLKS 9 struct airoha_clk_desc { @@ -66,14 +68,119 @@ struct airoha_clk_soc_data { }; static const u32 gsw_base[] = { 400000000, 500000000 }; +static const u32 emi_base[] = { 333000000, 400000000 }; +static const u32 bus_base[] = { 500000000, 540000000 }; static const u32 slic_base[] = { 100000000, 3125000 }; - +static const u32 npu_base[] = { 333000000, 400000000, 500000000 }; +/* EN7581 */ static const u32 emi7581_base[] = { 540000000, 480000000, 400000000, 300000000 }; static const u32 bus7581_base[] = { 600000000, 540000000 }; static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 }; static const u32 crypto_base[] = { 540000000, 480000000 }; static const u32 emmc7581_base[] = { 200000000, 150000000 }; +static const struct airoha_clk_desc en7523_base_clks[EN7523_MAX_CLKS] = { + [EN7523_CLK_GSW] = { + .id = EN7523_CLK_GSW, + .name = "gsw", + + .base_reg = REG_GSW_CLK_DIV_SEL, + .base_bits = 1, + .base_shift = 8, + .base_values = gsw_base, + .n_base_values = ARRAY_SIZE(gsw_base), + + .div_bits = 3, + .div_shift = 0, + .div_step = 1, + .div_offset = 1, + }, + [EN7523_CLK_EMI] = { + .id = EN7523_CLK_EMI, + .name = "emi", + + .base_reg = REG_EMI_CLK_DIV_SEL, + .base_bits = 1, + .base_shift = 8, + .base_values = emi_base, + .n_base_values = ARRAY_SIZE(emi_base), + + .div_bits = 3, + .div_shift = 0, + .div_step = 1, + .div_offset = 1, + }, + [EN7523_CLK_BUS] = { + .id = EN7523_CLK_BUS, + .name = "bus", + + .base_reg = REG_BUS_CLK_DIV_SEL, + .base_bits = 1, + .base_shift = 8, + .base_values = bus_base, + .n_base_values = ARRAY_SIZE(bus_base), + + .div_bits = 3, + .div_shift = 0, + .div_step = 1, + .div_offset = 1, + }, + [EN7523_CLK_SLIC] = { + .id = EN7523_CLK_SLIC, + .name = "slic", + + .base_reg = REG_SPI_CLK_FREQ_SEL, + .base_bits = 1, + .base_shift = 0, + .base_values = slic_base, + .n_base_values = ARRAY_SIZE(slic_base), + + .div_reg = REG_SPI_CLK_DIV_SEL, + .div_bits = 5, + .div_shift = 24, + .div_val0 = 20, + .div_step = 2, + }, + [EN7523_CLK_SPI] = { + .id = EN7523_CLK_SPI, + .name = "spi", + + .base_reg = REG_SPI_CLK_DIV_SEL, + + .base_value = 400000000, + + .div_bits = 5, + .div_shift = 8, + .div_val0 = 40, + .div_step = 2, + }, + [EN7523_CLK_NPU] = { + .id = EN7523_CLK_NPU, + .name = "npu", + + .base_reg = REG_NPU_CLK_DIV_SEL, + .base_bits = 2, + .base_shift = 8, + .base_values = npu_base, + .n_base_values = ARRAY_SIZE(npu_base), + + .div_bits = 3, + .div_shift = 0, + .div_step = 1, + .div_offset = 1, + }, + [EN7523_CLK_CRYPTO] = { + .id = EN7523_CLK_CRYPTO, + .name = "crypto", + + .base_reg = REG_CRYPTO_CLKSRC, + .base_bits = 1, + .base_shift = 0, + .base_values = emi_base, + .n_base_values = ARRAY_SIZE(emi_base), + } +}; + static const struct airoha_clk_desc en7581_base_clks[EN7581_MAX_CLKS] = { [EN7523_CLK_GSW] = { .id = EN7523_CLK_GSW, @@ -400,14 +507,8 @@ const struct clk_ops airoha_clk_ops = { static int airoha_clk_probe(struct udevice *dev) { struct airoha_clk_priv *priv = dev_get_priv(dev); - ofnode chip_scu_node; - - chip_scu_node = ofnode_by_compatible(ofnode_null(), - "airoha,en7581-chip-scu"); - if (!ofnode_valid(chip_scu_node)) - return -EINVAL; - priv->chip_scu_map = syscon_node_to_regmap(chip_scu_node); + priv->chip_scu_map = airoha_get_chip_scu_regmap(); if (IS_ERR(priv->chip_scu_map)) return PTR_ERR(priv->chip_scu_map); @@ -431,12 +532,20 @@ static int airoha_clk_bind(struct udevice *dev) return ret; } +static const struct airoha_clk_soc_data en7523_data = { + .num_clocks = ARRAY_SIZE(en7523_base_clks), + .descs = en7523_base_clks, +}; + static const struct airoha_clk_soc_data en7581_data = { .num_clocks = ARRAY_SIZE(en7581_base_clks), .descs = en7581_base_clks, }; static const struct udevice_id airoha_clk_ids[] = { + { .compatible = "airoha,en7523-scu", + .data = (ulong)&en7523_data, + }, { .compatible = "airoha,en7581-scu", .data = (ulong)&en7581_data, }, diff --git a/drivers/clk/altera/clk-agilex.c b/drivers/clk/altera/clk-agilex.c index 242740a4b00..fdbf834bb2f 100644 --- a/drivers/clk/altera/clk-agilex.c +++ b/drivers/clk/altera/clk-agilex.c @@ -14,6 +14,7 @@ #include <dm/lists.h> #include <dm/util.h> #include <dt-bindings/clock/agilex-clock.h> +#include <linux/bitfield.h> #include <linux/bitops.h> #include <asm/arch/clock_manager.h> @@ -22,6 +23,8 @@ DECLARE_GLOBAL_DATA_PTR; struct socfpga_clk_plat { void __iomem *regs; + int pllgrp; + int bitmask; }; /* @@ -544,14 +547,11 @@ static u32 clk_get_emac_clk_hz(struct socfpga_clk_plat *plat, u32 emac_id) /* Get EMAC clock source */ ctl = CM_REG_READL(plat, CLKMGR_PERPLL_EMACCTL); if (emac_id == AGILEX_EMAC0_CLK) - ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_OFFSET) & - CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_MASK; + ctl = FIELD_GET(CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_MASK, ctl); else if (emac_id == AGILEX_EMAC1_CLK) - ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_OFFSET) & - CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_MASK; + ctl = FIELD_GET(CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_MASK, ctl); else if (emac_id == AGILEX_EMAC2_CLK) - ctl = (ctl >> CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_OFFSET) & - CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_MASK; + ctl = FIELD_GET(CLKMGR_PERPLLGRP_EMACCTL_EMAC2SELB_MASK, ctl); else return 0; @@ -643,8 +643,125 @@ static ulong socfpga_clk_get_rate(struct clk *clk) } } +static int bitmask_from_clk_id(struct clk *clk) +{ + struct socfpga_clk_plat *plat = dev_get_plat(clk->dev); + + switch (clk->id) { + case AGILEX_MPU_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_MPUCLK_MASK; + break; + case AGILEX_L4_MAIN_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_L4MAINCLK_MASK; + break; + case AGILEX_L4_MP_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_L4MPCLK_MASK; + break; + case AGILEX_L4_SP_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_L4SPCLK_MASK; + break; + case AGILEX_CS_AT_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_CSCLK_MASK; + break; + case AGILEX_CS_TRACE_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_CSCLK_MASK; + break; + case AGILEX_CS_PDBG_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_CSCLK_MASK; + break; + case AGILEX_CS_TIMER_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_CSTIMERCLK_MASK; + break; + case AGILEX_S2F_USER0_CLK: + plat->pllgrp = CLKMGR_MAINPLL_EN; + plat->bitmask = CLKMGR_MAINPLLGRP_EN_S2FUSER0CLK_MASK; + break; + case AGILEX_EMAC0_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_EMAC0CLK_MASK; + break; + case AGILEX_EMAC1_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_EMAC1CLK_MASK; + break; + case AGILEX_EMAC2_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_EMAC2CLK_MASK; + break; + case AGILEX_EMAC_PTP_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_EMACPTPCLK_MASK; + break; + case AGILEX_GPIO_DB_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_GPIODBCLK_MASK; + break; + case AGILEX_SDMMC_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK; + break; + case AGILEX_S2F_USER1_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_S2FUSER1CLK_MASK; + break; + case AGILEX_PSI_REF_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_PSIREFCLK_MASK; + break; + case AGILEX_USB_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_USBCLK_MASK; + break; + case AGILEX_SPI_M_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_SPIMCLK_MASK; + break; + case AGILEX_NAND_CLK: + plat->pllgrp = CLKMGR_PERPLL_EN; + plat->bitmask = CLKMGR_PERPLLGRP_EN_NANDCLK_MASK; + break; + default: + return -ENXIO; + } + + return 0; +} + static int socfpga_clk_enable(struct clk *clk) { + struct socfpga_clk_plat *plat = dev_get_plat(clk->dev); + uintptr_t base_addr = (uintptr_t)plat->regs; + int ret; + + ret = bitmask_from_clk_id(clk); + if (ret) + return ret; + + setbits_le32(base_addr + plat->pllgrp, plat->bitmask); + + return 0; +} + +static int socfpga_clk_disable(struct clk *clk) +{ + struct socfpga_clk_plat *plat = dev_get_plat(clk->dev); + uintptr_t base_addr = (uintptr_t)plat->regs; + int ret; + + ret = bitmask_from_clk_id(clk); + if (ret) + return ret; + + clrbits_le32(base_addr + plat->pllgrp, plat->bitmask); + return 0; } @@ -672,6 +789,7 @@ static int socfpga_clk_of_to_plat(struct udevice *dev) static struct clk_ops socfpga_clk_ops = { .enable = socfpga_clk_enable, + .disable = socfpga_clk_disable, .get_rate = socfpga_clk_get_rate, }; diff --git a/drivers/clk/altera/clk-agilex.h b/drivers/clk/altera/clk-agilex.h index b3e8841a512..be639957940 100644 --- a/drivers/clk/altera/clk-agilex.h +++ b/drivers/clk/altera/clk-agilex.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) 2019 Intel Corporation <www.intel.com> + * Copyright (C) 2025 Altera Corporation <www.altera.com> */ #ifndef _CLK_AGILEX_ @@ -210,7 +211,26 @@ struct cm_config { #define CLKMGR_LOSTLOCK_SET_MASK BIT(0) +#define CLKMGR_MAINPLLGRP_EN_MPUCLK_MASK BIT(0) +#define CLKMGR_MAINPLLGRP_EN_L4MAINCLK_MASK BIT(1) +#define CLKMGR_MAINPLLGRP_EN_L4MPCLK_MASK BIT(2) +#define CLKMGR_MAINPLLGRP_EN_L4SPCLK_MASK BIT(3) +#define CLKMGR_MAINPLLGRP_EN_CSCLK_MASK BIT(4) +#define CLKMGR_MAINPLLGRP_EN_CSTIMERCLK_MASK BIT(5) +#define CLKMGR_MAINPLLGRP_EN_S2FUSER0CLK_MASK BIT(6) + +#define CLKMGR_PERPLLGRP_EN_EMAC0CLK_MASK BIT(0) +#define CLKMGR_PERPLLGRP_EN_EMAC1CLK_MASK BIT(1) +#define CLKMGR_PERPLLGRP_EN_EMAC2CLK_MASK BIT(2) +#define CLKMGR_PERPLLGRP_EN_EMACPTPCLK_MASK BIT(3) +#define CLKMGR_PERPLLGRP_EN_GPIODBCLK_MASK BIT(4) #define CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK BIT(5) +#define CLKMGR_PERPLLGRP_EN_S2FUSER1CLK_MASK BIT(6) +#define CLKMGR_PERPLLGRP_EN_PSIREFCLK_MASK BIT(7) +#define CLKMGR_PERPLLGRP_EN_USBCLK_MASK BIT(8) +#define CLKMGR_PERPLLGRP_EN_SPIMCLK_MASK BIT(9) +#define CLKMGR_PERPLLGRP_EN_NANDCLK_MASK BIT(10) + #define CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_OFFSET 26 #define CLKMGR_PERPLLGRP_EMACCTL_EMAC0SELB_MASK BIT(26) #define CLKMGR_PERPLLGRP_EMACCTL_EMAC1SELB_OFFSET 27 diff --git a/drivers/clk/at91/Kconfig b/drivers/clk/at91/Kconfig index 4563892647b..faeaa2808b0 100644 --- a/drivers/clk/at91/Kconfig +++ b/drivers/clk/at91/Kconfig @@ -1,6 +1,6 @@ config CLK_AT91 bool "AT91 clock drivers" - depends on CLK + depends on CLK && ARCH_AT91 select MISC help This option is used to enable the AT91 clock driver. diff --git a/drivers/clk/at91/clk-sam9x60-pll.c b/drivers/clk/at91/clk-sam9x60-pll.c index 65be2775ac3..66f01472739 100644 --- a/drivers/clk/at91/clk-sam9x60-pll.c +++ b/drivers/clk/at91/clk-sam9x60-pll.c @@ -183,11 +183,8 @@ static int sam9x60_frac_pll_enable(struct clk *clk) AT91_PMC_PLL_UPDT_ID_MSK, AT91_PMC_PLL_UPDT_STUPTIM(0x3f) | pll->id); - /* Recommended value for AT91_PMC_PLL_ACR */ - if (pll->characteristics->upll) - val = AT91_PMC_PLL_ACR_DEFAULT_UPLL; - else - val = AT91_PMC_PLL_ACR_DEFAULT_PLLA; + /* Load recommended value for PMC_PLL_ACR */ + val = pll->characteristics->acr; pmc_write(base, AT91_PMC_PLL_ACR, val); if (pll->characteristics->upll) { diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 580c9964ff4..f38868d1665 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -42,6 +42,7 @@ struct clk_pll_characteristics { u16 *icpll; u8 *out; u8 upll : 1; + u32 acr; }; struct clk_pll_layout { diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index e04266a2be2..2251e2846fa 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -123,6 +123,7 @@ static const struct clk_pll_characteristics apll_characteristics = { .num_output = ARRAY_SIZE(plla_outputs), .output = plla_outputs, .core_output = core_outputs, + .acr = 0x00020010UL, }; static const struct clk_pll_characteristics upll_characteristics = { @@ -131,6 +132,7 @@ static const struct clk_pll_characteristics upll_characteristics = { .output = upll_outputs, .core_output = core_outputs, .upll = true, + .acr = 0x12023010UL, /* fIN = [18 MHz, 32 MHz]*/ }; /* Layout for fractional PLLs. */ diff --git a/drivers/clk/at91/sam9x7.c b/drivers/clk/at91/sam9x7.c index ad9865feff0..9ea253e6ff8 100644 --- a/drivers/clk/at91/sam9x7.c +++ b/drivers/clk/at91/sam9x7.c @@ -164,6 +164,7 @@ static const struct clk_pll_characteristics plla_characteristics = { .num_output = ARRAY_SIZE(plla_outputs), .output = plla_outputs, .core_output = plla_core_outputs, + .acr = 0x00020010UL, /* Old ACR_DEFAULT_PLLA value */ }; static const struct clk_pll_characteristics upll_characteristics = { @@ -172,6 +173,7 @@ static const struct clk_pll_characteristics upll_characteristics = { .output = upll_outputs, .core_output = upll_core_outputs, .upll = true, + .acr = 0x12023010UL, /* fIN=[20 MHz, 32 MHz] */ }; static const struct clk_pll_characteristics lvdspll_characteristics = { @@ -179,6 +181,7 @@ static const struct clk_pll_characteristics lvdspll_characteristics = { .num_output = ARRAY_SIZE(lvdspll_outputs), .output = lvdspll_outputs, .core_output = lvdspll_core_outputs, + .acr = 0x12023010UL, /* fIN=[20 MHz, 32 MHz] */ }; static const struct clk_pll_characteristics audiopll_characteristics = { @@ -186,6 +189,7 @@ static const struct clk_pll_characteristics audiopll_characteristics = { .num_output = ARRAY_SIZE(audiopll_outputs), .output = audiopll_outputs, .core_output = audiopll_core_outputs, + .acr = 0x12023010UL, /* fIN=[20 MHz, 32 MHz] */ }; static const struct clk_pll_characteristics plladiv2_characteristics = { @@ -193,6 +197,7 @@ static const struct clk_pll_characteristics plladiv2_characteristics = { .num_output = ARRAY_SIZE(plladiv2_outputs), .output = plladiv2_outputs, .core_output = plladiv2_core_outputs, + .acr = 0x00020010UL, /* Old ACR_DEFAULT_PLLA value */ }; /* Layout for fractional PLLs. */ diff --git a/drivers/clk/at91/sama7d65.c b/drivers/clk/at91/sama7d65.c index 8d2c25e6fa9..9f0b394543b 100644 --- a/drivers/clk/at91/sama7d65.c +++ b/drivers/clk/at91/sama7d65.c @@ -184,6 +184,7 @@ static const struct clk_pll_characteristics pll_characteristics = { .num_output = ARRAY_SIZE(pll_outputs), .output = pll_outputs, .core_output = core_outputs, + .acr = 0x00070010UL, }; /* Layout for fractional PLLs. */ diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index c0e27828b1a..f24d251857f 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -169,6 +169,7 @@ static const struct clk_pll_characteristics pll_characteristics = { .num_output = ARRAY_SIZE(pll_outputs), .output = pll_outputs, .core_output = core_outputs, + .acr = 0x00070010UL, }; /* Layout for fractional PLLs. */ diff --git a/drivers/clk/clk-stub.c b/drivers/clk/clk-stub.c index 5f5aca41d5b..117266ac778 100644 --- a/drivers/clk/clk-stub.c +++ b/drivers/clk/clk-stub.c @@ -50,8 +50,11 @@ static struct clk_ops stub_clk_ops = { static const struct udevice_id stub_clk_ids[] = { { .compatible = "qcom,rpmcc" }, + { .compatible = "qcom,sdm670-rpmh-clk" }, { .compatible = "qcom,sdm845-rpmh-clk" }, + { .compatible = "qcom,sc7180-rpmh-clk" }, { .compatible = "qcom,sc7280-rpmh-clk" }, + { .compatible = "qcom,sm6350-rpmh-clk" }, { .compatible = "qcom,sm8150-rpmh-clk" }, { .compatible = "qcom,sm8250-rpmh-clk" }, { .compatible = "qcom,sm8550-rpmh-clk" }, diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c index a7d89f32cd7..683ac822a01 100644 --- a/drivers/clk/clk_scmi.c +++ b/drivers/clk/clk_scmi.c @@ -8,6 +8,7 @@ #include <clk-uclass.h> #include <dm.h> #include <dm/device_compat.h> +#include <dm/device-internal.h> #include <scmi_agent.h> #include <scmi_agent-uclass.h> #include <scmi_protocols.h> @@ -16,7 +17,9 @@ struct clk_scmi { struct clk clk; + char name[SCMI_CLOCK_NAME_LENGTH_MAX]; u32 ctrl_flags; + bool attrs_resolved; }; struct scmi_clock_priv { @@ -84,7 +87,7 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks) return 0; } -static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name, +static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char *name, u32 *attr) { struct scmi_clock_priv *priv = dev_get_priv(dev); @@ -108,7 +111,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name, if (ret) return ret; - *name = strdup(out.clock_name); + strncpy(name, out.clock_name, SCMI_CLOCK_NAME_LENGTH_MAX); *attr = out.attributes; } else { struct scmi_clk_attribute_out out; @@ -125,7 +128,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name, if (ret) return ret; - *name = strdup(out.clock_name); + strncpy(name, out.clock_name, SCMI_CLOCK_NAME_LENGTH_MAX); *attr = out.attributes; } @@ -134,39 +137,93 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name, static int scmi_clk_gate(struct clk *clk, int enable) { - struct scmi_clk_state_in in = { + struct scmi_clock_priv *priv = dev_get_parent_priv(clk->dev); + struct scmi_clk_state_in_v1 in_v1 = { + .clock_id = clk_get_id(clk), + .attributes = enable, + }; + /* Valid only from SCMI clock v2.1 */ + struct scmi_clk_state_in_v2 in_v2 = { .clock_id = clk_get_id(clk), .attributes = enable, }; struct scmi_clk_state_out out; - struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, - SCMI_CLOCK_CONFIG_SET, - in, out); + struct scmi_msg msg_v1 = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, + SCMI_CLOCK_CONFIG_SET, + in_v1, out); + struct scmi_msg msg_v2 = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, + SCMI_CLOCK_CONFIG_SET, + in_v2, out); int ret; - ret = devm_scmi_process_msg(clk->dev, &msg); + ret = devm_scmi_process_msg(clk->dev, + (priv->version < CLOCK_PROTOCOL_VERSION_2_1) ? + &msg_v1 : &msg_v2); if (ret) return ret; return scmi_to_linux_errno(out.status); } -static int scmi_clk_enable(struct clk *clk) +static int scmi_clk_get_ctrl_flags(struct clk *clk, u32 *ctrl_flags) { struct clk_scmi *clkscmi; + struct udevice *dev; + u32 attributes; struct clk *c; int ret; - if (!CONFIG_IS_ENABLED(CLK_CCF)) - return scmi_clk_gate(clk, 1); - ret = clk_get_by_id(clk->id, &c); if (ret) return ret; + dev = c->dev->parent; + clkscmi = container_of(c, struct clk_scmi, clk); - if (clkscmi->ctrl_flags & SUPPORT_CLK_STAT_CONTROL) + if (!clkscmi->attrs_resolved) { + char name[SCMI_CLOCK_NAME_LENGTH_MAX]; + ret = scmi_clk_get_attibute(dev, clk->id & CLK_ID_MSK, + name, &attributes); + if (ret) + return ret; + + strncpy(clkscmi->name, name, SCMI_CLOCK_NAME_LENGTH_MAX); + if (CLK_HAS_RESTRICTIONS(attributes)) { + u32 perm; + + ret = scmi_clk_get_permissions(dev, clk->id & CLK_ID_MSK, &perm); + if (ret < 0) + clkscmi->ctrl_flags = 0; + else + clkscmi->ctrl_flags = perm; + } else { + clkscmi->ctrl_flags = SUPPORT_CLK_STAT_CONTROL | + SUPPORT_CLK_PARENT_CONTROL | + SUPPORT_CLK_RATE_CONTROL; + } + + clkscmi->attrs_resolved = true; + } + + *ctrl_flags = clkscmi->ctrl_flags; + + return 0; +} + +static int scmi_clk_enable(struct clk *clk) +{ + u32 ctrl_flags; + int ret; + + if (!CONFIG_IS_ENABLED(CLK_CCF)) + return scmi_clk_gate(clk, 1); + + ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags); + if (ret) + return ret; + + if (ctrl_flags & SUPPORT_CLK_STAT_CONTROL) return scmi_clk_gate(clk, 1); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ @@ -176,20 +233,17 @@ static int scmi_clk_enable(struct clk *clk) static int scmi_clk_disable(struct clk *clk) { - struct clk_scmi *clkscmi; - struct clk *c; + u32 ctrl_flags; int ret; if (!CONFIG_IS_ENABLED(CLK_CCF)) return scmi_clk_gate(clk, 0); - ret = clk_get_by_id(clk->id, &c); + ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags); if (ret) return ret; - clkscmi = container_of(c, struct clk_scmi, clk); - - if (clkscmi->ctrl_flags & SUPPORT_CLK_STAT_CONTROL) + if (ctrl_flags & SUPPORT_CLK_STAT_CONTROL) return scmi_clk_gate(clk, 0); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ @@ -247,20 +301,17 @@ static ulong __scmi_clk_set_rate(struct clk *clk, ulong rate) static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) { - struct clk_scmi *clkscmi; - struct clk *c; + u32 ctrl_flags; int ret; if (!CONFIG_IS_ENABLED(CLK_CCF)) return __scmi_clk_set_rate(clk, rate); - ret = clk_get_by_id(clk->id, &c); + ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags); if (ret) return ret; - clkscmi = container_of(c, struct clk_scmi, clk); - - if (clkscmi->ctrl_flags & SUPPORT_CLK_RATE_CONTROL) + if (ctrl_flags & SUPPORT_CLK_RATE_CONTROL) return __scmi_clk_set_rate(clk, rate); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ @@ -271,7 +322,7 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) static int scmi_clk_probe(struct udevice *dev) { - struct clk_scmi *clk_scmi; + struct clk_scmi *clk_scmi_bulk, *clk_scmi; struct scmi_clock_priv *priv = dev_get_priv(dev); size_t num_clocks, i; int ret; @@ -300,39 +351,23 @@ static int scmi_clk_probe(struct udevice *dev) return ret; } + clk_scmi_bulk = kzalloc(num_clocks * sizeof(*clk_scmi), GFP_KERNEL); + if (!clk_scmi_bulk) + return -ENOMEM; + for (i = 0; i < num_clocks; i++) { - char *clock_name; - u32 attributes; + clk_scmi = clk_scmi_bulk + i; + char *clock_name = clk_scmi->name; - if (!scmi_clk_get_attibute(dev, i, &clock_name, &attributes)) { - clk_scmi = kzalloc(sizeof(*clk_scmi), GFP_KERNEL); - if (!clk_scmi || !clock_name) - ret = -ENOMEM; - else - ret = clk_register(&clk_scmi->clk, dev->driver->name, - clock_name, dev->name); - - if (ret) { - free(clk_scmi); - free(clock_name); - return ret; - } - - dev_clk_dm(dev, i, &clk_scmi->clk); - - if (CLK_HAS_RESTRICTIONS(attributes)) { - u32 perm; - - ret = scmi_clk_get_permissions(dev, i, &perm); - if (ret < 0) - clk_scmi->ctrl_flags = 0; - else - clk_scmi->ctrl_flags = perm; - } else { - clk_scmi->ctrl_flags = SUPPORT_CLK_STAT_CONTROL | SUPPORT_CLK_PARENT_CONTROL | - SUPPORT_CLK_RATE_CONTROL; - } - } + snprintf(clock_name, SCMI_CLOCK_NAME_LENGTH_MAX, "scmi-%zu", i); + + ret = clk_register(&clk_scmi->clk, dev->driver->name, + clock_name, dev->name); + if (ret) + return ret; + + dev_clk_dm(dev, i, &clk_scmi->clk); + dev_set_parent_priv(clk_scmi->clk.dev, priv); } return 0; @@ -359,20 +394,17 @@ static int __scmi_clk_set_parent(struct clk *clk, struct clk *parent) static int scmi_clk_set_parent(struct clk *clk, struct clk *parent) { - struct clk_scmi *clkscmi; - struct clk *c; + u32 ctrl_flags; int ret; if (!CONFIG_IS_ENABLED(CLK_CCF)) - return -ENOTSUPP; + return __scmi_clk_set_parent(clk, parent); - ret = clk_get_by_id(clk->id, &c); + ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags); if (ret) return ret; - clkscmi = container_of(c, struct clk_scmi, clk); - - if (clkscmi->ctrl_flags & SUPPORT_CLK_PARENT_CONTROL) + if (ctrl_flags & SUPPORT_CLK_PARENT_CONTROL) return __scmi_clk_set_parent(clk, parent); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ diff --git a/drivers/clk/clk_versaclock.c b/drivers/clk/clk_versaclock.c index 9ccaf13d242..19a787eaf0c 100644 --- a/drivers/clk/clk_versaclock.c +++ b/drivers/clk/clk_versaclock.c @@ -850,7 +850,7 @@ static char *versaclock_get_name(const char *dev_name, const char *clk_name, int buf = malloc(length); if (!buf) - ERR_PTR(-ENOMEM); + return ERR_PTR(-ENOMEM); if (index < 0) snprintf(buf, length, "%s.%s", dev_name, clk_name); @@ -904,12 +904,12 @@ int versaclock_probe(struct udevice *dev) if (IS_ERR(mux_name)) return PTR_ERR(mux_name); - clk_register(&vc5->clk_mux, "versaclock-mux", mux_name, vc5->pin_xin->dev->name); - - if (!IS_ERR(vc5->pin_xin)) + if (!IS_ERR(vc5->pin_xin)) { + clk_register(&vc5->clk_mux, "versaclock-mux", mux_name, vc5->pin_xin->dev->name); vc5_mux_set_parent(&vc5->clk_mux, 1); - else + } else { vc5_mux_set_parent(&vc5->clk_mux, 0); + } /* Configure Optional Loading Capacitance for external XTAL */ if (!(vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)) { diff --git a/drivers/clk/clk_versal.c b/drivers/clk/clk_versal.c index cb98f34b5ec..c62a747036d 100644 --- a/drivers/clk/clk_versal.c +++ b/drivers/clk/clk_versal.c @@ -121,25 +121,19 @@ static unsigned int clock_max_idx __section(".data"); #define PM_QUERY_DATA 35 -static int versal_pm_query(struct versal_pm_query_data qdata, u32 *ret_payload) -{ - struct pt_regs regs; - - regs.regs[0] = PM_SIP_SVC | PM_QUERY_DATA; - regs.regs[1] = ((u64)qdata.arg1 << 32) | qdata.qid; - regs.regs[2] = ((u64)qdata.arg3 << 32) | qdata.arg2; +typedef int (*versal_pm_query_t)(struct versal_pm_query_data qdata, + u32 *ret_payload); +static versal_pm_query_t __data versal_pm_query; - smc_call(®s); +static int versal_pm_query_legacy(struct versal_pm_query_data qdata, + u32 *ret_payload) +{ + int ret; - if (ret_payload) { - ret_payload[0] = (u32)regs.regs[0]; - ret_payload[1] = upper_32_bits(regs.regs[0]); - ret_payload[2] = (u32)regs.regs[1]; - ret_payload[3] = upper_32_bits(regs.regs[1]); - ret_payload[4] = (u32)regs.regs[2]; - } + ret = smc_call_handler(PM_QUERY_DATA, qdata.qid, qdata.arg1, qdata.arg2, + qdata.arg3, 0, 0, ret_payload); - return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : regs.regs[0]; + return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : ret; } static inline int versal_is_valid_clock(u32 clk_id) @@ -356,7 +350,8 @@ static u32 versal_clock_get_div(u32 clk_id) u32 ret_payload[PAYLOAD_ARG_CNT]; u32 div; - xilinx_pm_request(PM_CLOCK_GETDIVIDER, clk_id, 0, 0, 0, ret_payload); + xilinx_pm_request(PM_CLOCK_GETDIVIDER, clk_id, 0, 0, 0, 0, 0, + ret_payload); div = ret_payload[1]; return div; @@ -366,7 +361,8 @@ static u32 versal_clock_set_div(u32 clk_id, u32 div) { u32 ret_payload[PAYLOAD_ARG_CNT]; - xilinx_pm_request(PM_CLOCK_SETDIVIDER, clk_id, div, 0, 0, ret_payload); + xilinx_pm_request(PM_CLOCK_SETDIVIDER, clk_id, div, 0, 0, 0, 0, + ret_payload); return div; } @@ -424,7 +420,7 @@ static u32 versal_clock_get_parentid(u32 clk_id) if (versal_clock_mux(clk_id)) { xilinx_pm_request(PM_CLOCK_GETPARENT, clk_id, 0, 0, 0, - ret_payload); + 0, 0, ret_payload); parent_id = ret_payload[1]; } @@ -442,7 +438,8 @@ static u64 versal_clock_get_pll_rate(u32 clk_id) u32 parent_rate, parent_id, parent_ref_clk_id; u32 id = clk_id & 0xFFF; - xilinx_pm_request(PM_CLOCK_GETSTATE, clk_id, 0, 0, 0, ret_payload); + xilinx_pm_request(PM_CLOCK_GETSTATE, clk_id, 0, 0, 0, 0, 0, + ret_payload); res = ret_payload[1]; if (!res) { printf("0%x PLL not enabled\n", clk_id); @@ -453,9 +450,11 @@ static u64 versal_clock_get_pll_rate(u32 clk_id) parent_ref_clk_id = versal_clock_get_parentid(parent_id); parent_rate = versal_clock_get_ref_rate(parent_ref_clk_id); - xilinx_pm_request(PM_CLOCK_GETDIVIDER, clk_id, 0, 0, 0, ret_payload); + xilinx_pm_request(PM_CLOCK_GETDIVIDER, clk_id, 0, 0, 0, 0, 0, + ret_payload); fbdiv = ret_payload[1]; - xilinx_pm_request(PM_CLOCK_PLL_GETPARAM, clk_id, 2, 0, 0, ret_payload); + xilinx_pm_request(PM_CLOCK_PLL_GETPARAM, clk_id, 2, 0, 0, 0, 0, + ret_payload); frac = ret_payload[1]; freq = (fbdiv * parent_rate) >> (1 << frac); @@ -679,6 +678,10 @@ static int versal_clk_probe(struct udevice *dev) debug("%s\n", __func__); + versal_pm_query = (versal_pm_query_t)dev_get_driver_data(dev); + if (!versal_pm_query) + return -EINVAL; + ret = versal_clock_get_freq_by_name("pl_alt_ref", dev, &pl_alt_ref_clk); if (ret == -ENODATA) { @@ -767,8 +770,10 @@ static int versal_clk_enable(struct clk *clk) clk_id = priv->clk[clk->id].clk_id; - if (versal_clock_gate(clk_id)) - return xilinx_pm_request(PM_CLOCK_ENABLE, clk_id, 0, 0, 0, NULL); + if (versal_clock_gate(clk_id)) { + return xilinx_pm_request(PM_CLOCK_ENABLE, clk_id, 0, 0, 0, + 0, 0, NULL); + } return 0; } @@ -783,7 +788,7 @@ static struct clk_ops versal_clk_ops = { }; static const struct udevice_id versal_clk_ids[] = { - { .compatible = "xlnx,versal-clk" }, + { .compatible = "xlnx,versal-clk", .data = (ulong)versal_pm_query_legacy }, { } }; diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 5d7faaa3eab..a7a42b2edb6 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -916,8 +916,6 @@ static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, return -EINVAL; case CLKID_PCIE_PLL: return meson_pcie_pll_set_rate(clk, rate); - - return 0; case CLKID_VPU: return meson_clk_set_rate_by_id(clk, meson_mux_get_parent(clk, CLKID_VPU), rate, diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 34e41461e72..8504ed5d656 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -103,6 +103,21 @@ config CLK_QCOM_SM6115 on the Snapdragon SM6115 SoC. This driver supports the clocks and resets exposed by the GCC hardware block. +config CLK_QCOM_SM6350 + bool "Qualcomm SM6350 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon SM6350 SoC. This driver supports the clocks + +config CLK_QCOM_SM7150 + bool "Qualcomm SM7150 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon SM7150 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + config CLK_QCOM_SM8150 bool "Qualcomm SM8150 GCC" select CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index b3d95b0faa3..82a5b166196 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -16,6 +16,8 @@ obj-$(CONFIG_CLK_QCOM_QCS615) += clock-qcs615.o obj-$(CONFIG_CLK_QCOM_SA8775P) += clock-sa8775p.o obj-$(CONFIG_CLK_QCOM_SC7280) += clock-sc7280.o obj-$(CONFIG_CLK_QCOM_SM6115) += clock-sm6115.o +obj-$(CONFIG_CLK_QCOM_SM6350) += clock-sm6350.o +obj-$(CONFIG_CLK_QCOM_SM7150) += clock-sm7150.o obj-$(CONFIG_CLK_QCOM_SM8150) += clock-sm8150.o obj-$(CONFIG_CLK_QCOM_SM8250) += clock-sm8250.o obj-$(CONFIG_CLK_QCOM_SM8550) += clock-sm8550.o diff --git a/drivers/clk/qcom/clock-sc7280.c b/drivers/clk/qcom/clock-sc7280.c index 47e0ca5f0e5..55a233df394 100644 --- a/drivers/clk/qcom/clock-sc7280.c +++ b/drivers/clk/qcom/clock-sc7280.c @@ -38,6 +38,22 @@ static const struct freq_tbl ftbl_gcc_usb30_sec_master_clk_src[] = { { } }; +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s2_clk_src[] = { + F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625), + F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625), + F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75), + F(48000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 25), + F(52174000, CFG_CLK_SRC_GPLL0, 1, 2, 23), + F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75), + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15), + F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25), + F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0), + { } +}; + static ulong sc7280_set_rate(struct clk *clk, ulong rate) { struct msm_clk_priv *priv = dev_get_priv(clk->dev); @@ -47,6 +63,16 @@ static ulong sc7280_set_rate(struct clk *clk, ulong rate) debug("%s: %s, requested rate=%ld\n", __func__, priv->data->clks[clk->id].name, rate); switch (clk->id) { + case GCC_QUPV3_WRAP0_S5_CLK: /* UART5 */ + freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s2_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, 0x17600, + freq->pre_div, freq->m, freq->n, freq->src, 16); + return freq->freq; + case GCC_QUPV3_WRAP0_S7_CLK: /* UART7 */ + freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s2_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, 0x17860, + freq->pre_div, freq->m, freq->n, freq->src, 16); + return freq->freq; case GCC_USB30_PRIM_MASTER_CLK: freq = qcom_find_freq(ftbl_gcc_usb30_prim_master_clk_src, rate); clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR, @@ -107,6 +133,8 @@ static const struct gate_clk sc7280_clks[] = { GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x52008, BIT(10)), GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x52008, BIT(11)), GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x52008, BIT(13)), + GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x52008, BIT(15)), + GATE_CLK(GCC_QUPV3_WRAP0_S7_CLK, 0x52008, BIT(17)), GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x77010, BIT(0)), GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x770cc, BIT(0)), GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77018, BIT(0)), diff --git a/drivers/clk/qcom/clock-sdm845.c b/drivers/clk/qcom/clock-sdm845.c index 5c8702ef2fe..c9a057cf6f9 100644 --- a/drivers/clk/qcom/clock-sdm845.c +++ b/drivers/clk/qcom/clock-sdm845.c @@ -23,6 +23,7 @@ #define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf018 #define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf030 #define USB3_PRIM_PHY_AUX_CMD_RCGR 0xf05c +#define SDCC1_APPS_CLK_CMD_RCGR 0x26028 #define SDCC2_APPS_CLK_CMD_RCGR 0x1400c static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { @@ -44,6 +45,18 @@ static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { { } }; +static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = { + F(144000, CFG_CLK_SRC_CXO, 16, 3, 25), + F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), + F(20000000, CFG_CLK_SRC_GPLL0_EVEN, 5, 1, 3), + F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 6, 1, 2), + F(50000000, CFG_CLK_SRC_GPLL0_EVEN, 6, 0, 0), + F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0), + F(192000000, CFG_CLK_SRC_GPLL6, 2, 0, 0), + F(384000000, CFG_CLK_SRC_GPLL6, 1, 0, 0), + { } +}; + static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), F(9600000, CFG_CLK_SRC_CXO, 2, 0, 0), @@ -55,6 +68,22 @@ static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { { } }; +static ulong sdm670_clk_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + const struct freq_tbl *freq; + + switch (clk->id) { + case GCC_SDCC1_APPS_CLK: + freq = qcom_find_freq(ftbl_gcc_sdcc1_apps_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, SDCC1_APPS_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + default: + return 0; + } +} + static ulong sdm845_clk_set_rate(struct clk *clk, ulong rate) { struct msm_clk_priv *priv = dev_get_priv(clk->dev); @@ -76,6 +105,54 @@ static ulong sdm845_clk_set_rate(struct clk *clk, ulong rate) } } +static const struct gate_clk sdm670_clks[] = { + GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x8201c, 0x00000001), + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x0502c, 0x00000001), + GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x5200c, 0x00000400), + GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x5200c, 0x00000800), + GATE_CLK(GCC_QUPV3_WRAP0_S2_CLK, 0x5200c, 0x00001000), + GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x5200c, 0x00002000), + GATE_CLK(GCC_QUPV3_WRAP0_S4_CLK, 0x5200c, 0x00004000), + GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x5200c, 0x00008000), + GATE_CLK(GCC_QUPV3_WRAP0_S6_CLK, 0x5200c, 0x00010000), + GATE_CLK(GCC_QUPV3_WRAP0_S7_CLK, 0x5200c, 0x00020000), + GATE_CLK(GCC_QUPV3_WRAP1_S0_CLK, 0x5200c, 0x00400000), + GATE_CLK(GCC_QUPV3_WRAP1_S1_CLK, 0x5200c, 0x00800000), + GATE_CLK(GCC_QUPV3_WRAP1_S3_CLK, 0x5200c, 0x02000000), + GATE_CLK(GCC_QUPV3_WRAP1_S4_CLK, 0x5200c, 0x04000000), + GATE_CLK(GCC_QUPV3_WRAP1_S5_CLK, 0x5200c, 0x08000000), + GATE_CLK(GCC_QUPV3_WRAP1_S6_CLK, 0x5200c, 0x10000000), + GATE_CLK(GCC_QUPV3_WRAP1_S7_CLK, 0x5200c, 0x20000000), + GATE_CLK(GCC_QUPV3_WRAP_0_M_AHB_CLK, 0x5200c, 0x00000040), + GATE_CLK(GCC_QUPV3_WRAP_0_S_AHB_CLK, 0x5200c, 0x00000080), + GATE_CLK(GCC_QUPV3_WRAP_1_M_AHB_CLK, 0x5200c, 0x00100000), + GATE_CLK(GCC_QUPV3_WRAP_1_S_AHB_CLK, 0x5200c, 0x00200000), + GATE_CLK(GCC_SDCC1_AHB_CLK, 0x26008, 0x00000001), + GATE_CLK(GCC_SDCC1_APPS_CLK, 0x26004, 0x00000001), + GATE_CLK(GCC_SDCC1_ICE_CORE_CLK, 0x2600c, 0x00000001), + GATE_CLK(GCC_SDCC2_AHB_CLK, 0x14008, 0x00000001), + GATE_CLK(GCC_SDCC2_APPS_CLK, 0x14004, 0x00000001), + GATE_CLK(GCC_SDCC4_AHB_CLK, 0x16008, 0x00000001), + GATE_CLK(GCC_SDCC4_APPS_CLK, 0x16004, 0x00000001), + GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, 0x00000001), + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x82024, 0x00000001), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77010, 0x00000001), + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x7700c, 0x00000001), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x77058, 0x00000001), + GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x7708c, 0x00000001), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x77018, 0x00000001), + GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x77014, 0x00000001), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x77054, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x0f00c, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x0f014, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x0f010, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_CLKREF_CLK, 0x8c008, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x0f04c, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x0f050, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x0f054, 0x00000001), + GATE_CLK(GCC_USB_PHY_CFG_AHB2PHY_CLK, 0x6a004, 0x00000001), +}; + static const struct gate_clk sdm845_clks[] = { GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x8201c, 0x00000001), GATE_CLK(GCC_AGGRE_USB3_SEC_AXI_CLK, 0x82020, 0x00000001), @@ -140,6 +217,28 @@ static const struct gate_clk sdm845_clks[] = { GATE_CLK(GCC_USB_PHY_CFG_AHB2PHY_CLK, 0x6a004, 0x00000001), }; +static int sdm670_clk_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + debug("%s: clk %s\n", __func__, sdm670_clks[clk->id].name); + + switch (clk->id) { + case GCC_USB30_PRIM_MASTER_CLK: + qcom_gate_clk_en(priv, GCC_USB_PHY_CFG_AHB2PHY_CLK); + /* These numbers are just pulled from the frequency tables in the Linux driver */ + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR, + (4.5 * 2) - 1, 0, 0, 1 << 8, 8); + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR, + 1, 0, 0, 0, 8); + clk_rcg_set_rate_mnd(priv->base, USB3_PRIM_PHY_AUX_CMD_RCGR, + 1, 0, 0, 0, 8); + break; + } + + return qcom_gate_clk_en(priv, clk->id); +} + static int sdm845_clk_enable(struct clk *clk) { struct msm_clk_priv *priv = dev_get_priv(clk->dev); @@ -188,6 +287,17 @@ static const struct qcom_reset_map sdm845_gcc_resets[] = { [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 }, }; +static const struct qcom_power_map sdm670_gdscs[] = { + [UFS_PHY_GDSC] = { 0x77004 }, + [USB30_PRIM_GDSC] = { 0xf004 }, + [HLOS1_VOTE_AGGRE_NOC_MMU_AUDIO_TBU_GDSC] = { 0x7d030 }, + [HLOS1_VOTE_AGGRE_NOC_MMU_TBU1_GDSC] = { 0x7d034 }, + [HLOS1_VOTE_AGGRE_NOC_MMU_TBU2_GDSC] = { 0x7d038 }, + [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = { 0x7d040 }, + [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = { 0x7d048 }, + [HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC] = { 0x7d044 }, +}; + static const struct qcom_power_map sdm845_gdscs[] = { [PCIE_0_GDSC] = { 0x6b004 }, [PCIE_1_GDSC] = { 0x8d004 }, @@ -292,6 +402,19 @@ static const char *const sdm845_rcg_names[] = { "GCC_UFS_PHY_PHY_AUX", }; +static struct msm_clk_data sdm670_clk_data = { + /* Snapdragon 670 can function without its own exclusive resets. */ + .resets = sdm845_gcc_resets, + .num_resets = ARRAY_SIZE(sdm845_gcc_resets), + .clks = sdm670_clks, + .num_clks = ARRAY_SIZE(sdm670_clks), + .power_domains = sdm670_gdscs, + .num_power_domains = ARRAY_SIZE(sdm670_gdscs), + + .enable = sdm670_clk_enable, + .set_rate = sdm670_clk_set_rate, +}; + static struct msm_clk_data sdm845_clk_data = { .resets = sdm845_gcc_resets, .num_resets = ARRAY_SIZE(sdm845_gcc_resets), @@ -311,6 +434,10 @@ static struct msm_clk_data sdm845_clk_data = { static const struct udevice_id gcc_sdm845_of_match[] = { { + .compatible = "qcom,gcc-sdm670", + .data = (ulong)&sdm670_clk_data, + }, + { .compatible = "qcom,gcc-sdm845", .data = (ulong)&sdm845_clk_data, }, diff --git a/drivers/clk/qcom/clock-sm6350.c b/drivers/clk/qcom/clock-sm6350.c new file mode 100644 index 00000000000..ee6653848c7 --- /dev/null +++ b/drivers/clk/qcom/clock-sm6350.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Clock drivers for Qualcomm sm6350 + * + * (C) Copyright 2024 Linaro Ltd. + * (C) Copyright 2025 Luca Weiss <luca.weiss@fairphone.com> + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <linux/bug.h> +#include <linux/bitops.h> +#include <dt-bindings/clock/qcom,gcc-sm6350.h> + +#include "clock-qcom.h" + +#undef CFG_CLK_SRC_GPLL0_ODD +#define CFG_CLK_SRC_GPLL0_ODD (2 << 8) +#define CFG_CLK_SRC_GPLL6_EVEN (2 << 8) + +#define GCC_SE12_UART_RCG_REG 0x223a8 +#define GCC_SDCC2_APPS_CLK_SRC_REG 0x2000c + +#define APCS_GPLL7_STATUS 0x7000 +#define APCS_GPLLX_ENA_REG 0x52010 + +static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s3_clk_src[] = { + F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625), + F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625), + F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75), + F(48000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 25), + F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75), + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15), + F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25), + F(100000000, CFG_CLK_SRC_GPLL0_EVEN, 3, 0, 0), + F(102400000, CFG_CLK_SRC_GPLL0_EVEN, 1, 128, 375), + F(112000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 28, 75), + F(117964800, CFG_CLK_SRC_GPLL0_EVEN, 1, 6144, 15625), + F(120000000, CFG_CLK_SRC_GPLL0_EVEN, 2.5, 0, 0), + F(128000000, CFG_CLK_SRC_GPLL6_EVEN, 3, 0, 0), + {} +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), + F(9600000, CFG_CLK_SRC_CXO, 2, 0, 0), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(25000000, CFG_CLK_SRC_GPLL0_ODD, 8, 0, 0), + F(50000000, CFG_CLK_SRC_GPLL0_ODD, 4, 0, 0), + F(100000000, CFG_CLK_SRC_GPLL0_ODD, 2, 0, 0), + F(202000000, CFG_CLK_SRC_GPLL7, 4, 0, 0), + {} +}; + +static struct pll_vote_clk gpll7_vote_clk = { + .status = APCS_GPLL7_STATUS, + .status_bit = BIT(31), + .ena_vote = APCS_GPLLX_ENA_REG, + .vote_bit = BIT(7), +}; + +static ulong sm6350_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + const struct freq_tbl *freq; + + if (clk->id < priv->data->num_clks) + debug("%s: %s, requested rate=%ld\n", __func__, + priv->data->clks[clk->id].name, rate); + + switch (clk->id) { + case GCC_QUPV3_WRAP1_S3_CLK: /*UART9*/ + freq = qcom_find_freq(ftbl_gcc_qupv3_wrap1_s3_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, GCC_SE12_UART_RCG_REG, + freq->pre_div, freq->m, freq->n, freq->src, + 16); + + return freq->freq; + case GCC_SDCC2_APPS_CLK: + /* Enable GPLL7 so that we can point SDCC2_APPS_CLK_SRC at it */ + clk_enable_gpll0(priv->base, &gpll7_vote_clk); + freq = qcom_find_freq(ftbl_gcc_sdcc2_apps_clk_src, rate); + WARN(freq->src != CFG_CLK_SRC_GPLL7, + "SDCC2_APPS_CLK_SRC not set to GPLL7, requested rate %lu\n", + rate); + clk_rcg_set_rate_mnd(priv->base, GCC_SDCC2_APPS_CLK_SRC_REG, + freq->pre_div, freq->m, freq->n, + CFG_CLK_SRC_GPLL7, 8); + + return rate; + default: + return 0; + } +} + +static const struct gate_clk sm6350_clks[] = { + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x3e014, 0x00000001), + GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x3e010, 0x00000001), + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x1101c, 0x00000001), + GATE_CLK(GCC_QUPV3_WRAP1_S3_CLK, 0x52000, 0x00800000), + GATE_CLK(GCC_QUPV3_WRAP_1_M_AHB_CLK, 0x52000, 0x00040000), + GATE_CLK(GCC_QUPV3_WRAP_1_S_AHB_CLK, 0x52000, 0x00080000), + GATE_CLK(GCC_SDCC2_AHB_CLK, 0x20008, 0x00000001), + GATE_CLK(GCC_SDCC2_APPS_CLK, 0x20004, 0x00000001), + GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, 0x00000001), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x3a00c, 0x00000001), + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x3a034, 0x00000001), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x3a0a4, 0x00000001), + GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x3a0ac, 0x00000001), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x3a014, 0x00000001), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_1_CLK, 0x3a018, 0x00000001), + GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x3a010, 0x00000001), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x3a09c, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x1a00c, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x1a018, 0x00000001), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x1a014, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_CLKREF_CLK, 0x8c010, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x1a050, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x1a054, 0x00000001), + GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x1a058, 0x00000001), +}; + +static int sm6350_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (priv->data->num_clks < clk->id) { + debug("%s: unknown clk id %lu\n", __func__, clk->id); + return 0; + } + + debug("%s: clk %s\n", __func__, sm6350_clks[clk->id].name); + + switch (clk->id) { + case GCC_USB30_PRIM_MASTER_CLK: + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK); + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK); + break; + } + + return qcom_gate_clk_en(priv, clk->id); +} + +static const struct qcom_reset_map sm6350_gcc_resets[] = { + [GCC_QUSB2PHY_PRIM_BCR] = { 0x1d000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x1e000 }, + [GCC_SDCC1_BCR] = { 0x4b000 }, + [GCC_SDCC2_BCR] = { 0x20000 }, + [GCC_UFS_PHY_BCR] = { 0x3a000 }, + [GCC_USB30_PRIM_BCR] = { 0x1a000 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x1c000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x1c008 }, +}; + +static const struct qcom_power_map sm6350_gdscs[] = { + [USB30_PRIM_GDSC] = { 0x1a004 }, + [UFS_PHY_GDSC] = { 0x3a004 }, + [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = { 0xb7040 }, + [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = { 0xb7044 }, +}; + +static struct msm_clk_data sm6350_gcc_data = { + .resets = sm6350_gcc_resets, + .num_resets = ARRAY_SIZE(sm6350_gcc_resets), + .clks = sm6350_clks, + .num_clks = ARRAY_SIZE(sm6350_clks), + .power_domains = sm6350_gdscs, + .num_power_domains = ARRAY_SIZE(sm6350_gdscs), + + .enable = sm6350_enable, + .set_rate = sm6350_set_rate, +}; + +static const struct udevice_id gcc_sm6350_of_match[] = { + { + .compatible = "qcom,gcc-sm6350", + .data = (ulong)&sm6350_gcc_data, + }, + {} +}; + +U_BOOT_DRIVER(gcc_sm6350) = { + .name = "gcc_sm6350", + .id = UCLASS_NOP, + .of_match = gcc_sm6350_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/qcom/clock-sm7150.c b/drivers/clk/qcom/clock-sm7150.c new file mode 100644 index 00000000000..8fe2076e55e --- /dev/null +++ b/drivers/clk/qcom/clock-sm7150.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Clock drivers for Qualcomm SM7150 + * + * (C) Copyright 2025 Danila Tikhonov <danila@jiaxyga.com> + * (C) Copyright 2025 Jens Reidel <adrian@mainlining.org> + * + * Based on Linux Kernel driver + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <linux/bug.h> +#include <linux/bitops.h> +#include <dt-bindings/clock/qcom,sm7150-gcc.h> + +#include "clock-qcom.h" + +#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf01c +#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf034 +#define USB3_PRIM_PHY_AUX_CLK_CMD_RCGR 0xf060 + +#define SE8_UART_APPS_CMD_RCGR 0x18278 +#define GCC_SDCC2_APPS_CLK_SRC_REG 0x1400c + +#define APCS_GPLL7_STATUS 0x27000 +#define APCS_GPLLX_ENA_REG 0x52000 + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625), + F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625), + F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75), + F(48000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 25), + F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75), + F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15), + F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25), + F(100000000, CFG_CLK_SRC_GPLL0_EVEN, 3, 0, 0), + F(102400000, CFG_CLK_SRC_GPLL0_EVEN, 1, 128, 375), + F(112000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 28, 75), + F(117964800, CFG_CLK_SRC_GPLL0_EVEN, 1, 6144, 15625), + F(120000000, CFG_CLK_SRC_GPLL0_EVEN, 2.5, 0, 0), + F(128000000, CFG_CLK_SRC_GPLL0, 1, 16, 75), + { } +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), + F(9600000, CFG_CLK_SRC_CXO, 2, 0, 0), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 12, 0, 0), + F(50000000, CFG_CLK_SRC_GPLL0_EVEN, 6, 0, 0), + F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0), + F(208000000, CFG_CLK_SRC_GPLL7, 4, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { + F(66666667, CFG_CLK_SRC_GPLL0, 4.5, 0, 0), + F(133333333, CFG_CLK_SRC_GPLL0_EVEN, 4.5, 0, 0), + F(200000000, CFG_CLK_SRC_GPLL0, 3, 0, 0), + F(240000000, CFG_CLK_SRC_GPLL0, 2.5, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_mock_utmi_clk_src[] = { + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(20000000, CFG_CLK_SRC_GPLL0_EVEN, 15, 0, 0), + F(40000000, CFG_CLK_SRC_GPLL0_EVEN, 7.5, 0, 0), + F(60000000, CFG_CLK_SRC_GPLL0, 10, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_usb3_prim_phy_aux_clk_src[] = { + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + { } +}; + +static ulong sm7150_clk_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + const struct freq_tbl *freq; + + if (clk->id < priv->data->num_clks) + debug("%s: %s, requested rate=%ld\n", __func__, priv->data->clks[clk->id].name, rate); + + switch (clk->id) { + case GCC_QUPV3_WRAP1_S2_CLK: /* UART8 */ + freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s0_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, SE8_UART_APPS_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 16); + return freq->freq; + case GCC_USB30_PRIM_MASTER_CLK: + freq = qcom_find_freq(ftbl_gcc_usb30_prim_master_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MASTER_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_USB30_PRIM_MOCK_UTMI_CLK: + freq = qcom_find_freq(ftbl_gcc_usb30_prim_mock_utmi_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 0); + return freq->freq; + case GCC_USB3_PRIM_PHY_AUX_CLK_SRC: + freq = qcom_find_freq(ftbl_gcc_usb3_prim_phy_aux_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, USB3_PRIM_PHY_AUX_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 0); + return freq->freq; + case GCC_SDCC2_APPS_CLK: + freq = qcom_find_freq(ftbl_gcc_sdcc2_apps_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, GCC_SDCC2_APPS_CLK_SRC_REG, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + default: + return 0; + } +} + +static const struct gate_clk sm7150_clks[] = { + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x82024, BIT(0)), + GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x8201c, BIT(0)), + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x502c, BIT(0)), + GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x5200c, BIT(10)), + GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x5200c, BIT(11)), + GATE_CLK(GCC_QUPV3_WRAP0_S2_CLK, 0x5200c, BIT(12)), + GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x5200c, BIT(13)), + GATE_CLK(GCC_QUPV3_WRAP0_S4_CLK, 0x5200c, BIT(14)), + GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x5200c, BIT(15)), + GATE_CLK(GCC_QUPV3_WRAP0_S6_CLK, 0x5200c, BIT(16)), + GATE_CLK(GCC_QUPV3_WRAP0_S7_CLK, 0x5200c, BIT(17)), + GATE_CLK(GCC_QUPV3_WRAP1_S0_CLK, 0x5200c, BIT(22)), + GATE_CLK(GCC_QUPV3_WRAP1_S1_CLK, 0x5200c, BIT(23)), + GATE_CLK(GCC_QUPV3_WRAP1_S2_CLK, 0x5200c, BIT(24)), + GATE_CLK(GCC_QUPV3_WRAP1_S3_CLK, 0x5200c, BIT(25)), + GATE_CLK(GCC_QUPV3_WRAP1_S4_CLK, 0x5200c, BIT(26)), + GATE_CLK(GCC_QUPV3_WRAP1_S5_CLK, 0x5200c, BIT(27)), + GATE_CLK(GCC_QUPV3_WRAP1_S6_CLK, 0x5200c, BIT(28)), + GATE_CLK(GCC_QUPV3_WRAP1_S7_CLK, 0x5200c, BIT(29)), + GATE_CLK(GCC_QUPV3_WRAP_0_M_AHB_CLK, 0x5200c, BIT(6)), + GATE_CLK(GCC_QUPV3_WRAP_0_S_AHB_CLK, 0x5200c, BIT(7)), + GATE_CLK(GCC_QUPV3_WRAP_1_M_AHB_CLK, 0x5200c, BIT(20)), + GATE_CLK(GCC_QUPV3_WRAP_1_S_AHB_CLK, 0x5200c, BIT(21)), + GATE_CLK(GCC_SDCC1_AHB_CLK, 0x12008, BIT(0)), + GATE_CLK(GCC_SDCC1_APPS_CLK, 0x1200c, BIT(0)), + GATE_CLK(GCC_SDCC1_ICE_CORE_CLK, 0x12040, BIT(0)), + GATE_CLK(GCC_SDCC2_AHB_CLK, 0x14008, BIT(0)), + GATE_CLK(GCC_SDCC2_APPS_CLK, 0x14004, BIT(0)), + GATE_CLK(GCC_SDCC4_AHB_CLK, 0x16008, BIT(0)), + GATE_CLK(GCC_SDCC4_APPS_CLK, 0x16004, BIT(0)), + GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77014, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x77038, BIT(0)), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x77090, BIT(0)), + GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x77094, BIT(0)), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x7701c, BIT(0)), + GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x77018, BIT(0)), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x7708c, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x0f010, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x0f018, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x0f014, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_CLKREF_CLK, 0x8c010, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0x0f050, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x0f054, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x0f058, BIT(0)), + GATE_CLK(GCC_USB_PHY_CFG_AHB2PHY_CLK, 0x6a004, BIT(0)), +}; + +static int sm7150_clk_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + if (priv->data->num_clks < clk->id) { + debug("%s: unknown clk id %lu\n", __func__, clk->id); + return 0; + } + + debug("%s: clk %s\n", __func__, sm7150_clks[clk->id].name); + + switch (clk->id) { + case GCC_AGGRE_USB3_PRIM_AXI_CLK: + qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK); + fallthrough; + case GCC_USB30_PRIM_MASTER_CLK: + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_AUX_CLK); + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK); + break; + } + + return qcom_gate_clk_en(priv, clk->id); +} + +static const struct qcom_reset_map sm7150_gcc_resets[] = { + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB30_PRIM_BCR] = { 0xf000 }, + [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 }, + [GCC_USB3_DP_PHY_SEC_BCR] = { 0x50014 }, + [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 }, + [GCC_USB3_PHY_SEC_BCR] = { 0x5000c }, + [GCC_QUSB2PHY_PRIM_BCR] = { 0x26000 }, +}; + +static const struct qcom_power_map sm7150_gdscs[] = { + [PCIE_0_GDSC] = { 0x6b004 }, + [UFS_PHY_GDSC] = { 0x77004 }, + [USB30_PRIM_GDSC] = { 0xf004 }, +}; + +static const phys_addr_t sm7150_rcg_addrs[] = { + 0x10f01c, // USB30_PRIM_MASTER_CLK_CMD_RCGR + 0x10f034, // USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR + 0x10f060, // USB3_PRIM_PHY_AUX_CLK_CMD_RCGR, +}; + +static const char *const sm7150_rcg_names[] = { + "USB30_PRIM_MASTER_CLK", + "USB30_PRIM_MOCK_UTMI_CLK", + "USB3_PRIM_PHY_AUX_CLK", +}; + +static struct msm_clk_data sm7150_gcc_data = { + .resets = sm7150_gcc_resets, + .num_resets = ARRAY_SIZE(sm7150_gcc_resets), + .clks = sm7150_clks, + .num_clks = ARRAY_SIZE(sm7150_clks), + + .power_domains = sm7150_gdscs, + .num_power_domains = ARRAY_SIZE(sm7150_gdscs), + + .enable = sm7150_clk_enable, + .set_rate = sm7150_clk_set_rate, + + .dbg_rcg_addrs = sm7150_rcg_addrs, + .num_rcgs = ARRAY_SIZE(sm7150_rcg_addrs), + .dbg_rcg_names = sm7150_rcg_names, +}; + +static const struct udevice_id gcc_sm7150_of_match[] = { + { .compatible = "qcom,sm7150-gcc", .data = (ulong)&sm7150_gcc_data, }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(gcc_sm7150) = { + .name = "gcc_sm7150", + .id = UCLASS_NOP, + .of_match = gcc_sm7150_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; diff --git a/drivers/clk/qcom/clock-sm8250.c b/drivers/clk/qcom/clock-sm8250.c index cc481258d22..37268c4eaf5 100644 --- a/drivers/clk/qcom/clock-sm8250.c +++ b/drivers/clk/qcom/clock-sm8250.c @@ -18,14 +18,9 @@ #define GCC_SE12_UART_RCG_REG 0x184D0 #define GCC_SDCC2_APPS_CLK_SRC_REG 0x1400c -#define APCS_GPLL0_ENA_VOTE 0x79000 #define APCS_GPLL9_STATUS 0x1c000 #define APCS_GPLLX_ENA_REG 0x52018 -#define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf020 -#define USB30_PRIM_MOCK_UTMI_CLK_CMD_RCGR 0xf038 -#define USB3_PRIM_PHY_AUX_CMD_RCGR 0xf064 - static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s4_clk_src[] = { F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625), F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625), diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 12966d02a22..51c87cc3606 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -51,8 +51,8 @@ config CLK_R8A7794 Enable this to support the clocks on Renesas R8A7794 SoC. config CLK_RCAR_GEN3 - bool "Renesas R-Car Gen3 and Gen4 clock driver" - def_bool y if RCAR_64 + bool "Renesas R-Car Gen3, Gen4, RZ/G2L clock driver" + def_bool y if RCAR_GEN3 || RCAR_GEN4 || RZG2L depends on CLK_RENESAS select CLK_RCAR select CLK_RCAR_CPG_LIB diff --git a/drivers/clk/rockchip/clk_px30.c b/drivers/clk/rockchip/clk_px30.c index ad7e1c0f246..b5054e84c32 100644 --- a/drivers/clk/rockchip/clk_px30.c +++ b/drivers/clk/rockchip/clk_px30.c @@ -1360,6 +1360,9 @@ static ulong px30_clk_set_rate(struct clk *clk, ulong rate) case SCLK_GMAC_RMII: ret = px30_mac_set_speed_clk(priv, rate); break; + /* Might occur in cru assigned-clocks, can be ignored here */ + case SCLK_GPU: + break; #endif default: return -ENOENT; @@ -1726,6 +1729,9 @@ static ulong px30_pmuclk_set_rate(struct clk *clk, ulong rate) case SCLK_UART0_PMU: ret = px30_pmu_uart0_set_clk(priv, rate); break; + /* Might occur in pmucru assigned-clocks, can be ignored here */ + case SCLK_WIFI_PMU: + break; default: return -ENOENT; } diff --git a/drivers/clk/sifive/Kconfig b/drivers/clk/sifive/Kconfig index 20fc004b59e..01e4f33415e 100644 --- a/drivers/clk/sifive/Kconfig +++ b/drivers/clk/sifive/Kconfig @@ -2,7 +2,7 @@ config CLK_SIFIVE bool "SiFive SoC driver support" - depends on CLK + depends on CLK && RISCV help SoC drivers for SiFive Linux-capable SoCs. diff --git a/drivers/clk/sophgo/clk-common.h b/drivers/clk/sophgo/clk-common.h index a9e83d0d689..a18673f397c 100644 --- a/drivers/clk/sophgo/clk-common.h +++ b/drivers/clk/sophgo/clk-common.h @@ -70,7 +70,7 @@ cv1800b_clk_setfield(void *base, struct cv1800b_clk_regfield *field, u32 val) u32 new_val = (readl(base + field->offset) & ~mask) | ((val << field->shift) & mask); - return writel(new_val, base + field->offset); + writel(new_val, base + field->offset); } #endif /* __CLK_SOPHGO_COMMON_H__ */ diff --git a/drivers/clk/ti/Kconfig b/drivers/clk/ti/Kconfig index fbcdefd889a..fdda283d6d3 100644 --- a/drivers/clk/ti/Kconfig +++ b/drivers/clk/ti/Kconfig @@ -5,14 +5,14 @@ config CLK_TI_AM3_DPLL bool "TI AM33XX Digital Phase-Locked Loop (DPLL) clock drivers" - depends on CLK && OF_CONTROL + depends on CLK && OF_CONTROL && ARCH_OMAP2PLUS help This enables the DPLL clock drivers support on AM33XX SoCs. The DPLL provides all interface clocks and functional clocks to the processor. config CLK_TI_CTRL bool "TI OMAP4 clock controller" - depends on CLK && OF_CONTROL + depends on CLK && OF_CONTROL && ARCH_OMAP2PLUS help This enables the clock controller driver support on TI's SoCs. @@ -49,7 +49,7 @@ config CLK_K3_PLL Enables PLL clock support for K3 SoC family of devices. config SPL_CLK_K3_PLL - bool "PLL clock support for K3 SoC family of devices" + bool "PLL clock support for K3 SoC family of devices in SPL" depends on CLK && LIB_RATIONAL && SPL help Enables PLL clock support for K3 SoC family of devices. @@ -61,7 +61,7 @@ config CLK_K3 Enables the clock translation layer from DT to device clocks. config SPL_CLK_K3 - bool "Clock support for K3 SoC family of devices" + bool "Clock support for K3 SoC family of devices in SPL" depends on CLK && SPL help Enables the clock translation layer from DT to device clocks. diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index e040e3f2806..cf1cf8abfbe 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -1221,13 +1221,16 @@ int ofnode_decode_display_timing(ofnode parent, int index, int ret = 0; timings = ofnode_find_subnode(parent, "display-timings"); - if (!ofnode_valid(timings)) - return -EINVAL; - - i = 0; - ofnode_for_each_subnode(node, timings) { - if (i++ == index) - break; + if (ofnode_valid(timings)) { + i = 0; + ofnode_for_each_subnode(node, timings) { + if (i++ == index) + break; + } + } else { + if (index != 0) + return -EINVAL; + node = ofnode_find_subnode(parent, "panel-timing"); } if (!ofnode_valid(node)) @@ -1629,18 +1632,6 @@ bool ofnode_pre_reloc(ofnode node) ofnode_read_bool(node, "bootph-pre-sram")) return gd->flags & GD_FLG_RELOC; - if (IS_ENABLED(CONFIG_OF_TAG_MIGRATE)) { - /* detect and handle old tags */ - if (ofnode_read_bool(node, "u-boot,dm-pre-reloc") || - ofnode_read_bool(node, "u-boot,dm-pre-proper") || - ofnode_read_bool(node, "u-boot,dm-spl") || - ofnode_read_bool(node, "u-boot,dm-tpl") || - ofnode_read_bool(node, "u-boot,dm-vpl")) { - gd->flags |= GD_FLG_OF_TAG_MIGRATE; - return true; - } - } - return false; #endif } diff --git a/drivers/cpu/imx8_cpu.c b/drivers/cpu/imx8_cpu.c index 950630453f9..5f17122c36c 100644 --- a/drivers/cpu/imx8_cpu.c +++ b/drivers/cpu/imx8_cpu.c @@ -113,6 +113,8 @@ static const char *get_imx_type_str(u32 imxtype) return "91(01)";/* iMX91 9x9 Specific feature */ case MXC_CPU_IMX95: return "95"; + case MXC_CPU_IMX94: + return "94"; default: return "??"; } @@ -190,7 +192,7 @@ static int cpu_imx_get_temp(struct cpu_imx_plat *plat) return 0xdeadbeef; } - return cpu_tmp; + return cpu_tmp / 1000; } #else static int cpu_imx_get_temp(struct cpu_imx_plat *plat) diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c index 8f7a821ebf3..07d336c074a 100644 --- a/drivers/crypto/fsl/jr.c +++ b/drivers/crypto/fsl/jr.c @@ -642,7 +642,7 @@ static int rng_init(uint8_t sec_idx, ccsr_sec_t *sec) */ if (!inst_handles) { kick_trng(ent_delay, sec); - ent_delay += 400; + ent_delay = ent_delay * 2; } /* * if instantiate_rng(...) fails, the loop will rerun diff --git a/drivers/crypto/tegra/Kconfig b/drivers/crypto/tegra/Kconfig index b027609307b..0f2acaaade1 100644 --- a/drivers/crypto/tegra/Kconfig +++ b/drivers/crypto/tegra/Kconfig @@ -1,6 +1,6 @@ config TEGRA_AES bool "Support the Tegra AES" - depends on DM_AES + depends on ARCH_TEGRA && DM_AES help This provides a means to encrypt and decrypt data using the Tegra Bit Stream Engine for Video/Audio. Also may provide a mean to diff --git a/drivers/ddr/altera/iossm_mailbox.c b/drivers/ddr/altera/iossm_mailbox.c index 21f94959a04..2a2f86a650e 100644 --- a/drivers/ddr/altera/iossm_mailbox.c +++ b/drivers/ddr/altera/iossm_mailbox.c @@ -38,6 +38,8 @@ #define IOSSM_STATUS_CMD_RESPONSE_ERROR(n) FIELD_GET(IOSSM_STATUS_CMD_RESPONSE_ERROR_MASK, n) #define IOSSM_STATUS_GENERAL_ERROR_MASK GENMASK(4, 1) #define IOSSM_STATUS_GENERAL_ERROR(n) FIELD_GET(IOSSM_STATUS_GENERAL_ERROR_MASK, n) +#define IOSSM_MAILBOX_SPEC_VERSION_MASK GENMASK(2, 0) +#define IOSSM_MAILBOX_SPEC_VERSION(n) FIELD_GET(IOSSM_MAILBOX_SPEC_VERSION_MASK, n) /* Offset of Mailbox Read-only Registers */ #define IOSSM_MAILBOX_HEADER_OFFSET 0x0 @@ -383,6 +385,23 @@ err: return ret; } +static bool is_mailbox_spec_compatible(struct io96b_info *io96b_ctrl) +{ + u32 mailbox_header; + u8 mailbox_spec_ver; + + mailbox_header = readl(io96b_ctrl->io96b[0].io96b_csr_addr + + IOSSM_MAILBOX_HEADER_OFFSET); + mailbox_spec_ver = IOSSM_MAILBOX_SPEC_VERSION(mailbox_header); + printf("%s: IOSSM mailbox version: %d\n", __func__, mailbox_spec_ver); + + /* for now there are two mailbox spec versions, 0 and 1; only version 1 is compatible */ + if (!mailbox_spec_ver) + return false; + + return true; +} + /* * Initial function to be called to set memory interface IP type and instance ID * IP type and instance ID need to be determined before sending mailbox command @@ -392,6 +411,11 @@ void io96b_mb_init(struct io96b_info *io96b_ctrl) int i, j; u32 mem_intf_info_0, mem_intf_info_1; + if (!is_mailbox_spec_compatible(io96b_ctrl)) { + printf("DDR: Failed to get compatible mailbox version\n"); + hang(); + } + debug("%s: num_instance %d\n", __func__, io96b_ctrl->num_instance); for (i = 0; i < io96b_ctrl->num_instance; i++) { diff --git a/drivers/ddr/altera/sdram_soc64.c b/drivers/ddr/altera/sdram_soc64.c index f8fc92060db..2d0093c591c 100644 --- a/drivers/ddr/altera/sdram_soc64.c +++ b/drivers/ddr/altera/sdram_soc64.c @@ -85,11 +85,11 @@ int emif_reset(struct altera_sdram_plat *plat) debug("DDR: Triggerring emif reset\n"); hmc_ecc_writel(plat, DDR_HMC_CORE2SEQ_INT_REQ, RSTHANDSHAKECTRL); - /* if seq2core[3] = 0, we are good */ + /* if seq2core[2:0] = 0b0000_0111, we are good */ ret = wait_for_bit_le32((const void *)(plat->hmc + RSTHANDSHAKESTAT), - DDR_HMC_SEQ2CORE_INT_RESP_MASK, - false, 1000, false); + DDR_HMC_SEQ2CORE_INT_REQ_ACK_MASK, + true, 1000, false); if (ret) { printf("DDR: failed to get ack from EMIF\n"); return ret; diff --git a/drivers/ddr/altera/sdram_soc64.h b/drivers/ddr/altera/sdram_soc64.h index 6031cef560e..6fe0653922c 100644 --- a/drivers/ddr/altera/sdram_soc64.h +++ b/drivers/ddr/altera/sdram_soc64.h @@ -77,7 +77,7 @@ struct altera_sdram_plat { #define DDR_HMC_INTMODE_INTMODE_SET_MSK BIT(0) #define DDR_HMC_RSTHANDSHAKE_MASK 0x0000000f #define DDR_HMC_CORE2SEQ_INT_REQ 0x0000000f -#define DDR_HMC_SEQ2CORE_INT_RESP_MASK BIT(3) +#define DDR_HMC_SEQ2CORE_INT_REQ_ACK_MASK GENMASK(2, 0) #define DDR_HMC_HPSINTFCSEL_ENABLE_MASK 0x001f1f1f #define DDR_HMC_ERRINTEN_INTMASK \ diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig index e33b0056d0b..2cf4289b448 100644 --- a/drivers/dfu/Kconfig +++ b/drivers/dfu/Kconfig @@ -98,6 +98,7 @@ config DFU_SCSI config SET_DFU_ALT_INFO bool "Dynamic set of DFU alternate information" + depends on !COMPILE_TEST help This option allows to call the function set_dfu_alt_info to dynamically build dfu_alt_info in board. diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c index afc64fd5280..6df3917e129 100644 --- a/drivers/fastboot/fb_nand.c +++ b/drivers/fastboot/fb_nand.c @@ -157,8 +157,13 @@ int fastboot_nand_get_part_info(const char *part_name, struct part_info **part_info, char *response) { struct mtd_info *mtd = NULL; + int ret; + + ret = fb_nand_lookup(part_name, &mtd, part_info, response); + if (ret) + return -ENOENT; - return fb_nand_lookup(part_name, &mtd, part_info, response); + return ret; } /** diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index e07ec3929b2..3742467caee 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -3,6 +3,7 @@ * Xilinx Zynq MPSoC Firmware driver * * Copyright (C) 2018-2019 Xilinx, Inc. + * Copyright (C) 2022 - 2025, Advanced Micro Devices, Inc. */ #include <asm/arch/hardware.h> @@ -158,7 +159,7 @@ unsigned int zynqmp_firmware_version(void) if (pm_api_version == ZYNQMP_PM_VERSION_INVALID) { ret = xilinx_pm_request(PM_GET_API_VERSION, 0, 0, 0, 0, - ret_payload); + 0, 0, ret_payload); if (ret) panic("PMUFW is not found - Please load it!\n"); @@ -202,7 +203,7 @@ int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 value int ret; ret = xilinx_pm_request(PM_IOCTL, node, IOCTL_SET_GEM_CONFIG, - config, value, NULL); + config, value, 0, 0, NULL); if (ret) printf("%s: node %d: set_gem_config %d failed\n", __func__, node, config); @@ -215,7 +216,7 @@ int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value) int ret; ret = xilinx_pm_request(PM_IOCTL, node, IOCTL_SET_SD_CONFIG, - config, value, NULL); + config, value, 0, 0, NULL); if (ret) printf("%s: node %d: set_sd_config %d failed\n", __func__, node, config); @@ -236,7 +237,7 @@ u32 zynqmp_pm_get_bootmode_reg(void) } ret = xilinx_pm_request(PM_IOCTL, CRP_BOOT_MODE_REG_NODE, IOCTL_READ_REG, - CRP_BOOT_MODE_REG_OFFSET, 0, ret_payload); + CRP_BOOT_MODE_REG_OFFSET, 0, 0, 0, ret_payload); if (ret) { printf("%s: node 0x%x: get_bootmode 0x%x failed\n", __func__, CRP_BOOT_MODE_REG_NODE, CRP_BOOT_MODE_REG_OFFSET); @@ -259,7 +260,8 @@ u32 zynqmp_pm_get_pmc_multi_boot_reg(void) } ret = xilinx_pm_request(PM_IOCTL, PM_REG_PMC_GLOBAL_NODE, IOCTL_READ_REG, - PMC_MULTI_BOOT_MODE_REG_OFFSET, 0, ret_payload); + PMC_MULTI_BOOT_MODE_REG_OFFSET, 0, 0, 0, + ret_payload); if (ret) { printf("%s: node 0x%x: get_bootmode 0x%x failed\n", __func__, PM_REG_PMC_GLOBAL_NODE, PMC_MULTI_BOOT_MODE_REG_OFFSET); @@ -276,7 +278,7 @@ int zynqmp_pm_feature(const u32 api_id) /* Check feature check API version */ ret = xilinx_pm_request(PM_FEATURE_CHECK, api_id, 0, 0, 0, - ret_payload); + 0, 0, ret_payload); if (ret) return ret; @@ -296,7 +298,7 @@ int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id) /* Check feature check API version */ ret = xilinx_pm_request(PM_FEATURE_CHECK, PM_FEATURE_CHECK, 0, 0, 0, - ret_payload); + 0, 0, ret_payload); if (ret) return ret; @@ -308,7 +310,7 @@ int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id) */ ret = xilinx_pm_request(PM_FEATURE_CHECK, api_id, 0, 0, 0, - ret_payload); + 0, 0, ret_payload); if (ret) return ret; @@ -340,7 +342,7 @@ int zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size) flush_dcache_range((ulong)cfg_obj, (ulong)(cfg_obj + size)); err = xilinx_pm_request(PM_SET_CONFIGURATION, (u32)(u64)cfg_obj, 0, 0, - 0, ret_payload); + 0, 0, 0, ret_payload); if (err == XST_PM_NO_ACCESS) { return -EACCES; } @@ -425,13 +427,14 @@ U_BOOT_DRIVER(zynqmp_power) = { smc_call_handler_t __data smc_call_handler; static int smc_call_legacy(u32 api_id, u32 arg0, u32 arg1, u32 arg2, - u32 arg3, u32 *ret_payload) + u32 arg3, u32 arg4, u32 arg5, u32 *ret_payload) { struct pt_regs regs; regs.regs[0] = PM_SIP_SVC | api_id; regs.regs[1] = ((u64)arg1 << 32) | arg0; regs.regs[2] = ((u64)arg3 << 32) | arg2; + regs.regs[3] = arg4; smc_call(®s); @@ -441,16 +444,18 @@ static int smc_call_legacy(u32 api_id, u32 arg0, u32 arg1, u32 arg2, ret_payload[2] = (u32)regs.regs[1]; ret_payload[3] = upper_32_bits(regs.regs[1]); ret_payload[4] = (u32)regs.regs[2]; + ret_payload[5] = upper_32_bits((u32)regs.regs[2]); + ret_payload[6] = (u32)regs.regs[3]; } return (ret_payload) ? ret_payload[0] : 0; } int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2, - u32 arg3, u32 *ret_payload) + u32 arg3, u32 arg4, u32 arg5, u32 *ret_payload) { - debug("%s at EL%d, API ID: 0x%0x, 0x%0x, 0x%0x, 0x%0x, 0x%0x\n", - __func__, current_el(), api_id, arg0, arg1, arg2, arg3); + debug("%s at EL%d, API ID: 0x%0x, 0x%0x, 0x%0x, 0x%0x, 0x%0x, 0x%0x, 0x%0x\n", + __func__, current_el(), api_id, arg0, arg1, arg2, arg3, arg4, arg5); if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3) { #if defined(CONFIG_ZYNQMP_IPI) @@ -459,7 +464,7 @@ int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2, * is capable to handle PMUFW_PAYLOAD_ARG_CNT bytes but the * firmware API is limited by the SMC call size */ - u32 regs[] = {api_id, arg0, arg1, arg2, arg3}; + u32 regs[] = {api_id, arg0, arg1, arg2, arg3, arg4, arg5}; int ret; if (api_id == PM_FPGA_LOAD) { @@ -481,7 +486,8 @@ int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2, #endif } - return smc_call_handler(api_id, arg0, arg1, arg2, arg3, ret_payload); + return smc_call_handler(api_id, arg0, arg1, arg2, arg3, arg4, + arg5, ret_payload); } static const struct udevice_id zynqmp_firmware_ids[] = { diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig index 8cf85f0d7a1..33e089c460b 100644 --- a/drivers/firmware/scmi/Kconfig +++ b/drivers/firmware/scmi/Kconfig @@ -41,3 +41,11 @@ config SCMI_AGENT_OPTEE help Enable the SCMI communication channel based on OP-TEE transport for compatible "linaro,scmi-optee". + +config SCMI_ID_VENDOR_80 + bool + +config SCMI_ID_VENDOR_82 + bool + +source "drivers/firmware/scmi/vendors/imx/Kconfig" diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile index dae42863589..6129726f817 100644 --- a/drivers/firmware/scmi/Makefile +++ b/drivers/firmware/scmi/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_SCMI_AGENT_MAILBOX) += mailbox_agent.o obj-$(CONFIG_SCMI_AGENT_OPTEE) += optee_agent.o obj-$(CONFIG_SCMI_POWER_DOMAIN) += pwdom.o obj-$(CONFIG_SANDBOX) += sandbox-scmi_agent.o sandbox-scmi_devices.o +obj-y += vendors/imx/ diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index 74a87832dcb..5b242a039c2 100644 --- a/drivers/firmware/scmi/sandbox-scmi_agent.c +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -828,7 +828,7 @@ static int sandbox_scmi_clock_rate_get(struct udevice *dev, static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg) { - struct scmi_clk_state_in *in = NULL; + struct scmi_clk_state_in_v1 *in = NULL; struct scmi_clk_state_out *out = NULL; struct sandbox_scmi_clk *clk_state = NULL; @@ -836,7 +836,7 @@ static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg) !msg->out_msg || msg->out_msg_sz < sizeof(*out)) return -EINVAL; - in = (struct scmi_clk_state_in *)msg->in_msg; + in = (struct scmi_clk_state_in_v1 *)msg->in_msg; out = (struct scmi_clk_state_out *)msg->out_msg; clk_state = get_scmi_clk_state(in->clock_id); diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 69a277e8786..ad825d66da2 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -86,21 +86,41 @@ struct udevice *scmi_get_protocol(struct udevice *dev, case SCMI_PROTOCOL_ID_BASE: proto = priv->base_dev; break; +#if IS_ENABLED(CONFIG_SCMI_POWER_DOMAIN) case SCMI_PROTOCOL_ID_POWER_DOMAIN: proto = priv->pwdom_dev; break; +#endif +#if IS_ENABLED(CONFIG_CLK_SCMI) case SCMI_PROTOCOL_ID_CLOCK: proto = priv->clock_dev; break; +#endif +#if IS_ENABLED(CONFIG_RESET_SCMI) case SCMI_PROTOCOL_ID_RESET_DOMAIN: proto = priv->resetdom_dev; break; +#endif +#if IS_ENABLED(CONFIG_DM_REGULATOR_SCMI) case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: proto = priv->voltagedom_dev; break; +#endif +#if IS_ENABLED(CONFIG_PINCTRL_IMX_SCMI) case SCMI_PROTOCOL_ID_PINCTRL: proto = priv->pinctrl_dev; break; +#endif +#if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_80) + case SCMI_PROTOCOL_ID_VENDOR_80: + proto = priv->vendor_dev_80; + break; +#endif +#if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_82) + case SCMI_PROTOCOL_ID_VENDOR_82: + proto = priv->vendor_dev_82; + break; +#endif default: dev_err(dev, "Protocol not supported\n"); proto = NULL; @@ -139,21 +159,41 @@ static int scmi_add_protocol(struct udevice *dev, case SCMI_PROTOCOL_ID_BASE: priv->base_dev = proto; break; +#if IS_ENABLED(CONFIG_SCMI_POWER_DOMAIN) case SCMI_PROTOCOL_ID_POWER_DOMAIN: priv->pwdom_dev = proto; break; +#endif +#if IS_ENABLED(CONFIG_CLK_SCMI) case SCMI_PROTOCOL_ID_CLOCK: priv->clock_dev = proto; break; +#endif +#if IS_ENABLED(CONFIG_RESET_SCMI) case SCMI_PROTOCOL_ID_RESET_DOMAIN: priv->resetdom_dev = proto; break; +#endif +#if IS_ENABLED(CONFIG_DM_REGULATOR_SCMI) case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: priv->voltagedom_dev = proto; break; +#endif +#if IS_ENABLED(CONFIG_PINCTRL_IMX_SCMI) case SCMI_PROTOCOL_ID_PINCTRL: priv->pinctrl_dev = proto; break; +#endif +#if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_80) + case SCMI_PROTOCOL_ID_VENDOR_80: + priv->vendor_dev_80 = proto; + break; +#endif +#if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_82) + case SCMI_PROTOCOL_ID_VENDOR_82: + priv->vendor_dev_82 = proto; + break; +#endif default: dev_err(dev, "Protocol not supported\n"); return -EPROTO; diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c index 237871559f0..cd1c0801f72 100644 --- a/drivers/firmware/scmi/smt.c +++ b/drivers/firmware/scmi/smt.c @@ -61,20 +61,6 @@ int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt) if (device_is_compatible(dev, "arm,scmi") && ofnode_has_property(dev_ofnode(dev), "mboxes")) scmi_smt_enable_intr(smt, true); -#ifdef CONFIG_ARM - if (dcache_status()) { - u32 align_size; - - if (IS_ENABLED(CONFIG_ARM64)) - align_size = PAGE_SIZE; - else - align_size = MMU_SECTION_SIZE; - - mmu_set_region_dcache_behaviour(ALIGN_DOWN((uintptr_t)smt->buf, align_size), - ALIGN(smt->size, align_size), DCACHE_OFF); - } -#endif - return 0; } diff --git a/drivers/firmware/scmi/vendors/imx/Kconfig b/drivers/firmware/scmi/vendors/imx/Kconfig new file mode 100644 index 00000000000..16850502bbb --- /dev/null +++ b/drivers/firmware/scmi/vendors/imx/Kconfig @@ -0,0 +1,15 @@ +config IMX_SM_CPU + bool "Enable i.MX System Manager CPU API" + depends on ARCH_IMX9 && SCMI_FIRMWARE + select SCMI_ID_VENDOR_82 + help + If you say Y here to enable i.MX System Manager CPU + API to work on some NXP i.MX processors. + +config IMX_SM_LMM + bool "Enable i.MX System Manager Logical Machine API" + depends on ARCH_IMX9 && SCMI_FIRMWARE + select SCMI_ID_VENDOR_80 + help + If you say Y here to enable i.MX System Manager Logical Machine + API to work on some NXP i.MX processors. diff --git a/drivers/firmware/scmi/vendors/imx/Makefile b/drivers/firmware/scmi/vendors/imx/Makefile new file mode 100644 index 00000000000..59ff8640dc1 --- /dev/null +++ b/drivers/firmware/scmi/vendors/imx/Makefile @@ -0,0 +1,8 @@ +# +# Copyright 2025 NXP +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_IMX_SM_CPU) += imx-sm-cpu.o +obj-$(CONFIG_IMX_SM_LMM) += imx-sm-lmm.o diff --git a/drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c b/drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c new file mode 100644 index 00000000000..28dfac642ec --- /dev/null +++ b/drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * i.MX SCMI CPU protocol + * + * Copyright 2025 NXP + */ + +#include <compiler.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <misc.h> +#include <scmi_agent.h> +#include <scmi_agent-uclass.h> +#include <scmi_protocols.h> +#include <scmi_nxp_protocols.h> + +enum scmi_imx_cpu_protocol_cmd { + SCMI_IMX_CPU_ATTRIBUTES = 0x3, + SCMI_IMX_CPU_START = 0x4, + SCMI_IMX_CPU_STOP = 0x5, + SCMI_IMX_CPU_RESET_VECTOR_SET = 0x6, + SCMI_IMX_CPU_INFO_GET = 0xC, +}; + +struct scmi_imx_cpu_priv { + u32 nr_cpu; +}; + +struct scmi_imx_cpu_reset_vector_set_in { + __le32 cpuid; +#define CPU_VEC_FLAGS_RESUME BIT(31) +#define CPU_VEC_FLAGS_START BIT(30) +#define CPU_VEC_FLAGS_BOOT BIT(29) + __le32 flags; + __le32 resetvectorlow; + __le32 resetvectorhigh; +}; + +struct scmi_imx_cpu_info_get_out { + __le32 status; +#define CPU_RUN_MODE_START 0 +#define CPU_RUN_MODE_HOLD 1 +#define CPU_RUN_MODE_STOP 2 +#define CPU_RUN_MODE_SLEEP 3 + __le32 runmode; + __le32 sleepmode; + __le32 resetvectorlow; + __le32 resetvectorhigh; +}; + +int scmi_imx_cpu_start(struct udevice *dev, u32 cpuid, bool start) +{ + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_VENDOR_82, + .message_id = SCMI_IMX_CPU_STOP, + .in_msg = (u8 *)&cpuid, + .in_msg_sz = sizeof(cpuid), + .out_msg = (u8 *)&status, + .out_msg_sz = sizeof(status), + }; + int ret; + + if (!dev) + return -EINVAL; + + if (start) + msg.message_id = SCMI_IMX_CPU_START; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + + if (status) + return scmi_to_linux_errno(status); + + return 0; +} + +int scmi_imx_cpu_reset_vector_set(struct udevice *dev, u32 cpuid, u32 flags, u64 vector, + bool start, bool boot, bool resume) +{ + struct scmi_imx_cpu_reset_vector_set_in in; + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_VENDOR_82, + .message_id = SCMI_IMX_CPU_RESET_VECTOR_SET, + .in_msg = (u8 *)&in, + .in_msg_sz = sizeof(in), + .out_msg = (u8 *)&status, + .out_msg_sz = sizeof(status), + }; + int ret; + + if (!dev) + return -EINVAL; + + in.cpuid = cpu_to_le32(cpuid); + in.flags = cpu_to_le32(0); + if (start) + in.flags |= CPU_VEC_FLAGS_START; + if (boot) + in.flags |= CPU_VEC_FLAGS_BOOT; + if (resume) + in.flags |= CPU_VEC_FLAGS_RESUME; + in.resetvectorlow = cpu_to_le32(lower_32_bits(vector)); + in.resetvectorhigh = cpu_to_le32(upper_32_bits(vector)); + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + + if (status) + return scmi_to_linux_errno(status); + + return 0; +} + +int scmi_imx_cpu_started(struct udevice *dev, u32 cpuid, bool *started) +{ + struct scmi_imx_cpu_info_get_out out; + u32 mode; + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_VENDOR_82, + .message_id = SCMI_IMX_CPU_INFO_GET, + .in_msg = (u8 *)&cpuid, + .in_msg_sz = sizeof(cpuid), + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + if (!dev) + return -EINVAL; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + + status = cpu_to_le32(out.status); + if (status) + return scmi_to_linux_errno(status); + + mode = le32_to_cpu(out.runmode); + if (mode == CPU_RUN_MODE_START || mode == CPU_RUN_MODE_SLEEP) + *started = true; + + return 0; +} + +static int scmi_imx_cpu_probe(struct udevice *dev) +{ + int ret; + + ret = devm_scmi_of_get_channel(dev); + if (ret) { + dev_err(dev, "failed to get channel (%d)\n", ret); + return ret; + } + + return 0; +} + +U_BOOT_DRIVER(scmi_imx_cpu) = { + .name = "scmi_imx_cpu", + .id = UCLASS_SCMI_BASE, + .probe = scmi_imx_cpu_probe, + .priv_auto = sizeof(struct scmi_imx_cpu_priv), +}; + +static struct scmi_proto_match match[] = { + { .proto_id = SCMI_PROTOCOL_ID_VENDOR_82}, + { /* Sentinel */ } +}; + +U_BOOT_SCMI_PROTO_DRIVER(scmi_imx_cpu, match); diff --git a/drivers/firmware/scmi/vendors/imx/imx-sm-lmm.c b/drivers/firmware/scmi/vendors/imx/imx-sm-lmm.c new file mode 100644 index 00000000000..2fd791ca853 --- /dev/null +++ b/drivers/firmware/scmi/vendors/imx/imx-sm-lmm.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * i.MX SCMI LMM protocol + * + * Copyright 2025 NXP + */ + +#include <compiler.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <linux/types.h> +#include <misc.h> +#include <scmi_agent.h> +#include <scmi_agent-uclass.h> +#include <scmi_protocols.h> +#include <scmi_nxp_protocols.h> + +enum scmi_imx_lmm_protocol_cmd { + SCMI_IMX_LMM_ATTRIBUTES = 0x3, + SCMI_IMX_LMM_BOOT = 0x4, + SCMI_IMX_LMM_RESET = 0x5, + SCMI_IMX_LMM_SHUTDOWN = 0x6, + SCMI_IMX_LMM_WAKE = 0x7, + SCMI_IMX_LMM_SUSPEND = 0x8, + SCMI_IMX_LMM_NOTIFY = 0x9, + SCMI_IMX_LMM_RESET_REASON = 0xA, + SCMI_IMX_LMM_POWER_ON = 0xB, + SCMI_IMX_LMM_RESET_VECTOR_SET = 0xC, +}; + +struct scmi_imx_lmm_priv { + u32 nr_lmm; +}; + +struct scmi_msg_imx_lmm_attributes_out { + __le32 status; + __le32 lmid; + __le32 attributes; + __le32 state; + __le32 errstatus; + u8 name[LMM_MAX_NAME]; +}; + +struct scmi_imx_lmm_reset_vector_set_in { + __le32 lmid; + __le32 cpuid; + __le32 flags; /* reserved for future extension */ + __le32 resetvectorlow; + __le32 resetvectorhigh; +}; + +struct scmi_imx_lmm_shutdown_in { + __le32 lmid; +#define SCMI_IMX_LMM_SHUTDOWN_GRACEFUL BIT(0) + __le32 flags; +}; + +int scmi_imx_lmm_info(struct udevice *dev, u32 lmid, struct scmi_imx_lmm_info *info) +{ + struct scmi_msg_imx_lmm_attributes_out out; + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_VENDOR_80, + .message_id = SCMI_IMX_LMM_ATTRIBUTES, + .in_msg = (u8 *)&lmid, + .in_msg_sz = sizeof(lmid), + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + if (!dev) + return -EINVAL; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + + status = cpu_to_le32(out.status); + if (status) + return scmi_to_linux_errno(status); + + info->lmid = le32_to_cpu(out.lmid); + info->state = le32_to_cpu(out.state); + info->errstatus = le32_to_cpu(out.errstatus); + strcpy(info->name, out.name); + dev_dbg(dev, "i.MX LMM: Logical Machine(%d), name: %s\n", + info->lmid, info->name); + + return ret; +} + +int scmi_imx_lmm_power_boot(struct udevice *dev, u32 lmid, bool boot) +{ + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_VENDOR_80, + .message_id = SCMI_IMX_LMM_POWER_ON, + .in_msg = (u8 *)&lmid, + .in_msg_sz = sizeof(lmid), + .out_msg = (u8 *)&status, + .out_msg_sz = sizeof(status), + }; + int ret; + + if (!dev) + return -EINVAL; + + if (boot) + msg.message_id = SCMI_IMX_LMM_BOOT; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + + if (status) + return scmi_to_linux_errno(status); + + return 0; +} + +int scmi_imx_lmm_reset_vector_set(struct udevice *dev, u32 lmid, u32 cpuid, u32 flags, u64 vector) +{ + struct scmi_imx_lmm_reset_vector_set_in in; + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_VENDOR_80, + .message_id = SCMI_IMX_LMM_RESET_VECTOR_SET, + .in_msg = (u8 *)&in, + .in_msg_sz = sizeof(in), + .out_msg = (u8 *)&status, + .out_msg_sz = sizeof(status), + }; + int ret; + + if (!dev) + return -EINVAL; + + in.lmid = lmid; + in.cpuid = cpuid; + in.flags = flags; + in.resetvectorlow = vector & 0xFFFFFFFF; + in.resetvectorhigh = vector >> 32; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + + if (status) + return scmi_to_linux_errno(status); + + return 0; +} + +int scmi_imx_lmm_shutdown(struct udevice *dev, u32 lmid, bool flags) +{ + struct scmi_imx_lmm_shutdown_in in; + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_VENDOR_80, + .message_id = SCMI_IMX_LMM_SHUTDOWN, + .in_msg = (u8 *)&in, + .in_msg_sz = sizeof(in), + .out_msg = (u8 *)&status, + .out_msg_sz = sizeof(status), + }; + int ret; + + if (!dev) + return -EINVAL; + + in.lmid = lmid; + if (flags & SCMI_IMX_LMM_SHUTDOWN_GRACEFUL) + in.flags = cpu_to_le32(SCMI_IMX_LMM_SHUTDOWN_GRACEFUL); + else + in.flags = cpu_to_le32(0); + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + + if (status) + return scmi_to_linux_errno(status); + + return 0; +} + +static int scmi_imx_lmm_probe(struct udevice *dev) +{ + int ret; + + ret = devm_scmi_of_get_channel(dev); + if (ret) { + dev_err(dev, "failed to get channel (%d)\n", ret); + return ret; + } + + return 0; +} + +U_BOOT_DRIVER(scmi_imx_lmm) = { + .name = "scmi_imx_lmm", + .id = UCLASS_SCMI_BASE, + .probe = scmi_imx_lmm_probe, + .priv_auto = sizeof(struct scmi_imx_lmm_priv), +}; + +static struct scmi_proto_match match[] = { + { .proto_id = SCMI_PROTOCOL_ID_VENDOR_80}, + { /* Sentinel */ } +}; + +U_BOOT_SCMI_PROTO_DRIVER(scmi_imx_lmm, match); diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 8013afef304..6f57dcfe8de 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -191,9 +191,9 @@ static int ti_sci_get_response(struct ti_sci_info *info, /* Sanity check for message response */ if (hdr->seq != info->seq) { - dev_dbg(info->dev, "%s: Message for %d is not expected\n", + dev_err(info->dev, "%s: Message for %d is not expected\n", __func__, hdr->seq); - return ret; + return -EINVAL; } if (msg->len > info->desc->max_msg_size) { @@ -1365,6 +1365,8 @@ static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle, if (ret) return ret; + resp = (struct ti_sci_msg_resp_get_clock_parent *)xfer->tx_message.buf; + *parent_id = resp->parent_id; return ret; @@ -3083,7 +3085,10 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle, dev_err(dev, "%s resource type ids not available\n", of_prop); return ERR_PTR(sets); } - temp = malloc(sets); + temp = devm_kmalloc(dev, sets, GFP_KERNEL); + if (!temp) + return ERR_PTR(-ENOMEM); + sets /= sizeof(u32); res->sets = sets; @@ -3123,6 +3128,7 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle, return ERR_PTR(-ENOMEM); } + devm_kfree(dev, temp); if (valid_set) return res; diff --git a/drivers/fpga/versalpl.c b/drivers/fpga/versalpl.c index 624493ad838..630d1ecfea3 100644 --- a/drivers/fpga/versalpl.c +++ b/drivers/fpga/versalpl.c @@ -40,13 +40,12 @@ static int versal_load(xilinx_desc *desc, const void *buf, size_t bsize, buf_lo = lower_32_bits(bin_buf); buf_hi = upper_32_bits(bin_buf); - if (desc->family == xilinx_versal2) { ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_hi, - buf_lo, 0, ret_payload); + buf_lo, 0, 0, 0, ret_payload); } else { ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_lo, - buf_hi, 0, ret_payload); + buf_hi, 0, 0, 0, ret_payload); } if (ret) diff --git a/drivers/fpga/zynqmppl.c b/drivers/fpga/zynqmppl.c index 1199b249e36..048d0d2e7a1 100644 --- a/drivers/fpga/zynqmppl.c +++ b/drivers/fpga/zynqmppl.c @@ -291,7 +291,7 @@ static int zynqmp_load(xilinx_desc *desc, const void *buf, size_t bsize, buf_hi = upper_32_bits(bin_buf); ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo, buf_hi, - bsize_req, bstype, ret_payload); + bsize_req, bstype, 0, 0, ret_payload); if (ret) printf("PL FPGA LOAD failed with err: 0x%08x\n", ret); @@ -335,11 +335,11 @@ static int zynqmp_loads(xilinx_desc *desc, const void *buf, size_t bsize, ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo, buf_hi, (u32)(uintptr_t)fpga_sec_info->userkey_addr, - flag, ret_payload); + flag, 0, 0, ret_payload); else ret = xilinx_pm_request(PM_FPGA_LOAD, buf_lo, buf_hi, (u32)bsize, - flag, ret_payload); + flag, 0, 0, ret_payload); if (ret) puts("PL FPGA LOAD fail\n"); @@ -356,7 +356,7 @@ static int zynqmp_pcap_info(xilinx_desc *desc) u32 ret_payload[PAYLOAD_ARG_CNT]; ret = xilinx_pm_request(PM_FPGA_GET_STATUS, 0, 0, 0, - 0, ret_payload); + 0, 0, 0, ret_payload); if (!ret) printf("PCAP status\t0x%x\n", ret_payload[1]); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 58e464106a3..b5729a39774 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -340,6 +340,7 @@ config NPCM_SGPIO config OMAP_GPIO bool "TI OMAP GPIO driver" depends on ARCH_OMAP2PLUS + select TI_SYSC if OF_CONTROL default y help Support GPIO controllers on the TI OMAP3/4/5 and related (such as @@ -695,12 +696,6 @@ config SLG7XL45106_I2C_GPO 8-bit gpo expander, all gpo lines are controlled by writing value into data register. -config FTGPIO010 - bool "Faraday Technology FTGPIO010 driver" - depends on DM_GPIO - help - Support for GPIOs on Faraday Technology's FTGPIO010 controller. - config ADP5585_GPIO bool "ADP5585 GPIO driver" depends on DM_GPIO && DM_I2C diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 83e10c79b91..73c94329e36 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -77,7 +77,6 @@ obj-$(CONFIG_SL28CPLD_GPIO) += sl28cpld-gpio.o obj-$(CONFIG_ADP5588_GPIO) += adp5588_gpio.o obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN) += zynqmp_gpio_modepin.o obj-$(CONFIG_SLG7XL45106_I2C_GPO) += gpio_slg7xl45106.o -obj-$(CONFIG_FTGPIO010) += ftgpio010.o obj-$(CONFIG_$(PHASE_)ADP5585_GPIO) += adp5585_gpio.o obj-$(CONFIG_RZG2L_GPIO) += rzg2l-gpio.o obj-$(CONFIG_MPFS_GPIO) += mpfs_gpio.o diff --git a/drivers/gpio/ftgpio010.c b/drivers/gpio/ftgpio010.c deleted file mode 100644 index 4cb550a540c..00000000000 --- a/drivers/gpio/ftgpio010.c +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Faraday Technology's FTGPIO010 controller. - */ - -#include <dm.h> -#include <asm/io.h> -#include <asm/gpio.h> - -struct ftgpio010_regs { - u32 out; - u32 in; - u32 direction; // 1 - output - u32 reserved; - u32 set; - u32 clear; -}; - -struct ftgpio010_plat { - struct ftgpio010_regs __iomem *regs; -}; - -static int ftgpio010_direction_input(struct udevice *dev, unsigned int pin) -{ - struct ftgpio010_plat *plat = dev_get_plat(dev); - struct ftgpio010_regs *const regs = plat->regs; - - clrbits_le32(®s->direction, 1 << pin); - return 0; -} - -static int ftgpio010_direction_output(struct udevice *dev, unsigned int pin, - int val) -{ - struct ftgpio010_plat *plat = dev_get_plat(dev); - struct ftgpio010_regs *const regs = plat->regs; - - /* change the data first, then the direction. to avoid glitch */ - out_le32(val ? ®s->set : ®s->clear, 1 << pin); - setbits_le32(®s->direction, 1 << pin); - - return 0; -} - -static int ftgpio010_get_value(struct udevice *dev, unsigned int pin) -{ - struct ftgpio010_plat *plat = dev_get_plat(dev); - struct ftgpio010_regs *const regs = plat->regs; - - return in_le32(®s->in) >> pin & 1; -} - -static int ftgpio010_set_value(struct udevice *dev, unsigned int pin, int val) -{ - struct ftgpio010_plat *plat = dev_get_plat(dev); - struct ftgpio010_regs *const regs = plat->regs; - - out_le32(val ? ®s->set : ®s->clear, 1 << pin); - return 0; -} - -static int ftgpio010_get_function(struct udevice *dev, unsigned int pin) -{ - struct ftgpio010_plat *plat = dev_get_plat(dev); - struct ftgpio010_regs *const regs = plat->regs; - - if (in_le32(®s->direction) >> pin & 1) - return GPIOF_OUTPUT; - return GPIOF_INPUT; -} - -static int ftgpio010_probe(struct udevice *dev) -{ - struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); - - uc_priv->gpio_count = ofnode_read_u32_default(dev_ofnode(dev), - "nr-gpios", 32); - return 0; -} - -static int ftgpio010_of_to_plat(struct udevice *dev) -{ - struct ftgpio010_plat *plat = dev_get_plat(dev); - - plat->regs = dev_read_addr_ptr(dev); - return 0; -} - -static const struct dm_gpio_ops ftgpio010_ops = { - .direction_input = ftgpio010_direction_input, - .direction_output = ftgpio010_direction_output, - .get_value = ftgpio010_get_value, - .set_value = ftgpio010_set_value, - .get_function = ftgpio010_get_function, -}; - -static const struct udevice_id ftgpio010_ids[] = { - { .compatible = "faraday,ftgpio010" }, - { } -}; - -U_BOOT_DRIVER(ftgpio010) = { - .name = "ftgpio010", - .id = UCLASS_GPIO, - .of_match = ftgpio010_ids, - .ops = &ftgpio010_ops, - .of_to_plat = ftgpio010_of_to_plat, - .plat_auto = sizeof(struct ftgpio010_plat), - .probe = ftgpio010_probe, -}; diff --git a/drivers/gpio/gpio-aspeed-g7.c b/drivers/gpio/gpio-aspeed-g7.c index 4c6ab86203c..4607468ca05 100644 --- a/drivers/gpio/gpio-aspeed-g7.c +++ b/drivers/gpio/gpio-aspeed-g7.c @@ -141,7 +141,7 @@ static const struct udevice_id aspeed_gpio_ids[] = { { } }; -U_BOOT_DRIVER(gpio_aspeed) = { +U_BOOT_DRIVER(gpio_aspeed_g7) = { .name = "gpio-aspeed", .id = UCLASS_GPIO, .of_match = aspeed_gpio_ids, diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index d1a39938809..c1ad20177f7 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -18,16 +18,13 @@ #define GPIO_IOINTSEL 0x00 /* General IO/Interrupt Switching Register */ #define GPIO_INOUTSEL 0x04 /* General Input/Output Switching Register */ #define GPIO_OUTDT 0x08 /* General Output Register */ -#define GPIO_INDT 0x0c /* General Input Register */ -#define GPIO_INTDT 0x10 /* Interrupt Display Register */ -#define GPIO_INTCLR 0x14 /* Interrupt Clear Register */ -#define GPIO_INTMSK 0x18 /* Interrupt Mask Register */ -#define GPIO_MSKCLR 0x1c /* Interrupt Mask Clear Register */ -#define GPIO_POSNEG 0x20 /* Positive/Negative Logic Select Register */ -#define GPIO_EDGLEVEL 0x24 /* Edge/level Select Register */ -#define GPIO_FILONOFF 0x28 /* Chattering Prevention On/Off Register */ -#define GPIO_BOTHEDGE 0x4c /* One Edge/Both Edge Select Register */ -#define GPIO_INEN 0x50 /* General Input Enable Register */ +#define GPIO_INDT_G2 0x0c /* General Input Register */ +#define GPIO_POSNEG_G2 0x20 /* Positive/Negative Logic Select Register */ +#define GPIO_INEN_G4 0x50 /* General Input Enable Register */ + +#define GPIO_INDT_G5 0x1c /* General Input Register */ +#define GPIO_POSNEG_G5 0x90 /* Positive/Negative Logic Select Register */ +#define GPIO_INEN_G5 0x18 /* General Input Enable Register */ #define RCAR_MAX_GPIO_PER_BANK 32 @@ -35,15 +32,22 @@ DECLARE_GLOBAL_DATA_PTR; +struct rcar_gpio_data { + u32 quirks; + u32 indt_offset; + u32 posneg_offset; + u32 inen_offset; +}; + struct rcar_gpio_priv { - void __iomem *regs; - u32 quirks; - int pfc_offset; + void __iomem *regs; + const struct rcar_gpio_data *data; }; static int rcar_gpio_get_value(struct udevice *dev, unsigned offset) { struct rcar_gpio_priv *priv = dev_get_priv(dev); + const struct rcar_gpio_data *data = priv->data; const u32 bit = BIT(offset); /* @@ -53,7 +57,7 @@ static int rcar_gpio_get_value(struct udevice *dev, unsigned offset) if (readl(priv->regs + GPIO_INOUTSEL) & bit) return !!(readl(priv->regs + GPIO_OUTDT) & bit); else - return !!(readl(priv->regs + GPIO_INDT) & bit); + return !!(readl(priv->regs + data->indt_offset) & bit); } static int rcar_gpio_set_value(struct udevice *dev, unsigned offset, @@ -73,6 +77,7 @@ static void rcar_gpio_set_direction(struct udevice *dev, unsigned offset, bool output) { struct rcar_gpio_priv *priv = dev_get_priv(dev); + const struct rcar_gpio_data *data = priv->data; void __iomem *regs = priv->regs; /* @@ -82,14 +87,14 @@ static void rcar_gpio_set_direction(struct udevice *dev, unsigned offset, */ /* Configure postive logic in POSNEG */ - clrbits_le32(regs + GPIO_POSNEG, BIT(offset)); + clrbits_le32(regs + data->posneg_offset, BIT(offset)); /* Select "Input Enable/Disable" in INEN */ - if (priv->quirks & RCAR_GPIO_HAS_INEN) { + if (data->quirks & RCAR_GPIO_HAS_INEN) { if (output) - clrbits_le32(regs + GPIO_INEN, BIT(offset)); + clrbits_le32(regs + data->inen_offset, BIT(offset)); else - setbits_le32(regs + GPIO_INEN, BIT(offset)); + setbits_le32(regs + data->inen_offset, BIT(offset)); } /* Select "General Input/Output Mode" in IOINTSEL */ @@ -149,12 +154,11 @@ static int rcar_gpio_probe(struct udevice *dev) int ret; priv->regs = dev_read_addr_ptr(dev); - priv->quirks = dev_get_driver_data(dev); + priv->data = (const struct rcar_gpio_data *)dev_get_driver_data(dev); uc_priv->bank_name = dev->name; ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, node, "gpio-ranges", NULL, 3, 0, &args); - priv->pfc_offset = ret == 0 ? args.args[1] : -1; uc_priv->gpio_count = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK; ret = clk_get_by_index(dev, 0, &clk); @@ -172,17 +176,37 @@ static int rcar_gpio_probe(struct udevice *dev) return 0; } +static const struct rcar_gpio_data rcar_gpio_gen2_data = { + .indt_offset = GPIO_INDT_G2, + .posneg_offset = GPIO_POSNEG_G2, +}; + +static const struct rcar_gpio_data rcar_gpio_gen3_data = { + .quirks = RCAR_GPIO_HAS_INEN, + .indt_offset = GPIO_INDT_G2, + .posneg_offset = GPIO_POSNEG_G2, + .inen_offset = GPIO_INEN_G4, +}; + +static const struct rcar_gpio_data rcar_gpio_gen5_data = { + .quirks = RCAR_GPIO_HAS_INEN, + .indt_offset = GPIO_INDT_G5, + .posneg_offset = GPIO_POSNEG_G5, + .inen_offset = GPIO_INEN_G5, +}; + static const struct udevice_id rcar_gpio_ids[] = { - { .compatible = "renesas,gpio-r8a7795" }, - { .compatible = "renesas,gpio-r8a7796" }, - { .compatible = "renesas,gpio-r8a77965" }, - { .compatible = "renesas,gpio-r8a77970" }, - { .compatible = "renesas,gpio-r8a77990" }, - { .compatible = "renesas,gpio-r8a77995" }, - { .compatible = "renesas,gpio-r8a779a0", .data = RCAR_GPIO_HAS_INEN }, - { .compatible = "renesas,rcar-gen2-gpio" }, - { .compatible = "renesas,rcar-gen3-gpio" }, - { .compatible = "renesas,rcar-gen4-gpio", .data = RCAR_GPIO_HAS_INEN }, + { .compatible = "renesas,gpio-r8a7795", .data = (ulong)&rcar_gpio_gen2_data }, + { .compatible = "renesas,gpio-r8a7796", .data = (ulong)&rcar_gpio_gen2_data }, + { .compatible = "renesas,gpio-r8a77965", .data = (ulong)&rcar_gpio_gen2_data }, + { .compatible = "renesas,gpio-r8a77970", .data = (ulong)&rcar_gpio_gen2_data }, + { .compatible = "renesas,gpio-r8a77990", .data = (ulong)&rcar_gpio_gen2_data }, + { .compatible = "renesas,gpio-r8a77995", .data = (ulong)&rcar_gpio_gen2_data }, + { .compatible = "renesas,gpio-r8a779a0", .data = (ulong)&rcar_gpio_gen3_data }, + { .compatible = "renesas,rcar-gen2-gpio", .data = (ulong)&rcar_gpio_gen2_data }, + { .compatible = "renesas,rcar-gen3-gpio", .data = (ulong)&rcar_gpio_gen2_data }, + { .compatible = "renesas,rcar-gen4-gpio", .data = (ulong)&rcar_gpio_gen3_data }, + { .compatible = "renesas,rcar-gen5-gpio", .data = (ulong)&rcar_gpio_gen5_data }, { /* sentinel */ } }; diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 3d9f8b32b8d..7559b8dc7e2 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -378,7 +378,7 @@ U_BOOT_DRIVER(gpio_hog) = { #else int gpio_hog_lookup_name(const char *name, struct gpio_desc **desc) { - return 0; + return -ENODEV; } #endif diff --git a/drivers/gpio/intel_gpio.c b/drivers/gpio/intel_gpio.c index 0ab6e8a90bc..ac2fb8bc2cc 100644 --- a/drivers/gpio/intel_gpio.c +++ b/drivers/gpio/intel_gpio.c @@ -116,26 +116,26 @@ static int intel_gpio_set_flags(struct udevice *dev, unsigned int offset, { struct udevice *pinctrl = dev_get_parent(dev); u32 bic0 = 0, bic1 = 0; - u32 or0, or1; + u32 or0 = 0, or1 = 0; uint config_offset; config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset); if (flags & GPIOD_IS_OUT) { - bic0 |= PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE | + bic0 = PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE | PAD_CFG0_TX_DISABLE; - or0 |= PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE; + or0 = PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE; } else if (flags & GPIOD_IS_IN) { - bic0 |= PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE | + bic0 = PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE | PAD_CFG0_RX_DISABLE; - or0 |= PAD_CFG0_MODE_GPIO | PAD_CFG0_TX_DISABLE; + or0 = PAD_CFG0_MODE_GPIO | PAD_CFG0_TX_DISABLE; } if (flags & GPIOD_PULL_UP) { - bic1 |= PAD_CFG1_PULL_MASK; - or1 |= PAD_CFG1_PULL_UP_20K; + bic1 = PAD_CFG1_PULL_MASK; + or1 = PAD_CFG1_PULL_UP_20K; } else if (flags & GPIOD_PULL_DOWN) { - bic1 |= PAD_CFG1_PULL_MASK; - or1 |= PAD_CFG1_PULL_DN_20K; + bic1 = PAD_CFG1_PULL_MASK; + or1 = PAD_CFG1_PULL_DN_20K; } pcr_clrsetbits32(pinctrl, PAD_CFG0_OFFSET(config_offset), bic0, or0); diff --git a/drivers/gpio/qcom_spmi_gpio.c b/drivers/gpio/qcom_spmi_gpio.c index 22c8072534e..1a7c7c48dfc 100644 --- a/drivers/gpio/qcom_spmi_gpio.c +++ b/drivers/gpio/qcom_spmi_gpio.c @@ -743,6 +743,10 @@ static int qcom_spmi_pmic_gpio_probe(struct udevice *dev) } static const struct udevice_id qcom_spmi_pmic_gpio_ids[] = { + { .compatible = "qcom,pm6150l-gpio" }, + { .compatible = "qcom,pm6350-gpio" }, + { .compatible = "qcom,pm660l-gpio" }, + { .compatible = "qcom,pm7325-gpio" }, { .compatible = "qcom,pm8550-gpio" }, { .compatible = "qcom,pm8550b-gpio" }, { .compatible = "qcom,pm8550ve-gpio" }, diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c index 3d1e18854f2..c61419ef980 100644 --- a/drivers/gpio/tegra_gpio.c +++ b/drivers/gpio/tegra_gpio.c @@ -182,21 +182,6 @@ static int tegra_gpio_get_value(struct udevice *dev, unsigned offset) return (val >> GPIO_BIT(gpio)) & 1; } -/* write GPIO OUT value to pin 'gpio' */ -static int tegra_gpio_set_value(struct udevice *dev, unsigned offset, int value) -{ - struct tegra_port_info *state = dev_get_priv(dev); - int gpio = state->base_gpio + offset; - - debug("gpio_set_value: pin = %d (port %d:bit %d), value = %d\n", - gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), value); - - /* Configure GPIO output value. */ - set_level(gpio, value); - - return 0; -} - void gpio_config_table(const struct tegra_gpio_config *config, int len) { int i; @@ -258,11 +243,30 @@ static int tegra_gpio_rfree(struct udevice *dev, unsigned int offset) return 0; } +static int tegra_gpio_set_flags(struct udevice *dev, unsigned int offset, ulong flags) +{ + struct tegra_port_info *state = dev_get_priv(dev); + int gpio = state->base_gpio + offset; + + debug("gpio_set_flags: pin = %d (port %d:bit %d), flag = %lx\n", + gpio, GPIO_FULLPORT(gpio), GPIO_BIT(gpio), flags); + + if (flags & GPIOD_IS_AF) { + return tegra_gpio_rfree(dev, offset); + } else if (flags & GPIOD_IS_IN) { + return tegra_gpio_direction_input(dev, offset); + } else if (flags & GPIOD_IS_OUT) { + bool value = flags & GPIOD_IS_OUT_ACTIVE; + + return tegra_gpio_direction_output(dev, offset, value); + } + + return 0; +} + static const struct dm_gpio_ops gpio_tegra_ops = { - .direction_input = tegra_gpio_direction_input, - .direction_output = tegra_gpio_direction_output, + .set_flags = tegra_gpio_set_flags, .get_value = tegra_gpio_get_value, - .set_value = tegra_gpio_set_value, .get_function = tegra_gpio_get_function, .xlate = tegra_gpio_xlate, .rfree = tegra_gpio_rfree, diff --git a/drivers/gpio/zynqmp_gpio_modepin.c b/drivers/gpio/zynqmp_gpio_modepin.c index 8aaffaf37b3..4c5de9ba69b 100644 --- a/drivers/gpio/zynqmp_gpio_modepin.c +++ b/drivers/gpio/zynqmp_gpio_modepin.c @@ -23,14 +23,14 @@ static int get_gpio_modepin(u32 *ret_payload) { return xilinx_pm_request(PM_MMIO_READ, ZYNQMP_CRL_APB_BOOT_PIN_CTRL, - 0, 0, 0, ret_payload); + 0, 0, 0, 0, 0, ret_payload); } static int set_gpio_modepin(int val) { return xilinx_pm_request(PM_MMIO_WRITE, ZYNQMP_CRL_APB_BOOT_PIN_CTRL, ZYNQMP_CRL_APB_BOOTPIN_CTRL_MASK, - val, 0, NULL); + val, 0, 0, 0, NULL); } static int modepin_gpio_direction_input(struct udevice *dev, diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 108b24b3dd2..55465dc1d46 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -308,6 +308,13 @@ config SYS_I2C_MTK If you want to use MediaTek I2C interface, say Y here. If unsure, say N. +config SYS_I2C_MT7621 + bool "Mediatek MT7621 I2C driver" + help + This selects the Mediatek MT7621 I2C driver. + If you want to use the MediaTek MT7621 I2C controller, say Y here. + If unsure, say N. + config SYS_I2C_MICROCHIP bool "Microchip I2C driver" help @@ -661,7 +668,7 @@ config SYS_I2C_QUP config SYS_I2C_GENI bool "Qualcomm Generic Interface (GENI) I2C controller" - depends on ARCH_SNAPDRAGON + depends on ARCH_SNAPDRAGON && QCOM_GENI help Support for the Qualcomm Generic Interface (GENI) I2C interface. The Generic Interface (GENI) is a firmware based Qualcomm Universal diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 42326db85f6..5fe30d0df4f 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_SYS_I2C_MV) += mv_i2c.o obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o obj-$(CONFIG_SYS_I2C_MTK) += mtk_i2c.o +obj-$(CONFIG_SYS_I2C_MT7621) += mt7621_i2c.o obj-$(CONFIG_SYS_I2C_NEXELL) += nx_i2c.o obj-$(CONFIG_SYS_I2C_NPCM) += npcm_i2c.o obj-$(CONFIG_SYS_I2C_OCORES) += ocores_i2c.o diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index a54976e7889..8ad716f410e 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -764,7 +764,7 @@ int designware_i2c_of_to_plat(struct udevice *bus) ret = reset_get_bulk(bus, &priv->resets); if (ret) { - if (ret != -ENOTSUPP) + if (ret != -ENOTSUPP && ret != -ENOENT) dev_warn(bus, "Can't get reset: %d\n", ret); } else { reset_deassert_bulk(&priv->resets); diff --git a/drivers/i2c/geni_i2c.c b/drivers/i2c/geni_i2c.c index eabf5c76c21..d29e00fdf41 100644 --- a/drivers/i2c/geni_i2c.c +++ b/drivers/i2c/geni_i2c.c @@ -22,6 +22,7 @@ #include <reset.h> #include <time.h> #include <soc/qcom/geni-se.h> +#include <soc/qcom/qup-fw-load.h> #define SE_I2C_TX_TRANS_LEN 0x26c #define SE_I2C_RX_TRANS_LEN 0x270 @@ -331,15 +332,13 @@ static int geni_i2c_disable_clocks(struct udevice *dev, struct geni_i2c_priv *ge if (geni->is_master_hub) { ret = clk_disable(&geni->core); if (ret) { - dev_err(dev, "clk_enable core failed %d\n", ret); - return ret; + dev_err(dev, "clk_disable core failed %d\n", ret); } } ret = clk_disable(&geni->se); if (ret) { - dev_err(dev, "clk_enable se failed %d\n", ret); - return ret; + dev_err(dev, "clk_disable se failed %d\n", ret); } return 0; @@ -501,6 +500,13 @@ static int geni_i2c_probe(struct udevice *dev) proto &= FW_REV_PROTOCOL_MSK; proto >>= FW_REV_PROTOCOL_SHFT; + if (proto == GENI_SE_INVALID_PROTO) { + qcom_geni_load_firmware(geni->base, dev); + proto = readl(geni->base + GENI_FW_REVISION_RO); + proto &= FW_REV_PROTOCOL_MSK; + proto >>= FW_REV_PROTOCOL_SHFT; + } + if (proto != GENI_SE_I2C) { dev_err(dev, "Invalid proto %d\n", proto); geni_i2c_disable_clocks(dev, geni); diff --git a/drivers/i2c/mt7621_i2c.c b/drivers/i2c/mt7621_i2c.c new file mode 100644 index 00000000000..e162df49f67 --- /dev/null +++ b/drivers/i2c/mt7621_i2c.c @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * U-Boot driver for the MediaTek MT7621 I2C controller. + * + * Derived from the Linux kernel driver: + * drivers/i2c/busses/i2c-mt7621.c + * + * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com> + * Copyright (C) 2014 Sittisak <sittisaks@hotmail.com> + * Copyright (C) 2016 Michael Lee <igvtee@gmail.com> + * Copyright (C) 2018 Jan Breuer <jan.breuer@jaybee.cz> + * Copyright (C) 2025 Justin Swartz <justin.swartz@risingedge.co.za> + */ + +#include <asm/io.h> +#include <dm/device.h> +#include <dm/device_compat.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/printk.h> +#include <dm.h> +#include <clk.h> +#include <i2c.h> +#include <log.h> +#include <reset.h> +#include <time.h> + +#define REG_SM0CFG2 0x28 +#define REG_SM0CTL0 0x40 +#define REG_SM0CTL1 0x44 +#define REG_SM0D0 0x50 +#define REG_SM0D1 0x54 + +#define SM0CFG2_MODE_MANUAL 0 + +#define SM0CTL0_ODRAIN BIT(31) +#define SM0CTL0_CLK_DIV_MASK (0x7ff << 16) +#define SM0CTL0_CLK_DIV_MAX 0x7ff +#define SM0CTL0_EN BIT(1) +#define SM0CTL0_SCL_STRETCH BIT(0) + +#define SM0CTL1_TRI BIT(0) +#define SM0CTL1_TRI_IDLE 0 +#define SM0CTL1_START (1 << 4) +#define SM0CTL1_WRITE (2 << 4) +#define SM0CTL1_STOP (3 << 4) +#define SM0CTL1_READ_LAST (4 << 4) +#define SM0CTL1_READ (5 << 4) +#define SM0CTL1_PGLEN(x) ((((x) - 1) << 8) & SM0CTL1_PGLEN_MASK) +#define SM0CTL1_PGLEN_MASK (0x7 << 8) +#define SM0CTL1_ACK_MASK (0xff << 16) + +#define TIMEOUT_1SEC 1000 +#define I2C_MAX_STD_MODE_FREQ 100000 + +struct mt7621_i2c_priv { + void __iomem *base; + uint speed; + u32 clk_div; + struct clk clk; + struct reset_ctl reset_ctl; +}; + +static int mt7621_i2c_wait_idle(struct udevice *dev) +{ + struct mt7621_i2c_priv *priv = dev_get_priv(dev); + ulong start_time = get_timer(0); + u32 value; + + while (get_timer(start_time) < TIMEOUT_1SEC) { + value = readl(priv->base + REG_SM0CTL1); + if ((value & SM0CTL1_TRI) == SM0CTL1_TRI_IDLE) + return 0; + + udelay(10); + } + + return -ETIMEDOUT; +} + +static int mt7621_i2c_reset(struct udevice *dev) +{ + struct mt7621_i2c_priv *priv = dev_get_priv(dev); + u32 value; + + reset_assert(&priv->reset_ctl); + udelay(100); + reset_deassert(&priv->reset_ctl); + + value = readl(priv->base + REG_SM0CTL0); + value &= ~SM0CTL0_CLK_DIV_MASK; + value |= (priv->clk_div << 16) & SM0CTL0_CLK_DIV_MASK; + value |= SM0CTL0_EN | SM0CTL0_SCL_STRETCH; + writel(value, priv->base + REG_SM0CTL0); + + writel(SM0CFG2_MODE_MANUAL, priv->base + REG_SM0CFG2); + return 0; +} + +static int mt7621_i2c_master_start(struct udevice *dev) +{ + struct mt7621_i2c_priv *priv = dev_get_priv(dev); + + writel(SM0CTL1_START | SM0CTL1_TRI, priv->base + REG_SM0CTL1); + return mt7621_i2c_wait_idle(dev); +} + +static int mt7621_i2c_master_stop(struct udevice *dev) +{ + struct mt7621_i2c_priv *priv = dev_get_priv(dev); + + writel(SM0CTL1_STOP | SM0CTL1_TRI, priv->base + REG_SM0CTL1); + return mt7621_i2c_wait_idle(dev); +} + +static int mt7621_i2c_master_cmd(struct udevice *dev, u32 cmd, int len) +{ + struct mt7621_i2c_priv *priv = dev_get_priv(dev); + + writel(cmd | SM0CTL1_TRI | SM0CTL1_PGLEN(len), + priv->base + REG_SM0CTL1); + + return mt7621_i2c_wait_idle(dev); +} + +static int mt7621_i2c_7bit_address(struct udevice *dev, struct i2c_msg *msg) +{ + struct mt7621_i2c_priv *priv = dev_get_priv(dev); + u32 addr = msg->addr << 1; + + if (msg->flags & I2C_M_RD) + addr |= 1; + + writel(addr, priv->base + REG_SM0D0); + return mt7621_i2c_master_cmd(dev, SM0CTL1_WRITE, 1); +} + +static int mt7621_i2c_10bit_address(struct udevice *dev, struct i2c_msg *msg) +{ + struct mt7621_i2c_priv *priv = dev_get_priv(dev); + u16 addr = 0xf0 | ((msg->addr >> 7) & 0x06) | (msg->addr & 0xff) << 8; + + if (msg->flags & I2C_M_RD) + addr |= 1; + + writel(addr, priv->base + REG_SM0D0); + return mt7621_i2c_master_cmd(dev, SM0CTL1_WRITE, 2); +} + +static int mt7621_i2c_address(struct udevice *dev, struct i2c_msg *msg) +{ + int ret; + + if (msg->flags & I2C_M_TEN) { + ret = mt7621_i2c_10bit_address(dev, msg); + if (ret) + return ret; + } else { + ret = mt7621_i2c_7bit_address(dev, msg); + if (ret) + return ret; + } + + return 0; +} + +static int mt7621_i2c_check_ack(struct udevice *dev, struct i2c_msg *msg, + u32 length) +{ + struct mt7621_i2c_priv *priv = dev_get_priv(dev); + u32 status = readl(priv->base + REG_SM0CTL1); + u32 expected = GENMASK(length - 1, 0); + u32 mask = (expected << 16) & SM0CTL1_ACK_MASK; + + if (msg->flags & I2C_M_IGNORE_NAK) + return 0; + + if ((status & mask) != mask) + return -ENXIO; + + return 0; +} + +static int mt7621_i2c_master_read(struct udevice *dev, struct i2c_msg *msg) +{ + struct mt7621_i2c_priv *priv = dev_get_priv(dev); + int offset, length, last, ret; + u32 cmd; + u32 data[2]; + + for (offset = 0; offset < msg->len; offset += 8) { + if (msg->len - offset >= 8) + length = 8; + else + length = msg->len - offset; + + last = msg->len - offset <= 8; + cmd = last ? SM0CTL1_READ_LAST : SM0CTL1_READ; + ret = mt7621_i2c_master_cmd(dev, cmd, length); + if (ret) + return ret; + + data[0] = readl(priv->base + REG_SM0D0); + data[1] = readl(priv->base + REG_SM0D1); + memcpy(&msg->buf[offset], data, length); + } + + return 0; +} + +static int mt7621_i2c_master_write(struct udevice *dev, struct i2c_msg *msg) +{ + struct mt7621_i2c_priv *priv = dev_get_priv(dev); + int offset, length, ret; + u32 data[2]; + + for (offset = 0; offset < msg->len; offset += 8) { + if (msg->len - offset >= 8) + length = 8; + else + length = msg->len - offset; + + memcpy(data, &msg->buf[offset], length); + writel(data[0], priv->base + REG_SM0D0); + writel(data[1], priv->base + REG_SM0D1); + + ret = mt7621_i2c_master_cmd(dev, SM0CTL1_WRITE, length); + if (ret) + return ret; + + ret = mt7621_i2c_check_ack(dev, msg, length); + if (ret) + return ret; + } + + return 0; +} + +static int mt7621_i2c_xfer(struct udevice *dev, struct i2c_msg *msgs, int count) +{ + struct i2c_msg *msg; + int index, ret; + + for (index = 0; index < count; index++) { + msg = &msgs[index]; + + ret = mt7621_i2c_wait_idle(dev); + if (ret) + goto reset; + + ret = mt7621_i2c_master_start(dev); + if (ret) + goto reset; + + ret = mt7621_i2c_address(dev, msg); + if (ret) + goto reset; + + ret = mt7621_i2c_check_ack(dev, msg, 1); + if (ret) + goto stop; + + if (msg->flags & I2C_M_RD) { + ret = mt7621_i2c_master_read(dev, msg); + if (ret) + goto reset; + } else { + ret = mt7621_i2c_master_write(dev, msg); + if (ret) + goto reset; + } + } + + ret = mt7621_i2c_wait_idle(dev); + if (ret) + goto reset; + + ret = mt7621_i2c_master_stop(dev); + if (ret) + goto reset; + + return 0; + +stop: + ret = mt7621_i2c_master_stop(dev); + if (ret) + goto reset; + return -ENXIO; + +reset: + mt7621_i2c_reset(dev); + return ret; +} + +static int mt7621_i2c_set_speed(struct udevice *dev, uint speed) +{ + struct mt7621_i2c_priv *priv = dev_get_priv(dev); + ulong clk_rate = clk_get_rate(&priv->clk); + + priv->speed = speed; + priv->clk_div = clk_rate / priv->speed - 1; + + if (priv->clk_div < 99) + priv->clk_div = 99; + + if (priv->clk_div > SM0CTL0_CLK_DIV_MAX) + priv->clk_div = SM0CTL0_CLK_DIV_MAX; + + return 0; +} + +static const struct dm_i2c_ops mt7621_i2c_ops = { + .xfer = mt7621_i2c_xfer, + .set_bus_speed = mt7621_i2c_set_speed, + .deblock = mt7621_i2c_reset, +}; + +static int mt7621_i2c_of_to_plat(struct udevice *dev) +{ + struct mt7621_i2c_priv *priv = dev_get_priv(dev); + + priv->base = dev_remap_addr(dev); + return 0; +} + +int mt7621_i2c_probe(struct udevice *dev) +{ + struct mt7621_i2c_priv *priv = dev_get_priv(dev); + int ret; + + priv->base = dev_remap_addr(dev); + if (!priv->base) { + dev_err(dev, "failed to get base address\n"); + return -EINVAL; + } + + ret = clk_get_by_name(dev, "sys_clock", &priv->clk); + if (ret) { + dev_err(dev, "failed to get clock source\n"); + return ret; + } + + ret = reset_get_by_name(dev, "i2c_reset", &priv->reset_ctl); + if (ret) { + dev_err(dev, "failed to get reset control\n"); + return ret; + } + + ret = clk_enable(&priv->clk); + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + + mt7621_i2c_set_speed(dev, I2C_MAX_STD_MODE_FREQ); + mt7621_i2c_reset(dev); + + return 0; +} + +static const struct udevice_id mt7621_i2c_ids[] = { + { .compatible = "mediatek,mt7621-i2c" }, + { } +}; + +U_BOOT_DRIVER(mt7621_i2c) = { + .name = "mt7621_i2c", + .id = UCLASS_I2C, + .of_match = mt7621_i2c_ids, + .of_to_plat = mt7621_i2c_of_to_plat, + .probe = mt7621_i2c_probe, + .priv_auto = sizeof(struct mt7621_i2c_priv), + .ops = &mt7621_i2c_ops, +}; diff --git a/drivers/i2c/muxes/i2c-mux-uclass.c b/drivers/i2c/muxes/i2c-mux-uclass.c index 012881de05b..7f4eb914af2 100644 --- a/drivers/i2c/muxes/i2c-mux-uclass.c +++ b/drivers/i2c/muxes/i2c-mux-uclass.c @@ -130,7 +130,7 @@ static int i2c_mux_post_probe(struct udevice *mux) return 0; } -int i2c_mux_select(struct udevice *dev) +static int i2c_mux_select(struct udevice *dev) { struct i2c_mux_bus *plat = dev_get_parent_plat(dev); struct udevice *mux = dev->parent; @@ -142,7 +142,7 @@ int i2c_mux_select(struct udevice *dev) return ops->select(mux, dev, plat->channel); } -int i2c_mux_deselect(struct udevice *dev) +static int i2c_mux_deselect(struct udevice *dev) { struct i2c_mux_bus *plat = dev_get_parent_plat(dev); struct udevice *mux = dev->parent; diff --git a/drivers/i2c/rcar_i2c.c b/drivers/i2c/rcar_i2c.c index 3bd5108fd23..9562119bb5b 100644 --- a/drivers/i2c/rcar_i2c.c +++ b/drivers/i2c/rcar_i2c.c @@ -368,6 +368,7 @@ static const struct udevice_id rcar_i2c_ids[] = { { .compatible = "renesas,rcar-gen2-i2c", .data = RCAR_I2C_TYPE_GEN2 }, { .compatible = "renesas,rcar-gen3-i2c", .data = RCAR_I2C_TYPE_GEN3 }, { .compatible = "renesas,rcar-gen4-i2c", .data = RCAR_I2C_TYPE_GEN3 }, + { .compatible = "renesas,rcar-gen5-i2c", .data = RCAR_I2C_TYPE_GEN3 }, { } }; diff --git a/drivers/iommu/qcom-hyp-smmu.c b/drivers/iommu/qcom-hyp-smmu.c index 2e51ce4f242..5b37c21f66c 100644 --- a/drivers/iommu/qcom-hyp-smmu.c +++ b/drivers/iommu/qcom-hyp-smmu.c @@ -388,8 +388,10 @@ static struct iommu_ops qcom_smmu_ops = { }; static const struct udevice_id qcom_smmu500_ids[] = { - { .compatible = "qcom,sdm845-smmu-500" }, + { .compatible = "qcom,sc7180-smmu-500" }, { .compatible = "qcom,sc7280-smmu-500" }, + { .compatible = "qcom,sdm845-smmu-500" }, + { .compatible = "qcom,sm6350-smmu-500" }, { .compatible = "qcom,smmu-500", }, { /* sentinel */ } }; diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index c98cbf92fab..1cd3638cb16 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -11,6 +11,7 @@ config LED config LED_BOOT bool "Enable LED boot support" + depends on LED help Enable LED boot support. @@ -22,6 +23,7 @@ config LED_BOOT config LED_ACTIVITY bool "Enable LED activity support" + depends on LED help Enable LED activity support. @@ -137,7 +139,8 @@ config SPL_LED_GPIO See the help of LED_GPIO for details. config LED_STATUS - bool "Enable status LED API" + bool "Enable legacy status LED API" + depends on !LED help Allows common u-boot commands to use a board's leds to provide status for activities like booting and downloading files. diff --git a/drivers/led/led-uclass.c b/drivers/led/led-uclass.c index edcdeee1e9a..1efdbe272c3 100644 --- a/drivers/led/led-uclass.c +++ b/drivers/led/led-uclass.c @@ -65,6 +65,9 @@ int led_get_by_label(const char *label, struct udevice **devp) /* Ignore the top-level LED node */ if (uc_plat->label && !strcmp(label, uc_plat->label)) return uclass_get_device_tail(dev, 0, devp); + + if (!strcmp(label, ofnode_get_name(dev_ofnode(dev)))) + return uclass_get_device_tail(dev, 0, devp); } return -ENODEV; diff --git a/drivers/mailbox/mailbox-uclass.c b/drivers/mailbox/mailbox-uclass.c index 4bf4987ce0a..fef437a4281 100644 --- a/drivers/mailbox/mailbox-uclass.c +++ b/drivers/mailbox/mailbox-uclass.c @@ -132,6 +132,15 @@ int mbox_recv(struct mbox_chan *chan, void *data, ulong timeout_us) debug("%s(chan=%p, data=%p, timeout_us=%ld)\n", __func__, chan, data, timeout_us); + /* + * Some shared memory mailboxes may have empty receive operation, + * because the data are polled by upper layers directly from the + * shared memory region, and there is no completion interrupt or + * bit of any sort. + */ + if (!ops->recv) + return 0; + start_time = timer_get_us(); /* * Account for partial us ticks, but if timeout_us is 0, ensure we diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index eaee739c6aa..591d9d9c656 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -14,7 +14,7 @@ config MEMORY For now this uclass has no methods yet. config ATMEL_EBI - bool "Support for Atmel EBI" + bool help Driver for Atmel EBI controller. This is a dummy driver. Doesn't provide an access to EBI controller. Select diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 29b84430ff5..dde773ab6b1 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -83,6 +83,15 @@ config GATEWORKS_SC boards to provide a boot watchdog, power control, temperature monitor, voltage ADCs, and EEPROM. +config QCOM_GENI + bool "Qualcomm Generic Interface (GENI) driver" + depends on MISC + select PARTITION_TYPE_GUID + help + Enable support for Qualcomm GENI and it's peripherals. GENI is responseible + for providing a common interface for various peripherals like UART, I2C, SPI, + etc. + config ROCKCHIP_EFUSE bool "Rockchip e-fuse support" depends on MISC @@ -440,6 +449,7 @@ config STM32MP_FUSE config K3_FUSE bool "Enable TI K3 fuse wrapper providing the fuse API" depends on MISC && CMD_FUSE && CMD_FUSE_WRITEBUFF + depends on ARCH_K3 help If you say Y here, you will get support for the fuse API (OTP) for TI K3 architecture. diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index dc5eb3af19c..1d950f7a0ab 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_QFW_MMIO) += qfw_mmio.o obj-$(CONFIG_QFW_SMBIOS) += qfw_smbios.o obj-$(CONFIG_SANDBOX) += qfw_sandbox.o endif +obj-$(CONFIG_QCOM_GENI) += qcom_geni.o obj-$(CONFIG_$(PHASE_)ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_$(PHASE_)ROCKCHIP_OTP) += rockchip-otp.o obj-$(CONFIG_$(PHASE_)ROCKCHIP_IODOMAIN) += rockchip-io-domain.o diff --git a/drivers/misc/fs_loader.c b/drivers/misc/fs_loader.c index 32aff35835b..2928cf75f89 100644 --- a/drivers/misc/fs_loader.c +++ b/drivers/misc/fs_loader.c @@ -228,53 +228,6 @@ int request_firmware_into_buf(struct udevice *dev, return ret; } -int request_firmware_into_buf_via_script(void **buf, size_t max_size, - const char *script_name, - size_t *retsize) -{ - char *args[2] = { "run", (char *)script_name }; - int ret, repeatable; - ulong addr, size; - - if (!buf || !script_name || !max_size) - return -EINVAL; - - /* Run the firmware loading script */ - ret = cmd_process(0, 2, args, &repeatable, NULL); - if (ret) { - log_err("Firmware loading script '%s' not defined or failed.\n", - script_name); - return -EINVAL; - } - - /* Find out where the firmware got loaded and how long it is */ - addr = env_get_hex("fw_addr", 0); - size = env_get_hex("fw_size", 0); - - /* Clear the variables set by the firmware loading script */ - env_set("fw_addr", NULL); - env_set("fw_size", NULL); - - if (!addr || !size) { - log_err("Firmware address (0x%lx) or size (0x%lx) are invalid.\n", - addr, size); - return -EINVAL; - } - - if (size > max_size) { - log_err("Loaded firmware size 0x%lx exceeded maximum allowed size 0x%zx.\n", - size, max_size); - return -E2BIG; - } - - if (retsize) - *retsize = size; - - memcpy(*buf, (void *)addr, size); - - return 0; -} - static int fs_loader_of_to_plat(struct udevice *dev) { u32 phandlepart[2]; diff --git a/drivers/misc/nuvoton_nct6102d.c b/drivers/misc/nuvoton_nct6102d.c index a3ca037d25f..c4a8ecaa1b3 100644 --- a/drivers/misc/nuvoton_nct6102d.c +++ b/drivers/misc/nuvoton_nct6102d.c @@ -4,8 +4,8 @@ */ #include <nuvoton_nct6102d.h> +#include <pnp_def.h> #include <asm/io.h> -#include <asm/pnp_def.h> static void superio_outb(int reg, int val) { diff --git a/drivers/misc/qcom_geni.c b/drivers/misc/qcom_geni.c new file mode 100644 index 00000000000..a62ae6a2478 --- /dev/null +++ b/drivers/misc/qcom_geni.c @@ -0,0 +1,580 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2025, Linaro Ltd. + */ + +#define pr_fmt(fmt) "GENI-SE: " fmt + +#include <blk.h> +#include <part.h> +#include <dm/device.h> +#include <dm/read.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <elf.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <misc.h> +#include <linux/printk.h> +#include <soc/qcom/geni-se.h> +#include <soc/qcom/qup-fw-load.h> +#include <dm/device_compat.h> + +struct qup_se_rsc { + phys_addr_t base; + phys_addr_t wrapper_base; + struct udevice *dev; + + enum geni_se_xfer_mode mode; + enum geni_se_protocol_type protocol; +}; + +struct geni_se_plat { + bool need_firmware_load; +}; + +/** + * geni_enable_interrupts() Enable interrupts. + * @rsc: Pointer to a structure representing SE-related resources. + * + * Enable the required interrupts during the firmware load process. + * + * Return: None. + */ +static void geni_enable_interrupts(struct qup_se_rsc *rsc) +{ + u32 reg_value; + + /* Enable required interrupts. */ + writel_relaxed(M_COMMON_GENI_M_IRQ_EN, rsc->base + GENI_M_IRQ_ENABLE); + + reg_value = S_CMD_OVERRUN_EN | S_ILLEGAL_CMD_EN | + S_CMD_CANCEL_EN | S_CMD_ABORT_EN | + S_GP_IRQ_0_EN | S_GP_IRQ_1_EN | + S_GP_IRQ_2_EN | S_GP_IRQ_3_EN | + S_RX_FIFO_WR_ERR_EN | S_RX_FIFO_RD_ERR_EN; + writel_relaxed(reg_value, rsc->base + GENI_S_IRQ_ENABLE); + + /* DMA mode configuration. */ + reg_value = DMA_TX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK | + DMA_TX_IRQ_EN_SET_SBE_EN_SET_BMSK | + DMA_TX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK; + writel_relaxed(reg_value, rsc->base + DMA_TX_IRQ_EN_SET); + reg_value = DMA_RX_IRQ_EN_SET_FLUSH_DONE_EN_SET_BMSK | + DMA_RX_IRQ_EN_SET_RESET_DONE_EN_SET_BMSK | + DMA_RX_IRQ_EN_SET_SBE_EN_SET_BMSK | + DMA_RX_IRQ_EN_SET_DMA_DONE_EN_SET_BMSK; + writel_relaxed(reg_value, rsc->base + DMA_RX_IRQ_EN_SET); +} + +/** + * geni_flash_fw_revision() - Flash the firmware revision. + * @rsc: Pointer to a structure representing SE-related resources. + * @hdr: Pointer to the ELF header of the Serial Engine. + * + * Flash the firmware revision and protocol into the respective register. + * + * Return: None. + */ +static void geni_flash_fw_revision(struct qup_se_rsc *rsc, struct elf_se_hdr *hdr) +{ + u32 reg_value; + + /* Flash firmware revision register. */ + reg_value = (hdr->serial_protocol << FW_REV_PROTOCOL_SHFT) | + (hdr->fw_version & 0xFF << FW_REV_VERSION_SHFT); + writel_relaxed(reg_value, rsc->base + SE_GENI_FW_REVISION); + + reg_value = (hdr->serial_protocol << FW_REV_PROTOCOL_SHFT) | + (hdr->fw_version & 0xFF << FW_REV_VERSION_SHFT); + + writel_relaxed(reg_value, rsc->base + SE_S_FW_REVISION); +} + +/** + * geni_configure_xfer_mode() - Set the transfer mode. + * @rsc: Pointer to a structure representing SE-related resources. + * + * Set the transfer mode to either FIFO or DMA according to the mode specified by the protocol + * driver. + * + * Return: 0 if successful, otherwise return an error value. + */ +static int geni_configure_xfer_mode(struct qup_se_rsc *rsc) +{ + /* Configure SE FIFO, DMA or GSI mode. */ + switch (rsc->mode) { + case GENI_GPI_DMA: + geni_setbits32(rsc->base + QUPV3_SE_GENI_DMA_MODE_EN, + GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK); + writel_relaxed(0x0, rsc->base + SE_IRQ_EN); + writel_relaxed(SE_GSI_EVENT_EN_BMSK, rsc->base + SE_GSI_EVENT_EN); + break; + + case GENI_SE_FIFO: + geni_clrbits32(rsc->base + QUPV3_SE_GENI_DMA_MODE_EN, + GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK); + writel_relaxed(SE_IRQ_EN_RMSK, rsc->base + SE_IRQ_EN); + writel_relaxed(0x0, rsc->base + SE_GSI_EVENT_EN); + break; + + case GENI_SE_DMA: + geni_setbits32(rsc->base + QUPV3_SE_GENI_DMA_MODE_EN, + GENI_DMA_MODE_EN_GENI_DMA_MODE_EN_BMSK); + writel_relaxed(SE_IRQ_EN_RMSK, rsc->base + SE_IRQ_EN); + writel_relaxed(0x0, rsc->base + SE_GSI_EVENT_EN); + break; + + default: + dev_err(rsc->dev, "invalid se mode: %d\n", rsc->mode); + return -EINVAL; + } + return 0; +} + +/** + * geni_config_common_control() - Configure common CGC and disable high priority interrupt. + * @rsc: Pointer to a structure representing SE-related resources. + * + * Configure the common CGC and disable high priority interrupts until the current low priority + * interrupts are handled. + * + * Return: None. + */ +static void geni_config_common_control(struct qup_se_rsc *rsc) +{ + /* + * Disable high priority interrupt until current low priority interrupts are handled. + */ + geni_setbits32(rsc->wrapper_base + QUPV3_COMMON_CFG, + FAST_SWITCH_TO_HIGH_DISABLE_BMASK); + + /* + * Set AHB_M_CLK_CGC_ON to indicate hardware controls se-wrapper cgc clock. + */ + geni_setbits32(rsc->wrapper_base + QUPV3_SE_AHB_M_CFG, + AHB_M_CLK_CGC_ON_BMASK); + + /* Let hardware to control common cgc. */ + geni_setbits32(rsc->wrapper_base + QUPV3_COMMON_CGC_CTRL, + COMMON_CSR_SLV_CLK_CGC_ON_BMASK); +} + +static int load_se_firmware(struct qup_se_rsc *rsc, struct elf_se_hdr *hdr) +{ + const u32 *fw_val_arr, *cfg_val_arr; + const u8 *cfg_idx_arr; + u32 i, reg_value, mask, ramn_cnt; + int ret; + + fw_val_arr = (const u32 *)((u8 *)hdr + hdr->fw_offset); + cfg_idx_arr = (const u8 *)hdr + hdr->cfg_idx_offset; + cfg_val_arr = (const u32 *)((u8 *)hdr + hdr->cfg_val_offset); + + geni_config_common_control(rsc); + + /* Allows to drive corresponding data according to hardware value. */ + writel_relaxed(0x0, rsc->base + GENI_OUTPUT_CTRL); + + /* Set SCLK and HCLK to program RAM */ + geni_setbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK | + GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK); + writel_relaxed(0x0, rsc->base + SE_GENI_CLK_CTRL); + geni_clrbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK | + GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK); + + /* Enable required clocks for DMA CSR, TX and RX. */ + reg_value = DMA_GENERAL_CFG_AHB_SEC_SLV_CLK_CGC_ON_BMSK | + DMA_GENERAL_CFG_DMA_AHB_SLV_CLK_CGC_ON_BMSK | + DMA_GENERAL_CFG_DMA_TX_CLK_CGC_ON_BMSK | + DMA_GENERAL_CFG_DMA_RX_CLK_CGC_ON_BMSK; + + geni_setbits32(rsc->base + DMA_GENERAL_CFG, reg_value); + + /* Let hardware control CGC by default. */ + writel_relaxed(DEFAULT_CGC_EN, rsc->base + GENI_CGC_CTRL); + + /* Set version of the configuration register part of firmware. */ + writel_relaxed(hdr->cfg_version, rsc->base + GENI_INIT_CFG_REVISION); + writel_relaxed(hdr->cfg_version, rsc->base + GENI_S_INIT_CFG_REVISION); + + /* Configure GENI primitive table. */ + for (i = 0; i < hdr->cfg_size_in_items; i++) + writel_relaxed(cfg_val_arr[i], + rsc->base + GENI_CFG_REG0 + (cfg_idx_arr[i] * sizeof(u32))); + + /* Configure condition for assertion of RX_RFR_WATERMARK condition. */ + reg_value = readl_relaxed(rsc->base + QUPV3_SE_HW_PARAM_1); + mask = (reg_value >> RX_FIFO_WIDTH_BIT) & RX_FIFO_WIDTH_MASK; + writel_relaxed(mask - 2, rsc->base + GENI_RX_RFR_WATERMARK_REG); + + /* Let hardware control CGC */ + geni_setbits32(rsc->base + GENI_OUTPUT_CTRL, DEFAULT_IO_OUTPUT_CTRL_MSK); + + ret = geni_configure_xfer_mode(rsc); + if (ret) { + dev_err(rsc->dev, "failed to configure xfer mode: %d\n", ret); + return ret; + } + + geni_enable_interrupts(rsc); + + geni_flash_fw_revision(rsc, hdr); + + ramn_cnt = hdr->fw_size_in_items; + if (hdr->fw_size_in_items % 2 != 0) + ramn_cnt++; + + if (ramn_cnt >= MAX_GENI_CFG_RAMn_CNT) { + dev_err(rsc->dev, "firmware size is too large\n"); + return -EINVAL; + } + + /* Program RAM address space. */ + for (i = 0; i < hdr->fw_size_in_items; i++) + writel_relaxed(fw_val_arr[i], rsc->base + SE_GENI_CFG_RAMN + i * sizeof(u32)); + + /* Put default values on GENI's output pads. */ + writel_relaxed(0x1, rsc->base + GENI_FORCE_DEFAULT_REG); + + /* High to low SCLK and HCLK to finish RAM. */ + geni_setbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK | + GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK); + geni_setbits32(rsc->base + SE_GENI_CLK_CTRL, GENI_CLK_CTRL_SER_CLK_SEL_BMSK); + geni_clrbits32(rsc->base + GENI_CGC_CTRL, GENI_CGC_CTRL_PROG_RAM_SCLK_OFF_BMSK | + GENI_CGC_CTRL_PROG_RAM_HCLK_OFF_BMSK); + + /* Serial engine DMA interface is enabled. */ + geni_setbits32(rsc->base + SE_DMA_IF_EN, DMA_IF_EN_DMA_IF_EN_BMSK); + + /* Enable or disable FIFO interface of the serial engine. */ + if (rsc->mode == GENI_SE_FIFO) + geni_clrbits32(rsc->base + SE_FIFO_IF_DISABLE, FIFO_IF_DISABLE); + else + geni_setbits32(rsc->base + SE_FIFO_IF_DISABLE, FIFO_IF_DISABLE); + + return 0; +} + +/** + * elf_phdr_valid() - Validate an ELF header. + * @phdr: Pointer to the ELF header. + * + * Validate the ELF header by comparing the fields stored in p_flags and the payload type. + * + * Return: true if the validation is successful, false otherwise. + */ +static bool elf_phdr_valid(const Elf32_Phdr *phdr) +{ + if (phdr->p_type != PT_LOAD || !phdr->p_memsz) + return false; + + if (MI_PBT_PAGE_MODE_VALUE(phdr->p_flags) == MI_PBT_NON_PAGED_SEGMENT && + MI_PBT_SEGMENT_TYPE_VALUE(phdr->p_flags) != MI_PBT_HASH_SEGMENT && + MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) != MI_PBT_NOTUSED_SEGMENT && + MI_PBT_ACCESS_TYPE_VALUE(phdr->p_flags) != MI_PBT_SHARED_SEGMENT) + return true; + + return false; +} + +/** + * valid_seg_size() - Validate the segment size. + * @pelfseg: Pointer to the ELF header. + * @p_filesz: Pointer to the file size. + * + * Validate the ELF segment size by comparing the file size. + * + * Return: true if the segment is valid, false if the segment is invalid. + */ +static bool valid_seg_size(struct elf_se_hdr *pelfseg, Elf32_Word p_filesz) +{ + if (p_filesz >= pelfseg->fw_offset + pelfseg->fw_size_in_items * sizeof(u32) && + p_filesz >= pelfseg->cfg_idx_offset + pelfseg->cfg_size_in_items * sizeof(u8) && + p_filesz >= pelfseg->cfg_val_offset + pelfseg->cfg_size_in_items * sizeof(u32)) + return true; + return false; +} + +/** + * read_elf() - Read an ELF file. + * @rsc: Pointer to the SE resources structure. + * @fw: Pointer to the firmware buffer. + * @pelfseg: Pointer to the SE-specific ELF header. + * @phdr: Pointer to one of the valid headers from the list in the firmware buffer. + * + * Read the ELF file and output a pointer to the header data, which contains the firmware data and + * any other details. + * + * Return: 0 if successful, otherwise return an error value. + */ +static int read_elf(struct qup_se_rsc *rsc, const void *fw, + struct elf_se_hdr **pelfseg) +{ + Elf32_Phdr *phdr; + const Elf32_Ehdr *ehdr = (const Elf32_Ehdr *)fw; + Elf32_Phdr *phdrs = (Elf32_Phdr *)(ehdr + 1); + const u8 *addr; + int i; + + ehdr = (Elf32_Ehdr *)fw; + + if (ehdr->e_phnum < 2) + return -EINVAL; + + for (i = 0; i < ehdr->e_phnum; i++) { + phdr = &phdrs[i]; + if (!elf_phdr_valid(phdr)) + continue; + + if (phdr->p_filesz >= sizeof(struct elf_se_hdr)) { + addr = fw + phdr->p_offset; + *pelfseg = (struct elf_se_hdr *)addr; + + if ((*pelfseg)->magic == MAGIC_NUM_SE && + (*pelfseg)->version == 1 && + valid_seg_size(*pelfseg, phdr->p_filesz) && + (*pelfseg)->serial_protocol == rsc->protocol && + (*pelfseg)->serial_protocol != GENI_SE_NONE) + return 0; + } + } + return -EINVAL; +} + +int qcom_geni_load_firmware(phys_addr_t qup_base, + struct udevice *dev) +{ + struct qup_se_rsc rsc; + struct elf_se_hdr *hdr; + int ret; + void *fw; + + rsc.dev = dev; + rsc.base = qup_base; + rsc.wrapper_base = dev_read_addr(dev->parent); + + /* FIXME: GSI DMA mode if device has property qcom,gsi-dma-allowed */ + rsc.mode = GENI_SE_FIFO; + + switch (device_get_uclass_id(dev)) { + case UCLASS_I2C: + rsc.protocol = GENI_SE_I2C; + break; + case UCLASS_SPI: + rsc.protocol = GENI_SE_SPI; + break; + case UCLASS_SERIAL: + rsc.protocol = GENI_SE_UART; + break; + default: + return -EINVAL; + } + + /* The firmware blob is the private data of the GENI wrapper (parent) */ + fw = dev_get_priv(dev->parent); + + ret = read_elf(&rsc, fw, &hdr); + if (ret) { + dev_err(dev, "Failed to read ELF: %d\n", ret); + return ret; + } + + dev_info(dev, "Loading QUP firmware...\n"); + + return load_se_firmware(&rsc, hdr); +} + +/* + * We need to determine if firmware loading is necessary. Best way to do that is to check the FW + * revision of each QUP and see if it has already been loaded. + */ +static int geni_se_of_to_plat(struct udevice *dev) +{ + ofnode child; + struct resource res; + u32 proto; + struct geni_se_plat *plat = dev_get_plat(dev); + + plat->need_firmware_load = false; + + dev_for_each_subnode(child, dev) { + if (!ofnode_is_enabled(child)) + continue; + + if (ofnode_read_resource(child, 0, &res)) + continue; + + proto = readl(res.start + GENI_FW_REVISION_RO); + proto &= FW_REV_PROTOCOL_MSK; + proto >>= FW_REV_PROTOCOL_SHFT; + + if (proto == GENI_SE_INVALID_PROTO) + plat->need_firmware_load = true; + } + + return 0; +} + +#define QUPFW_PART_TYPE_GUID "21d1219f-2ed1-4ab4-930a-41a16ae75f7f" + +static int find_qupfw_part(struct udevice **blk_dev, struct disk_partition *part_info) +{ + struct blk_desc *desc; + int ret, partnum; + + uclass_foreach_dev_probe(UCLASS_BLK, *blk_dev) { + if (device_get_uclass_id(*blk_dev) != UCLASS_BLK) + continue; + + desc = dev_get_uclass_plat(*blk_dev); + if (!desc || desc->part_type == PART_TYPE_UNKNOWN) + continue; + for (partnum = 1;; partnum++) { + ret = part_get_info(desc, partnum, part_info); + if (ret) + break; + if (!strcmp(part_info->type_guid, QUPFW_PART_TYPE_GUID)) + return 0; + } + } + + return -ENOENT; +} + +static int probe_children_load_firmware(struct udevice *dev) +{ + struct geni_se_plat *plat; + ofnode child; + struct udevice *child_dev; + struct resource res; + u32 proto; + int ret; + + plat = dev_get_plat(dev); + + dev_for_each_subnode(child, dev) { + if (!ofnode_is_enabled(child)) + continue; + + if (ofnode_read_resource(child, 0, &res)) + continue; + + proto = readl(res.start + GENI_FW_REVISION_RO); + proto &= FW_REV_PROTOCOL_MSK; + proto >>= FW_REV_PROTOCOL_SHFT; + + if (proto != GENI_SE_INVALID_PROTO) + continue; + + ret = 0; + /* Find the device for this ofnode, or bind it */ + if (device_find_global_by_ofnode(child, &child_dev)) + ret = lists_bind_fdt(dev, child, &child_dev, NULL, false); + if (ret) { + /* Skip nodes that don't have drivers */ + debug("Failed to probe child %s: %d\n", ofnode_get_name(child), ret); + continue; + } + debug("Probing child %s for fw loading\n", child_dev->name); + device_probe(child_dev); + } + + return 0; +} + +#define MAX_FW_BUF_SIZE (128 * 1024) + +/* + * Load firmware for QCOM GENI peripherals from the dedicated partition on storage and bind/probe + * all the peripheral devices that need firmware to be loaded. + */ +static int qcom_geni_fw_initialise(void) +{ + debug("Loading firmware for QCOM GENI SE\n"); + struct udevice *geni_wrapper, *blk_dev; + struct disk_partition part_info; + int ret; + void *fw_buf; + size_t fw_size = MAX_FW_BUF_SIZE; + struct geni_se_plat *plat; + + /* Find the first GENI SE wrapper that needs fw loading */ + for (uclass_first_device(UCLASS_MISC, &geni_wrapper); + geni_wrapper; + uclass_next_device(&geni_wrapper)) { + if (device_get_uclass_id(geni_wrapper) == UCLASS_MISC && + !strcmp(geni_wrapper->driver->name, "geni-se-qup")) { + plat = dev_get_plat(geni_wrapper); + if (plat->need_firmware_load) + break; + } + } + if (!geni_wrapper) { + pr_err("GENI SE wrapper not found\n"); + return 0; + } + + ret = find_qupfw_part(&blk_dev, &part_info); + if (ret) { + pr_err("QUP firmware partition not found\n"); + return 0; + } + + if (part_info.size * part_info.blksz > MAX_FW_BUF_SIZE) { + pr_err("Firmware partition too large\n"); + return -EINVAL; + } + fw_size = part_info.size * part_info.blksz; + + fw_buf = malloc(fw_size); + if (!fw_buf) { + pr_err("Failed to allocate buffer for firmware\n"); + return -ENOMEM; + } + memset(fw_buf, 0, fw_size); + + ret = blk_read(blk_dev, part_info.start, part_info.size, fw_buf); + if (ret < 0) { + pr_err("Failed to read firmware from partition\n"); + free(fw_buf); + return 0; + } + + /* + * OK! Firmware is loaded, now bind and probe remaining children. They will attempt to load + * firmware during probe. Do this for each GENI SE wrapper that needs firmware loading. + */ + for (; geni_wrapper; + uclass_next_device(&geni_wrapper)) { + if (device_get_uclass_id(geni_wrapper) == UCLASS_MISC && + !strcmp(geni_wrapper->driver->name, "geni-se-qup")) { + plat = dev_get_plat(geni_wrapper); + if (plat->need_firmware_load) { + dev_set_priv(geni_wrapper, fw_buf); + probe_children_load_firmware(geni_wrapper); + } + } + } + + return 0; +} + +EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, qcom_geni_fw_initialise); + +static const struct udevice_id geni_ids[] = { + { .compatible = "qcom,geni-se-qup" }, + {} +}; + +U_BOOT_DRIVER(geni_se_qup) = { + .name = "geni-se-qup", + .id = UCLASS_MISC, + .of_match = geni_ids, + .of_to_plat = geni_se_of_to_plat, + .plat_auto = sizeof(struct geni_se_plat), + .flags = DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; diff --git a/drivers/misc/qfw_acpi.c b/drivers/misc/qfw_acpi.c index c6c052ac6c3..721f42ecbc3 100644 --- a/drivers/misc/qfw_acpi.c +++ b/drivers/misc/qfw_acpi.c @@ -265,7 +265,6 @@ out: struct acpi_rsdp *rsdp = ctx->rsdp; rsdp->length = sizeof(*rsdp); - rsdp->xsdt_address = 0; rsdp->ext_checksum = table_compute_checksum((u8 *)rsdp, sizeof(*rsdp)); gd_set_acpi_start(acpi_get_rsdp_addr()); diff --git a/drivers/misc/smsc_lpc47m.c b/drivers/misc/smsc_lpc47m.c index 1b15907b093..cc3d3f9de06 100644 --- a/drivers/misc/smsc_lpc47m.c +++ b/drivers/misc/smsc_lpc47m.c @@ -3,8 +3,8 @@ * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com> */ +#include <pnp_def.h> #include <asm/io.h> -#include <asm/pnp_def.h> static void pnp_enter_conf_state(u16 dev) { diff --git a/drivers/misc/winbond_w83627.c b/drivers/misc/winbond_w83627.c index 87b9043e65c..8c5b121b8e9 100644 --- a/drivers/misc/winbond_w83627.c +++ b/drivers/misc/winbond_w83627.c @@ -3,8 +3,8 @@ * Copyright (C) 2016 Stefan Roese <sr@denx.de> */ +#include <pnp_def.h> #include <asm/io.h> -#include <asm/pnp_def.h> #define WINBOND_ENTRY_KEY 0x87 #define WINBOND_EXIT_KEY 0xaa diff --git a/drivers/mmc/cv1800b_sdhci.c b/drivers/mmc/cv1800b_sdhci.c index 377e6a887df..036e798f374 100644 --- a/drivers/mmc/cv1800b_sdhci.c +++ b/drivers/mmc/cv1800b_sdhci.c @@ -19,6 +19,7 @@ struct cv1800b_sdhci_plat { struct mmc mmc; }; +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static void cv1800b_set_tap_delay(struct sdhci_host *host, u16 tap) { sdhci_writel(host, PHY_TX_SRC_INVERT | tap << 16, SDHCI_PHY_TX_RX_DLY); @@ -31,7 +32,6 @@ static void cv1800b_sdhci_reset(struct sdhci_host *host, u8 mask) udelay(10); } -#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) static int cv1800b_execute_tuning(struct mmc *mmc, u8 opcode) { struct sdhci_host *host = dev_get_priv(mmc->dev); diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index a51494380ce..d9c05b223d5 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -419,6 +419,10 @@ static int dwmci_send_cmd_common(struct dwmci_host *host, struct mmc_cmd *cmd, if (cmd->resp_type & MMC_RSP_CRC) flags |= DWMCI_CMD_CHECK_CRC; + host->volt_switching = (cmd->cmdidx == SD_CMD_SWITCH_UHS18V); + if (host->volt_switching) + flags |= DWMCI_CMD_VOLT_SWITCH; + flags |= cmd->cmdidx | DWMCI_CMD_START | DWMCI_CMD_USE_HOLD_REG; debug("Sending CMD%d\n", cmd->cmdidx); @@ -427,6 +431,10 @@ static int dwmci_send_cmd_common(struct dwmci_host *host, struct mmc_cmd *cmd, for (i = 0; i < retry; i++) { mask = dwmci_readl(host, DWMCI_RINTSTS); + if (host->volt_switching && (mask & DWMCI_INTMSK_VOLTSW)) { + dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_VOLTSW); + break; + } if (mask & DWMCI_INTMSK_CDONE) { if (!data) dwmci_writel(host, DWMCI_RINTSTS, mask); @@ -507,20 +515,24 @@ static int dwmci_control_clken(struct dwmci_host *host, bool on) { const u32 val = on ? DWMCI_CLKEN_ENABLE | DWMCI_CLKEN_LOW_PWR : 0; const u32 cmd_only_clk = DWMCI_CMD_PRV_DAT_WAIT | DWMCI_CMD_UPD_CLK; - int timeout = 10000; - u32 status; + int i, timeout = 10000; + u32 flags, mask; dwmci_writel(host, DWMCI_CLKENA, val); /* Inform CIU */ - dwmci_writel(host, DWMCI_CMD, DWMCI_CMD_START | cmd_only_clk); - do { - status = dwmci_readl(host, DWMCI_CMD); - if (timeout-- < 0) { - debug("%s: Timeout!\n", __func__); - return -ETIMEDOUT; + flags = DWMCI_CMD_START | cmd_only_clk; + if (host->volt_switching) + flags |= DWMCI_CMD_VOLT_SWITCH; + dwmci_writel(host, DWMCI_CMD, flags); + + for (i = 0; i < timeout; i++) { + mask = dwmci_readl(host, DWMCI_RINTSTS); + if (mask & DWMCI_INTMSK_CDONE) { + dwmci_writel(host, DWMCI_RINTSTS, DWMCI_INTMSK_CDONE); + break; } - } while (status & DWMCI_CMD_START); + } return 0; } @@ -554,7 +566,7 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) unsigned long sclk; int ret; - if (freq == host->clock || freq == 0) + if (!freq) return 0; /* @@ -632,17 +644,11 @@ static int dwmci_set_ios(struct mmc *mmc) if (mmc->vqmmc_supply) { int ret; - ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply, false); - if (ret) - return ret; - if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) - regulator_set_value(mmc->vqmmc_supply, 1800000); + ret = regulator_set_value(mmc->vqmmc_supply, 1800000); else - regulator_set_value(mmc->vqmmc_supply, 3300000); - - ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply, true); - if (ret) + ret = regulator_set_value(mmc->vqmmc_supply, 3300000); + if (ret && ret != -ENOSYS) return ret; } #endif diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index 12e37cb4b78..7ccd113bd79 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -18,15 +18,33 @@ #include <linux/printk.h> #define DWMMC_MAX_CH_NUM 4 -#define DWMMC_MAX_FREQ 52000000 +#define DWMMC_MAX_FREQ 208000000 #define DWMMC_MIN_FREQ 400000 #define DWMMC_MMC0_SDR_TIMING_VAL 0x03030001 #define DWMMC_MMC2_SDR_TIMING_VAL 0x03020001 #define EXYNOS4412_FIXED_CIU_CLK_DIV 4 -/* Quirks */ +/* CLKSEL register defines */ +#define CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0) +#define CLKSEL_UP_SAMPLE(x, y) (((x) & ~CLKSEL_CCLK_SAMPLE(7)) | \ + CLKSEL_CCLK_SAMPLE(y)) + +/** + * DOC: Quirk flags for different Exynos DW MMC blocks + * + * %DWMCI_QUIRK_DISABLE_SMU: DW MMC block has Security Management Unit (SMU) + * which has to be configured in non-encryption mode during driver's init. + * + * %DWMCI_QUIRK_DISABLE_FMP: DW MMC block has Flash Memory Protector (FMP) which + * has to be disabled during driver's init. This flag disables FMP encryption + * and lets external non-secure main CPUs access the SFR (peripheral memory + * region, i.e. registers) in MMC core. Although it's usually done by early + * bootloaders (before U-Boot), in some cases like during USB boot the FMP might + * be left unconfigured. + */ #define DWMCI_QUIRK_DISABLE_SMU BIT(0) +#define DWMCI_QUIRK_DISABLE_FMP BIT(1) #ifdef CONFIG_DM_MMC #include <dm.h> @@ -121,22 +139,6 @@ static int exynos_dwmmc_set_sclk(struct dwmci_host *host, unsigned long rate) return 0; } -/* Configure CLKSEL register with chosen timing values */ -static int exynos_dwmci_clksel(struct dwmci_host *host) -{ - struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host); - u32 timing; - - if (host->mmc->selected_mode == MMC_DDR_52) - timing = priv->ddr_timing; - else - timing = priv->sdr_timing; - - dwmci_writel(host, priv->chip->clksel, timing); - - return 0; -} - /** * exynos_dwmmc_get_ciu_div - Get internal clock divider value * @host: MMC controller object @@ -160,15 +162,45 @@ static u8 exynos_dwmmc_get_ciu_div(struct dwmci_host *host) & DWMCI_DIVRATIO_MASK) + 1; } +/* Configure CLKSEL register with chosen timing values */ +static int exynos_dwmci_clksel(struct dwmci_host *host) +{ + struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host); + u8 clk_div = exynos_dwmmc_get_ciu_div(host) - 1; + u32 timing; + + switch (host->mmc->selected_mode) { + case MMC_DDR_52: + timing = priv->ddr_timing; + break; + case UHS_SDR104: + case UHS_SDR50: + timing = (priv->sdr_timing & 0xfff8ffff) | (clk_div << 16); + break; + case UHS_DDR50: + timing = (priv->ddr_timing & 0xfff8ffff) | (clk_div << 16); + break; + default: + timing = priv->sdr_timing; + } + + dwmci_writel(host, priv->chip->clksel, timing); + + return 0; +} + static unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq) { unsigned long sclk; u8 clk_div; int err; - /* Should be double rate for DDR mode */ - if (host->mmc->selected_mode == MMC_DDR_52 && host->mmc->bus_width == 8) + /* Should be double rate for DDR or HS mode */ + if ((host->mmc->selected_mode == MMC_DDR_52 && + host->mmc->bus_width == 8) || + host->mmc->selected_mode == MMC_HS_400) { freq *= 2; + } clk_div = exynos_dwmmc_get_ciu_div(host); err = exynos_dwmmc_set_sclk(host, freq * clk_div); @@ -201,6 +233,18 @@ static void exynos_dwmci_board_init(struct dwmci_host *host) MPSCTRL_NON_SECURE_WRITE_BIT | MPSCTRL_VALID); } + if (priv->chip->quirks & DWMCI_QUIRK_DISABLE_FMP) { + u32 reg; + + reg = dwmci_readl(host, EMMCP_MPSECURITY); + if (reg & MPSECURITY_FMP_ON || + reg & MPSECURITY_MMC_SFR_PROT_ON) { + reg &= ~MPSECURITY_FMP_ON; + reg &= ~MPSECURITY_MMC_SFR_PROT_ON; + dwmci_writel(host, EMMCP_MPSECURITY, reg); + } + } + if (priv->sdr_timing) exynos_dwmci_clksel(host); } @@ -282,6 +326,75 @@ static int exynos_dwmmc_of_to_plat(struct udevice *dev) return 0; } +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) +static int exynos_dwmmc_get_best_clksmpl(u8 candidates) +{ + int i; + + for (i = 0; i < 8; i++) { + candidates = (candidates >> 1) | (candidates << 7); /* ror */ + if ((candidates & 0xc7) == 0xc7) + return i; + } + + for (i = 0; i < 8; i++) { + candidates = (candidates >> 1) | (candidates << 7); /* ror */ + if ((candidates & 0x83) == 0x83) + return i; + } + + /* + * If no valid clock sample values are found, use the first candidate + * bit for clock sample value. + */ + for (i = 0; i < 8; i++) { + candidates = (candidates >> 1) | (candidates << 7); /* ror */ + if ((candidates & 0x1) == 0x1) + return i; + } + + return -EIO; +} + +static int exynos_dwmmc_execute_tuning(struct udevice *dev, u32 opcode) +{ + struct dwmci_exynos_priv_data *priv = dev_get_priv(dev); + struct dwmci_host *host = &priv->host; + struct mmc *mmc = mmc_get_mmc_dev(dev); + u8 start_smpl, smpl, candidates = 0; + u32 clksel; + int ret; + + clksel = dwmci_readl(host, priv->chip->clksel); + start_smpl = CLKSEL_CCLK_SAMPLE(clksel); + + do { + dwmci_writel(host, DWMCI_TMOUT, ~0); + + /* Move to the next clksmpl */ + smpl = (clksel + 1) & 0x7; + clksel = CLKSEL_UP_SAMPLE(clksel, smpl); + dwmci_writel(host, priv->chip->clksel, clksel); + + if (!mmc_send_tuning(mmc, opcode)) + candidates |= (1 << smpl); + + } while (start_smpl != smpl); + + ret = exynos_dwmmc_get_best_clksmpl(candidates); + if (ret < 0) { + printf("DWMMC%d: No candidates for clksmpl\n", host->dev_index); + return ret; + } + + dwmci_writel(host, priv->chip->clksel, CLKSEL_UP_SAMPLE(clksel, ret)); + + return 0; +} +#endif /* CONFIG_MMC_SUPPORTS_TUNING */ + +struct dm_mmc_ops exynos_dwmmc_ops; + static int exynos_dwmmc_probe(struct udevice *dev) { struct exynos_mmc_plat *plat = dev_get_plat(dev); @@ -291,6 +404,12 @@ static int exynos_dwmmc_probe(struct udevice *dev) unsigned long freq; int err; + /* Extend generic 'dm_dwmci_ops' with .execute_tuning implementation */ + memcpy(&exynos_dwmmc_ops, &dm_dwmci_ops, sizeof(struct dm_mmc_ops)); +#if CONFIG_IS_ENABLED(MMC_SUPPORTS_TUNING) + exynos_dwmmc_ops.execute_tuning = exynos_dwmmc_execute_tuning; +#endif + #ifndef CONFIG_CPU_V7A err = clk_get_by_index(dev, 1, &priv->clk); /* ciu */ if (err) @@ -303,7 +422,7 @@ static int exynos_dwmmc_probe(struct udevice *dev) flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE; err = exynos_pinmux_config(host->dev_id, flag); if (err) { - printf("DWMMC%d not configure\n", host->dev_index); + printf("DWMMC%d not configured\n", host->dev_index); return err; } #endif @@ -321,7 +440,8 @@ static int exynos_dwmmc_probe(struct udevice *dev) host->name = dev->name; host->board_init = exynos_dwmci_board_init; - host->caps = MMC_MODE_DDR_52MHz; + host->caps = MMC_MODE_DDR_52MHz | MMC_MODE_HS200 | MMC_MODE_HS400 | + UHS_CAPS; host->clksel = exynos_dwmci_clksel; host->get_mmc_clk = exynos_dwmci_get_clk; @@ -368,6 +488,11 @@ static const struct exynos_dwmmc_variant exynos7_smu_drv_data = { .quirks = DWMCI_QUIRK_DISABLE_SMU, }; +static const struct exynos_dwmmc_variant exynos850_drv_data = { + .clksel = DWMCI_CLKSEL64, + .quirks = DWMCI_QUIRK_DISABLE_SMU | DWMCI_QUIRK_DISABLE_FMP, +}; + static const struct udevice_id exynos_dwmmc_ids[] = { { .compatible = "samsung,exynos4412-dw-mshc", @@ -379,11 +504,20 @@ static const struct udevice_id exynos_dwmmc_ids[] = { .compatible = "samsung,exynos5420-dw-mshc", .data = (ulong)&exynos5_drv_data, }, { + .compatible = "samsung,exynos5250-dw-mshc", + .data = (ulong)&exynos5_drv_data, + }, { .compatible = "samsung,exynos-dwmmc", .data = (ulong)&exynos5_drv_data, }, { .compatible = "samsung,exynos7-dw-mshc-smu", .data = (ulong)&exynos7_smu_drv_data, + }, { + .compatible = "samsung,exynos7870-dw-mshc-smu", + .data = (ulong)&exynos7_smu_drv_data, + }, { + .compatible = "samsung,exynos850-dw-mshc-smu", + .data = (ulong)&exynos850_drv_data, }, { } }; @@ -395,8 +529,8 @@ U_BOOT_DRIVER(exynos_dwmmc_drv) = { .of_to_plat = exynos_dwmmc_of_to_plat, .bind = exynos_dwmmc_bind, .probe = exynos_dwmmc_probe, - .ops = &dm_dwmci_ops, + .ops = &exynos_dwmmc_ops, .priv_auto = sizeof(struct dwmci_exynos_priv_data), .plat_auto = sizeof(struct exynos_mmc_plat), }; -#endif +#endif /* CONFIG_DM_MMC */ diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index b1cfa3cd7c2..bf82c515600 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -643,6 +643,19 @@ static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage) return 0; } + +static bool mmc_sd_card_using_v18(struct mmc *mmc) +{ + /* + * According to the SD spec., the Bus Speed Mode (function group 1) bits + * 2 to 4 are zero if the card is initialized at 3.3V signal level. Thus + * they can be used to determine if the card has already switched to + * 1.8V signaling. + */ + bool volt = mmc->sd3_bus_mode & + (SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50); + return volt; +} #endif static int sd_send_op_cond(struct mmc *mmc, bool uhs_en) @@ -1369,9 +1382,6 @@ static int sd_get_capabilities(struct mmc *mmc) ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); struct mmc_data data; int timeout; -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) - u32 sd3_bus_mode; -#endif mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY); @@ -1451,16 +1461,16 @@ static int sd_get_capabilities(struct mmc *mmc) if (mmc->version < SD_VERSION_3) return 0; - sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f; - if (sd3_bus_mode & SD_MODE_UHS_SDR104) + mmc->sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f; + if (mmc->sd3_bus_mode & SD_MODE_UHS_SDR104) mmc->card_caps |= MMC_CAP(UHS_SDR104); - if (sd3_bus_mode & SD_MODE_UHS_SDR50) + if (mmc->sd3_bus_mode & SD_MODE_UHS_SDR50) mmc->card_caps |= MMC_CAP(UHS_SDR50); - if (sd3_bus_mode & SD_MODE_UHS_SDR25) + if (mmc->sd3_bus_mode & SD_MODE_UHS_SDR25) mmc->card_caps |= MMC_CAP(UHS_SDR25); - if (sd3_bus_mode & SD_MODE_UHS_SDR12) + if (mmc->sd3_bus_mode & SD_MODE_UHS_SDR12) mmc->card_caps |= MMC_CAP(UHS_SDR12); - if (sd3_bus_mode & SD_MODE_UHS_DDR50) + if (mmc->sd3_bus_mode & SD_MODE_UHS_DDR50) mmc->card_caps |= MMC_CAP(UHS_DDR50); #endif @@ -1546,7 +1556,7 @@ static int sd_select_bus_width(struct mmc *mmc, int w) } #endif -#if CONFIG_IS_ENABLED(MMC_WRITE) +#if CONFIG_IS_ENABLED(MMC_WRITE) && !CONFIG_IS_ENABLED(MMC_TINY) static int sd_read_ssr(struct mmc *mmc) { static const unsigned int sd_au_size[] = { @@ -1830,7 +1840,11 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; const struct mode_width_tuning *mwt; #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) - bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false; + /* + * Enable UHS mode if the card advertises 1.8V support (S18R in OCR) + * or is already operating at 1.8V signaling. + */ + bool uhs_en = (mmc->ocr & OCR_S18R) || mmc_sd_card_using_v18(mmc); #else bool uhs_en = false; #endif @@ -2701,6 +2715,27 @@ static int mmc_startup(struct mmc *mmc) err = sd_get_capabilities(mmc); if (err) return err; + +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) + /* + * If the card has already switched to 1.8V signaling, then + * set the signal voltage to 1.8V. + */ + if (mmc_sd_card_using_v18(mmc)) { + /* + * During a signal voltage level switch, the clock must be gated + * for 5 ms according to the SD spec. + */ + mmc_set_clock(mmc, mmc->clock, MMC_CLK_DISABLE); + err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); + if (err) + return err; + /* Keep clock gated for at least 10 ms, though spec only says 5 ms */ + mdelay(10); + mmc_set_clock(mmc, mmc->clock, MMC_CLK_ENABLE); + } +#endif + err = sd_select_mode_and_width(mmc, mmc->card_caps); } else { err = mmc_get_capabilities(mmc); @@ -2844,6 +2879,16 @@ static int mmc_power_on(struct mmc *mmc) return ret; } } + + if (mmc->vqmmc_supply) { + int ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply, + true); + + if (ret && ret != -ENOSYS) { + printf("Error enabling VQMMC supply : %d\n", ret); + return ret; + } + } #endif return 0; } @@ -2861,6 +2906,16 @@ static int mmc_power_off(struct mmc *mmc) return ret; } } + + if (mmc->vqmmc_supply) { + int ret = regulator_set_enable_if_allowed(mmc->vqmmc_supply, + false); + + if (ret && ret != -ENOSYS) { + pr_debug("Error disabling VQMMC supply : %d\n", ret); + return ret; + } + } #endif return 0; } diff --git a/drivers/mmc/octeontx_hsmmc.c b/drivers/mmc/octeontx_hsmmc.c index 3b5e1221732..bb4fb29424b 100644 --- a/drivers/mmc/octeontx_hsmmc.c +++ b/drivers/mmc/octeontx_hsmmc.c @@ -1545,7 +1545,7 @@ static int octeontx_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, slot->is_acmd = (cmd->cmdidx == MMC_CMD_APP_CMD); - if (!cmd->resp_type & MMC_RSP_PRESENT) + if (!(cmd->resp_type & MMC_RSP_PRESENT)) debug(" Response type: 0x%x, no response expected\n", cmd->resp_type); /* Get the response if present */ @@ -2828,9 +2828,6 @@ static void octeontx_mmc_io_drive_setup(struct mmc *mmc) struct octeontx_mmc_slot *slot = mmc_to_slot(mmc); union mio_emm_io_ctl io_ctl; - if (slot->drive < 0 || slot->slew < 0) - return; - io_ctl.u = 0; io_ctl.s.drive = slot->drive; io_ctl.s.slew = slot->slew; diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 92bc72b267c..ae742080643 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -651,6 +651,7 @@ static int omap_hsmmc_execute_tuning(struct udevice *dev, uint opcode) printf("Couldn't get temperature for tuning\n"); return ret; } + temperature /= 1000; val = readl(&mmc_base->dll); val |= DLL_SWT; writel(val, &mmc_base->dll); diff --git a/drivers/mmc/owl_mmc.c b/drivers/mmc/owl_mmc.c index bd4906f58e7..c18807b1f49 100644 --- a/drivers/mmc/owl_mmc.c +++ b/drivers/mmc/owl_mmc.c @@ -135,19 +135,19 @@ static void owl_mmc_prepare_data(struct owl_mmc_priv *priv, setbits_le32(priv->reg_base + OWL_REG_SD_EN, OWL_SD_EN_BSEL); - writel(data->blocks, priv->reg_base + OWL_REG_SD_BLK_NUM); - writel(data->blocksize, priv->reg_base + OWL_REG_SD_BLK_SIZE); - total = data->blocksize * data->blocks; - - if (total < 512) - writel(total, priv->reg_base + OWL_REG_SD_BUF_SIZE); - else - writel(512, priv->reg_base + OWL_REG_SD_BUF_SIZE); - /* DMA STOP */ writel(0x0, SD_DMA_CHANNEL(priv->dma_channel, 0) + DMA_START); if (data) { + writel(data->blocks, priv->reg_base + OWL_REG_SD_BLK_NUM); + writel(data->blocksize, priv->reg_base + OWL_REG_SD_BLK_SIZE); + total = data->blocksize * data->blocks; + + if (total < 512) + writel(total, priv->reg_base + OWL_REG_SD_BUF_SIZE); + else + writel(512, priv->reg_base + OWL_REG_SD_BUF_SIZE); + if (data->flags == MMC_DATA_READ) { buf = (ulong) (data->dest); owl_dma_config(priv, (ulong) priv->reg_base + diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 556f07eaf8f..14976a8d30d 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -864,6 +864,7 @@ static const struct udevice_id renesas_sdhi_match[] = { { .compatible = "renesas,sdhi-r8a77990", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,sdhi-r8a77995", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,rcar-gen4-sdhi", .data = RENESAS_GEN3_QUIRKS }, + { .compatible = "renesas,rcar-gen5-sdhi", .data = RENESAS_GEN3_QUIRKS }, { .compatible = "renesas,rzg2l-sdhi", .data = RENESAS_GEN3_QUIRKS }, { /* sentinel */ } }; diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c index 5e025d76a82..8116e464278 100644 --- a/drivers/mmc/rockchip_sdhci.c +++ b/drivers/mmc/rockchip_sdhci.c @@ -9,6 +9,7 @@ #include <dm.h> #include <dm/ofnode.h> #include <dt-structs.h> +#include <linux/bitfield.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/libfdt.h> @@ -86,6 +87,9 @@ #define DLL_CMDOUT_SRC_CLK_NEG BIT(28) #define DLL_CMDOUT_EN_SRC_CLK_NEG BIT(29) #define DLL_CMDOUT_BOTH_CLK_EDGE BIT(30) +#define DLL_TAPVALUE_FROM_SW BIT(25) +#define DLL_TAP_VALUE_PREP(x) FIELD_PREP(GENMASK(15, 8), (x)) +#define DLL_LOCK_VALUE_GET(x) FIELD_GET(GENMASK(7, 0), (x)) #define DLL_LOCK_WO_TMOUT(x) \ ((((x) & DWCMSHC_EMMC_DLL_LOCKED) == DWCMSHC_EMMC_DLL_LOCKED) && \ @@ -93,6 +97,7 @@ #define ROCKCHIP_MAX_CLKS 3 #define FLAG_INVERTER_FLAG_IN_RXCLK BIT(0) +#define FLAG_TAPVALUE_FROM_SW BIT(1) struct rockchip_sdhc_plat { struct mmc_config cfg; @@ -317,7 +322,7 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab struct sdhci_data *data = (struct sdhci_data *)dev_get_driver_data(priv->dev); struct mmc *mmc = host->mmc; int val, ret; - u32 extra, txclk_tapnum; + u32 extra, txclk_tapnum, dll_tap_value; if (!enable) { sdhci_writel(host, 0, DWCMSHC_EMMC_DLL_CTRL); @@ -347,7 +352,15 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab if (ret) return ret; - extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_RXCLK_ORI_GATE; + if (data->flags & FLAG_TAPVALUE_FROM_SW) + dll_tap_value = DLL_TAPVALUE_FROM_SW | + DLL_TAP_VALUE_PREP(DLL_LOCK_VALUE_GET(val) * 2); + else + dll_tap_value = 0; + + extra = DWCMSHC_EMMC_DLL_DLYENA | + DLL_RXCLK_ORI_GATE | + dll_tap_value; if (data->flags & FLAG_INVERTER_FLAG_IN_RXCLK) extra |= DLL_RXCLK_NO_INVERTER; sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_RXCLK); @@ -361,19 +374,22 @@ static int rk3568_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enab DLL_CMDOUT_BOTH_CLK_EDGE | DWCMSHC_EMMC_DLL_DLYENA | data->hs400_cmdout_tapnum | - DLL_CMDOUT_TAPNUM_FROM_SW; + DLL_CMDOUT_TAPNUM_FROM_SW | + dll_tap_value; sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CMDOUT); } extra = DWCMSHC_EMMC_DLL_DLYENA | DLL_TXCLK_TAPNUM_FROM_SW | DLL_TXCLK_NO_INVERTER | - txclk_tapnum; + txclk_tapnum | + dll_tap_value; sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_TXCLK); extra = DWCMSHC_EMMC_DLL_DLYENA | data->hs400_strbin_tapnum | - DLL_STRBIN_TAPNUM_FROM_SW; + DLL_STRBIN_TAPNUM_FROM_SW | + dll_tap_value; sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_STRBIN); } else { /* @@ -663,6 +679,7 @@ static const struct sdhci_data rk3528_data = { .set_ios_post = rk3568_sdhci_set_ios_post, .set_clock = rk3568_sdhci_set_clock, .config_dll = rk3568_sdhci_config_dll, + .flags = FLAG_TAPVALUE_FROM_SW, .hs200_txclk_tapnum = 0xc, .hs400_txclk_tapnum = 0x6, .hs400_cmdout_tapnum = 0x6, diff --git a/drivers/mmc/sdhci-cadence6.c b/drivers/mmc/sdhci-cadence6.c index 9a92b8437a6..ead96dc0c91 100644 --- a/drivers/mmc/sdhci-cadence6.c +++ b/drivers/mmc/sdhci-cadence6.c @@ -180,10 +180,8 @@ static int sdhci_cdns6_reset_phy_dll(struct sdhci_cdns_plat *plat, bool reset) int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 mode) { - DECLARE_GLOBAL_DATA_PTR; struct sdhci_cdns6_phy_cfg *sdhci_cdns6_phy_cfgs; struct sdhci_cdns6_ctrl_cfg *sdhci_cdns6_ctrl_cfgs; - const fdt32_t *prop; u32 tmp; int i, ret; @@ -216,19 +214,11 @@ int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 m return -EINVAL; } - for (i = 0; i < SDHCI_CDNS6_PHY_CFG_NUM; i++) { - prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), - sdhci_cdns6_phy_cfgs[i].property, NULL); - if (prop) - sdhci_cdns6_phy_cfgs[i].val = *prop; - } + for (i = 0; i < SDHCI_CDNS6_PHY_CFG_NUM; i++) + dev_read_u32(dev, sdhci_cdns6_phy_cfgs[i].property, &sdhci_cdns6_phy_cfgs[i].val); - for (i = 0; i < SDHCI_CDNS6_CTRL_CFG_NUM; i++) { - prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), - sdhci_cdns6_ctrl_cfgs[i].property, NULL); - if (prop) - sdhci_cdns6_ctrl_cfgs[i].val = *prop; - } + for (i = 0; i < SDHCI_CDNS6_CTRL_CFG_NUM; i++) + dev_read_u32(dev, sdhci_cdns6_ctrl_cfgs[i].property, &sdhci_cdns6_ctrl_cfgs[i].val); /* Switch On the DLL Reset */ sdhci_cdns6_reset_phy_dll(plat, true); diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c index 3b86bc9b18c..db4e0129c2e 100644 --- a/drivers/mmc/socfpga_dw_mmc.c +++ b/drivers/mmc/socfpga_dw_mmc.c @@ -29,7 +29,9 @@ struct socfpga_dwmci_plat { /* socfpga implmentation specific driver private data */ struct dwmci_socfpga_priv_data { + struct udevice *dev; struct dwmci_host host; + struct clk mmc_clk_ciu; unsigned int drvsel; unsigned int smplsel; }; @@ -51,28 +53,23 @@ static void socfpga_dwmci_reset(struct udevice *dev) static int socfpga_dwmci_clksel(struct dwmci_host *host) { struct dwmci_socfpga_priv_data *priv = host->priv; + int ret; + u32 sdmmc_mask = ((priv->smplsel & 0x7) << SYSMGR_SDMMC_SMPLSEL_SHIFT) | ((priv->drvsel & 0x7) << SYSMGR_SDMMC_DRVSEL_SHIFT); - /* Get clock manager base address */ - struct udevice *clkmgr_dev; - int ret = uclass_get_device_by_name(UCLASS_CLK, "clock-controller@ffd10000", &clkmgr_dev); - + ret = clk_get_by_name(priv->dev, "ciu", &priv->mmc_clk_ciu); if (ret) { - printf("Failed to get clkmgr device: %d\n", ret); + debug("%s: Failed to get SDMMC clock from dts\n", __func__); return ret; } - fdt_addr_t clkmgr_base = dev_read_addr(clkmgr_dev); - - if (clkmgr_base == FDT_ADDR_T_NONE) { - printf("Failed to read base address from clkmgr DT node\n"); - return -EINVAL; - } - /* Disable SDMMC clock. */ - clrbits_le32(clkmgr_base + CLKMGR_PERPLL_EN, - CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); + ret = clk_disable(&priv->mmc_clk_ciu); + if (ret) { + printf("%s: Failed to disable SDMMC clock\n", __func__); + return ret; + } debug("%s: drvsel %d smplsel %d\n", __func__, priv->drvsel, priv->smplsel); @@ -92,8 +89,11 @@ static int socfpga_dwmci_clksel(struct dwmci_host *host) #endif /* Enable SDMMC clock */ - setbits_le32(clkmgr_base + CLKMGR_PERPLL_EN, - CLKMGR_PERPLLGRP_EN_SDMMCCLK_MASK); + ret = clk_enable(&priv->mmc_clk_ciu); + if (ret) { + printf("%s: Failed to enable SDMMC clock\n", __func__); + return ret; + } return 0; } @@ -169,6 +169,7 @@ static int socfpga_dwmmc_probe(struct udevice *dev) struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct dwmci_socfpga_priv_data *priv = dev_get_priv(dev); struct dwmci_host *host = &priv->host; + priv->dev = dev; int ret; ret = socfpga_dwmmc_get_clk_rate(dev); diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c index 3b682918b03..eda95b72f49 100644 --- a/drivers/mmc/zynq_sdhci.c +++ b/drivers/mmc/zynq_sdhci.c @@ -125,7 +125,7 @@ __weak int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value) } __weak int xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2, - u32 arg3, u32 *ret_payload) + u32 arg3, u32 arg4, u32 arg5, u32 *ret_payload) { return 0; } @@ -331,7 +331,8 @@ static inline int arasan_zynqmp_set_in_tapdelay(u32 node_id, u32 itap_delay) } else { return xilinx_pm_request(PM_IOCTL, node_id, IOCTL_SET_SD_TAPDELAY, - PM_TAPDELAY_INPUT, itap_delay, NULL); + PM_TAPDELAY_INPUT, itap_delay, 0, 0, + NULL); } return 0; @@ -350,7 +351,8 @@ static inline int arasan_zynqmp_set_out_tapdelay(u32 node_id, u32 otap_delay) } else { return xilinx_pm_request(PM_IOCTL, node_id, IOCTL_SET_SD_TAPDELAY, - PM_TAPDELAY_OUTPUT, otap_delay, NULL); + PM_TAPDELAY_OUTPUT, otap_delay, 0, 0, + NULL); } } @@ -367,7 +369,8 @@ static inline int zynqmp_dll_reset(u32 node_id, u32 type) SD1_DLL_RST : 0); } else { return xilinx_pm_request(PM_IOCTL, node_id, - IOCTL_SD_DLL_RESET, type, 0, NULL); + IOCTL_SD_DLL_RESET, type, 0, 0, 0, + NULL); } } @@ -1021,7 +1024,7 @@ static int sdhci_zynqmp_set_dynamic_config(struct arasan_sdhci_priv *priv, ret = xilinx_pm_request(PM_REQUEST_NODE, priv->node_id, ZYNQMP_PM_CAPABILITY_ACCESS, ZYNQMP_PM_MAX_QOS, - ZYNQMP_PM_REQUEST_ACK_NO, NULL); + ZYNQMP_PM_REQUEST_ACK_NO, 0, 0, NULL); if (ret) { dev_err(dev, "Request node failed for %d\n", priv->node_id); return ret; diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index e76601a5545..86752b5926d 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -41,6 +41,7 @@ config MTD_BLOCK config SYS_MTDPARTS_RUNTIME bool "Allow MTDPARTS to be configured at runtime" + depends on !COMPILE_TEST help This option allows to call the function board_mtdparts_default to dynamically build the variables mtdids and mtdparts at runtime. @@ -166,7 +167,7 @@ config SYS_FLASH_QUIET_TEST config SYS_FLASH_CHECKSUM bool "Compute and print flash CRC if 'flashchecksum' is set in the environment" - depends on MTD_NOR_FLASH + depends on (FLASH_CFI_DRIVER && !CFI_FLASH) help If the variable flashchecksum is set in the environment, perform a CRC of the flash and print the value to console. @@ -222,6 +223,7 @@ config SYS_MAX_FLASH_SECT config SAMSUNG_ONENAND bool "Samsung OneNAND driver support" + depends on S5P config USE_SYS_MAX_FLASH_BANKS bool "Enable Max number of Flash memory banks" diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 9c8a32bb0a8..c76c10e1ef9 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -11,7 +11,6 @@ config SYS_NAND_SELF_INIT config SPL_SYS_NAND_SELF_INIT bool - depends on !SPL_NAND_SIMPLE help This option, if enabled, provides more flexible and linux-like NAND initialization process, in SPL. @@ -50,6 +49,8 @@ config SYS_NAND_NO_SUBPAGE_WRITE config DM_NAND_ATMEL bool "Support Atmel NAND controller with DM support" + depends on ARCH_AT91 + select ATMEL_EBI select SYS_NAND_SELF_INIT imply SYS_NAND_USE_FLASH_BBT help @@ -58,6 +59,7 @@ config DM_NAND_ATMEL config NAND_ATMEL bool "Support Atmel NAND controller" + depends on ARCH_AT91 select SYS_NAND_SELF_INIT imply SYS_NAND_USE_FLASH_BBT help @@ -115,6 +117,7 @@ endif config NAND_BRCMNAND bool "Support Broadcom NAND controller" depends on OF_CONTROL && DM && DM_MTD + depends on ARCH_BCMBCA || ARCH_BMIPS || TARGET_BCMNS || TARGET_BCMNS3 select SYS_NAND_SELF_INIT help Enable the driver for NAND flash on platforms using a Broadcom NAND @@ -148,6 +151,7 @@ config NAND_BRCMNAND_IPROC config NAND_DAVINCI bool "Support TI Davinci NAND controller" + depends on ARCH_DAVINCI || ARCH_KEYSTONE select SYS_NAND_SELF_INIT if TARGET_DA850EVM help Enable this driver for NAND flash controllers available in TI Davinci @@ -192,7 +196,7 @@ config SPL_NAND_LOAD config NAND_CADENCE bool "Support Cadence NAND controller as a DT device" - depends on OF_CONTROL && DM_MTD + depends on OF_CONTROL && DM_MTD && ARCH_SOCFPGA select SYS_NAND_SELF_INIT select SPL_SYS_NAND_SELF_INIT select SPL_NAND_BASE @@ -234,6 +238,7 @@ config NAND_FSL_ELBC_DT config NAND_FSL_IFC bool "Support Freescale Integrated Flash Controller NAND driver" + depends on ARCH_LS1021A || FSL_LSCH2 || FSL_LSCH3 || PPC select TPL_SYS_NAND_SELF_INIT if TPL_NAND_SUPPORT select TPL_NAND_INIT if TPL && !TPL_FRAMEWORK select SPL_SYS_NAND_SELF_INIT @@ -257,13 +262,14 @@ config NAND_KMETER1 config NAND_LPC32XX_MLC bool "Support LPC32XX_MLC controller" + depends on ARCH_LPC32XX select SYS_NAND_SELF_INIT help Enable the LPC32XX MLC NAND controller. config NAND_OMAP_GPMC bool "Support OMAP GPMC NAND controller" - depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || ARCH_K3 + depends on ARCH_OMAP2PLUS || ARCH_K3 select SYS_NAND_SELF_INIT if ARCH_K3 select SPL_NAND_INIT if ARCH_K3 select SPL_SYS_NAND_SELF_INIT if ARCH_K3 @@ -431,6 +437,7 @@ endif config NAND_PXA3XX bool "Support for NAND on PXA3xx and Armada 370/XP/38x" + depends on ARCH_MVEBU select SYS_NAND_SELF_INIT select DM_MTD select REGMAP @@ -446,7 +453,6 @@ config NAND_SANDBOX select SYS_NAND_SELF_INIT select SPL_SYS_NAND_SELF_INIT select SPL_NAND_INIT - select SYS_NAND_SOFT_ECC select BCH select NAND_ECC_BCH imply CMD_NAND @@ -490,7 +496,7 @@ endif config NAND_ARASAN bool "Configure Arasan Nand" select SYS_NAND_SELF_INIT - depends on DM_MTD + depends on DM_MTD && ARCH_ZYNQMP imply CMD_NAND help This enables Nand driver support for Arasan nand flash @@ -553,6 +559,7 @@ endif config NAND_ZYNQ bool "Support for Zynq Nand controller" + depends on ARCH_ZYNQ select SPL_SYS_NAND_SELF_INIT select SYS_NAND_SELF_INIT select DM_MTD @@ -662,7 +669,6 @@ config SYS_NAND_PAGE_SIZE MVEBU_SPL_BOOT_DEVICE_NAND || \ (NAND_ATMEL && SPL_NAND_SUPPORT) || \ SPL_GENERATE_ATMEL_PMECC_HEADER || NAND_SANDBOX || NAND_CADENCE - depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC && !NAND_MT7621 help Number of data bytes in one page for the NAND chip on the board, not including the OOB area. @@ -672,7 +678,6 @@ config SYS_NAND_OOBSIZE depends on ARCH_SUNXI || NAND_OMAP_GPMC || \ SPL_NAND_SIMPLE || (NAND_MXC && SPL_NAND_SUPPORT) || \ (NAND_ATMEL && SPL_NAND_SUPPORT) || SPL_GENERATE_ATMEL_PMECC_HEADER - depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC help Number of bytes in the Out-Of-Band area for the NAND chip on the board. diff --git a/drivers/mtd/nand/raw/am335x_spl_bch.c b/drivers/mtd/nand/raw/am335x_spl_bch.c index 4b50f351d35..a77206d3815 100644 --- a/drivers/mtd/nand/raw/am335x_spl_bch.c +++ b/drivers/mtd/nand/raw/am335x_spl_bch.c @@ -212,6 +212,8 @@ void nand_init(void) if (nand_chip.select_chip) nand_chip.select_chip(mtd, 0); + mtd->writesize = CONFIG_SYS_NAND_PAGE_SIZE; + /* NAND chip may require reset after power-on */ nand_command(0, 0, 0, NAND_CMD_RESET); } diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index d3d1b93947b..48e3685d995 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -566,7 +566,7 @@ void nand_wait_ready(struct mtd_info *mtd) break; } - if (!chip->dev_ready(mtd)) + if (!chip->dev_ready || !chip->dev_ready(mtd)) pr_warn("timeout while waiting for chip to become ready\n"); } EXPORT_SYMBOL_GPL(nand_wait_ready); diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile index 65b836b34ca..a7a0b2cb4b9 100644 --- a/drivers/mtd/nand/spi/Makefile +++ b/drivers/mtd/nand/spi/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -spinand-objs := core.o esmt.o gigadevice.o macronix.o micron.o paragon.o -spinand-objs += toshiba.o winbond.o xtx.o +spinand-objs := core.o otp.o +spinand-objs += alliancememory.o ato.o esmt.o fmsh.o foresee.o gigadevice.o macronix.o +spinand-objs += micron.o paragon.o skyhigh.o toshiba.o winbond.o xtx.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o diff --git a/drivers/mtd/nand/spi/alliancememory.c b/drivers/mtd/nand/spi/alliancememory.c new file mode 100644 index 00000000000..a3772b8c2f0 --- /dev/null +++ b/drivers/mtd/nand/spi/alliancememory.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Author: Mario Kicherer <dev@kicherer.org> + */ + +#ifndef __UBOOT__ +#include <linux/device.h> +#include <linux/kernel.h> +#endif +#include <linux/mtd/spinand.h> + +#define SPINAND_MFR_ALLIANCEMEMORY 0x52 + +#define AM_STATUS_ECC_BITMASK (3 << 4) + +#define AM_STATUS_ECC_NONE_DETECTED (0 << 4) +#define AM_STATUS_ECC_CORRECTED (1 << 4) +#define AM_STATUS_ECC_ERRORED (2 << 4) +#define AM_STATUS_ECC_MAX_CORRECTED (3 << 4) + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); + +static int am_get_eccsize(struct mtd_info *mtd) +{ + if (mtd->oobsize == 64) + return 0x20; + else if (mtd->oobsize == 128) + return 0x38; + else if (mtd->oobsize == 256) + return 0x70; + else + return -EINVAL; +} + +static int am_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + int ecc_bytes; + + ecc_bytes = am_get_eccsize(mtd); + if (ecc_bytes < 0) + return ecc_bytes; + + region->offset = mtd->oobsize - ecc_bytes; + region->length = ecc_bytes; + + return 0; +} + +static int am_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + int ecc_bytes; + + if (section) + return -ERANGE; + + ecc_bytes = am_get_eccsize(mtd); + if (ecc_bytes < 0) + return ecc_bytes; + + /* + * It is unclear how many bytes are used for the bad block marker. We + * reserve the common two bytes here. + * + * The free area in this kind of flash is divided into chunks where the + * first 4 bytes of each chunk are unprotected. The number of chunks + * depends on the specific model. The models with 4096+256 bytes pages + * have 8 chunks, the others 4 chunks. + */ + + region->offset = 2; + region->length = mtd->oobsize - 2 - ecc_bytes; + + return 0; +} + +static const struct mtd_ooblayout_ops am_ooblayout = { + .ecc = am_ooblayout_ecc, + .rfree = am_ooblayout_free, +}; + +static int am_ecc_get_status(struct spinand_device *spinand, u8 status) +{ + switch (status & AM_STATUS_ECC_BITMASK) { + case AM_STATUS_ECC_NONE_DETECTED: + return 0; + + case AM_STATUS_ECC_CORRECTED: + /* + * use oobsize to determine the flash model and the maximum of + * correctable errors and return maximum - 1 by convention + */ + if (spinand->base.mtd->oobsize == 64) + return 3; + else + return 7; + + case AM_STATUS_ECC_ERRORED: + return -EBADMSG; + + case AM_STATUS_ECC_MAX_CORRECTED: + /* + * use oobsize to determine the flash model and the maximum of + * correctable errors + */ + if (spinand->base.mtd->oobsize == 64) + return 4; + else + return 8; + + default: + break; + } + + return -EINVAL; +} + +static const struct spinand_info alliancememory_spinand_table[] = { + SPINAND_INFO("AS5F34G04SND", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x2f), + NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&am_ooblayout, + am_ecc_get_status)), +}; + +static const struct spinand_manufacturer_ops alliancememory_spinand_manuf_ops = { +}; + +const struct spinand_manufacturer alliancememory_spinand_manufacturer = { + .id = SPINAND_MFR_ALLIANCEMEMORY, + .name = "AllianceMemory", + .chips = alliancememory_spinand_table, + .nchips = ARRAY_SIZE(alliancememory_spinand_table), + .ops = &alliancememory_spinand_manuf_ops, +}; diff --git a/drivers/mtd/nand/spi/ato.c b/drivers/mtd/nand/spi/ato.c new file mode 100644 index 00000000000..a726df3eb98 --- /dev/null +++ b/drivers/mtd/nand/spi/ato.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Aidan MacDonald + * + * Author: Aidan MacDonald <aidanmacdonald.0x0@gmail.com> + */ + +#ifndef __UBOOT__ +#include <linux/device.h> +#include <linux/kernel.h> +#endif +#include <linux/mtd/spinand.h> + + +#define SPINAND_MFR_ATO 0x9b + + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); + + +static int ato25d1ga_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 3) + return -ERANGE; + + region->offset = (16 * section) + 8; + region->length = 8; + return 0; +} + +static int ato25d1ga_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 3) + return -ERANGE; + + if (section) { + region->offset = (16 * section); + region->length = 8; + } else { + /* first byte of section 0 is reserved for the BBM */ + region->offset = 1; + region->length = 7; + } + + return 0; +} + +static const struct mtd_ooblayout_ops ato25d1ga_ooblayout = { + .ecc = ato25d1ga_ooblayout_ecc, + .rfree = ato25d1ga_ooblayout_free, +}; + + +static const struct spinand_info ato_spinand_table[] = { + SPINAND_INFO("ATO25D1GA", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x12), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&ato25d1ga_ooblayout, NULL)), +}; + +static const struct spinand_manufacturer_ops ato_spinand_manuf_ops = { +}; + +const struct spinand_manufacturer ato_spinand_manufacturer = { + .id = SPINAND_MFR_ATO, + .name = "ATO", + .chips = ato_spinand_table, + .nchips = ARRAY_SIZE(ato_spinand_table), + .ops = &ato_spinand_manuf_ops, +}; diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 3a1e7e18736..14af4264612 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -32,6 +32,7 @@ #include <linux/bug.h> #include <linux/mtd/spinand.h> #include <linux/printk.h> +#include <linux/delay.h> #endif struct spinand_plat { @@ -41,24 +42,9 @@ struct spinand_plat { /* SPI NAND index visible in MTD names */ static int spi_nand_idx; -static void spinand_cache_op_adjust_colum(struct spinand_device *spinand, - const struct nand_page_io_req *req, - u16 *column) +int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val) { - struct nand_device *nand = spinand_to_nand(spinand); - unsigned int shift; - - if (nand->memorg.planes_per_lun < 2) - return; - - /* The plane number is passed in MSB just above the column address */ - shift = fls(nand->memorg.pagesize); - *column |= req->pos.plane << shift; -} - -static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val) -{ - struct spi_mem_op op = SPINAND_GET_FEATURE_OP(reg, + struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(reg, spinand->scratchbuf); int ret; @@ -70,9 +56,9 @@ static int spinand_read_reg_op(struct spinand_device *spinand, u8 reg, u8 *val) return 0; } -static int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val) +int spinand_write_reg_op(struct spinand_device *spinand, u8 reg, u8 val) { - struct spi_mem_op op = SPINAND_SET_FEATURE_OP(reg, + struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(reg, spinand->scratchbuf); *spinand->scratchbuf = val; @@ -174,20 +160,12 @@ int spinand_select_target(struct spinand_device *spinand, unsigned int target) return 0; } -static int spinand_init_cfg_cache(struct spinand_device *spinand) +static int spinand_read_cfg(struct spinand_device *spinand) { struct nand_device *nand = spinand_to_nand(spinand); - struct udevice *dev = spinand->slave->dev; unsigned int target; int ret; - spinand->cfg_cache = devm_kzalloc(dev, - sizeof(*spinand->cfg_cache) * - nand->memorg.ntargets, - GFP_KERNEL); - if (!spinand->cfg_cache) - return -ENOMEM; - for (target = 0; target < nand->memorg.ntargets; target++) { ret = spinand_select_target(spinand, target); if (ret) @@ -206,6 +184,21 @@ static int spinand_init_cfg_cache(struct spinand_device *spinand) return 0; } +static int spinand_init_cfg_cache(struct spinand_device *spinand) +{ + struct nand_device *nand = spinand_to_nand(spinand); + struct udevice *dev = spinand->slave->dev; + + spinand->cfg_cache = devm_kcalloc(dev, + nand->memorg.ntargets, + sizeof(*spinand->cfg_cache), + GFP_KERNEL); + if (!spinand->cfg_cache) + return -ENOMEM; + + return 0; +} + static int spinand_init_quad_enable(struct spinand_device *spinand) { bool enable = false; @@ -229,9 +222,144 @@ static int spinand_ecc_enable(struct spinand_device *spinand, enable ? CFG_ECC_ENABLE : 0); } -static int spinand_write_enable_op(struct spinand_device *spinand) + +static int spinand_cont_read_enable(struct spinand_device *spinand, + bool enable) +{ + return spinand->set_cont_read(spinand, enable); +} + +static int spinand_check_ecc_status(struct spinand_device *spinand, u8 status) +{ + struct nand_device *nand = spinand_to_nand(spinand); + + if (spinand->eccinfo.get_status) + return spinand->eccinfo.get_status(spinand, status); + + switch (status & STATUS_ECC_MASK) { + case STATUS_ECC_NO_BITFLIPS: + return 0; + + case STATUS_ECC_HAS_BITFLIPS: + /* + * We have no way to know exactly how many bitflips have been + * fixed, so let's return the maximum possible value so that + * wear-leveling layers move the data immediately. + */ + return nanddev_get_ecc_conf(nand)->strength; + + case STATUS_ECC_UNCOR_ERROR: + return -EBADMSG; + + default: + break; + } + + return -EINVAL; +} + +static int spinand_noecc_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + return -ERANGE; +} + +static int spinand_noecc_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section) + return -ERANGE; + + /* Reserve 2 bytes for the BBM. */ + region->offset = 2; + region->length = 62; + + return 0; +} + +static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = { + .ecc = spinand_noecc_ooblayout_ecc, + .rfree = spinand_noecc_ooblayout_free, +}; + +static int spinand_ondie_ecc_init_ctx(struct nand_device *nand) +{ + struct spinand_device *spinand = nand_to_spinand(nand); + struct mtd_info *mtd = nanddev_to_mtd(nand); + + if (spinand->eccinfo.ooblayout) + mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout); + else + mtd_set_ooblayout(mtd, &spinand_noecc_ooblayout); + + return 0; +} + +static void spinand_ondie_ecc_cleanup_ctx(struct nand_device *nand) +{ +} + +static int spinand_ondie_ecc_prepare_io_req(struct nand_device *nand, + struct nand_page_io_req *req) +{ + struct spinand_device *spinand = nand_to_spinand(nand); + bool enable = (req->mode != MTD_OPS_RAW); + + if (!enable && spinand->flags & SPINAND_NO_RAW_ACCESS) + return -EOPNOTSUPP; + + memset(spinand->oobbuf, 0xff, nanddev_per_page_oobsize(nand)); + + /* Only enable or disable the engine */ + return spinand_ecc_enable(spinand, enable); +} + +static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand, + struct nand_page_io_req *req) +{ + struct spinand_device *spinand = nand_to_spinand(nand); + struct mtd_info *mtd = spinand_to_mtd(spinand); + int ret; + + if (req->mode == MTD_OPS_RAW) + return 0; + + /* Nothing to do when finishing a page write */ + if (req->type == NAND_PAGE_WRITE) + return 0; + + /* Finish a page read: check the status, report errors/bitflips */ + ret = spinand_check_ecc_status(spinand, spinand->last_wait_status); + if (ret == -EBADMSG) { + mtd->ecc_stats.failed++; + } else if (ret > 0) { + unsigned int pages; + + /* + * Continuous reads don't allow us to get the detail, + * so we may exagerate the actual number of corrected bitflips. + */ + if (!req->continuous) + pages = 1; + else + pages = req->datalen / nanddev_page_size(nand); + + mtd->ecc_stats.corrected += ret * pages; + } + + return ret; +} + +static void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status) +{ + struct spinand_device *spinand = nand_to_spinand(nand); + + spinand->last_wait_status = status; +} + +int spinand_write_enable_op(struct spinand_device *spinand) { - struct spi_mem_op op = SPINAND_WR_EN_DIS_OP(true); + struct spi_mem_op op = SPINAND_WR_EN_DIS_1S_0_0_OP(true); return spi_mem_exec_op(spinand->slave, &op); } @@ -241,7 +369,7 @@ static int spinand_load_page_op(struct spinand_device *spinand, { struct nand_device *nand = spinand_to_nand(spinand); unsigned int row = nanddev_pos_to_row(nand, &req->pos); - struct spi_mem_op op = SPINAND_PAGE_READ_OP(row); + struct spi_mem_op op = SPINAND_PAGE_READ_1S_1S_0_OP(row); return spi_mem_exec_op(spinand->slave, &op); } @@ -249,27 +377,25 @@ static int spinand_load_page_op(struct spinand_device *spinand, static int spinand_read_from_cache_op(struct spinand_device *spinand, const struct nand_page_io_req *req) { - struct spi_mem_op op = *spinand->op_templates.read_cache; struct nand_device *nand = spinand_to_nand(spinand); - struct mtd_info *mtd = nanddev_to_mtd(nand); - struct nand_page_io_req adjreq = *req; + struct mtd_info *mtd = spinand_to_mtd(spinand); + struct spi_mem_dirmap_desc *rdesc; unsigned int nbytes = 0; void *buf = NULL; u16 column = 0; - int ret; + ssize_t ret; if (req->datalen) { - adjreq.datalen = nanddev_page_size(nand); - adjreq.dataoffs = 0; - adjreq.databuf.in = spinand->databuf; buf = spinand->databuf; - nbytes = adjreq.datalen; + if (!req->continuous) + nbytes = nanddev_page_size(nand); + else + nbytes = round_up(req->dataoffs + req->datalen, + nanddev_page_size(nand)); + column = 0; } if (req->ooblen) { - adjreq.ooblen = nanddev_per_page_oobsize(nand); - adjreq.ooboffs = 0; - adjreq.oobbuf.in = spinand->oobbuf; nbytes += nanddev_per_page_oobsize(nand); if (!buf) { buf = spinand->oobbuf; @@ -277,28 +403,40 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand, } } - spinand_cache_op_adjust_colum(spinand, &adjreq, &column); - op.addr.val = column; + if (req->mode == MTD_OPS_RAW) + rdesc = spinand->dirmaps[req->pos.plane].rdesc; + else + rdesc = spinand->dirmaps[req->pos.plane].rdesc_ecc; + + if (spinand->flags & SPINAND_HAS_READ_PLANE_SELECT_BIT) + column |= req->pos.plane << fls(nanddev_page_size(nand)); - /* - * Some controllers are limited in term of max RX data size. In this - * case, just repeat the READ_CACHE operation after updating the - * column. - */ while (nbytes) { - op.data.buf.in = buf; - op.data.nbytes = nbytes; - ret = spi_mem_adjust_op_size(spinand->slave, &op); - if (ret) + ret = spi_mem_dirmap_read(rdesc, column, nbytes, buf); + if (ret < 0) return ret; - ret = spi_mem_exec_op(spinand->slave, &op); - if (ret) - return ret; + if (!ret || ret > nbytes) + return -EIO; - buf += op.data.nbytes; - nbytes -= op.data.nbytes; - op.addr.val += op.data.nbytes; + nbytes -= ret; + column += ret; + buf += ret; + + /* + * Dirmap accesses are allowed to toggle the CS. + * Toggling the CS during a continuous read is forbidden. + */ + if (nbytes && req->continuous) { + /* + * Spi controller with broken support of continuous + * reading was detected. Disable future use of + * continuous reading and return -EAGAIN to retry + * reading within regular mode. + */ + spinand->cont_read_possible = false; + return -EAGAIN; + } } if (req->datalen) @@ -322,14 +460,12 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand, static int spinand_write_to_cache_op(struct spinand_device *spinand, const struct nand_page_io_req *req) { - struct spi_mem_op op = *spinand->op_templates.write_cache; struct nand_device *nand = spinand_to_nand(spinand); - struct mtd_info *mtd = nanddev_to_mtd(nand); - struct nand_page_io_req adjreq = *req; - unsigned int nbytes = 0; - void *buf = NULL; - u16 column = 0; - int ret; + struct mtd_info *mtd = spinand_to_mtd(spinand); + struct spi_mem_dirmap_desc *wdesc; + unsigned int nbytes, column = 0; + void *buf = spinand->databuf; + ssize_t ret; /* * Looks like PROGRAM LOAD (AKA write cache) does not necessarily reset @@ -337,20 +473,16 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand, * must fill the page cache entirely even if we only want to program * the data portion of the page, otherwise we might corrupt the BBM or * user data previously programmed in OOB area. + * + * Only reset the data buffer manually, the OOB buffer is prepared by + * ECC engines ->prepare_io_req() callback. */ - memset(spinand->databuf, 0xff, - nanddev_page_size(nand) + - nanddev_per_page_oobsize(nand)); + nbytes = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); + memset(spinand->databuf, 0xff, nanddev_page_size(nand)); - if (req->datalen) { + if (req->datalen) memcpy(spinand->databuf + req->dataoffs, req->databuf.out, req->datalen); - adjreq.dataoffs = 0; - adjreq.datalen = nanddev_page_size(nand); - adjreq.databuf.out = spinand->databuf; - nbytes = adjreq.datalen; - buf = spinand->databuf; - } if (req->ooblen) { if (req->mode == MTD_OPS_AUTO_OOB) @@ -361,52 +493,27 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand, else memcpy(spinand->oobbuf + req->ooboffs, req->oobbuf.out, req->ooblen); - - adjreq.ooblen = nanddev_per_page_oobsize(nand); - adjreq.ooboffs = 0; - nbytes += nanddev_per_page_oobsize(nand); - if (!buf) { - buf = spinand->oobbuf; - column = nanddev_page_size(nand); - } } - spinand_cache_op_adjust_colum(spinand, &adjreq, &column); + if (req->mode == MTD_OPS_RAW) + wdesc = spinand->dirmaps[req->pos.plane].wdesc; + else + wdesc = spinand->dirmaps[req->pos.plane].wdesc_ecc; - op = *spinand->op_templates.write_cache; - op.addr.val = column; + if (spinand->flags & SPINAND_HAS_PROG_PLANE_SELECT_BIT) + column |= req->pos.plane << fls(nanddev_page_size(nand)); - /* - * Some controllers are limited in term of max TX data size. In this - * case, split the operation into one LOAD CACHE and one or more - * LOAD RANDOM CACHE. - */ while (nbytes) { - op.data.buf.out = buf; - op.data.nbytes = nbytes; - - ret = spi_mem_adjust_op_size(spinand->slave, &op); - if (ret) - return ret; - - ret = spi_mem_exec_op(spinand->slave, &op); - if (ret) + ret = spi_mem_dirmap_write(wdesc, column, nbytes, buf); + if (ret < 0) return ret; - buf += op.data.nbytes; - nbytes -= op.data.nbytes; - op.addr.val += op.data.nbytes; + if (!ret || ret > nbytes) + return -EIO; - /* - * We need to use the RANDOM LOAD CACHE operation if there's - * more than one iteration, because the LOAD operation resets - * the cache to 0xff. - */ - if (nbytes) { - column = op.addr.val; - op = *spinand->op_templates.update_cache; - op.addr.val = column; - } + nbytes -= ret; + column += ret; + buf += ret; } return 0; @@ -417,7 +524,7 @@ static int spinand_program_op(struct spinand_device *spinand, { struct nand_device *nand = spinand_to_nand(spinand); unsigned int row = nanddev_pos_to_row(nand, &req->pos); - struct spi_mem_op op = SPINAND_PROG_EXEC_OP(row); + struct spi_mem_op op = SPINAND_PROG_EXEC_1S_1S_0_OP(row); return spi_mem_exec_op(spinand->slave, &op); } @@ -425,28 +532,48 @@ static int spinand_program_op(struct spinand_device *spinand, static int spinand_erase_op(struct spinand_device *spinand, const struct nand_pos *pos) { - struct nand_device *nand = &spinand->base; + struct nand_device *nand = spinand_to_nand(spinand); unsigned int row = nanddev_pos_to_row(nand, pos); - struct spi_mem_op op = SPINAND_BLK_ERASE_OP(row); + struct spi_mem_op op = SPINAND_BLK_ERASE_1S_1S_0_OP(row); return spi_mem_exec_op(spinand->slave, &op); } -static int spinand_wait(struct spinand_device *spinand, u8 *s) +/** + * spinand_wait() - Poll memory device status + * @spinand: the spinand device + * @initial_delay_us: delay in us before starting to poll + * @poll_delay_us: time to sleep between reads in us + * @s: the pointer to variable to store the value of REG_STATUS + * + * This function polls a status register (REG_STATUS) and returns when + * the STATUS_READY bit is 0 or when the timeout has expired. + * + * Return: 0 on success, a negative error code otherwise. + */ +int spinand_wait(struct spinand_device *spinand, + unsigned long initial_delay_us, + unsigned long poll_delay_us, + u8 *s) { unsigned long start, stop; u8 status; int ret; + udelay(initial_delay_us); start = get_timer(0); - stop = 400; + stop = SPINAND_WAITRDY_TIMEOUT_MS; do { + schedule(); + ret = spinand_read_status(spinand, &status); if (ret) return ret; if (!(status & STATUS_BUSY)) goto out; + + udelay(poll_delay_us); } while (get_timer(start) < stop); /* @@ -467,9 +594,8 @@ out: static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr, u8 ndummy, u8 *buf) { - struct spi_mem_op op = SPINAND_READID_OP(naddr, ndummy, - spinand->scratchbuf, - SPINAND_MAX_ID_LEN); + struct spi_mem_op op = SPINAND_READID_1S_1S_1S_OP( + naddr, ndummy, spinand->scratchbuf, SPINAND_MAX_ID_LEN); int ret; ret = spi_mem_exec_op(spinand->slave, &op); @@ -481,14 +607,17 @@ static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr, static int spinand_reset_op(struct spinand_device *spinand) { - struct spi_mem_op op = SPINAND_RESET_OP; + struct spi_mem_op op = SPINAND_RESET_1S_0_0_OP; int ret; ret = spi_mem_exec_op(spinand->slave, &op); if (ret) return ret; - return spinand_wait(spinand, NULL); + return spinand_wait(spinand, + SPINAND_RESET_INITIAL_DELAY_US, + SPINAND_RESET_POLL_DELAY_US, + NULL); } static int spinand_lock_block(struct spinand_device *spinand, u8 lock) @@ -496,66 +625,64 @@ static int spinand_lock_block(struct spinand_device *spinand, u8 lock) return spinand_write_reg_op(spinand, REG_BLOCK_LOCK, lock); } -static int spinand_check_ecc_status(struct spinand_device *spinand, u8 status) +/** + * spinand_read_page() - Read a page + * @spinand: the spinand device + * @req: the I/O request + * + * Return: 0 or a positive number of bitflips corrected on success. + * A negative error code otherwise. + */ +int spinand_read_page(struct spinand_device *spinand, + const struct nand_page_io_req *req) { struct nand_device *nand = spinand_to_nand(spinand); - - if (spinand->eccinfo.get_status) - return spinand->eccinfo.get_status(spinand, status); - - switch (status & STATUS_ECC_MASK) { - case STATUS_ECC_NO_BITFLIPS: - return 0; - - case STATUS_ECC_HAS_BITFLIPS: - /* - * We have no way to know exactly how many bitflips have been - * fixed, so let's return the maximum possible value so that - * wear-leveling layers move the data immediately. - */ - return nand->eccreq.strength; - - case STATUS_ECC_UNCOR_ERROR: - return -EBADMSG; - - default: - break; - } - - return -EINVAL; -} - -static int spinand_read_page(struct spinand_device *spinand, - const struct nand_page_io_req *req, - bool ecc_enabled) -{ u8 status; int ret; + ret = spinand_ondie_ecc_prepare_io_req(nand, (struct nand_page_io_req *)req); + if (ret) + return ret; + ret = spinand_load_page_op(spinand, req); if (ret) return ret; - ret = spinand_wait(spinand, &status); + ret = spinand_wait(spinand, + SPINAND_READ_INITIAL_DELAY_US, + SPINAND_READ_POLL_DELAY_US, + &status); if (ret < 0) return ret; + spinand_ondie_ecc_save_status(nand, status); + ret = spinand_read_from_cache_op(spinand, req); if (ret) return ret; - if (!ecc_enabled) - return 0; - - return spinand_check_ecc_status(spinand, status); + return spinand_ondie_ecc_finish_io_req(nand, (struct nand_page_io_req *)req); } -static int spinand_write_page(struct spinand_device *spinand, - const struct nand_page_io_req *req) +/** + * spinand_write_page() - Write a page + * @spinand: the spinand device + * @req: the I/O request + * + * Return: 0 or a positive number of bitflips corrected on success. + * A negative error code otherwise. + */ +int spinand_write_page(struct spinand_device *spinand, + const struct nand_page_io_req *req) { + struct nand_device *nand = spinand_to_nand(spinand); u8 status; int ret; + ret = spinand_ondie_ecc_prepare_io_req(nand, (struct nand_page_io_req *)req); + if (ret) + return ret; + ret = spinand_write_enable_op(spinand); if (ret) return ret; @@ -568,63 +695,234 @@ static int spinand_write_page(struct spinand_device *spinand, if (ret) return ret; - ret = spinand_wait(spinand, &status); - if (!ret && (status & STATUS_PROG_FAILED)) - ret = -EIO; + ret = spinand_wait(spinand, + SPINAND_WRITE_INITIAL_DELAY_US, + SPINAND_WRITE_POLL_DELAY_US, + &status); + if (ret) + return ret; - return ret; + if (status & STATUS_PROG_FAILED) + return -EIO; + + return spinand_ondie_ecc_finish_io_req(nand, (struct nand_page_io_req *)req); } -static int spinand_mtd_read(struct mtd_info *mtd, loff_t from, - struct mtd_oob_ops *ops) +static int spinand_mtd_regular_page_read(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops, + unsigned int *max_bitflips) { struct spinand_device *spinand = mtd_to_spinand(mtd); struct nand_device *nand = mtd_to_nanddev(mtd); - unsigned int max_bitflips = 0; + struct mtd_ecc_stats old_stats; struct nand_io_iter iter; - bool enable_ecc = false; + bool disable_ecc = false; bool ecc_failed = false; - int ret = 0; + unsigned int retry_mode = 0; + int ret; - if (ops->mode != MTD_OPS_RAW && spinand->eccinfo.ooblayout) - enable_ecc = true; + old_stats = mtd->ecc_stats; -#ifndef __UBOOT__ - mutex_lock(&spinand->lock); -#endif + if (ops->mode == MTD_OPS_RAW || !mtd->ooblayout) + disable_ecc = true; - nanddev_io_for_each_page(nand, from, ops, &iter) { + nanddev_io_for_each_page(nand, NAND_PAGE_READ, from, ops, &iter) { schedule(); - ret = spinand_select_target(spinand, iter.req.pos.target); - if (ret) - break; + if (disable_ecc) + iter.req.mode = MTD_OPS_RAW; - ret = spinand_ecc_enable(spinand, enable_ecc); + ret = spinand_select_target(spinand, iter.req.pos.target); if (ret) break; - ret = spinand_read_page(spinand, &iter.req, enable_ecc); +read_retry: + ret = spinand_read_page(spinand, &iter.req); if (ret < 0 && ret != -EBADMSG) break; - if (ret == -EBADMSG) { + if (ret == -EBADMSG && spinand->set_read_retry) { + if (spinand->read_retries && (++retry_mode <= spinand->read_retries)) { + ret = spinand->set_read_retry(spinand, retry_mode); + if (ret < 0) { + spinand->set_read_retry(spinand, 0); + return ret; + } + + /* Reset ecc_stats; retry */ + mtd->ecc_stats = old_stats; + goto read_retry; + } else { + /* No more retry modes; real failure */ + ecc_failed = true; + } + } else if (ret == -EBADMSG) { ecc_failed = true; - mtd->ecc_stats.failed++; } else { - mtd->ecc_stats.corrected += ret; - max_bitflips = max_t(unsigned int, max_bitflips, ret); + *max_bitflips = max_t(unsigned int, *max_bitflips, ret); } ret = 0; ops->retlen += iter.req.datalen; ops->oobretlen += iter.req.ooblen; + + /* Reset to retry mode 0 */ + if (retry_mode) { + retry_mode = 0; + ret = spinand->set_read_retry(spinand, retry_mode); + if (ret < 0) + return ret; + } + } + + if (ecc_failed && !ret) + ret = -EBADMSG; + + return ret; +} + +static int spinand_mtd_continuous_page_read(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops, + unsigned int *max_bitflips) +{ + struct spinand_device *spinand = mtd_to_spinand(mtd); + struct nand_device *nand = mtd_to_nanddev(mtd); + struct nand_io_iter iter; + u8 status; + int ret; + + ret = spinand_cont_read_enable(spinand, true); + if (ret) + return ret; + + /* + * The cache is divided into two halves. While one half of the cache has + * the requested data, the other half is loaded with the next chunk of data. + * Therefore, the host can read out the data continuously from page to page. + * Each data read must be a multiple of 4-bytes and full pages should be read; + * otherwise, the data output might get out of sequence from one read command + * to another. + */ + nanddev_io_for_each_block(nand, NAND_PAGE_READ, from, ops, &iter) { + schedule(); + ret = spinand_select_target(spinand, iter.req.pos.target); + if (ret) + goto end_cont_read; + + ret = spinand_ondie_ecc_prepare_io_req(nand, &iter.req); + if (ret) + goto end_cont_read; + + ret = spinand_load_page_op(spinand, &iter.req); + if (ret) + goto end_cont_read; + + ret = spinand_wait(spinand, SPINAND_READ_INITIAL_DELAY_US, + SPINAND_READ_POLL_DELAY_US, NULL); + if (ret < 0) + goto end_cont_read; + + ret = spinand_read_from_cache_op(spinand, &iter.req); + if (ret) + goto end_cont_read; + + ops->retlen += iter.req.datalen; + + ret = spinand_read_status(spinand, &status); + if (ret) + goto end_cont_read; + + spinand_ondie_ecc_save_status(nand, status); + + ret = spinand_ondie_ecc_finish_io_req(nand, &iter.req); + if (ret < 0) + goto end_cont_read; + + *max_bitflips = max_t(unsigned int, *max_bitflips, ret); + ret = 0; + } + +end_cont_read: + /* + * Once all the data has been read out, the host can either pull CS# + * high and wait for tRST or manually clear the bit in the configuration + * register to terminate the continuous read operation. We have no + * guarantee the SPI controller drivers will effectively deassert the CS + * when we expect them to, so take the register based approach. + */ + spinand_cont_read_enable(spinand, false); + + return ret; +} + +static void spinand_cont_read_init(struct spinand_device *spinand) +{ + /* OOBs cannot be retrieved so external/on-host ECC engine won't work */ + if (spinand->set_cont_read) { + spinand->cont_read_possible = true; + } +} + +static bool spinand_use_cont_read(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + struct spinand_device *spinand = nand_to_spinand(nand); + struct nand_pos start_pos, end_pos; + + if (!spinand->cont_read_possible) + return false; + + /* OOBs won't be retrieved */ + if (ops->ooblen || ops->oobbuf) + return false; + + nanddev_offs_to_pos(nand, from, &start_pos); + nanddev_offs_to_pos(nand, from + ops->len - 1, &end_pos); + + /* + * Continuous reads never cross LUN boundaries. Some devices don't + * support crossing planes boundaries. Some devices don't even support + * crossing blocks boundaries. The common case being to read through UBI, + * we will very rarely read two consequent blocks or more, so it is safer + * and easier (can be improved) to only enable continuous reads when + * reading within the same erase block. + */ + if (start_pos.target != end_pos.target || + start_pos.plane != end_pos.plane || + start_pos.eraseblock != end_pos.eraseblock) + return false; + + return start_pos.page < end_pos.page; +} + +static int spinand_mtd_read(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + struct spinand_device *spinand = mtd_to_spinand(mtd); + unsigned int max_bitflips = 0; + int ret; + +#ifndef __UBOOT__ + mutex_lock(&spinand->lock); +#endif + + if (spinand_use_cont_read(mtd, from, ops)) { + ret = spinand_mtd_continuous_page_read(mtd, from, ops, &max_bitflips); + if (ret == -EAGAIN && !spinand->cont_read_possible) { + /* + * Spi controller with broken support of continuous + * reading was detected (see spinand_read_from_cache_op()), + * repeat reading in regular mode. + */ + ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips); + } + } else { + ret = spinand_mtd_regular_page_read(mtd, from, ops, &max_bitflips); } #ifndef __UBOOT__ mutex_unlock(&spinand->lock); #endif - if (ecc_failed && !ret) - ret = -EBADMSG; return ret ? ret : max_bitflips; } @@ -635,23 +933,22 @@ static int spinand_mtd_write(struct mtd_info *mtd, loff_t to, struct spinand_device *spinand = mtd_to_spinand(mtd); struct nand_device *nand = mtd_to_nanddev(mtd); struct nand_io_iter iter; - bool enable_ecc = false; + bool disable_ecc = false; int ret = 0; - if (ops->mode != MTD_OPS_RAW && mtd->ooblayout) - enable_ecc = true; + if (ops->mode == MTD_OPS_RAW || !mtd->ooblayout) + disable_ecc = true; #ifndef __UBOOT__ mutex_lock(&spinand->lock); #endif - nanddev_io_for_each_page(nand, to, ops, &iter) { + nanddev_io_for_each_page(nand, NAND_PAGE_WRITE, to, ops, &iter) { schedule(); - ret = spinand_select_target(spinand, iter.req.pos.target); - if (ret) - break; + if (disable_ecc) + iter.req.mode = MTD_OPS_RAW; - ret = spinand_ecc_enable(spinand, enable_ecc); + ret = spinand_select_target(spinand, iter.req.pos.target); if (ret) break; @@ -681,9 +978,17 @@ static bool spinand_isbad(struct nand_device *nand, const struct nand_pos *pos) .oobbuf.in = marker, .mode = MTD_OPS_RAW, }; + int ret; spinand_select_target(spinand, pos->target); - spinand_read_page(spinand, &req, false); + + ret = spinand_read_page(spinand, &req); + if (ret == -EOPNOTSUPP) { + /* Retry with ECC in case raw access is not supported */ + req.mode = MTD_OPS_PLACE_OOB; + spinand_read_page(spinand, &req); + } + if (marker[0] != 0xff || marker[1] != 0xff) return true; @@ -727,11 +1032,14 @@ static int spinand_markbad(struct nand_device *nand, const struct nand_pos *pos) if (ret) return ret; - ret = spinand_write_enable_op(spinand); - if (ret) - return ret; + ret = spinand_write_page(spinand, &req); + if (ret == -EOPNOTSUPP) { + /* Retry with ECC in case raw access is not supported */ + req.mode = MTD_OPS_PLACE_OOB; + ret = spinand_write_page(spinand, &req); + } - return spinand_write_page(spinand, &req); + return ret; } static int spinand_mtd_block_markbad(struct mtd_info *mtd, loff_t offs) @@ -751,6 +1059,7 @@ static int spinand_mtd_block_markbad(struct mtd_info *mtd, loff_t offs) #ifndef __UBOOT__ mutex_unlock(&spinand->lock); #endif + return ret; } @@ -772,7 +1081,11 @@ static int spinand_erase(struct nand_device *nand, const struct nand_pos *pos) if (ret) return ret; - ret = spinand_wait(spinand, &status); + ret = spinand_wait(spinand, + SPINAND_ERASE_INITIAL_DELAY_US, + SPINAND_ERASE_POLL_DELAY_US, + &status); + if (!ret && (status & STATUS_ERASE_FAILED)) ret = -EIO; @@ -819,6 +1132,91 @@ static int spinand_mtd_block_isreserved(struct mtd_info *mtd, loff_t offs) return ret; } +static struct spi_mem_dirmap_desc *spinand_create_rdesc( + struct spinand_device *spinand, + struct spi_mem_dirmap_info *info) +{ + struct nand_device *nand = spinand_to_nand(spinand); + struct spi_mem_dirmap_desc *desc = NULL; + + if (spinand->cont_read_possible) { + /* + * spi controller may return an error if info->length is + * too large + */ + info->length = nanddev_eraseblock_size(nand); + desc = spi_mem_dirmap_create(spinand->slave, info); + } + + if (IS_ERR_OR_NULL(desc)) { + /* + * continuous reading is not supported by flash or + * its spi controller, use regular reading + */ + spinand->cont_read_possible = false; + + info->length = nanddev_page_size(nand) + + nanddev_per_page_oobsize(nand); + desc = spi_mem_dirmap_create(spinand->slave, info); + } + + return desc; +} + +static int spinand_create_dirmap(struct spinand_device *spinand, + unsigned int plane) +{ + struct nand_device *nand = spinand_to_nand(spinand); + struct spi_mem_dirmap_info info = { 0 }; + struct spi_mem_dirmap_desc *desc; + + /* The plane number is passed in MSB just above the column address */ + info.offset = plane << fls(nand->memorg.pagesize); + + info.length = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); + info.op_tmpl = *spinand->op_templates.update_cache; + desc = spi_mem_dirmap_create(spinand->slave, &info); + if (IS_ERR(desc)) + return PTR_ERR(desc); + + spinand->dirmaps[plane].wdesc = desc; + + info.op_tmpl = *spinand->op_templates.read_cache; + desc = spinand_create_rdesc(spinand, &info); + if (IS_ERR(desc)) { + spi_mem_dirmap_destroy(spinand->dirmaps[plane].wdesc); + return PTR_ERR(desc); + } + + spinand->dirmaps[plane].rdesc = desc; + + spinand->dirmaps[plane].wdesc_ecc = spinand->dirmaps[plane].wdesc; + spinand->dirmaps[plane].rdesc_ecc = spinand->dirmaps[plane].rdesc; + + return 0; +} + +static int spinand_create_dirmaps(struct spinand_device *spinand) +{ + struct nand_device *nand = spinand_to_nand(spinand); + int i, ret; + + spinand->dirmaps = devm_kzalloc(spinand->slave->dev, + sizeof(*spinand->dirmaps) * + nand->memorg.planes_per_lun, + GFP_KERNEL); + if (!spinand->dirmaps) + return -ENOMEM; + + for (i = 0; i < nand->memorg.planes_per_lun; i++) { + ret = spinand_create_dirmap(spinand, i); + if (ret) + return ret; + } + + return 0; +} + static const struct nand_ops spinand_ops = { .erase = spinand_erase, .markbad = spinand_markbad, @@ -826,13 +1224,18 @@ static const struct nand_ops spinand_ops = { }; static const struct spinand_manufacturer *spinand_manufacturers[] = { + &alliancememory_spinand_manufacturer, + &ato_spinand_manufacturer, + &esmt_c8_spinand_manufacturer, + &fmsh_spinand_manufacturer, + &foresee_spinand_manufacturer, &gigadevice_spinand_manufacturer, ¯onix_spinand_manufacturer, µn_spinand_manufacturer, ¶gon_spinand_manufacturer, + &skyhigh_spinand_manufacturer, &toshiba_spinand_manufacturer, &winbond_spinand_manufacturer, - &esmt_c8_spinand_manufacturer, &xtx_spinand_manufacturer, }; @@ -860,7 +1263,7 @@ static int spinand_manufacturer_match(struct spinand_device *spinand, spinand->manufacturer = manufacturer; return 0; } - return -ENOTSUPP; + return -EOPNOTSUPP; } static int spinand_id_detect(struct spinand_device *spinand) @@ -894,8 +1297,19 @@ static int spinand_id_detect(struct spinand_device *spinand) static int spinand_manufacturer_init(struct spinand_device *spinand) { - if (spinand->manufacturer->ops->init) - return spinand->manufacturer->ops->init(spinand); + int ret; + + if (spinand->manufacturer->ops->init) { + ret = spinand->manufacturer->ops->init(spinand); + if (ret) + return ret; + } + + if (spinand->configure_chip) { + ret = spinand->configure_chip(spinand); + if (ret) + return ret; + } return 0; } @@ -912,10 +1326,13 @@ spinand_select_op_variant(struct spinand_device *spinand, const struct spinand_op_variants *variants) { struct nand_device *nand = spinand_to_nand(spinand); + const struct spi_mem_op *best_variant = NULL; + u64 best_op_duration_ns = ULLONG_MAX; unsigned int i; for (i = 0; i < variants->nops; i++) { struct spi_mem_op op = variants->ops[i]; + u64 op_duration_ns = 0; unsigned int nbytes; int ret; @@ -932,13 +1349,17 @@ spinand_select_op_variant(struct spinand_device *spinand, break; nbytes -= op.data.nbytes; + + op_duration_ns += spi_mem_calc_op_duration(&op); } - if (!nbytes) - return &variants->ops[i]; + if (!nbytes && op_duration_ns < best_op_duration_ns) { + best_op_duration_ns = op_duration_ns; + best_variant = &variants->ops[i]; + } } - return NULL; + return best_variant; } static int spinand_setup_slave(struct spinand_device *spinand, @@ -994,11 +1415,17 @@ int spinand_match_and_init(struct spinand_device *spinand, return ret; nand->memorg = table[i].memorg; - nand->eccreq = table[i].eccreq; + nanddev_set_ecc_requirements(nand, &table[i].eccreq); spinand->eccinfo = table[i].eccinfo; spinand->flags = table[i].flags; spinand->id.len = 1 + table[i].devid.len; spinand->select_target = table[i].select_target; + spinand->configure_chip = table[i].configure_chip; + spinand->set_cont_read = table[i].set_cont_read; + spinand->fact_otp = &table[i].fact_otp; + spinand->user_otp = &table[i].user_otp; + spinand->read_retries = table[i].read_retries; + spinand->set_read_retry = table[i].set_read_retry; op = spinand_select_op_variant(spinand, info->op_variants.read_cache); @@ -1057,35 +1484,55 @@ static int spinand_detect(struct spinand_device *spinand) return 0; } -static int spinand_noecc_ooblayout_ecc(struct mtd_info *mtd, int section, - struct mtd_oob_region *region) +static int spinand_init_flash(struct spinand_device *spinand) { - return -ERANGE; -} + struct udevice *dev = spinand->slave->dev; + struct nand_device *nand = spinand_to_nand(spinand); + int ret, i; -static int spinand_noecc_ooblayout_free(struct mtd_info *mtd, int section, - struct mtd_oob_region *region) -{ - if (section) - return -ERANGE; + ret = spinand_read_cfg(spinand); + if (ret) + return ret; - /* Reserve 2 bytes for the BBM. */ - region->offset = 2; - region->length = 62; + ret = spinand_init_quad_enable(spinand); + if (ret) + return ret; - return 0; -} + ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0); + if (ret) + return ret; -static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = { - .ecc = spinand_noecc_ooblayout_ecc, - .rfree = spinand_noecc_ooblayout_free, -}; + ret = spinand_manufacturer_init(spinand); + if (ret) { + dev_err(dev, + "Failed to initialize the SPI NAND chip (err = %d)\n", + ret); + return ret; + } + + /* After power up, all blocks are locked, so unlock them here. */ + for (i = 0; i < nand->memorg.ntargets; i++) { + ret = spinand_select_target(spinand, i); + if (ret) + break; + + ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED); + if (ret) + break; + } + + if (ret) + spinand_manufacturer_cleanup(spinand); + + return ret; +} static int spinand_init(struct spinand_device *spinand) { + struct udevice *dev = spinand->slave->dev; struct mtd_info *mtd = spinand_to_mtd(spinand); struct nand_device *nand = mtd_to_nanddev(mtd); - int ret, i; + int ret; /* * We need a scratch buffer because the spi_mem interface requires that @@ -1104,9 +1551,8 @@ static int spinand_init(struct spinand_device *spinand) * may use this buffer for DMA access. * Memory allocated by devm_ does not guarantee DMA-safe alignment. */ - spinand->databuf = kzalloc(nanddev_page_size(nand) + - nanddev_per_page_oobsize(nand), - GFP_KERNEL); + spinand->databuf = kzalloc(nanddev_eraseblock_size(nand), + GFP_KERNEL); if (!spinand->databuf) { ret = -ENOMEM; goto err_free_bufs; @@ -1118,41 +1564,25 @@ static int spinand_init(struct spinand_device *spinand) if (ret) goto err_free_bufs; - ret = spinand_init_quad_enable(spinand); + ret = spinand_init_flash(spinand); if (ret) goto err_free_bufs; - ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0); - if (ret) - goto err_free_bufs; - - ret = spinand_manufacturer_init(spinand); - if (ret) { - dev_err(spinand->slave->dev, - "Failed to initialize the SPI NAND chip (err = %d)\n", - ret); - goto err_free_bufs; - } - - /* After power up, all blocks are locked, so unlock them here. */ - for (i = 0; i < nand->memorg.ntargets; i++) { - ret = spinand_select_target(spinand, i); - if (ret) - goto err_manuf_cleanup; - - ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED); - if (ret) - goto err_manuf_cleanup; - } - ret = nanddev_init(nand, &spinand_ops, THIS_MODULE); if (ret) goto err_manuf_cleanup; + spinand_ecc_enable(spinand, false); + ret = spinand_ondie_ecc_init_ctx(nand); + if (ret) + goto err_cleanup_nanddev; + /* - * Right now, we don't support ECC, so let the whole oob - * area is available for user. + * Continuous read can only be enabled with an on-die ECC engine, so the + * ECC initialization must have happened previously. */ + spinand_cont_read_init(spinand); + mtd->_read_oob = spinand_mtd_read; mtd->_write_oob = spinand_mtd_write; mtd->_block_isbad = spinand_mtd_block_isbad; @@ -1160,19 +1590,36 @@ static int spinand_init(struct spinand_device *spinand) mtd->_block_isreserved = spinand_mtd_block_isreserved; mtd->_erase = spinand_mtd_erase; - if (spinand->eccinfo.ooblayout) - mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout); - else - mtd_set_ooblayout(mtd, &spinand_noecc_ooblayout); + if (spinand_user_otp_size(spinand) || spinand_fact_otp_size(spinand)) { + ret = spinand_set_mtd_otp_ops(spinand); + if (ret) + goto err_cleanup_ecc_engine; + } ret = mtd_ooblayout_count_freebytes(mtd); if (ret < 0) - goto err_cleanup_nanddev; + goto err_cleanup_ecc_engine; mtd->oobavail = ret; + /* Propagate ECC information to mtd_info */ + mtd->ecc_strength = nanddev_get_ecc_conf(nand)->strength; + mtd->ecc_step_size = nanddev_get_ecc_conf(nand)->step_size; + mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4); + + ret = spinand_create_dirmaps(spinand); + if (ret) { + dev_err(dev, + "Failed to create direct mappings for read/write operations (err = %d)\n", + ret); + goto err_cleanup_ecc_engine; + } + return 0; +err_cleanup_ecc_engine: + spinand_ondie_ecc_cleanup_ctx(nand); + err_cleanup_nanddev: nanddev_cleanup(nand); @@ -1189,6 +1636,7 @@ static void spinand_cleanup(struct spinand_device *spinand) { struct nand_device *nand = spinand_to_nand(spinand); + spinand_ondie_ecc_cleanup_ctx(nand); nanddev_cleanup(nand); spinand_manufacturer_cleanup(spinand); kfree(spinand->databuf); @@ -1294,12 +1742,14 @@ static const struct spi_device_id spinand_ids[] = { { .name = "spi-nand" }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(spi, spinand_ids); #ifdef CONFIG_OF static const struct of_device_id spinand_of_ids[] = { { .compatible = "spi-nand" }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, spinand_of_ids); #endif static struct spi_mem_driver spinand_drv = { diff --git a/drivers/mtd/nand/spi/esmt.c b/drivers/mtd/nand/spi/esmt.c index 7e07b26827a..6a46f3a3bfc 100644 --- a/drivers/mtd/nand/spi/esmt.c +++ b/drivers/mtd/nand/spi/esmt.c @@ -8,25 +8,33 @@ #ifndef __UBOOT__ #include <linux/device.h> #include <linux/kernel.h> +#else +#include <dm/device_compat.h> +#include <spi-mem.h> +#include <spi.h> #endif #include <linux/mtd/spinand.h> /* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */ #define SPINAND_MFR_ESMT_C8 0xc8 +#define ESMT_F50L1G41LB_CFG_OTP_PROTECT BIT(7) +#define ESMT_F50L1G41LB_CFG_OTP_LOCK \ + (CFG_OTP_ENABLE | ESMT_F50L1G41LB_CFG_OTP_PROTECT) + static SPINAND_OP_VARIANTS(read_cache_variants, - SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); static SPINAND_OP_VARIANTS(write_cache_variants, - SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), - SPINAND_PROG_LOAD(true, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); static SPINAND_OP_VARIANTS(update_cache_variants, - SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), - SPINAND_PROG_LOAD(false, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); /* * OOB spare area map (64 bytes) @@ -104,24 +112,117 @@ static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = { .rfree = f50l1g41lb_ooblayout_free, }; +static int f50l1g41lb_otp_info(struct spinand_device *spinand, size_t len, + struct otp_info *buf, size_t *retlen, bool user) +{ + if (len < sizeof(*buf)) + return -EINVAL; + + buf->locked = 0; + buf->start = 0; + buf->length = user ? spinand_user_otp_size(spinand) : + spinand_fact_otp_size(spinand); + + *retlen = sizeof(*buf); + return 0; +} + +static int f50l1g41lb_fact_otp_info(struct spinand_device *spinand, size_t len, + struct otp_info *buf, size_t *retlen) +{ + return f50l1g41lb_otp_info(spinand, len, buf, retlen, false); +} + +static int f50l1g41lb_user_otp_info(struct spinand_device *spinand, size_t len, + struct otp_info *buf, size_t *retlen) +{ + return f50l1g41lb_otp_info(spinand, len, buf, retlen, true); +} + +static int f50l1g41lb_otp_lock(struct spinand_device *spinand, loff_t from, + size_t len) +{ + struct spi_mem_op write_op = SPINAND_WR_EN_DIS_1S_0_0_OP(true); + struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0); + u8 status; + int ret; + + ret = spinand_upd_cfg(spinand, ESMT_F50L1G41LB_CFG_OTP_LOCK, + ESMT_F50L1G41LB_CFG_OTP_LOCK); + if (!ret) + return ret; + + ret = spi_mem_exec_op(spinand->slave, &write_op); + if (!ret) + goto out; + + ret = spi_mem_exec_op(spinand->slave, &exec_op); + if (!ret) + goto out; + + ret = spinand_wait(spinand, + SPINAND_WRITE_INITIAL_DELAY_US, + SPINAND_WRITE_POLL_DELAY_US, + &status); + if (!ret && (status & STATUS_PROG_FAILED)) + ret = -EIO; + +out: + if (spinand_upd_cfg(spinand, ESMT_F50L1G41LB_CFG_OTP_LOCK, 0)) { + dev_warn(spinand->slave->dev, + "Can not disable OTP mode\n"); + ret = -EIO; + } + + return ret; +} + +static const struct spinand_user_otp_ops f50l1g41lb_user_otp_ops = { + .info = f50l1g41lb_user_otp_info, + .lock = f50l1g41lb_otp_lock, + .read = spinand_user_otp_read, + .write = spinand_user_otp_write, +}; + +static const struct spinand_fact_otp_ops f50l1g41lb_fact_otp_ops = { + .info = f50l1g41lb_fact_otp_info, + .read = spinand_fact_otp_read, +}; + static const struct spinand_info esmt_c8_spinand_table[] = { SPINAND_INFO("F50L1G41LB", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01, 0x7f, + 0x7f, 0x7f), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), 0, - SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)), + SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL), + SPINAND_USER_OTP_INFO(28, 2, &f50l1g41lb_user_otp_ops), + SPINAND_FACT_OTP_INFO(2, 0, &f50l1g41lb_fact_otp_ops)), SPINAND_INFO("F50D1G41LB", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11, 0x7f, + 0x7f), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), 0, + SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL), + SPINAND_USER_OTP_INFO(28, 2, &f50l1g41lb_user_otp_ops), + SPINAND_FACT_OTP_INFO(2, 0, &f50l1g41lb_fact_otp_ops)), + SPINAND_INFO("F50D2G41KA", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51, 0x7f, + 0x7f, 0x7f), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)), }; diff --git a/drivers/mtd/nand/spi/fmsh.c b/drivers/mtd/nand/spi/fmsh.c new file mode 100644 index 00000000000..80837b7dd42 --- /dev/null +++ b/drivers/mtd/nand/spi/fmsh.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + * + * Author: Dingqiang Lin <jon.lin@rock-chips.com> + */ + +#ifndef __UBOOT__ +#include <linux/device.h> +#include <linux/kernel.h> +#endif +#include <linux/mtd/spinand.h> + +#define SPINAND_MFR_FMSH 0xA1 + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); + +static int fm25s01a_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + return -ERANGE; +} + +static int fm25s01a_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section) + return -ERANGE; + + region->offset = 2; + region->length = 62; + + return 0; +} + +static const struct mtd_ooblayout_ops fm25s01a_ooblayout = { + .ecc = fm25s01a_ooblayout_ecc, + .rfree = fm25s01a_ooblayout_free, +}; + +static const struct spinand_info fmsh_spinand_table[] = { + SPINAND_INFO("FM25S01A", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)), +}; + +static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = { +}; + +const struct spinand_manufacturer fmsh_spinand_manufacturer = { + .id = SPINAND_MFR_FMSH, + .name = "Fudan Micro", + .chips = fmsh_spinand_table, + .nchips = ARRAY_SIZE(fmsh_spinand_table), + .ops = &fmsh_spinand_manuf_ops, +}; diff --git a/drivers/mtd/nand/spi/foresee.c b/drivers/mtd/nand/spi/foresee.c new file mode 100644 index 00000000000..370f8494fb5 --- /dev/null +++ b/drivers/mtd/nand/spi/foresee.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2023, SberDevices. All Rights Reserved. + * + * Author: Martin Kurbanov <mmkurbanov@salutedevices.com> + */ + +#ifndef __UBOOT__ +#include <linux/device.h> +#include <linux/kernel.h> +#endif +#include <linux/mtd/spinand.h> + +#define SPINAND_MFR_FORESEE 0xCD + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); + +static int f35sqa002g_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + return -ERANGE; +} + +static int f35sqa002g_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section) + return -ERANGE; + + /* Reserve 2 bytes for the BBM. */ + region->offset = 2; + region->length = 62; + + return 0; +} + +static const struct mtd_ooblayout_ops f35sqa002g_ooblayout = { + .ecc = f35sqa002g_ooblayout_ecc, + .rfree = f35sqa002g_ooblayout_free, +}; + +static int f35sqa002g_ecc_get_status(struct spinand_device *spinand, u8 status) +{ + struct nand_device *nand = spinand_to_nand(spinand); + + switch (status & STATUS_ECC_MASK) { + case STATUS_ECC_NO_BITFLIPS: + return 0; + + case STATUS_ECC_HAS_BITFLIPS: + return nanddev_get_ecc_conf(nand)->strength; + + default: + break; + } + + /* More than 1-bit error was detected in one or more sectors and + * cannot be corrected. + */ + return -EBADMSG; +} + +static const struct spinand_info foresee_spinand_table[] = { + SPINAND_INFO("F35SQA002G", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x72, 0x72), + NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&f35sqa002g_ooblayout, + f35sqa002g_ecc_get_status)), + SPINAND_INFO("F35SQA001G", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x71, 0x71), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&f35sqa002g_ooblayout, + f35sqa002g_ecc_get_status)), +}; + +static const struct spinand_manufacturer_ops foresee_spinand_manuf_ops = { +}; + +const struct spinand_manufacturer foresee_spinand_manufacturer = { + .id = SPINAND_MFR_FORESEE, + .name = "FORESEE", + .chips = foresee_spinand_table, + .nchips = ARRAY_SIZE(foresee_spinand_table), + .ops = &foresee_spinand_manuf_ops, +}; diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c index fe8c76acac6..32fbe11e908 100644 --- a/drivers/mtd/nand/spi/gigadevice.c +++ b/drivers/mtd/nand/spi/gigadevice.c @@ -28,44 +28,44 @@ #define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR (7 << 4) static SPINAND_OP_VARIANTS(read_cache_variants, - SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); static SPINAND_OP_VARIANTS(read_cache_variants_f, - SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0)); + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_3A_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_3A_1S_1S_1S_OP(0, 0, NULL, 0, 0)); static SPINAND_OP_VARIANTS(read_cache_variants_1gq5, - SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); static SPINAND_OP_VARIANTS(read_cache_variants_2gq5, - SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); static SPINAND_OP_VARIANTS(write_cache_variants, - SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), - SPINAND_PROG_LOAD(true, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); static SPINAND_OP_VARIANTS(update_cache_variants, - SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), - SPINAND_PROG_LOAD(false, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); static int gd5fxgq4xa_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *region) @@ -189,8 +189,8 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand, u8 status) { u8 status2; - struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2, - &status2); + struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(GD5FXGQXXEXXG_REG_STATUS2, + spinand->scratchbuf); int ret; switch (status & STATUS_ECC_MASK) { @@ -211,6 +211,7 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand, * report the maximum of 4 in this case */ /* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */ + status2 = *(spinand->scratchbuf); return ((status & STATUS_ECC_MASK) >> 2) | ((status2 & STATUS_ECC_MASK) >> 4); @@ -231,8 +232,8 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand, u8 status) { u8 status2; - struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2, - &status2); + struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(GD5FXGQXXEXXG_REG_STATUS2, + spinand->scratchbuf); int ret; switch (status & STATUS_ECC_MASK) { @@ -252,6 +253,7 @@ static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand, * 1 ... 4 bits are flipped (and corrected) */ /* bits sorted this way (1...0): ECCSE1, ECCSE0 */ + status2 = *(spinand->scratchbuf); return ((status2 & STATUS_ECC_MASK) >> 4) + 1; case STATUS_ECC_UNCOR_ERROR: @@ -535,6 +537,26 @@ static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F1GM9UExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x91, 0x01), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), + SPINAND_INFO("GD5F1GM9RExxG", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x81, 0x01), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout, + gd5fxgq4uexxg_ecc_get_status)), }; static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = { diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c index 86bffc2800b..f21103bb15a 100644 --- a/drivers/mtd/nand/spi/macronix.c +++ b/drivers/mtd/nand/spi/macronix.c @@ -5,6 +5,7 @@ * Author: Boris Brezillon <boris.brezillon@bootlin.com> */ +#include <linux/bitfield.h> #ifndef __UBOOT__ #include <linux/device.h> #include <linux/kernel.h> @@ -13,21 +14,35 @@ #include <linux/mtd/spinand.h> #define SPINAND_MFR_MACRONIX 0xC2 -#define MACRONIX_ECCSR_MASK 0x0F +#define MACRONIX_ECCSR_BF_LAST_PAGE(eccsr) FIELD_GET(GENMASK(3, 0), eccsr) +#define MACRONIX_ECCSR_BF_ACCUMULATED_PAGES(eccsr) FIELD_GET(GENMASK(7, 4), eccsr) +#define MACRONIX_CFG_CONT_READ BIT(2) +#define MACRONIX_FEATURE_ADDR_READ_RETRY 0x70 +#define MACRONIX_NUM_READ_RETRY_MODES 5 + +#define STATUS_ECC_HAS_BITFLIPS_THRESHOLD (3 << 4) + +/* Bitflip theshold configuration register */ +#define REG_CFG_BFT 0x10 +#define CFG_BFT(x) FIELD_PREP(GENMASK(7, 4), (x)) + +struct macronix_priv { + bool cont_read; +}; static SPINAND_OP_VARIANTS(read_cache_variants, - SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); static SPINAND_OP_VARIANTS(write_cache_variants, - SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), - SPINAND_PROG_LOAD(true, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); static SPINAND_OP_VARIANTS(update_cache_variants, - SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), - SPINAND_PROG_LOAD(false, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); static int mx35lfxge4ab_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *region) @@ -52,8 +67,9 @@ static const struct mtd_ooblayout_ops mx35lfxge4ab_ooblayout = { .rfree = mx35lfxge4ab_ooblayout_free, }; -static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr) +static int macronix_get_eccsr(struct spinand_device *spinand, u8 *eccsr) { + struct macronix_priv *priv = spinand->priv; struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x7c, 1), SPI_MEM_OP_NO_ADDR, SPI_MEM_OP_DUMMY(1, 1), @@ -63,12 +79,21 @@ static int mx35lf1ge4ab_get_eccsr(struct spinand_device *spinand, u8 *eccsr) if (ret) return ret; - *eccsr &= MACRONIX_ECCSR_MASK; + /* + * ECCSR exposes the number of bitflips for the last read page in bits [3:0]. + * Continuous read compatible chips also expose the maximum number of + * bitflips for the whole (continuous) read operation in bits [7:4]. + */ + if (!priv->cont_read) + *eccsr = MACRONIX_ECCSR_BF_LAST_PAGE(*eccsr); + else + *eccsr = MACRONIX_ECCSR_BF_ACCUMULATED_PAGES(*eccsr); + return 0; } -static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand, - u8 status) +static int macronix_ecc_get_status(struct spinand_device *spinand, + u8 status) { struct nand_device *nand = spinand_to_nand(spinand); u8 eccsr; @@ -86,14 +111,14 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand, * in order to avoid forcing the wear-leveling layer to move * data around if it's not necessary. */ - if (mx35lf1ge4ab_get_eccsr(spinand, &eccsr)) - return nand->eccreq.strength; + if (macronix_get_eccsr(spinand, spinand->scratchbuf)) + return nanddev_get_ecc_conf(nand)->strength; - if (WARN_ON(eccsr > nand->eccreq.strength || !eccsr)) - return nand->eccreq.strength; + eccsr = *spinand->scratchbuf; + if (WARN_ON(eccsr > nanddev_get_ecc_conf(nand)->strength || !eccsr)) + return nanddev_get_ecc_conf(nand)->strength; return eccsr; - default: break; } @@ -101,6 +126,38 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand, return -EINVAL; } +static int macronix_set_cont_read(struct spinand_device *spinand, bool enable) +{ + struct macronix_priv *priv = spinand->priv; + int ret; + + ret = spinand_upd_cfg(spinand, MACRONIX_CFG_CONT_READ, + enable ? MACRONIX_CFG_CONT_READ : 0); + if (ret) + return ret; + + priv->cont_read = enable; + + return 0; +} + +/** + * macronix_set_read_retry - Set the retry mode + * @spinand: SPI NAND device + * @retry_mode: Specify which retry mode to set + * + * Return: 0 on success, a negative error code otherwise. + */ +static int macronix_set_read_retry(struct spinand_device *spinand, + unsigned int retry_mode) +{ + struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(MACRONIX_FEATURE_ADDR_READ_RETRY, + spinand->scratchbuf); + + *spinand->scratchbuf = retry_mode; + return spi_mem_exec_op(spinand->slave, &op); +} + static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO("MX35LF1GE4AB", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12), @@ -111,7 +168,7 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status)), SPINAND_INFO("MX35LF2GE4AB", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22), NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1), @@ -119,10 +176,12 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - SPINAND_HAS_QE_BIT, + SPINAND_HAS_QE_BIT | + SPINAND_HAS_PROG_PLANE_SELECT_BIT | + SPINAND_HAS_READ_PLANE_SELECT_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), SPINAND_INFO("MX35LF2GE4AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x26), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x26, 0x03), NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -130,9 +189,12 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status), + SPINAND_CONT_READ(macronix_set_cont_read), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), SPINAND_INFO("MX35LF4GE4AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37, 0x03), NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -140,34 +202,67 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status), + SPINAND_CONT_READ(macronix_set_cont_read), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), SPINAND_INFO("MX35LF1G24AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14, 0x03), NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), SPINAND_HAS_QE_BIT, - SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), SPINAND_INFO("MX35LF2G24AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24, 0x03), NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), + SPINAND_HAS_QE_BIT | + SPINAND_HAS_PROG_PLANE_SELECT_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), + SPINAND_INFO("MX35LF2G24AD-Z4I8", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x64, 0x03), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), SPINAND_HAS_QE_BIT, - SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), SPINAND_INFO("MX35LF4G24AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35, 0x03), NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), + SPINAND_HAS_QE_BIT | + SPINAND_HAS_PROG_PLANE_SELECT_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), + SPINAND_INFO("MX35LF4G24AD-Z4I8", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x75, 0x03), + NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), SPINAND_HAS_QE_BIT, - SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)), + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), SPINAND_INFO("MX31LF1GE4BC", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x1e), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), @@ -177,7 +272,7 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status)), SPINAND_INFO("MX31UF1GE4BC", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x9e), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), @@ -187,7 +282,7 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status)), SPINAND_INFO("MX35LF2G14AC", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x20), @@ -196,21 +291,38 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - SPINAND_HAS_QE_BIT, + SPINAND_HAS_QE_BIT | + SPINAND_HAS_PROG_PLANE_SELECT_BIT | + SPINAND_HAS_READ_PLANE_SELECT_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status)), SPINAND_INFO("MX35UF4G24AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5, 0x03), NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), + SPINAND_HAS_QE_BIT | + SPINAND_HAS_PROG_PLANE_SELECT_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, + macronix_ecc_get_status), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), + SPINAND_INFO("MX35UF4G24AD-Z4I8", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xf5, 0x03), + NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), SPINAND_INFO("MX35UF4GE4AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7, 0x03), NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -218,7 +330,10 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status), + SPINAND_CONT_READ(macronix_set_cont_read), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), SPINAND_INFO("MX35UF2G14AC", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa0), NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1), @@ -226,21 +341,38 @@ static const struct spinand_info macronix_spinand_table[] = { SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), - SPINAND_HAS_QE_BIT, + SPINAND_HAS_QE_BIT | + SPINAND_HAS_PROG_PLANE_SELECT_BIT | + SPINAND_HAS_READ_PLANE_SELECT_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status)), SPINAND_INFO("MX35UF2G24AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4, 0x03), NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), + SPINAND_HAS_QE_BIT | + SPINAND_HAS_PROG_PLANE_SELECT_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, + macronix_ecc_get_status), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), + SPINAND_INFO("MX35UF2G24AD-Z4I8", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe4, 0x03), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), SPINAND_INFO("MX35UF2GE4AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6, 0x03), NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -248,9 +380,12 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status), + SPINAND_CONT_READ(macronix_set_cont_read), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), SPINAND_INFO("MX35UF2GE4AC", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2, 0x01), NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(4, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -258,7 +393,8 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status), + SPINAND_CONT_READ(macronix_set_cont_read)), SPINAND_INFO("MX35UF1G14AC", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x90), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), @@ -268,9 +404,9 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status)), SPINAND_INFO("MX35UF1G24AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94, 0x03), NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -278,9 +414,11 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), SPINAND_INFO("MX35UF1GE4AD", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96, 0x03), NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -288,9 +426,12 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), + macronix_ecc_get_status), + SPINAND_CONT_READ(macronix_set_cont_read), + SPINAND_READ_RETRY(MACRONIX_NUM_READ_RETRY_MODES, + macronix_set_read_retry)), SPINAND_INFO("MX35UF1GE4AC", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92), + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92, 0x01), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(4, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, @@ -298,11 +439,51 @@ static const struct spinand_info macronix_spinand_table[] = { &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, - mx35lf1ge4ab_ecc_get_status)), - + macronix_ecc_get_status), + SPINAND_CONT_READ(macronix_set_cont_read)), + SPINAND_INFO("MX31LF2GE4BC", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x2e), + NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, + macronix_ecc_get_status)), + SPINAND_INFO("MX3UF2GE4BC", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae), + NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, + macronix_ecc_get_status)), }; +static int macronix_spinand_init(struct spinand_device *spinand) +{ + struct macronix_priv *priv; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spinand->priv = priv; + + return 0; +} + +static void macronix_spinand_cleanup(struct spinand_device *spinand) +{ + kfree(spinand->priv); +} + static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = { + .init = macronix_spinand_init, + .cleanup = macronix_spinand_cleanup, }; const struct spinand_manufacturer macronix_spinand_manufacturer = { diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c index b538213ed8e..9af3e99664f 100644 --- a/drivers/mtd/nand/spi/micron.c +++ b/drivers/mtd/nand/spi/micron.c @@ -9,12 +9,18 @@ #ifndef __UBOOT__ #include <linux/device.h> #include <linux/kernel.h> +#include <linux/spi/spi-mem.h> +#else +#include <dm/device_compat.h> +#include <spi-mem.h> +#include <spi.h> #endif #include <linux/mtd/spinand.h> +#include <linux/string.h> #define SPINAND_MFR_MICRON 0x2c -#define MICRON_STATUS_ECC_MASK GENMASK(7, 4) +#define MICRON_STATUS_ECC_MASK GENMASK(6, 4) #define MICRON_STATUS_ECC_NO_BITFLIPS (0 << 4) #define MICRON_STATUS_ECC_1TO3_BITFLIPS (1 << 4) #define MICRON_STATUS_ECC_4TO6_BITFLIPS (3 << 4) @@ -30,34 +36,38 @@ #define MICRON_SELECT_DIE(x) ((x) << 6) +#define MICRON_MT29F2G01ABAGD_CFG_OTP_STATE BIT(7) +#define MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK \ + (CFG_OTP_ENABLE | MICRON_MT29F2G01ABAGD_CFG_OTP_STATE) + static SPINAND_OP_VARIANTS(quadio_read_cache_variants, - SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); static SPINAND_OP_VARIANTS(x4_write_cache_variants, - SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), - SPINAND_PROG_LOAD(true, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); static SPINAND_OP_VARIANTS(x4_update_cache_variants, - SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), - SPINAND_PROG_LOAD(false, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); /* Micron MT29F2G01AAAED Device */ static SPINAND_OP_VARIANTS(x4_read_cache_variants, - SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); static SPINAND_OP_VARIANTS(x1_write_cache_variants, - SPINAND_PROG_LOAD(true, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); static SPINAND_OP_VARIANTS(x1_update_cache_variants, - SPINAND_PROG_LOAD(false, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); static int micron_8_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *region) @@ -133,7 +143,7 @@ static const struct mtd_ooblayout_ops micron_4_ooblayout = { static int micron_select_target(struct spinand_device *spinand, unsigned int target) { - struct spi_mem_op op = SPINAND_SET_FEATURE_OP(MICRON_DIE_SELECT_REG, + struct spi_mem_op op = SPINAND_SET_FEATURE_1S_1S_1S_OP(MICRON_DIE_SELECT_REG, spinand->scratchbuf); if (target > 1) @@ -170,6 +180,136 @@ static int micron_8_ecc_get_status(struct spinand_device *spinand, return -EINVAL; } +static inline bool mem_is_zero(const void *s, size_t n) +{ + return !memchr_inv(s, 0, n); +} + +static int mt29f2g01abagd_otp_is_locked(struct spinand_device *spinand) +{ + size_t bufsize = spinand_otp_page_size(spinand); + size_t retlen; + u8 *buf; + int ret; + + buf = kmalloc(bufsize, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = spinand_upd_cfg(spinand, + MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK, + MICRON_MT29F2G01ABAGD_CFG_OTP_STATE); + if (ret) + goto free_buf; + + ret = spinand_user_otp_read(spinand, 0, bufsize, &retlen, buf); + + if (spinand_upd_cfg(spinand, MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK, + 0)) { + dev_warn(spinand->slave->dev, + "Can not disable OTP mode\n"); + ret = -EIO; + } + + if (ret) + goto free_buf; + + /* If all zeros, then the OTP area is locked. */ + if (mem_is_zero(buf, bufsize)) + ret = 1; + +free_buf: + kfree(buf); + return ret; +} + +static int mt29f2g01abagd_otp_info(struct spinand_device *spinand, size_t len, + struct otp_info *buf, size_t *retlen, + bool user) +{ + int locked; + + if (len < sizeof(*buf)) + return -EINVAL; + + locked = mt29f2g01abagd_otp_is_locked(spinand); + if (locked < 0) + return locked; + + buf->locked = locked; + buf->start = 0; + buf->length = user ? spinand_user_otp_size(spinand) : + spinand_fact_otp_size(spinand); + + *retlen = sizeof(*buf); + return 0; +} + +static int mt29f2g01abagd_fact_otp_info(struct spinand_device *spinand, + size_t len, struct otp_info *buf, + size_t *retlen) +{ + return mt29f2g01abagd_otp_info(spinand, len, buf, retlen, false); +} + +static int mt29f2g01abagd_user_otp_info(struct spinand_device *spinand, + size_t len, struct otp_info *buf, + size_t *retlen) +{ + return mt29f2g01abagd_otp_info(spinand, len, buf, retlen, true); +} + +static int mt29f2g01abagd_otp_lock(struct spinand_device *spinand, loff_t from, + size_t len) +{ + struct spi_mem_op write_op = SPINAND_WR_EN_DIS_1S_0_0_OP(true); + struct spi_mem_op exec_op = SPINAND_PROG_EXEC_1S_1S_0_OP(0); + u8 status; + int ret; + + ret = spinand_upd_cfg(spinand, + MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK, + MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK); + if (!ret) + return ret; + + ret = spi_mem_exec_op(spinand->slave, &write_op); + if (!ret) + goto out; + + ret = spi_mem_exec_op(spinand->slave, &exec_op); + if (!ret) + goto out; + + ret = spinand_wait(spinand, + SPINAND_WRITE_INITIAL_DELAY_US, + SPINAND_WRITE_POLL_DELAY_US, + &status); + if (!ret && (status & STATUS_PROG_FAILED)) + ret = -EIO; + +out: + if (spinand_upd_cfg(spinand, MICRON_MT29F2G01ABAGD_CFG_OTP_LOCK, 0)) { + dev_warn(spinand->slave->dev, + "Can not disable OTP mode\n"); + ret = -EIO; + } + + return ret; +} + +static const struct spinand_user_otp_ops mt29f2g01abagd_user_otp_ops = { + .info = mt29f2g01abagd_user_otp_info, + .lock = mt29f2g01abagd_otp_lock, + .read = spinand_user_otp_read, + .write = spinand_user_otp_write, +}; + +static const struct spinand_fact_otp_ops mt29f2g01abagd_fact_otp_ops = { + .info = mt29f2g01abagd_fact_otp_info, + .read = spinand_fact_otp_read, +}; + static const struct spinand_info micron_spinand_table[] = { /* M79A 2Gb 3.3V */ SPINAND_INFO("MT29F2G01ABAGD", @@ -181,7 +321,9 @@ static const struct spinand_info micron_spinand_table[] = { &x4_update_cache_variants), 0, SPINAND_ECCINFO(µn_8_ooblayout, - micron_8_ecc_get_status)), + micron_8_ecc_get_status), + SPINAND_USER_OTP_INFO(12, 2, &mt29f2g01abagd_user_otp_ops), + SPINAND_FACT_OTP_INFO(2, 0, &mt29f2g01abagd_fact_otp_ops)), /* M79A 2Gb 1.8V */ SPINAND_INFO("MT29F2G01ABBGD", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25), diff --git a/drivers/mtd/nand/spi/otp.c b/drivers/mtd/nand/spi/otp.c new file mode 100644 index 00000000000..e6ef78d9464 --- /dev/null +++ b/drivers/mtd/nand/spi/otp.c @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025, SaluteDevices. All Rights Reserved. + * + * Author: Martin Kurbanov <mmkurbanov@salutedevices.com> + */ + +#include <linux/mtd/mtd.h> +#include <linux/mtd/spinand.h> +#ifdef __UBOOT__ +#include <spi.h> +#include <dm/device_compat.h> +#endif + +/** + * spinand_otp_page_size() - Get SPI-NAND OTP page size + * @spinand: the spinand device + * + * Return: the OTP page size. + */ +size_t spinand_otp_page_size(struct spinand_device *spinand) +{ + struct nand_device *nand = spinand_to_nand(spinand); + + return nanddev_page_size(nand) + nanddev_per_page_oobsize(nand); +} + +static size_t spinand_otp_size(struct spinand_device *spinand, + const struct spinand_otp_layout *layout) +{ + return layout->npages * spinand_otp_page_size(spinand); +} + +/** + * spinand_fact_otp_size() - Get SPI-NAND factory OTP area size + * @spinand: the spinand device + * + * Return: the OTP size. + */ +size_t spinand_fact_otp_size(struct spinand_device *spinand) +{ + return spinand_otp_size(spinand, &spinand->fact_otp->layout); +} + +/** + * spinand_user_otp_size() - Get SPI-NAND user OTP area size + * @spinand: the spinand device + * + * Return: the OTP size. + */ +size_t spinand_user_otp_size(struct spinand_device *spinand) +{ + return spinand_otp_size(spinand, &spinand->user_otp->layout); +} + +static int spinand_otp_check_bounds(struct spinand_device *spinand, loff_t ofs, + size_t len, + const struct spinand_otp_layout *layout) +{ + if (ofs < 0 || ofs + len > spinand_otp_size(spinand, layout)) + return -EINVAL; + + return 0; +} + +static int spinand_user_otp_check_bounds(struct spinand_device *spinand, + loff_t ofs, size_t len) +{ + return spinand_otp_check_bounds(spinand, ofs, len, + &spinand->user_otp->layout); +} + +static int spinand_otp_rw(struct spinand_device *spinand, loff_t ofs, + size_t len, size_t *retlen, u8 *buf, bool is_write, + const struct spinand_otp_layout *layout) +{ + struct nand_page_io_req req = {}; + unsigned long long page; + size_t copied = 0; + size_t otp_pagesize = spinand_otp_page_size(spinand); + int ret; + + if (!len) + return 0; + + ret = spinand_otp_check_bounds(spinand, ofs, len, layout); + if (ret) + return ret; + + ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, CFG_OTP_ENABLE); + if (ret) + return ret; + + page = ofs; + req.dataoffs = do_div(page, otp_pagesize); + req.pos.page = page + layout->start_page; + req.type = is_write ? NAND_PAGE_WRITE : NAND_PAGE_READ; + req.mode = MTD_OPS_RAW; + req.databuf.in = buf; + + while (copied < len) { + req.datalen = min_t(unsigned int, + otp_pagesize - req.dataoffs, + len - copied); + + if (is_write) + ret = spinand_write_page(spinand, &req); + else + ret = spinand_read_page(spinand, &req); + + if (ret < 0) + break; + + req.databuf.in += req.datalen; + req.pos.page++; + req.dataoffs = 0; + copied += req.datalen; + } + + *retlen = copied; + + if (spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0)) { + dev_warn(spinand->slave->dev, + "Can not disable OTP mode\n"); + ret = -EIO; + } + + return ret; +} + +/** + * spinand_fact_otp_read() - Read from OTP area + * @spinand: the spinand device + * @ofs: the offset to read + * @len: the number of data bytes to read + * @retlen: the pointer to variable to store the number of read bytes + * @buf: the buffer to store the read data + * + * Return: 0 on success, an error code otherwise. + */ +int spinand_fact_otp_read(struct spinand_device *spinand, loff_t ofs, + size_t len, size_t *retlen, u8 *buf) +{ + return spinand_otp_rw(spinand, ofs, len, retlen, buf, false, + &spinand->fact_otp->layout); +} + +/** + * spinand_user_otp_read() - Read from OTP area + * @spinand: the spinand device + * @ofs: the offset to read + * @len: the number of data bytes to read + * @retlen: the pointer to variable to store the number of read bytes + * @buf: the buffer to store the read data + * + * Return: 0 on success, an error code otherwise. + */ +int spinand_user_otp_read(struct spinand_device *spinand, loff_t ofs, + size_t len, size_t *retlen, u8 *buf) +{ + return spinand_otp_rw(spinand, ofs, len, retlen, buf, false, + &spinand->user_otp->layout); +} + +/** + * spinand_user_otp_write() - Write to OTP area + * @spinand: the spinand device + * @ofs: the offset to write to + * @len: the number of bytes to write + * @retlen: the pointer to variable to store the number of written bytes + * @buf: the buffer with data to write + * + * Return: 0 on success, an error code otherwise. + */ +int spinand_user_otp_write(struct spinand_device *spinand, loff_t ofs, + size_t len, size_t *retlen, const u8 *buf) +{ + return spinand_otp_rw(spinand, ofs, len, retlen, (u8 *)buf, true, + &spinand->user_otp->layout); +} + +static int spinand_mtd_otp_info(struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf, + bool is_fact) +{ + struct spinand_device *spinand = mtd_to_spinand(mtd); + int ret; + + *retlen = 0; + + mutex_lock(&spinand->lock); + + if (is_fact) + ret = spinand->fact_otp->ops->info(spinand, len, buf, retlen); + else + ret = spinand->user_otp->ops->info(spinand, len, buf, retlen); + + mutex_unlock(&spinand->lock); + + return ret; +} + +static int spinand_mtd_fact_otp_info(struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf) +{ + return spinand_mtd_otp_info(mtd, len, retlen, buf, true); +} + +static int spinand_mtd_user_otp_info(struct mtd_info *mtd, size_t len, + size_t *retlen, struct otp_info *buf) +{ + return spinand_mtd_otp_info(mtd, len, retlen, buf, false); +} + +static int spinand_mtd_otp_read(struct mtd_info *mtd, loff_t ofs, size_t len, + size_t *retlen, u8 *buf, bool is_fact) +{ + struct spinand_device *spinand = mtd_to_spinand(mtd); + int ret; + + *retlen = 0; + + if (!len) + return 0; + + ret = spinand_otp_check_bounds(spinand, ofs, len, + is_fact ? &spinand->fact_otp->layout : + &spinand->user_otp->layout); + if (ret) + return ret; + + mutex_lock(&spinand->lock); + + if (is_fact) + ret = spinand->fact_otp->ops->read(spinand, ofs, len, retlen, + buf); + else + ret = spinand->user_otp->ops->read(spinand, ofs, len, retlen, + buf); + + mutex_unlock(&spinand->lock); + + return ret; +} + +static int spinand_mtd_fact_otp_read(struct mtd_info *mtd, loff_t ofs, + size_t len, size_t *retlen, u8 *buf) +{ + return spinand_mtd_otp_read(mtd, ofs, len, retlen, buf, true); +} + +static int spinand_mtd_user_otp_read(struct mtd_info *mtd, loff_t ofs, + size_t len, size_t *retlen, u8 *buf) +{ + return spinand_mtd_otp_read(mtd, ofs, len, retlen, buf, false); +} + +static int spinand_mtd_user_otp_write(struct mtd_info *mtd, loff_t ofs, + size_t len, size_t *retlen, u_char *buf) +{ + struct spinand_device *spinand = mtd_to_spinand(mtd); + const struct spinand_user_otp_ops *ops = spinand->user_otp->ops; + int ret; + + *retlen = 0; + + if (!len) + return 0; + + ret = spinand_user_otp_check_bounds(spinand, ofs, len); + if (ret) + return ret; + + mutex_lock(&spinand->lock); + ret = ops->write(spinand, ofs, len, retlen, buf); + mutex_unlock(&spinand->lock); + + return ret; +} + +#ifndef __UBOOT__ +static int spinand_mtd_user_otp_erase(struct mtd_info *mtd, loff_t ofs, + size_t len) +{ + struct spinand_device *spinand = mtd_to_spinand(mtd); + const struct spinand_user_otp_ops *ops = spinand->user_otp->ops; + int ret; + + if (!len) + return 0; + + ret = spinand_user_otp_check_bounds(spinand, ofs, len); + if (ret) + return ret; + + mutex_lock(&spinand->lock); + ret = ops->erase(spinand, ofs, len); + mutex_unlock(&spinand->lock); + + return ret; +} +#endif + +static int spinand_mtd_user_otp_lock(struct mtd_info *mtd, loff_t ofs, + size_t len) +{ + struct spinand_device *spinand = mtd_to_spinand(mtd); + const struct spinand_user_otp_ops *ops = spinand->user_otp->ops; + int ret; + + if (!len) + return 0; + + ret = spinand_user_otp_check_bounds(spinand, ofs, len); + if (ret) + return ret; + + mutex_lock(&spinand->lock); + ret = ops->lock(spinand, ofs, len); + mutex_unlock(&spinand->lock); + + return ret; +} + +/** + * spinand_set_mtd_otp_ops() - Setup OTP methods + * @spinand: the spinand device + * + * Setup OTP methods. + * + * Return: 0 on success, a negative error code otherwise. + */ +int spinand_set_mtd_otp_ops(struct spinand_device *spinand) +{ + struct mtd_info *mtd = spinand_to_mtd(spinand); + const struct spinand_fact_otp_ops *fact_ops = spinand->fact_otp->ops; + const struct spinand_user_otp_ops *user_ops = spinand->user_otp->ops; + + if (!user_ops && !fact_ops) + return -EINVAL; + + if (user_ops) { + if (user_ops->info) + mtd->_get_user_prot_info = spinand_mtd_user_otp_info; + + if (user_ops->read) + mtd->_read_user_prot_reg = spinand_mtd_user_otp_read; + + if (user_ops->write) + mtd->_write_user_prot_reg = spinand_mtd_user_otp_write; + + if (user_ops->lock) + mtd->_lock_user_prot_reg = spinand_mtd_user_otp_lock; +#ifndef __UBOOT__ + if (user_ops->erase) + mtd->_erase_user_prot_reg = spinand_mtd_user_otp_erase; +#endif + } + + if (fact_ops) { + if (fact_ops->info) + mtd->_get_fact_prot_info = spinand_mtd_fact_otp_info; + + if (fact_ops->read) + mtd->_read_fact_prot_reg = spinand_mtd_fact_otp_read; + } + + return 0; +} diff --git a/drivers/mtd/nand/spi/paragon.c b/drivers/mtd/nand/spi/paragon.c index 079431cea8f..a7106ae194b 100644 --- a/drivers/mtd/nand/spi/paragon.c +++ b/drivers/mtd/nand/spi/paragon.c @@ -11,8 +11,10 @@ #endif #include <linux/mtd/spinand.h> + #define SPINAND_MFR_PARAGON 0xa1 + #define PN26G0XA_STATUS_ECC_BITMASK (3 << 4) #define PN26G0XA_STATUS_ECC_NONE_DETECTED (0 << 4) @@ -20,21 +22,23 @@ #define PN26G0XA_STATUS_ECC_ERRORED (2 << 4) #define PN26G0XA_STATUS_ECC_8_CORRECTED (3 << 4) + static SPINAND_OP_VARIANTS(read_cache_variants, - SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); static SPINAND_OP_VARIANTS(write_cache_variants, - SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), - SPINAND_PROG_LOAD(true, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); static SPINAND_OP_VARIANTS(update_cache_variants, - SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), - SPINAND_PROG_LOAD(false, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); + static int pn26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *region) diff --git a/drivers/mtd/nand/spi/skyhigh.c b/drivers/mtd/nand/spi/skyhigh.c new file mode 100644 index 00000000000..5e9487bd27a --- /dev/null +++ b/drivers/mtd/nand/spi/skyhigh.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 SkyHigh Memory Limited + * + * Author: Takahiro Kuwano <takahiro.kuwano@infineon.com> + * Co-Author: KR Kim <kr.kim@skyhighmemory.com> + */ + +#ifndef __UBOOT__ +#include <linux/device.h> +#include <linux/kernel.h> +#endif +#include <linux/mtd/spinand.h> + +#define SPINAND_MFR_SKYHIGH 0x01 +#define SKYHIGH_STATUS_ECC_1TO2_BITFLIPS (1 << 4) +#define SKYHIGH_STATUS_ECC_3TO6_BITFLIPS (2 << 4) +#define SKYHIGH_STATUS_ECC_UNCOR_ERROR (3 << 4) +#define SKYHIGH_CONFIG_PROTECT_EN BIT(1) + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); + +static int skyhigh_spinand_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + /* ECC bytes are stored in hidden area. */ + return -ERANGE; +} + +static int skyhigh_spinand_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section) + return -ERANGE; + + /* ECC bytes are stored in hidden area. Reserve 2 bytes for the BBM. */ + region->offset = 2; + region->length = mtd->oobsize - 2; + + return 0; +} + +static const struct mtd_ooblayout_ops skyhigh_spinand_ooblayout = { + .ecc = skyhigh_spinand_ooblayout_ecc, + .rfree = skyhigh_spinand_ooblayout_free, +}; + +static int skyhigh_spinand_ecc_get_status(struct spinand_device *spinand, + u8 status) +{ + switch (status & STATUS_ECC_MASK) { + case STATUS_ECC_NO_BITFLIPS: + return 0; + + case SKYHIGH_STATUS_ECC_UNCOR_ERROR: + return -EBADMSG; + + case SKYHIGH_STATUS_ECC_1TO2_BITFLIPS: + return 2; + + case SKYHIGH_STATUS_ECC_3TO6_BITFLIPS: + return 6; + + default: + break; + } + + return -EINVAL; +} + +static const struct spinand_info skyhigh_spinand_table[] = { + SPINAND_INFO("S35ML01G301", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(6, 32), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_NO_RAW_ACCESS, + SPINAND_ECCINFO(&skyhigh_spinand_ooblayout, + skyhigh_spinand_ecc_get_status)), + SPINAND_INFO("S35ML01G300", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x14), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(6, 32), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_NO_RAW_ACCESS, + SPINAND_ECCINFO(&skyhigh_spinand_ooblayout, + skyhigh_spinand_ecc_get_status)), + SPINAND_INFO("S35ML02G300", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x25), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1), + NAND_ECCREQ(6, 32), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_NO_RAW_ACCESS, + SPINAND_ECCINFO(&skyhigh_spinand_ooblayout, + skyhigh_spinand_ecc_get_status)), + SPINAND_INFO("S35ML04G300", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35), + NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 2, 1, 1), + NAND_ECCREQ(6, 32), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + SPINAND_NO_RAW_ACCESS, + SPINAND_ECCINFO(&skyhigh_spinand_ooblayout, + skyhigh_spinand_ecc_get_status)), +}; + +static int skyhigh_spinand_init(struct spinand_device *spinand) +{ + /* + * Config_Protect_En (bit 1 in Block Lock register) must be set to 1 + * before writing other bits. Do it here before core unlocks all blocks + * by writing block protection bits. + */ + return spinand_write_reg_op(spinand, REG_BLOCK_LOCK, + SKYHIGH_CONFIG_PROTECT_EN); +} + +static const struct spinand_manufacturer_ops skyhigh_spinand_manuf_ops = { + .init = skyhigh_spinand_init, +}; + +const struct spinand_manufacturer skyhigh_spinand_manufacturer = { + .id = SPINAND_MFR_SKYHIGH, + .name = "SkyHigh", + .chips = skyhigh_spinand_table, + .nchips = ARRAY_SIZE(skyhigh_spinand_table), + .ops = &skyhigh_spinand_manuf_ops, +}; diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c index b9908e79271..2e7572d72b4 100644 --- a/drivers/mtd/nand/spi/toshiba.c +++ b/drivers/mtd/nand/spi/toshiba.c @@ -18,28 +18,28 @@ #define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4) static SPINAND_OP_VARIANTS(read_cache_variants, - SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); static SPINAND_OP_VARIANTS(write_cache_x4_variants, - SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), - SPINAND_PROG_LOAD(true, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); static SPINAND_OP_VARIANTS(update_cache_x4_variants, - SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), - SPINAND_PROG_LOAD(false, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); /* * Backward compatibility for 1st generation Serial NAND devices * which don't support Quad Program Load operation. */ static SPINAND_OP_VARIANTS(write_cache_variants, - SPINAND_PROG_LOAD(true, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); static SPINAND_OP_VARIANTS(update_cache_variants, - SPINAND_PROG_LOAD(false, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *region) @@ -76,7 +76,7 @@ static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand, { struct nand_device *nand = spinand_to_nand(spinand); u8 mbf = 0; - struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf); + struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(0x30, spinand->scratchbuf); switch (status & STATUS_ECC_MASK) { case STATUS_ECC_NO_BITFLIPS: @@ -93,12 +93,12 @@ static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand, * data around if it's not necessary. */ if (spi_mem_exec_op(spinand->slave, &op)) - return nand->eccreq.strength; + return nanddev_get_ecc_conf(nand)->strength; - mbf >>= 4; + mbf = *(spinand->scratchbuf) >> 4; - if (WARN_ON(mbf > nand->eccreq.strength || !mbf)) - return nand->eccreq.strength; + if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf)) + return nanddev_get_ecc_conf(nand)->strength; return mbf; @@ -269,6 +269,39 @@ static const struct spinand_info toshiba_spinand_table[] = { SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, tx58cxgxsxraix_ecc_get_status)), + /* 1.8V 1Gb (1st generation) */ + SPINAND_INFO("TC58NYG0S3HBAI4", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA1), + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, + tx58cxgxsxraix_ecc_get_status)), + /* 1.8V 4Gb (1st generation) */ + SPINAND_INFO("TH58NYG2S3HBAI4", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xAC), + NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 2, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_x4_variants, + &update_cache_x4_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, + tx58cxgxsxraix_ecc_get_status)), + /* 1.8V 8Gb (1st generation) */ + SPINAND_INFO("TH58NYG3S0HBAI6", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA3), + NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_x4_variants, + &update_cache_x4_variants), + SPINAND_HAS_QE_BIT, + SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, + tx58cxgxsxraix_ecc_get_status)), }; static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = { diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c index 16abf89dbbf..a89aaec516b 100644 --- a/drivers/mtd/nand/spi/winbond.c +++ b/drivers/mtd/nand/spi/winbond.c @@ -14,28 +14,83 @@ #include <linux/bitfield.h> #include <linux/bug.h> #include <linux/mtd/spinand.h> +#include <linux/delay.h> + +#define HZ_PER_MHZ 1000000UL #define SPINAND_MFR_WINBOND 0xEF #define WINBOND_CFG_BUF_READ BIT(3) -#define W25N04KV_STATUS_ECC_5_8_BITFLIPS FIELD_PREP_CONST(STATUS_ECC_MASK, 0x3) +#define W25N04KV_STATUS_ECC_5_8_BITFLIPS (3 << 4) + +#define W25N0XJW_SR4 0xD0 +#define W25N0XJW_SR4_HS BIT(2) + +#define W35N01JW_VCR_IO_MODE 0x00 +#define W35N01JW_VCR_IO_MODE_SINGLE_SDR 0xFF +#define W35N01JW_VCR_IO_MODE_OCTAL_SDR 0xDF +#define W35N01JW_VCR_IO_MODE_OCTAL_DDR_DS 0xE7 +#define W35N01JW_VCR_IO_MODE_OCTAL_DDR 0xC7 +#define W35N01JW_VCR_DUMMY_CLOCK_REG 0x01 + +/* + * "X2" in the core is equivalent to "dual output" in the datasheets, + * "X4" in the core is equivalent to "quad output" in the datasheets. + * Quad and octal capable chips feature an absolute maximum frequency of 166MHz. + */ + +static SPINAND_OP_VARIANTS(read_cache_octal_variants, + SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(0, 3, NULL, 0, 120 * HZ_PER_MHZ), + SPINAND_PAGE_READ_FROM_CACHE_1S_1D_8D_OP(0, 2, NULL, 0, 105 * HZ_PER_MHZ), + SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 20, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 16, NULL, 0, 162 * HZ_PER_MHZ), + SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 12, NULL, 0, 124 * HZ_PER_MHZ), + SPINAND_PAGE_READ_FROM_CACHE_1S_8S_8S_OP(0, 8, NULL, 0, 86 * HZ_PER_MHZ), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_8S_OP(0, 2, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_8S_OP(0, 1, NULL, 0, 133 * HZ_PER_MHZ), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); + +static SPINAND_OP_VARIANTS(write_cache_octal_variants, + SPINAND_PROG_LOAD_1S_8S_8S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_8S_OP(0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_octal_variants, + SPINAND_PROG_LOAD_1S_8S_8S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(read_cache_dual_quad_dtr_variants, + SPINAND_PAGE_READ_FROM_CACHE_1S_4D_4D_OP(0, 8, NULL, 0, 80 * HZ_PER_MHZ), + SPINAND_PAGE_READ_FROM_CACHE_1S_1D_4D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ), + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 4, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 104 * HZ_PER_MHZ), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2D_2D_OP(0, 4, NULL, 0, 80 * HZ_PER_MHZ), + SPINAND_PAGE_READ_FROM_CACHE_1S_1D_2D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 2, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 104 * HZ_PER_MHZ), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1D_1D_OP(0, 2, NULL, 0, 80 * HZ_PER_MHZ), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 54 * HZ_PER_MHZ)); static SPINAND_OP_VARIANTS(read_cache_variants, - SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); static SPINAND_OP_VARIANTS(write_cache_variants, - SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), - SPINAND_PROG_LOAD(true, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); static SPINAND_OP_VARIANTS(update_cache_variants, - SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), - SPINAND_PROG_LOAD(false, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *region) @@ -80,6 +135,18 @@ static int w25m02gv_select_target(struct spinand_device *spinand, return spi_mem_exec_op(spinand->slave, &op); } +static int w25n01kv_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 3) + return -ERANGE; + + region->offset = 64 + (8 * section); + region->length = 7; + + return 0; +} + static int w25n02kv_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *region) { @@ -104,17 +171,57 @@ static int w25n02kv_ooblayout_free(struct mtd_info *mtd, int section, return 0; } +static const struct mtd_ooblayout_ops w25n01kv_ooblayout = { + .ecc = w25n01kv_ooblayout_ecc, + .rfree = w25n02kv_ooblayout_free, +}; + static const struct mtd_ooblayout_ops w25n02kv_ooblayout = { .ecc = w25n02kv_ooblayout_ecc, .rfree = w25n02kv_ooblayout_free, }; +static int w35n01jw_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 7) + return -ERANGE; + + region->offset = (16 * section) + 12; + region->length = 4; + + return 0; +} + +static int w35n01jw_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section > 7) + return -ERANGE; + + region->offset = 16 * section; + region->length = 12; + + /* Extract BBM */ + if (!section) { + region->offset += 2; + region->length -= 2; + } + + return 0; +} + +static const struct mtd_ooblayout_ops w35n01jw_ooblayout = { + .ecc = w35n01jw_ooblayout_ecc, + .rfree = w35n01jw_ooblayout_free, +}; + static int w25n02kv_ecc_get_status(struct spinand_device *spinand, u8 status) { struct nand_device *nand = spinand_to_nand(spinand); u8 mbf = 0; - struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf); + struct spi_mem_op op = SPINAND_GET_FEATURE_1S_1S_1S_OP(0x30, spinand->scratchbuf); switch (status & STATUS_ECC_MASK) { case STATUS_ECC_NO_BITFLIPS: @@ -131,12 +238,12 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand, * data around if it's not necessary. */ if (spi_mem_exec_op(spinand->slave, &op)) - return nand->eccreq.strength; + return nanddev_get_ecc_conf(nand)->strength; - mbf >>= 4; + mbf = *(spinand->scratchbuf) >> 4; - if (WARN_ON(mbf > nand->eccreq.strength || !mbf)) - return nand->eccreq.strength; + if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf)) + return nanddev_get_ecc_conf(nand)->strength; return mbf; @@ -147,18 +254,126 @@ static int w25n02kv_ecc_get_status(struct spinand_device *spinand, return -EINVAL; } +static int w25n0xjw_hs_cfg(struct spinand_device *spinand) +{ + const struct spi_mem_op *op; + bool hs; + u8 sr4; + int ret; + + op = spinand->op_templates.read_cache; + if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr) + hs = false; + else if (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && + op->dummy.buswidth == 1 && op->data.buswidth == 1) + hs = false; + else if (!op->max_freq) + hs = true; + else + hs = false; + + ret = spinand_read_reg_op(spinand, W25N0XJW_SR4, &sr4); + if (ret) + return ret; + + if (hs) + sr4 |= W25N0XJW_SR4_HS; + else + sr4 &= ~W25N0XJW_SR4_HS; + + ret = spinand_write_reg_op(spinand, W25N0XJW_SR4, sr4); + if (ret) + return ret; + + return 0; +} + +static int w35n0xjw_write_vcr(struct spinand_device *spinand, u8 reg, u8 val) +{ + struct spi_mem_op op = + SPI_MEM_OP(SPI_MEM_OP_CMD(0x81, 1), + SPI_MEM_OP_ADDR(3, reg, 1), + SPI_MEM_OP_NO_DUMMY, + SPI_MEM_OP_DATA_OUT(1, spinand->scratchbuf, 1)); + int ret; + + *spinand->scratchbuf = val; + + ret = spinand_write_enable_op(spinand); + if (ret) + return ret; + + ret = spi_mem_exec_op(spinand->slave, &op); + if (ret) + return ret; + + /* + * Write VCR operation doesn't set the busy bit in SR, which means we + * cannot perform a status poll. Minimum time of 50ns is needed to + * complete the write. + */ + ndelay(50); + + return 0; +} + +static int w35n0xjw_vcr_cfg(struct spinand_device *spinand) +{ + const struct spi_mem_op *op; + unsigned int dummy_cycles; + bool dtr, single; + u8 io_mode; + int ret; + + op = spinand->op_templates.read_cache; + + single = (op->cmd.buswidth == 1 && op->addr.buswidth == 1 && op->data.buswidth == 1); + dtr = (op->cmd.dtr || op->addr.dtr || op->data.dtr); + if (single && !dtr) + io_mode = W35N01JW_VCR_IO_MODE_SINGLE_SDR; + else if (!single && !dtr) + io_mode = W35N01JW_VCR_IO_MODE_OCTAL_SDR; + else if (!single && dtr) + io_mode = W35N01JW_VCR_IO_MODE_OCTAL_DDR; + else + return -EINVAL; + + ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_IO_MODE, io_mode); + if (ret) + return ret; + + dummy_cycles = ((op->dummy.nbytes * 8) / op->dummy.buswidth) / (op->dummy.dtr ? 2 : 1); + switch (dummy_cycles) { + case 8: + case 12: + case 16: + case 20: + case 24: + case 28: + break; + default: + return -EINVAL; + } + ret = w35n0xjw_write_vcr(spinand, W35N01JW_VCR_DUMMY_CLOCK_REG, dummy_cycles); + if (ret) + return ret; + + return 0; +} + static const struct spinand_info winbond_spinand_table[] = { - SPINAND_INFO("W25M02GV", - SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), - NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2), + /* 512M-bit densities */ + SPINAND_INFO("W25N512GW", /* 1.8V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x20), + NAND_MEMORG(1, 2048, 64, 64, 512, 10, 1, 1, 1), NAND_ECCREQ(1, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), 0, - SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), - SPINAND_SELECT_TARGET(w25m02gv_select_target)), - SPINAND_INFO("W25N01GV", + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), + /* 1G-bit densities */ + SPINAND_INFO("W25N01GV", /* 3.3V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x21), NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(1, 512), @@ -167,7 +382,86 @@ static const struct spinand_info winbond_spinand_table[] = { &update_cache_variants), 0, SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), - SPINAND_INFO("W25N02KV", + SPINAND_INFO("W25N01GW", /* 1.8V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x21), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)), + SPINAND_INFO("W25N01JW", /* high-speed 1.8V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbc, 0x21), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_dual_quad_dtr_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), + SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)), + SPINAND_INFO("W25N01KV", /* 3.3V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21), + NAND_MEMORG(1, 2048, 96, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(4, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&w25n01kv_ooblayout, w25n02kv_ecc_get_status)), + SPINAND_INFO("W35N01JW", /* 1.8V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdc, 0x21), + NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants, + &write_cache_octal_variants, + &update_cache_octal_variants), + 0, + SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), + SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), + SPINAND_INFO("W35N02JW", /* 1.8V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x22), + NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 2, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants, + &write_cache_octal_variants, + &update_cache_octal_variants), + 0, + SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), + SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), + SPINAND_INFO("W35N04JW", /* 1.8V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xdf, 0x23), + NAND_MEMORG(1, 4096, 128, 64, 512, 10, 1, 4, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_octal_variants, + &write_cache_octal_variants, + &update_cache_octal_variants), + 0, + SPINAND_ECCINFO(&w35n01jw_ooblayout, NULL), + SPINAND_CONFIGURE_CHIP(w35n0xjw_vcr_cfg)), + /* 2G-bit densities */ + SPINAND_INFO("W25M02GV", /* 2x1G-bit 3.3V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab, 0x21), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), + SPINAND_SELECT_TARGET(w25m02gv_select_target)), + SPINAND_INFO("W25N02JW", /* high-speed 1.8V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xbf, 0x22), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 2, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_dual_quad_dtr_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL), + SPINAND_CONFIGURE_CHIP(w25n0xjw_hs_cfg)), + SPINAND_INFO("W25N02KV", /* 3.3V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22), NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), NAND_ECCREQ(8, 512), @@ -176,7 +470,17 @@ static const struct spinand_info winbond_spinand_table[] = { &update_cache_variants), 0, SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), - SPINAND_INFO("W25N04KV", + SPINAND_INFO("W25N02KW", /* 1.8V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x22), + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), + /* 4G-bit densities */ + SPINAND_INFO("W25N04KV", /* 3.3V */ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23), NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 2, 1, 1), NAND_ECCREQ(8, 512), @@ -185,6 +489,15 @@ static const struct spinand_info winbond_spinand_table[] = { &update_cache_variants), 0, SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), + SPINAND_INFO("W25N04KW", /* 1.8V */ + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xba, 0x23), + NAND_MEMORG(1, 2048, 128, 64, 4096, 40, 1, 1, 1), + NAND_ECCREQ(8, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)), }; static int winbond_spinand_init(struct spinand_device *spinand) diff --git a/drivers/mtd/nand/spi/xtx.c b/drivers/mtd/nand/spi/xtx.c index aee1849a71f..3e1f884fd89 100644 --- a/drivers/mtd/nand/spi/xtx.c +++ b/drivers/mtd/nand/spi/xtx.c @@ -25,20 +25,20 @@ #define XT26XXXD_STATUS_ECC_UNCOR_ERROR (2) static SPINAND_OP_VARIANTS(read_cache_variants, - SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0), - SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0)); + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); static SPINAND_OP_VARIANTS(write_cache_variants, - SPINAND_PROG_LOAD_X4(true, 0, NULL, 0), - SPINAND_PROG_LOAD(true, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); static SPINAND_OP_VARIANTS(update_cache_variants, - SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), - SPINAND_PROG_LOAD(false, 0, NULL, 0)); + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *region) diff --git a/drivers/mtd/nvmxip/nvmxip.c b/drivers/mtd/nvmxip/nvmxip.c index 594500f0c65..3d8597aca76 100644 --- a/drivers/mtd/nvmxip/nvmxip.c +++ b/drivers/mtd/nvmxip/nvmxip.c @@ -41,7 +41,7 @@ static ulong nvmxip_blk_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcn if (!buffer) return -EINVAL; - log_debug("[%s]: reading from blknr: %lu , blkcnt: %lu\n", dev->name, blknr, blkcnt); + log_debug("[%s]: reading from blknr: " LBAF " , blkcnt: " LBAF "\n", dev->name, blknr, blkcnt); virt_blkaddr = map_sysmem(blkaddr, 0); @@ -86,7 +86,7 @@ static int nvmxip_blk_probe(struct udevice *dev) desc->blksz = BIT(plat->lba_shift); desc->bdev = dev; - log_debug("[%s]: block storage layout\n lbas: %lu , log2blksz: %d, blksz: %lu\n", + log_debug("[%s]: block storage layout\n lbas: " LBAF " , log2blksz: %d, blksz: %lu\n", dev->name, desc->lba, desc->log2blksz, desc->blksz); return 0; diff --git a/drivers/mtd/nvmxip/nvmxip_qspi.c b/drivers/mtd/nvmxip/nvmxip_qspi.c index f14a822b5d5..1a109bee557 100644 --- a/drivers/mtd/nvmxip/nvmxip_qspi.c +++ b/drivers/mtd/nvmxip/nvmxip_qspi.c @@ -49,7 +49,7 @@ static int nvmxip_qspi_of_to_plat(struct udevice *dev) return -EINVAL; } - log_debug("[%s]: XIP device base addr: 0x%p , lba_shift: %d , lbas: %lu\n", + log_debug("[%s]: XIP device base addr: 0x%p , lba_shift: %d , lbas: " LBAF "\n", dev->name, (void *)(uintptr_t)plat->phys_base, plat->lba_shift, plat->lba); return 0; diff --git a/drivers/mtd/spi/sf_dataflash.c b/drivers/mtd/spi/sf_dataflash.c index 438eb3698d5..9094e008f60 100644 --- a/drivers/mtd/spi/sf_dataflash.c +++ b/drivers/mtd/spi/sf_dataflash.c @@ -138,11 +138,11 @@ static int spi_dataflash_erase(struct udevice *dev, u32 offset, size_t len) memset(dataflash->command, 0 , sizeof(dataflash->command)); command = dataflash->command; - debug("%s: erase addr=0x%x len 0x%x\n", dev->name, offset, len); + debug("%s: erase addr=0x%x len 0x%zx\n", dev->name, offset, len); div_u64_rem(len, spi_flash->page_size, &rem); if (rem) { - printf("%s: len(0x%x) isn't the multiple of page size(0x%x)\n", + printf("%s: len(0x%zx) isn't the multiple of page size(0x%x)\n", dev->name, len, spi_flash->page_size); return -EINVAL; } @@ -229,7 +229,7 @@ static int spi_dataflash_read(struct udevice *dev, u32 offset, size_t len, memset(dataflash->command, 0 , sizeof(dataflash->command)); command = dataflash->command; - debug("%s: erase addr=0x%x len 0x%x\n", dev->name, offset, len); + debug("%s: erase addr=0x%x len 0x%zx\n", dev->name, offset, len); debug("READ: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); @@ -287,7 +287,7 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len, memset(dataflash->command, 0 , sizeof(dataflash->command)); command = dataflash->command; - debug("%s: write 0x%x..0x%x\n", dev->name, offset, (offset + len)); + debug("%s: write 0x%x..0x%zx\n", dev->name, offset, (offset + len)); pageaddr = ((unsigned)offset / spi_flash->page_size); to = ((unsigned)offset % spi_flash->page_size); diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 0383175beb5..b6a07fa9063 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -591,6 +591,12 @@ const struct flash_info spi_nor_ids[] = { { INFO("w25m512jw", 0xef6119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { INFO("w25m512jv", 0xef7119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { INFO("w25h02jv", 0xef9022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25h512nw-am", 0xefa020, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25h01nw-am", 0xefa021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25h02nw-am", 0xefa022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q01nw-iq", 0xef6021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q01nw-im", 0xef8021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q02nw-im", 0xef8022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { INFO("w77q51nw", 0xef8a1a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, #endif #ifdef CONFIG_SPI_FLASH_XMC diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 45699b4a477..2ec968c85ff 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -936,12 +936,7 @@ static int validate_vid_hdr(const struct ubi_device *ubi, ubi_err(ubi, "bad data_size"); goto bad; } - } else if (lnum == used_ebs - 1) { - if (data_size == 0) { - ubi_err(ubi, "bad data_size at last LEB"); - goto bad; - } - } else { + } else if (lnum != used_ebs - 1) { ubi_err(ubi, "too high lnum"); goto bad; } diff --git a/drivers/mtd/ubispl/ubispl.c b/drivers/mtd/ubispl/ubispl.c index 9face5fae15..0143caa051d 100644 --- a/drivers/mtd/ubispl/ubispl.c +++ b/drivers/mtd/ubispl/ubispl.c @@ -779,7 +779,7 @@ static int ubi_scan_fastmap(struct ubi_scan_info *ubi, * that already so we merily copy it over. */ if (pnum == fm_anchor) - memcpy(vh, ubi->blockinfo + pnum, sizeof(*fm)); + memcpy(vh, ubi->blockinfo + pnum, sizeof(*vh)); if (i == 0) { if (be32_to_cpu(vh->vol_id) != UBI_FM_SB_VOLUME_ID) { diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index d1cb69f85ad..544e302d600 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -179,7 +179,7 @@ config CALXEDA_XGMAC machines. config DWC_ETH_XGMAC - bool "Synopsys DWC Ethernet XGMAC device support" + bool select PHYLIB help This driver supports the Synopsys Designware Ethernet XGMAC (10G @@ -190,7 +190,8 @@ config DWC_ETH_XGMAC_SOCFPGA bool "Synopsys DWC Ethernet XGMAC device support for SOCFPGA" select REGMAP select SYSCON - depends on DWC_ETH_XGMAC + select DWC_ETH_XGMAC + depends on ARCH_SOCFPGA default y if TARGET_SOCFPGA_AGILEX5 help The Synopsys Designware Ethernet XGMAC IP block with specific @@ -376,7 +377,7 @@ config ETH_DESIGNWARE_SOCFPGA select SYSCON select DW_ALTDESCRIPTOR bool "Altera SoCFPGA extras for Synopsys Designware Ethernet MAC" - depends on ETH_DESIGNWARE + depends on ARCH_SOCFPGA && ETH_DESIGNWARE help The Altera SoCFPGA requires additional configuration of the Altera system manager to correctly interface with the PHY. @@ -662,7 +663,7 @@ config MII config RMII bool "Enable RMII" help - Enable support of the Reduced Media-Independent Interface (MII) + Enable support of the Reduced Media-Independent Interface (RMII) config PCNET bool "AMD PCnet series Ethernet controller driver" @@ -841,11 +842,12 @@ config GMAC_ROCKCHIP config RENESAS_ETHER_SWITCH bool "Renesas Ethernet Switch support" - depends on DM_ETH && R8A779F0 + depends on DM_ETH && (R8A779F0 || R8A78000) select PHYLIB help This driver implements support for the Renesas Ethernet Switch - which is available on R-Car S4 SoC (r8a779f0). + which is available on R-Car S4 SoC (R8A779F0) and newer version + on R-Car X5H SoC (R8A78000). config RENESAS_RAVB bool "Renesas Ethernet AVB MAC" @@ -966,6 +968,9 @@ config TSEC_ENET This driver implements support for the (Enhanced) Three-Speed Ethernet Controller found on Freescale SoCs. +config MDIO_MT7531_MMIO + bool + source "drivers/net/mtk_eth/Kconfig" config HIFEMAC_ETH @@ -1002,8 +1007,9 @@ config FSL_ENETC config FSL_ENETC_NETC_BLK_CTRL bool "NXP ENETC NETC blocks control driver" - depends on FSL_ENETC && IMX95 - default y if IMX95 + depends on FSL_ENETC + depends on IMX95 || IMX94 + default y if IMX95 || IMX94 help This driver configures Integrated Endpoint Register Block (IERB) and Privileged Register Block (PRB) of NETC. For i.MX platforms, it also diff --git a/drivers/net/Makefile b/drivers/net/Makefile index f8f9a71f815..a3c3420898c 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_MACB) += macb.o obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o obj-$(CONFIG_MDIO_IPQ4019) += mdio-ipq4019.o obj-$(CONFIG_MDIO_GPIO_BITBANG) += mdio_gpio.o +obj-$(CONFIG_MDIO_MT7531_MMIO) += mdio-mt7531-mmio.o obj-$(CONFIG_MDIO_MUX_I2CREG) += mdio_mux_i2creg.o obj-$(CONFIG_MDIO_MUX_MESON_G12A) += mdio_mux_meson_g12a.o obj-$(CONFIG_MDIO_MUX_MESON_GXL) += mdio_mux_meson_gxl.o diff --git a/drivers/net/airoha_eth.c b/drivers/net/airoha_eth.c index 6588eb3a806..3234d875887 100644 --- a/drivers/net/airoha_eth.c +++ b/drivers/net/airoha_eth.c @@ -21,6 +21,7 @@ #include <linux/io.h> #include <linux/iopoll.h> #include <linux/time.h> +#include <asm/arch/scu-regmap.h> #define AIROHA_MAX_NUM_GDM_PORTS 1 #define AIROHA_MAX_NUM_QDMA 1 @@ -312,6 +313,25 @@ struct airoha_eth { struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS]; }; +struct airoha_eth_soc_data { + int num_xsi_rsts; + const char * const *xsi_rsts_names; + const char *switch_compatible; +}; + +static const char * const en7523_xsi_rsts_names[] = { + "hsi0-mac", + "hsi1-mac", + "hsi-mac", +}; + +static const char * const en7581_xsi_rsts_names[] = { + "hsi0-mac", + "hsi1-mac", + "hsi-mac", + "xfp-mac", +}; + static u32 airoha_rr(void __iomem *base, u32 offset) { return readl(base + offset); @@ -449,14 +469,10 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q, RX_RING_SIZE_MASK, FIELD_PREP(RX_RING_SIZE_MASK, ndesc)); - /* - * See arht_eth_free_pkt() for the reasons used to fill - * REG_RX_CPU_IDX(qid) register. - */ airoha_qdma_rmw(qdma, REG_RX_RING_SIZE(qid), RX_RING_THR_MASK, FIELD_PREP(RX_RING_THR_MASK, 0)); airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK, - FIELD_PREP(RX_RING_CPU_IDX_MASK, q->ndesc - 3)); + FIELD_PREP(RX_RING_CPU_IDX_MASK, q->ndesc - 1)); airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK, FIELD_PREP(RX_RING_DMA_IDX_MASK, q->head)); @@ -682,10 +698,12 @@ static int airoha_hw_init(struct udevice *dev, static int airoha_switch_init(struct udevice *dev, struct airoha_eth *eth) { + struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev); ofnode switch_node; fdt_addr_t addr; - switch_node = ofnode_by_compatible(ofnode_null(), "airoha,en7581-switch"); + switch_node = ofnode_by_compatible(ofnode_null(), + data->switch_compatible); if (!ofnode_valid(switch_node)) return -EINVAL; @@ -722,16 +740,12 @@ static int airoha_switch_init(struct udevice *dev, struct airoha_eth *eth) static int airoha_eth_probe(struct udevice *dev) { + struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev); struct airoha_eth *eth = dev_get_priv(dev); struct regmap *scu_regmap; - ofnode scu_node; - int ret; + int i, ret; - scu_node = ofnode_by_compatible(ofnode_null(), "airoha,en7581-scu"); - if (!ofnode_valid(scu_node)) - return -EINVAL; - - scu_regmap = syscon_node_to_regmap(scu_node); + scu_regmap = airoha_get_scu_regmap(); if (IS_ERR(scu_regmap)) return PTR_ERR(scu_regmap); @@ -751,11 +765,11 @@ static int airoha_eth_probe(struct udevice *dev) return -ENOMEM; eth->rsts.count = AIROHA_MAX_NUM_RSTS; - eth->xsi_rsts.resets = devm_kcalloc(dev, AIROHA_MAX_NUM_XSI_RSTS, + eth->xsi_rsts.resets = devm_kcalloc(dev, data->num_xsi_rsts, sizeof(struct reset_ctl), GFP_KERNEL); if (!eth->xsi_rsts.resets) return -ENOMEM; - eth->xsi_rsts.count = AIROHA_MAX_NUM_XSI_RSTS; + eth->xsi_rsts.count = data->num_xsi_rsts; ret = reset_get_by_name(dev, "fe", ð->rsts.resets[0]); if (ret) @@ -769,21 +783,12 @@ static int airoha_eth_probe(struct udevice *dev) if (ret) return ret; - ret = reset_get_by_name(dev, "hsi0-mac", ð->xsi_rsts.resets[0]); - if (ret) - return ret; - - ret = reset_get_by_name(dev, "hsi1-mac", ð->xsi_rsts.resets[1]); - if (ret) - return ret; - - ret = reset_get_by_name(dev, "hsi-mac", ð->xsi_rsts.resets[2]); - if (ret) - return ret; - - ret = reset_get_by_name(dev, "xfp-mac", ð->xsi_rsts.resets[3]); - if (ret) - return ret; + for (i = 0; i < data->num_xsi_rsts; i++) { + ret = reset_get_by_name(dev, data->xsi_rsts_names[i], + ð->xsi_rsts.resets[i]); + if (ret) + return ret; + } ret = airoha_hw_init(dev, eth); if (ret) @@ -920,7 +925,6 @@ static int arht_eth_free_pkt(struct udevice *dev, uchar *packet, int length) struct airoha_qdma *qdma = ð->qdma[0]; struct airoha_queue *q; int qid; - u16 prev, pprev; if (!packet) return 0; @@ -930,22 +934,29 @@ static int arht_eth_free_pkt(struct udevice *dev, uchar *packet, int length) /* * Due to cpu cache issue the airoha_qdma_reset_rx_desc() function - * will always touch 2 descriptors: - * - if current descriptor is even, then the previous and the one - * before previous descriptors will be touched (previous cacheline) - * - if current descriptor is odd, then only current and previous - * descriptors will be touched (current cacheline) + * will always touch 2 descriptors placed on the same cacheline: + * - if current descriptor is even, then current and next + * descriptors will be touched + * - if current descriptor is odd, then current and previous + * descriptors will be touched * - * Thus, to prevent possible destroying of rx queue, only (q->ndesc - 2) - * descriptors might be used for packet receiving. + * Thus, to prevent possible destroying of rx queue, we should: + * - do nothing in the even descriptor case, + * - utilize 2 descriptors (current and previous one) in the + * odd descriptor case. + * + * WARNING: Observations shows that PKTBUFSRX must be even and + * larger than 7 for reliable driver operations. */ - prev = (q->head + q->ndesc - 1) % q->ndesc; - pprev = (q->head + q->ndesc - 2) % q->ndesc; - q->head = (q->head + 1) % q->ndesc; + if (q->head & 0x01) { + airoha_qdma_reset_rx_desc(q, q->head - 1); + airoha_qdma_reset_rx_desc(q, q->head); - airoha_qdma_reset_rx_desc(q, prev); - airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK, - FIELD_PREP(RX_RING_CPU_IDX_MASK, pprev)); + airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK, + FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head)); + } + + q->head = (q->head + 1) % q->ndesc; return 0; } @@ -971,8 +982,25 @@ static int arht_eth_write_hwaddr(struct udevice *dev) return 0; } +static const struct airoha_eth_soc_data en7523_data = { + .xsi_rsts_names = en7523_xsi_rsts_names, + .num_xsi_rsts = ARRAY_SIZE(en7523_xsi_rsts_names), + .switch_compatible = "airoha,en7523-switch", +}; + +static const struct airoha_eth_soc_data en7581_data = { + .xsi_rsts_names = en7581_xsi_rsts_names, + .num_xsi_rsts = ARRAY_SIZE(en7581_xsi_rsts_names), + .switch_compatible = "airoha,en7581-switch", +}; + static const struct udevice_id airoha_eth_ids[] = { - { .compatible = "airoha,en7581-eth" }, + { .compatible = "airoha,en7523-eth", + .data = (ulong)&en7523_data, + }, + { .compatible = "airoha,en7581-eth", + .data = (ulong)&en7581_data, + }, { } }; diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 7ecedc3d7f0..6ed9c6d538a 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -125,6 +125,16 @@ static int dw_mdio_reset(struct mii_dev *bus) return __dw_mdio_reset(dev); } + +#if IS_ENABLED(CONFIG_BITBANGMII) +static int dw_bb_mdio_reset(struct mii_dev *bus) +{ + struct dw_eth_dev *priv = bus->priv; + + return __dw_mdio_reset(priv->dev); +} +#endif + #endif #if IS_ENABLED(CONFIG_DM_MDIO) @@ -348,7 +358,7 @@ static int dw_bb_mdio_init(const char *name, struct udevice *dev) bus->read = dw_bb_miiphy_read; bus->write = dw_bb_miiphy_write; #if CONFIG_IS_ENABLED(DM_GPIO) - bus->reset = dw_mdio_reset; + bus->reset = dw_bb_mdio_reset; #endif bus->priv = dwpriv; @@ -894,7 +904,7 @@ int designware_eth_probe(struct udevice *dev) if (ret) { debug("%s: No phy supply\n", dev->name); } else { - ret = regulator_set_enable(phy_supply, true); + ret = regulator_set_enable_if_allowed(phy_supply, true); if (ret) { puts("Error enabling phy supply\n"); return ret; diff --git a/drivers/net/fsl_enetc_mdio.c b/drivers/net/fsl_enetc_mdio.c index c1d491f2c5a..3d76d92a62a 100644 --- a/drivers/net/fsl_enetc_mdio.c +++ b/drivers/net/fsl_enetc_mdio.c @@ -11,6 +11,8 @@ #include <asm/io.h> #include <asm/processor.h> #include <miiphy.h> +#include <linux/delay.h> +#include <power/regulator.h> #include "fsl_enetc.h" @@ -135,6 +137,8 @@ static int enetc_mdio_probe(struct udevice *dev) struct pci_child_plat *pplat = dev_get_parent_plat(dev); struct enetc_mdio_priv *priv = dev_get_priv(dev); u16 cmd = PCI_COMMAND_MEMORY; + int ret; + struct udevice *supply = NULL; priv->regs_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, 0); if (!priv->regs_base) { @@ -144,6 +148,27 @@ static int enetc_mdio_probe(struct udevice *dev) priv->regs_base += ENETC_MDIO_BASE; + if (CONFIG_IS_ENABLED(DM_REGULATOR)) { + ret = device_get_supply_regulator(dev, "phy-supply", + &supply); + if (ret && ret != -ENOENT) { + printf("%s: device_get_supply_regulator failed: %d\n", + __func__, ret); + return ret; + } + + if (supply) { + regulator_set_enable(supply, false); + mdelay(100); + + ret = regulator_set_enable_if_allowed(supply, true); + if (ret) { + printf("%s: Error enabling phy supply\n", dev->name); + return ret; + } + } + } + if (pplat->vendor == PCI_VENDOR_ID_PHILIPS) /* i.MX95 */ cmd |= PCI_COMMAND_MASTER; diff --git a/drivers/net/fsl_enetc_netc_blk_ctrl.c b/drivers/net/fsl_enetc_netc_blk_ctrl.c index fecd66eb15a..8577bb75632 100644 --- a/drivers/net/fsl_enetc_netc_blk_ctrl.c +++ b/drivers/net/fsl_enetc_netc_blk_ctrl.c @@ -43,6 +43,18 @@ #define PCS_PROT_SFI BIT(4) #define PCS_PROT_10G_SXGMII BIT(6) +#define IMX94_MISC_SOC_CONTROL 0x0 +#define SEL_XPCS_1 BIT(1) +#define IMX94_XPCS_PORT_0 0x0 +#define IMX94_XPCS_PORT_1 0x1 + +#define IMX94_EXT_PIN_CONTROL 0x10 +#define MAC2_MAC3_SEL BIT(1) + +#define IMX94_NETC_LINK_CFG(a) (0x4c + (a) * 4) +#define NETC_LINK_CFG_MII_PROT GENMASK(3, 0) +#define NETC_LINK_CFG_IO_VAR GENMASK(19, 16) + /* NETC privileged register block register */ #define PRB_NETCRR 0x100 #define NETCRR_SR BIT(0) @@ -55,6 +67,7 @@ /* NETC integrated endpoint register block register */ #define IERB_EMDIOFAUXR 0x344 #define IERB_T0FAUXR 0x444 +#define IERB_ETBCR(a) (0x300c + 0x100 * (a)) #define IERB_EFAUXR(a) (0x3044 + 0x100 * (a)) #define IERB_VFAUXR(a) (0x4004 + 0x40 * (a)) #define FAUXR_LDID GENMASK(3, 0) @@ -64,6 +77,26 @@ #define IMX95_ENETC1_BUS_DEVFN 0x40 #define IMX95_ENETC2_BUS_DEVFN 0x80 +#define IMX94_ENETC3_BUS_DEVFN 0x0 +#define IMX94_TIMER0_BUS_DEVFN 0x1 +#define IMX94_SWITCH_BUS_DEVFN 0x2 +#define IMX94_ENETC0_BUS_DEVFN 0x100 +#define IMX94_TIMER1_BUS_DEVFN 0x101 +#define IMX94_ENETC1_BUS_DEVFN 0x140 +#define IMX94_ENETC2_BUS_DEVFN 0x180 +#define IMX94_TIMER2_BUS_DEVFN 0x181 +#define IMX94_ENETC0_LINK 3 +#define IMX94_ENETC1_LINK 4 +#define IMX94_ENETC2_LINK 5 +#define IMX94_ENETC0_OFFSET 0 +#define IMX94_ENETC1_OFFSET 1 +#define IMX94_ENETC2_OFFSET 2 +#define IMX94_SWITCH_PORT2 2 +#define IMX94_SWITCH_CPU_PORT 3 +#define IMX94_TIMER0_ID 0 +#define IMX94_TIMER1_ID 1 +#define IMX94_TIMER2_ID 2 + /* Flags for different platforms */ #define NETC_HAS_NETCMIX BIT(0) @@ -73,6 +106,15 @@ struct netc_blk_ctrl { void __iomem *netcmix; }; +struct netc_devinfo { + int (*netcmix_init)(struct udevice *dev); + int (*ierb_init)(struct udevice *dev); + void (*xpcs_port_init)(struct netc_blk_ctrl *priv, int port); +}; + +static struct netc_blk_ctrl *netc_bc; +static struct netc_devinfo *netc_di; + static void netc_reg_write(void __iomem *base, u32 offset, u32 val) { writel(val, base + offset); @@ -183,6 +225,142 @@ static int imx95_netcmix_init(struct udevice *dev) return 0; } +static int imx94_enetc_get_link_num(ofnode np) +{ + int bus_devfn; + + bus_devfn = netc_of_pci_get_bus_devfn(np); + if (bus_devfn < 0) + return -EINVAL; + + /* Parse ENETC link number */ + switch (bus_devfn) { + case IMX94_ENETC0_BUS_DEVFN: + return IMX94_ENETC0_LINK; + case IMX94_ENETC1_BUS_DEVFN: + return IMX94_ENETC1_LINK; + case IMX94_ENETC2_BUS_DEVFN: + return IMX94_ENETC2_LINK; + default: + return -EINVAL; + } +} + +static int imx94_link_config(struct netc_blk_ctrl *priv, + ofnode np, int link_id) +{ + phy_interface_t interface; + int mii_proto; + u32 val; + + interface = ofnode_read_phy_mode(np); + if (interface == -1) + return -EINVAL; + + mii_proto = netc_get_link_mii_protocol(interface); + if (mii_proto < 0) + return -EINVAL; + + val = mii_proto & NETC_LINK_CFG_MII_PROT; + if (mii_proto == MII_PROT_SERIAL) + val = u32_replace_bits(val, IO_VAR_16FF_16G_SERDES, + NETC_LINK_CFG_IO_VAR); + + netc_reg_write(priv->netcmix, IMX94_NETC_LINK_CFG(link_id), val); + + if (link_id == IMX94_ENETC0_LINK) { + val = netc_reg_read(priv->netcmix, IMX94_EXT_PIN_CONTROL); + val |= MAC2_MAC3_SEL; + netc_reg_write(priv->netcmix, IMX94_EXT_PIN_CONTROL, val); + } + + return 0; +} + +static int imx94_enetc_link_config(struct netc_blk_ctrl *priv, + ofnode np, bool *enetc0_en) +{ + int link_id; + + link_id = imx94_enetc_get_link_num(np); + if (link_id < 0) + return -EINVAL; + + if (link_id == IMX94_ENETC0_LINK) + *enetc0_en = true; + + return imx94_link_config(priv, np, link_id); +} + +static int imx94_switch_link_config(struct netc_blk_ctrl *priv, + ofnode np, bool *swp2_en) +{ + ofnode ports, child; + int port_id, err = 0; + + ports = ofnode_find_subnode(np, "ports"); + if (!ofnode_valid(ports)) + ports = ofnode_find_subnode(np, "ethernet-ports"); + if (!ofnode_valid(ports)) + return -ENODEV; + + ofnode_for_each_subnode(child, ports) { + if (ofnode_read_u32(child, "reg", &port_id) < 0) { + err = -ENODEV; + goto end; + } + + if (port_id == IMX94_SWITCH_CPU_PORT) + continue; + + if (port_id == IMX94_SWITCH_PORT2) + *swp2_en = true; + + err = imx94_link_config(priv, child, port_id); + if (err) + goto end; + } + +end: + return err; +} + +static int imx94_netcmix_init(struct udevice *dev) +{ + struct netc_blk_ctrl *priv = dev_get_priv(dev); + ofnode child, gchild; + bool enetc0_en = false, swp2_en = false; + int err; + + dev_for_each_subnode(child, dev) { + if (!ofnode_is_enabled(child)) + continue; + + ofnode_for_each_subnode(gchild, child) { + if (!ofnode_is_enabled(gchild)) + continue; + + if (ofnode_device_is_compatible(gchild, "pci1131,e101")) { + err = imx94_enetc_link_config(priv, gchild, &enetc0_en); + if (err) + return err; + } else if (ofnode_device_is_compatible(gchild, "pci1131,eef2")) { + err = imx94_switch_link_config(priv, gchild, &swp2_en); + if (err) + return err; + } + } + } + + if (enetc0_en && swp2_en) { + dev_err(dev, "Cannot enable swp2 and enetc0 at the same time\n"); + + return -EINVAL; + } + + return 0; +} + static bool netc_ierb_is_locked(struct netc_blk_ctrl *priv) { return !!(netc_reg_read(priv->prb, PRB_NETCRR) & NETCRR_LOCK); @@ -238,9 +416,99 @@ static int imx95_ierb_init(struct udevice *dev) return 0; } +static int imx94_enetc_get_enetc_offset(ofnode np) +{ + int bus_devfn; + + bus_devfn = netc_of_pci_get_bus_devfn(np); + if (bus_devfn < 0) + return -EINVAL; + + /* Parse ENETC offset */ + switch (bus_devfn) { + case IMX94_ENETC0_BUS_DEVFN: + return IMX94_ENETC0_OFFSET; + case IMX94_ENETC1_BUS_DEVFN: + return IMX94_ENETC1_OFFSET; + case IMX94_ENETC2_BUS_DEVFN: + return IMX94_ENETC2_OFFSET; + default: + return -EINVAL; + } +} + +static int imx94_enetc_get_timer_id(ofnode np) +{ + int bus_devfn; + + bus_devfn = netc_of_pci_get_bus_devfn(np); + if (bus_devfn < 0) + return -EINVAL; + + /* Parse ENETC PTP timer ID */ + switch (bus_devfn) { + case IMX94_TIMER0_BUS_DEVFN: + return IMX94_TIMER0_ID; + case IMX94_TIMER1_BUS_DEVFN: + return IMX94_TIMER1_ID; + case IMX94_TIMER2_BUS_DEVFN: + return IMX94_TIMER2_ID; + default: + return -EINVAL; + } +} + +static int imx94_enetc_update_tid(struct netc_blk_ctrl *priv, ofnode pf_np) +{ + ofnode timer_np; + int offset, tid; + + offset = imx94_enetc_get_enetc_offset(pf_np); + if (offset < 0) { + printf("Find unknown PF node.\n"); + return offset; + } + + timer_np = ofnode_parse_phandle(pf_np, "nxp,ptp-timer", 0); + if (!ofnode_valid(timer_np)) { + /* + * If nxp,ptp-timer is not set, the first timer of the bus + * where enetc is located will be used as the default timer. + */ + tid = IMX94_TIMER1_ID; + goto update_reg; + } + + tid = imx94_enetc_get_timer_id(timer_np); + if (tid < 0) { + printf("Incorrect bus/devfn of ptp-timer.\n"); + return tid; + } + +update_reg: + netc_reg_write(priv->ierb, IERB_ETBCR(offset), tid); + + return 0; +} + +static int imx94_ierb_init(struct udevice *dev) +{ + struct netc_blk_ctrl *priv = dev_get_priv(dev); + ofnode bus_np, pf_np; + int ret = 0; + + dev_for_each_subnode(bus_np, dev) + ofnode_for_each_subnode(pf_np, bus_np) + if (ofnode_device_is_compatible(pf_np, "pci1131,e101")) + ret = imx94_enetc_update_tid(priv, pf_np); + + return ret; +} + static int netc_ierb_init(struct udevice *dev) { struct netc_blk_ctrl *priv = dev_get_priv(dev); + struct netc_devinfo *devinfo = (struct netc_devinfo *)dev_get_driver_data(dev); int err; if (netc_ierb_is_locked(priv)) { @@ -251,9 +519,11 @@ static int netc_ierb_init(struct udevice *dev) } } - err = imx95_ierb_init(dev); - if (err) - return err; + if (devinfo->ierb_init) { + err = devinfo->ierb_init(dev); + if (err) + return err; + } err = netc_lock_ierb(priv); if (err) { @@ -264,6 +534,31 @@ static int netc_ierb_init(struct udevice *dev) return 0; } +static void imx94_netc_xpcs_port_init(struct netc_blk_ctrl *priv, int port) +{ + u32 val; + + val = netc_reg_read(priv->netcmix, IMX94_MISC_SOC_CONTROL); + if (port == IMX94_XPCS_PORT_1) + val |= SEL_XPCS_1; + else + val &= ~SEL_XPCS_1; + netc_reg_write(priv->netcmix, IMX94_MISC_SOC_CONTROL, val); +} + +void netc_xpcs_port_init(int port) +{ + struct netc_blk_ctrl *priv = netc_bc; + struct netc_devinfo *devinfo; + + if (!priv) + return; + + devinfo = netc_di; + if (devinfo->xpcs_port_init) + devinfo->xpcs_port_init(priv, port); +} + static int netc_prb_check_error(struct netc_blk_ctrl *priv) { if (netc_reg_read(priv->prb, PRB_NETCSR) & NETCSR_ERROR) @@ -272,14 +567,27 @@ static int netc_prb_check_error(struct netc_blk_ctrl *priv) return 0; } +static const struct netc_devinfo imx95_devinfo = { + .netcmix_init = imx95_netcmix_init, + .ierb_init = imx95_ierb_init, +}; + +static const struct netc_devinfo imx94_devinfo = { + .netcmix_init = imx94_netcmix_init, + .ierb_init = imx94_ierb_init, + .xpcs_port_init = imx94_netc_xpcs_port_init, +}; + static const struct udevice_id netc_blk_ctrl_match[] = { - { .compatible = "nxp,imx95-netc-blk-ctrl" }, + { .compatible = "nxp,imx95-netc-blk-ctrl", .data = (ulong)&imx95_devinfo }, + { .compatible = "nxp,imx94-netc-blk-ctrl", .data = (ulong)&imx94_devinfo }, {}, }; static int netc_blk_ctrl_probe(struct udevice *dev) { struct netc_blk_ctrl *priv = dev_get_priv(dev); + struct netc_devinfo *devinfo = (struct netc_devinfo *)dev_get_driver_data(dev); struct clk *ipg_clk; fdt_addr_t regs; int err; @@ -318,10 +626,12 @@ static int netc_blk_ctrl_probe(struct udevice *dev) priv->netcmix = (void __iomem *)regs; - err = imx95_netcmix_init(dev); - if (err) { - dev_err(dev, "Initializing NETCMIX failed\n"); - return err; + if (devinfo->netcmix_init) { + err = devinfo->netcmix_init(dev); + if (err) { + dev_err(dev, "Initializing NETCMIX failed\n"); + return err; + } } err = netc_ierb_init(dev); @@ -333,6 +643,9 @@ static int netc_blk_ctrl_probe(struct udevice *dev) if (netc_prb_check_error(priv) < 0) dev_warn(dev, "The current IERB configuration is invalid\n"); + netc_bc = priv; + netc_di = devinfo; + return 0; } diff --git a/drivers/net/mdio-mt7531-mmio.c b/drivers/net/mdio-mt7531-mmio.c new file mode 100644 index 00000000000..3e325ca58da --- /dev/null +++ b/drivers/net/mdio-mt7531-mmio.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <asm/io.h> +#include <dm.h> +#include <linux/bitfield.h> +#include <linux/iopoll.h> +#include <miiphy.h> + +#define MT7531_PHY_IAC 0x701c +#define MT7531_PHY_ACS_ST BIT(31) +#define MT7531_MDIO_REG_ADDR_CL22 GENMASK(29, 25) +#define MT7531_MDIO_DEV_ADDR MT7531_MDIO_REG_ADDR_CL22 +#define MT7531_MDIO_PHY_ADDR GENMASK(24, 20) +#define MT7531_MDIO_CMD GENMASK(19, 18) +#define MT7531_MDIO_CMD_READ_CL45 FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x3) +#define MT7531_MDIO_CMD_READ_CL22 FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x2) +#define MT7531_MDIO_CMD_WRITE FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x1) +#define MT7531_MDIO_CMD_ADDR FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x0) +#define MT7531_MDIO_ST GENMASK(17, 16) +#define MT7531_MDIO_ST_CL22 FIELD_PREP_CONST(MT7531_MDIO_ST, 0x1) +#define MT7531_MDIO_ST_CL45 FIELD_PREP_CONST(MT7531_MDIO_ST, 0x0) +#define MT7531_MDIO_RW_DATA GENMASK(15, 0) +#define MT7531_MDIO_REG_ADDR_CL45 MT7531_MDIO_RW_DATA + +#define MT7531_MDIO_TIMEOUT 100000 +#define MT7531_MDIO_SLEEP 20 + +struct mt7531_mdio_priv { + phys_addr_t switch_regs; +}; + +static int mt7531_mdio_wait_busy(struct mt7531_mdio_priv *priv) +{ + unsigned int busy; + + return readl_poll_sleep_timeout(priv->switch_regs + MT7531_PHY_IAC, + busy, (busy & MT7531_PHY_ACS_ST) == 0, + MT7531_MDIO_SLEEP, MT7531_MDIO_TIMEOUT); +} + +static int mt7531_mdio_read(struct mt7531_mdio_priv *priv, int addr, int devad, int reg) +{ + u32 val; + + if (devad != MDIO_DEVAD_NONE) { + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = MT7531_PHY_ACS_ST | + MT7531_MDIO_ST_CL45 | MT7531_MDIO_CMD_ADDR | + FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr) | + FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad) | + FIELD_PREP(MT7531_MDIO_REG_ADDR_CL45, reg); + + writel(val, priv->switch_regs + MT7531_PHY_IAC); + } + + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = MT7531_PHY_ACS_ST | FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr); + if (devad != MDIO_DEVAD_NONE) + val |= MT7531_MDIO_ST_CL45 | MT7531_MDIO_CMD_READ_CL45 | + FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad); + else + val |= MT7531_MDIO_ST_CL22 | MT7531_MDIO_CMD_READ_CL22 | + FIELD_PREP(MT7531_MDIO_REG_ADDR_CL22, reg); + + writel(val, priv->switch_regs + MT7531_PHY_IAC); + + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = readl(priv->switch_regs + MT7531_PHY_IAC); + return val & MT7531_MDIO_RW_DATA; +} + +static int mt7531_mdio_write(struct mt7531_mdio_priv *priv, int addr, int devad, + int reg, u16 value) +{ + u32 val; + + if (devad != MDIO_DEVAD_NONE) { + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = MT7531_PHY_ACS_ST | + MT7531_MDIO_ST_CL45 | MT7531_MDIO_CMD_ADDR | + FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr) | + FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad) | + FIELD_PREP(MT7531_MDIO_REG_ADDR_CL45, reg); + + writel(val, priv->switch_regs + MT7531_PHY_IAC); + } + + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = MT7531_PHY_ACS_ST | FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr) | + MT7531_MDIO_CMD_WRITE | FIELD_PREP(MT7531_MDIO_RW_DATA, value); + if (devad != MDIO_DEVAD_NONE) + val |= MT7531_MDIO_ST_CL45 | + FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad); + else + val |= MT7531_MDIO_ST_CL22 | + FIELD_PREP(MT7531_MDIO_REG_ADDR_CL22, reg); + + writel(val, priv->switch_regs + MT7531_PHY_IAC); + + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + return 0; +} + +int mt7531_mdio_mmio_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + struct mt7531_mdio_priv *priv = bus->priv; + + return mt7531_mdio_read(priv, addr, devad, reg); +} + +int mt7531_mdio_mmio_write(struct mii_dev *bus, int addr, int devad, + int reg, u16 value) +{ + struct mt7531_mdio_priv *priv = bus->priv; + + return mt7531_mdio_write(priv, addr, devad, reg, value); +} + +static int dm_mt7531_mdio_read(struct udevice *dev, int addr, int devad, int reg) +{ + struct mt7531_mdio_priv *priv = dev_get_priv(dev); + + return mt7531_mdio_read(priv, addr, devad, reg); +} + +static int dm_mt7531_mdio_write(struct udevice *dev, int addr, int devad, + int reg, u16 value) +{ + struct mt7531_mdio_priv *priv = dev_get_priv(dev); + + return mt7531_mdio_write(priv, addr, devad, reg, value); +} + +static const struct mdio_ops mt7531_mdio_ops = { + .read = dm_mt7531_mdio_read, + .write = dm_mt7531_mdio_write, +}; + +static int mt7531_mdio_probe(struct udevice *dev) +{ + struct mt7531_mdio_priv *priv = dev_get_priv(dev); + + priv->switch_regs = dev_read_addr(dev); + if (priv->switch_regs == FDT_ADDR_T_NONE) + return -EINVAL; + + return 0; +} + +U_BOOT_DRIVER(mt7531_mdio) = { + .name = "mt7531-mdio-mmio", + .id = UCLASS_MDIO, + .probe = mt7531_mdio_probe, + .ops = &mt7531_mdio_ops, + .priv_auto = sizeof(struct mt7531_mdio_priv), +}; diff --git a/drivers/net/mdio-mt7531-mmio.h b/drivers/net/mdio-mt7531-mmio.h new file mode 100644 index 00000000000..f98102cb939 --- /dev/null +++ b/drivers/net/mdio-mt7531-mmio.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +struct mt7531_mdio_mmio_priv { + phys_addr_t switch_regs; +}; + +int mt7531_mdio_mmio_read(struct mii_dev *bus, int addr, int devad, int reg); +int mt7531_mdio_mmio_write(struct mii_dev *bus, int addr, int devad, + int reg, u16 value); diff --git a/drivers/net/mdio_mux_meson_gxl.c b/drivers/net/mdio_mux_meson_gxl.c index 8ef3ae598b7..31898ed437e 100644 --- a/drivers/net/mdio_mux_meson_gxl.c +++ b/drivers/net/mdio_mux_meson_gxl.c @@ -19,6 +19,7 @@ #define REG2_LEDACT GENMASK(23, 22) #define REG2_LEDLINK GENMASK(25, 24) #define REG2_DIV4SEL BIT(27) +#define REG2_REVERSED BIT(28) #define REG2_ADCBYPASS BIT(30) #define REG2_CLKINSEL BIT(31) #define ETH_REG3 0x4 @@ -66,7 +67,7 @@ static int meson_gxl_enable_internal_mdio(struct mdio_mux_meson_gxl_priv *priv) * The only constraint is that it must match the one in * drivers/net/phy/meson-gxl.c to properly match the PHY. */ - writel(FIELD_PREP(REG2_PHYID, EPHY_GXL_ID), + writel(REG2_REVERSED | FIELD_PREP(REG2_PHYID, EPHY_GXL_ID), priv->regs + ETH_REG2); /* Enable the internal phy */ diff --git a/drivers/net/mtk_eth/Kconfig b/drivers/net/mtk_eth/Kconfig index e8cdf408237..5d4e54ab90e 100644 --- a/drivers/net/mtk_eth/Kconfig +++ b/drivers/net/mtk_eth/Kconfig @@ -1,6 +1,7 @@ config MEDIATEK_ETH bool "MediaTek Ethernet GMAC Driver" + depends on ARCH_MEDIATEK || ARCH_MTMIPS select PHYLIB select DM_GPIO select DM_RESET @@ -30,6 +31,7 @@ config MTK_ETH_SWITCH_MT7531 config MTK_ETH_SWITCH_MT7988 bool "Support for MediaTek MT7988 built-in ethernet switch" depends on TARGET_MT7988 + select MDIO_MT7531_MMIO default y config MTK_ETH_SWITCH_AN8855 diff --git a/drivers/net/mtk_eth/mt7531.c b/drivers/net/mtk_eth/mt7531.c index 32d6bebbbdb..965bc3cb7e9 100644 --- a/drivers/net/mtk_eth/mt7531.c +++ b/drivers/net/mtk_eth/mt7531.c @@ -22,17 +22,13 @@ static int mt7531_core_reg_read(struct mt753x_switch_priv *priv, u32 reg) { - u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0); - - return mt7531_mmd_read(priv, phy_addr, 0x1f, reg); + return mt7531_mmd_read(priv, 0, 0x1f, reg); } static void mt7531_core_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 val) { - u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0); - - mt7531_mmd_write(priv, phy_addr, 0x1f, reg, val); + mt7531_mmd_write(priv, 0, 0x1f, reg, val); } static void mt7531_core_pll_setup(struct mt753x_switch_priv *priv) @@ -171,7 +167,7 @@ static int mt7531_setup(struct mtk_eth_switch_priv *swpriv) { struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; u32 i, val, pmcr, port5_sgmii; - u16 phy_addr, phy_val; + u16 phy_val; priv->smi_addr = MT753X_DFL_SMI_ADDR; priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK; @@ -180,10 +176,9 @@ static int mt7531_setup(struct mtk_eth_switch_priv *swpriv) /* Turn off PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { - phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); - phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); + phy_val = mt7531_mii_read(priv, i, MII_BMCR); phy_val |= BMCR_PDOWN; - mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); + mt7531_mii_write(priv, i, MII_BMCR, phy_val); } /* Force MAC link down before reset */ @@ -239,10 +234,9 @@ static int mt7531_setup(struct mtk_eth_switch_priv *swpriv) /* Turn on PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { - phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); - phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); + phy_val = mt7531_mii_read(priv, i, MII_BMCR); phy_val &= ~BMCR_PDOWN; - mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); + mt7531_mii_write(priv, i, MII_BMCR, phy_val); } mt7531_phy_setting(priv); diff --git a/drivers/net/mtk_eth/mt7988.c b/drivers/net/mtk_eth/mt7988.c index a416d87840c..29b6363cbd7 100644 --- a/drivers/net/mtk_eth/mt7988.c +++ b/drivers/net/mtk_eth/mt7988.c @@ -6,6 +6,7 @@ * Author: Mark Lee <mark-mc.lee@mediatek.com> */ +#include <malloc.h> #include <miiphy.h> #include <linux/delay.h> #include <linux/mdio.h> @@ -14,6 +15,8 @@ #include "mtk_eth.h" #include "mt753x.h" +#include "../mdio-mt7531-mmio.h" + static int mt7988_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data) { *data = readl(priv->epriv.ethsys_base + GSW_BASE + reg); @@ -30,20 +33,34 @@ static int mt7988_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data) static void mt7988_phy_setting(struct mt753x_switch_priv *priv) { + struct mii_dev *mdio_bus = priv->mdio_bus; u16 val; u32 i; for (i = 0; i < MT753X_NUM_PHYS; i++) { + u16 addr = MT753X_PHY_ADDR(priv->phy_base, i); + + /* Set PHY to PHY page 1 */ + mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE, + 0x1f, 0x1); + /* Enable HW auto downshift */ - mt7531_mii_write(priv, i, 0x1f, 0x1); - val = mt7531_mii_read(priv, i, PHY_EXT_REG_14); + val = mt7531_mdio_mmio_read(mdio_bus, addr, MDIO_DEVAD_NONE, + PHY_EXT_REG_14); val |= PHY_EN_DOWN_SHFIT; - mt7531_mii_write(priv, i, PHY_EXT_REG_14, val); + mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE, + PHY_EXT_REG_14, val); /* PHY link down power saving enable */ - val = mt7531_mii_read(priv, i, PHY_EXT_REG_17); + val = mt7531_mdio_mmio_read(mdio_bus, addr, MDIO_DEVAD_NONE, + PHY_EXT_REG_17); val |= PHY_LINKDOWN_POWER_SAVING_EN; - mt7531_mii_write(priv, i, PHY_EXT_REG_17, val); + mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE, + PHY_EXT_REG_17, val); + + /* Restore PHY to PHY page 0 */ + mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE, + 0x1f, 0x0); } } @@ -58,24 +75,66 @@ static void mt7988_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable) mt7988_reg_write(priv, PMCR_REG(6), pmcr); } +static int mt7988_mdio_register(struct mt753x_switch_priv *priv) +{ + struct mt7531_mdio_mmio_priv *mdio_priv; + struct mii_dev *mdio_bus = mdio_alloc(); + int ret; + + if (!mdio_bus) + return -ENOMEM; + + mdio_priv = malloc(sizeof(*mdio_priv)); + if (!mdio_priv) + return -ENOMEM; + + mdio_priv->switch_regs = (phys_addr_t)priv->epriv.ethsys_base + GSW_BASE; + + mdio_bus->read = mt7531_mdio_mmio_read; + mdio_bus->write = mt7531_mdio_mmio_write; + snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name); + + mdio_bus->priv = mdio_priv; + + ret = mdio_register(mdio_bus); + if (ret) { + free(mdio_bus->priv); + mdio_free(mdio_bus); + return ret; + } + + priv->mdio_bus = mdio_bus; + + return 0; +} + static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) { struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; + struct mii_dev *mdio_bus; u16 phy_addr, phy_val; + int ret, i; u32 pmcr; - int i; priv->smi_addr = MT753X_DFL_SMI_ADDR; priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK; priv->reg_read = mt7988_reg_read; priv->reg_write = mt7988_reg_write; + ret = mt7988_mdio_register(priv); + if (ret) + return ret; + + mdio_bus = priv->mdio_bus; + /* Turn off PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); - phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); + phy_val = mt7531_mdio_mmio_read(mdio_bus, phy_addr, + MDIO_DEVAD_NONE, MII_BMCR); phy_val |= BMCR_PDOWN; - mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); + mt7531_mdio_mmio_write(mdio_bus, phy_addr, MDIO_DEVAD_NONE, + MII_BMCR, phy_val); } switch (priv->epriv.phy_interface) { @@ -129,21 +188,26 @@ static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) /* Turn on PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); - phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); + phy_val = mt7531_mdio_mmio_read(mdio_bus, phy_addr, + MDIO_DEVAD_NONE, MII_BMCR); phy_val &= ~BMCR_PDOWN; - mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); + mt7531_mdio_mmio_write(mdio_bus, phy_addr, MDIO_DEVAD_NONE, + MII_BMCR, phy_val); } mt7988_phy_setting(priv); - return mt7531_mdio_register(priv); + return 0; } -static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv) +static int mt7988_cleanup(struct mtk_eth_switch_priv *swpriv) { struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; + struct mii_dev *mdio_bus = priv->mdio_bus; - mdio_unregister(priv->mdio_bus); + mdio_unregister(mdio_bus); + free(mdio_bus->priv); + mdio_free(mdio_bus); return 0; } @@ -155,6 +219,6 @@ MTK_ETH_SWITCH(mt7988) = { .reset_wait_time = 50, .setup = mt7988_setup, - .cleanup = mt7531_cleanup, + .cleanup = mt7988_cleanup, .mac_control = mt7988_mac_control, }; diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 185c6a3156e..018be98705a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -56,6 +56,7 @@ endif # B53_SWITCH config MV88E61XX_SWITCH bool "Marvell MV88E61xx Ethernet switch PHY support." + depends on !COMPILE_TEST if MV88E61XX_SWITCH @@ -119,6 +120,7 @@ config PHY_BROADCOM config PHY_CORTINA bool "Cortina Ethernet PHYs support" + depends on !COMPILE_TEST config SYS_CORTINA_NO_FW_UPLOAD bool "Cortina firmware loading support" diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index f63a13824ca..903fcd667f6 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -338,7 +338,7 @@ static int aquantia_set_proto(struct phy_device *phydev, static int aquantia_dts_config(struct phy_device *phydev) { - ofnode node = phydev->node; + ofnode node = phy_get_ofnode(phydev); u32 prop; u16 reg; diff --git a/drivers/net/phy/mediatek/Kconfig b/drivers/net/phy/mediatek/Kconfig index bbda951e7d9..933271f01fa 100644 --- a/drivers/net/phy/mediatek/Kconfig +++ b/drivers/net/phy/mediatek/Kconfig @@ -6,8 +6,8 @@ config MTK_NET_PHYLIB config PHY_MEDIATEK_2P5GE bool "MediaTek built-in 2.5Gb ethernet PHYs" depends on OF_CONTROL && (TARGET_MT7987 || TARGET_MT7988) + select FW_LOADER select MTK_NET_PHYLIB - select FS_LOADER help Supports MediaTek SoC built-in 2.5Gb ethernet PHYs. diff --git a/drivers/net/phy/mediatek/mtk-2p5ge.c b/drivers/net/phy/mediatek/mtk-2p5ge.c index ab5007389a9..4090db0b474 100644 --- a/drivers/net/phy/mediatek/mtk-2p5ge.c +++ b/drivers/net/phy/mediatek/mtk-2p5ge.c @@ -10,7 +10,7 @@ #include <dm/of_access.h> #include <dm/pinctrl.h> #include <dm/ofnode.h> -#include <fs_loader.h> +#include <fw_loader.h> #include <linux/bitfield.h> #include <linux/delay.h> #include <linux/iopoll.h> @@ -249,7 +249,7 @@ int __weak mt7987_i2p5ge_get_fw(void **fw, size_t *fwsize, return -ENOMEM; ret = request_firmware_into_buf_via_script( - &pmb, MT7987_2P5GE_PMB_FW_SIZE, + pmb, MT7987_2P5GE_PMB_FW_SIZE, "mt7987_i2p5ge_load_pmb_firmware", fwsize); if (ret) { free(pmb); @@ -263,7 +263,7 @@ int __weak mt7987_i2p5ge_get_fw(void **fw, size_t *fwsize, } ret = request_firmware_into_buf_via_script( - &dsp, MT7987_2P5GE_DSPBITTB_SIZE, + dsp, MT7987_2P5GE_DSPBITTB_SIZE, "mt7987_i2p5ge_load_dspbit_firmware", dspfwsize); if (ret) { free(pmb); @@ -476,7 +476,7 @@ int __weak mt7988_i2p5ge_get_fw(void **fw, size_t *size) return -ENOMEM; ret = request_firmware_into_buf_via_script( - &pmb, MT7988_2P5GE_PMB_FW_SIZE, + pmb, MT7988_2P5GE_PMB_FW_SIZE, "mt7988_i2p5ge_load_pmb_firmware", size); if (ret) { free(pmb); diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 9702d042296..b58283fe3d5 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1250,3 +1250,116 @@ bool phy_interface_is_ncsi(void) return 0; #endif } + +/** + * __phy_read_page() - read the current page + * @phydev: a pointer to a &struct phy_device + * + * Returns page index or < 0 on error + */ +static int __phy_read_page(struct phy_device *phydev) +{ + struct phy_driver *drv = phydev->drv; + + if (!drv->read_page) { + debug("read_page callback not available, PHY driver not loaded?\n"); + return -EOPNOTSUPP; + } + + return drv->read_page(phydev); +} + +/** + * __phy_write_page() - Write a new page + * @phydev: a pointer to a &struct phy_device + * @page: page index to select + * + * Returns 0 or < 0 on error. + */ +static int __phy_write_page(struct phy_device *phydev, int page) +{ + struct phy_driver *drv = phydev->drv; + + if (!drv->write_page) { + debug("write_page callback not available, PHY driver not loaded?\n"); + return -EOPNOTSUPP; + } + + return drv->write_page(phydev, page); +} + +/** + * phy_save_page() - save the current page + * @phydev: a pointer to a &struct phy_device + * + * Return the current page number. On error, + * returns a negative errno. phy_restore_page() must always be called + * after this, irrespective of success or failure of this call. + */ +int phy_save_page(struct phy_device *phydev) +{ + return __phy_read_page(phydev); +} + +/** + * phy_select_page - Switch to a PHY page and return the previous page + * @phydev: a pointer to a &struct phy_device + * @page: desired page + * + * NOTE: Save the current PHY page, and set the current page. + * On error, returns a negative errno, otherwise returns the previous page number. + * phy_restore_page() must always be called after this, irrespective + * of success or failure of this call. + */ +int phy_select_page(struct phy_device *phydev, int page) +{ + int ret, oldpage; + + oldpage = ret = phy_save_page(phydev); + if (ret < 0) + return ret; + + if (oldpage != page) { + ret = __phy_write_page(phydev, page); + if (ret < 0) + return ret; + } + + return oldpage; +} + +/** + * phy_restore_page - Restore a previously saved page and propagate status + * @phydev: a pointer to a &struct phy_device + * @oldpage: the old page, return value from phy_save_page() or phy_select_page() + * @ret: operation's return code + * + * Restoring @oldpage if it is a valid page. + * This function propagates the earliest error code from the group of + * operations. + * + * Returns: + * @oldpage if it was a negative value, otherwise + * @ret if it was a negative errno value, otherwise + * phy_write_page()'s negative value if it were in error, otherwise + * @ret. + */ +int phy_restore_page(struct phy_device *phydev, int oldpage, int ret) +{ + int r; + + if (oldpage >= 0) { + r = __phy_write_page(phydev, oldpage); + + /* Propagate the operation return code if the page write + * was successful. + */ + if (ret >= 0 && r < 0) + ret = r; + } else { + /* Propagate the phy page selection error code */ + ret = oldpage; + } + + return ret; +}
\ No newline at end of file diff --git a/drivers/net/rswitch.c b/drivers/net/rswitch.c index f27587ac8bd..801c22bbdc7 100644 --- a/drivers/net/rswitch.c +++ b/drivers/net/rswitch.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Driver for Renesas Ethernet RSwitch2 (Ethernet-TSN). + * Driver for Renesas Ethernet RSwitch2 and RSwitch3 (Ethernet-TSN). * - * Copyright (C) 2021 Renesas Electronics Corporation + * Copyright (C) 2021-2025 Renesas Electronics Corporation * * Based on the Renesas Ethernet AVB driver. */ @@ -27,68 +27,61 @@ #define RSWITCH_SLEEP_US 1000 #define RSWITCH_TIMEOUT_US 1000000 -#define RSWITCH_NUM_HW 5 - -#define ETHA_TO_GWCA(i) ((i) % 2) -#define GWCA_TO_HW_INDEX(i) ((i) + 3) -#define HW_INDEX_TO_GWCA(i) ((i) - 3) +#define GWCA_TO_HW_INDEX(i, pt) ((i) + (pt)) +#define HW_INDEX_TO_GWCA(i, pt) ((i) - (pt)) #define RSWITCH_MAX_CTAG_PCP 7 /* Registers */ -#define RSWITCH_COMA_OFFSET 0x00009000 -#define RSWITCH_ETHA_OFFSET 0x0000a000 /* with RMAC */ #define RSWITCH_ETHA_SIZE 0x00002000 /* with RMAC */ -#define RSWITCH_GWCA_OFFSET 0x00010000 #define RSWITCH_GWCA_SIZE 0x00002000 -#define FWRO 0 -#define CARO RSWITCH_COMA_OFFSET -#define GWRO 0 -#define TARO 0 -#define RMRO 0x1000 - /* List of TSNA registers (ETHA) */ -#define EAMC (TARO + 0x0000) -#define EAMS (TARO + 0x0004) -#define EATDQDCR (TARO + 0x0060) -#define EATTFC (TARO + 0x0138) -#define EATASRIRM (TARO + 0x03e4) +#define EAMC 0x0000 +#define EAMS 0x0004 +#define EATDQDCR 0x0060 +#define EATTFC 0x0138 +#define EATASRIRM 0x03e4 /* Gateway CPU agent block (GWCA) */ -#define GWMC (GWRO + 0x0000) -#define GWMS (GWRO + 0x0004) -#define GWMTIRM (GWRO + 0x0100) -#define GWVCC (GWRO + 0x0130) -#define GWTTFC (GWRO + 0x0138) -#define GWDCBAC0 (GWRO + 0x0194) -#define GWDCBAC1 (GWRO + 0x0198) -#define GWTRCR (GWRO + 0x0200) -#define GWARIRM (GWRO + 0x0380) -#define GWDCCR (GWRO + 0x0400) +#define GWMC 0x0000 +#define GWMS 0x0004 +#define GWMTIRM 0x0100 +#define GWVCC 0x0130 +#define GWCKSC 0x013c +#define GWTTFC 0x0138 +#define GWDCBAC0 0x0194 +#define GWDCBAC1 0x0198 +#define GWTRCR 0x0200 +#define GWARIRM 0x0380 +#define GWDCCR 0x0400 /* List of Common Agent registers (COMA) */ -#define RRC (CARO + 0x0004) -#define RCEC (CARO + 0x0008) -#define RCDC (CARO + 0x000c) -#define CABPIRM (CARO + 0x0140) +#define RRC 0x0004 +#define RCEC 0x0008 +#define RCDC 0x000c +#define CABPIRM 0x0140 /* List of MFWD registers */ -#define FWPC (FWRO + 0x0100) -#define FWPBFCR (FWRO + 0x4a00) -#define FWPBFCSDCR (FWRO + 0x4a04) +#define FWPC 0x0100 +#define FWPBFCR 0x4a00 +#define FWPBFCSDCR 0x4a04 /* List of RMAC registers (RMAC) */ -#define MPSM (RMRO + 0x0000) -#define MPIC (RMRO + 0x0004) -#define MRMAC0 (RMRO + 0x0084) -#define MRMAC1 (RMRO + 0x0088) -#define MRAFC (RMRO + 0x008c) -#define MRSCE (RMRO + 0x0090) -#define MRSCP (RMRO + 0x0094) -#define MLVC (RMRO + 0x0180) -#define MLBC (RMRO + 0x0188) -#define MXGMIIC (RMRO + 0x0190) -#define MPCH (RMRO + 0x0194) -#define MANM (RMRO + 0x019c) -#define MMIS0 (RMRO + 0x0210) -#define MMIS1 (RMRO + 0x0220) +#define MPSM 0x1000 +#define MPIC 0x1004 +#define MIOC 0x1010 +#define MRMAC0 0x1084 +#define MRMAC1 0x1088 +#define MRAFC 0x108c +#define MRSCE 0x1090 +#define MRSCP 0x1094 +#define MLVC 0x1180 +#define MLBC 0x1188 +#define MXGMIIC 0x1190 +#define MPCH 0x1194 +#define MANM 0x119c +#define MMIS0 0x1210 +#define MMIS1 0x1220 + +/* MIOC */ +#define MIOC_BIT3_SET BIT(3) /* COMA */ #define RRC_RR BIT(0) @@ -117,8 +110,9 @@ FWPC0_IPDSA | FWPC0_IPHLA | FWPC0_MACSDA | \ FWPC0_MACHLA | FWPC0_MACHMA | FWPC0_VLANSA) -#define FWPBFC(i) (FWPBFCR + (i) * 0x10) -#define FWPBFCSDC(j, i) (FWPBFCSDCR + (i) * 0x10 + (j) * 0x04) +#define FWPBFC(i) (FWPBFCR + (i) * 0x10) +#define FWPBFCSDC(regoff, gwcaidx, ethaidx, ethaincr) \ + (FWPBFCSDCR + (regoff) + (ethaidx) * (ethaincr) + (gwcaidx) * 0x04) /* ETHA */ #define EATASRIRM_TASRIOG BIT(0) @@ -138,7 +132,6 @@ #define MPIC_PSMCS_MASK (0x7f << 16) #define MPIC_PSMHT_MASK (0x06 << 24) -#define MPIC_MDC_CLK_SET (0x06050000) #define MPSM_MFF_C45 BIT(2) #define MPSM_MFF_C22 0x0 @@ -192,13 +185,20 @@ enum rswitch_gwca_mode { #define GWDCC(i) (GWDCCR + (i) * 0x04) #define GWDCC_DQT BIT(11) #define GWDCC_BALR BIT(24) +#define GWCKSC_USMFSPE BIT(31) -struct rswitch_etha { +struct rswitch_etha_io { int index; void __iomem *addr; +}; + +struct rswitch_etha { + struct rswitch_etha_io mii; + struct rswitch_etha_io serdes; struct phy_device *phydev; struct mii_dev *bus; unsigned char *enetaddr; + bool xpcs; }; struct rswitch_gwca { @@ -207,11 +207,6 @@ struct rswitch_gwca { int num_chain; }; -/* Setting value */ -#define LINK_SPEED_100 100 -#define LINK_SPEED_1000 1000 -#define LINK_SPEED_2500 2500 - /* Decriptor */ #define RSWITCH_NUM_BASE_DESC 2 #define RSWITCH_TX_CHAIN_INDEX 0 @@ -220,43 +215,43 @@ struct rswitch_gwca { #define RSWITCH_NUM_RX_DESC 8 enum RX_DS_CC_BIT { - RX_DS = 0x0fff, /* Data size */ - RX_TR = 0x1000, /* Truncation indication */ - RX_EI = 0x2000, /* Error indication */ - RX_PS = 0xc000, /* Padding selection */ + RX_DS = 0x0fff, /* Data size */ + RX_TR = 0x1000, /* Truncation indication */ + RX_EI = 0x2000, /* Error indication */ + RX_PS = 0xc000, /* Padding selection */ }; enum DIE_DT { /* Frame data */ - DT_FSINGLE = 0x80, - DT_FSTART = 0x90, - DT_FMID = 0xa0, - DT_FEND = 0xb8, + DT_FSINGLE = 0x80, + DT_FSTART = 0x90, + DT_FMID = 0xa0, + DT_FEND = 0xb8, /* Chain control */ - DT_LEMPTY = 0xc0, - DT_EEMPTY = 0xd0, - DT_LINKFIX = 0x00, - DT_LINK = 0xe0, - DT_EOS = 0xf0, + DT_LEMPTY = 0xc0, + DT_EEMPTY = 0xd0, + DT_LINKFIX = 0x00, + DT_LINK = 0xe0, + DT_EOS = 0xf0, /* HW/SW arbitration */ - DT_FEMPTY = 0x40, - DT_FEMPTY_IS = 0x10, - DT_FEMPTY_IC = 0x20, - DT_FEMPTY_ND = 0x38, + DT_FEMPTY = 0x40, + DT_FEMPTY_IS = 0x10, + DT_FEMPTY_IC = 0x20, + DT_FEMPTY_ND = 0x38, DT_FEMPTY_START = 0x50, - DT_FEMPTY_MID = 0x60, - DT_FEMPTY_END = 0x70, + DT_FEMPTY_MID = 0x60, + DT_FEMPTY_END = 0x70, - DT_MASK = 0xf0, - DIE = 0x08, /* Descriptor Interrupt Enable */ + DT_MASK = 0xf0, + DIE = 0x08, /* Descriptor Interrupt Enable */ }; struct rswitch_desc { __le16 info_ds; /* Descriptor size */ - u8 die_dt; /* Descriptor interrupt enable and type */ - __u8 dptrh; /* Descriptor pointer MSB */ - __le32 dptrl; /* Descriptor pointer LSW */ + u8 die_dt; /* Descriptor interrupt enable and type */ + __u8 dptrh; /* Descriptor pointer MSB */ + __le32 dptrl; /* Descriptor pointer LSW */ } __packed; struct rswitch_rxdesc { @@ -268,6 +263,7 @@ struct rswitch_rxdesc { struct rswitch_port_priv { void __iomem *addr; + struct rswitch_drv_data *drv_data; struct phy serdes; struct rswitch_etha etha; struct rswitch_gwca gwca; @@ -280,7 +276,20 @@ struct rswitch_port_priv { struct rswitch_priv { void __iomem *addr; - struct clk *rsw_clk; + struct clk_bulk rsw_clk; +}; + +struct rswitch_drv_data { + u32 coma_offset; + u32 etha_offset; + u32 gwca_offset; + u32 mpid_mdc_clk; + u8 etha_incr; + u8 gwdcbac_offset; + u8 fwpbfcsdc_offset; + u8 cabpirm_offset; + int ports; + bool is_rsw3; }; static inline void rswitch_flush_dcache(u32 addr, u32 len) @@ -298,36 +307,39 @@ static inline void rswitch_invalidate_dcache(u32 addr, u32 len) static void rswitch_agent_clock_ctrl(struct rswitch_port_priv *priv, int port, int enable) { + struct rswitch_drv_data *drv_data = priv->drv_data; u32 val; if (enable) { - val = readl(priv->addr + RCEC); - if ((val & (RCEC_RCE | BIT(port))) != (RCEC_RCE | BIT(port))) - writel(val | RCEC_RCE | BIT(port), priv->addr + RCEC); + val = readl(priv->addr + drv_data->coma_offset + RCEC); + if ((val & (RCEC_RCE | BIT(port))) != (RCEC_RCE | BIT(port))) { + writel(val | RCEC_RCE | BIT(port), + priv->addr + drv_data->coma_offset + RCEC); + } } else { - setbits_le32(priv->addr + RCDC, BIT(port)); + setbits_le32(priv->addr + drv_data->coma_offset + RCDC, BIT(port)); } } static int rswitch_etha_change_mode(struct rswitch_port_priv *priv, + struct rswitch_etha_io *etha_io, enum rswitch_etha_mode mode) { - struct rswitch_etha *etha = &priv->etha; u32 pval; int ret; /* Enable clock */ - rswitch_agent_clock_ctrl(priv, etha->index, 1); + rswitch_agent_clock_ctrl(priv, etha_io->index, 1); - writel(mode, etha->addr + EAMC); + writel(mode, etha_io->addr + EAMC); - ret = readl_poll_sleep_timeout(etha->addr + EAMS, pval, + ret = readl_poll_sleep_timeout(etha_io->addr + EAMS, pval, (pval & EAMS_OPS_MASK) == mode, RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); /* Disable clock */ if (mode == EAMC_OPC_DISABLE) - rswitch_agent_clock_ctrl(priv, etha->index, 0); + rswitch_agent_clock_ctrl(priv, etha_io->index, 0); return ret; } @@ -355,7 +367,7 @@ static int rswitch_gwca_change_mode(struct rswitch_port_priv *priv, return ret; } -static int rswitch_mii_access_c22(struct rswitch_etha *etha, bool read, +static int rswitch_mii_access_c22(struct rswitch_etha_io *etha_io, bool read, int phyad, int regad, int data) { const u32 pop = read ? MDIO_READ_C22 : MDIO_WRITE_C22; @@ -363,18 +375,18 @@ static int rswitch_mii_access_c22(struct rswitch_etha *etha, bool read, int ret; /* Clear Station Management Mode : Clause 22 */ - clrbits_le32(etha->addr + MPSM, MPSM_MFF_C45); + clrbits_le32(etha_io->addr + MPSM, MPSM_MFF_C45); /* Clear completion flags */ - writel(MMIS1_CLEAR_FLAGS, etha->addr + MMIS1); + writel(MMIS1_CLEAR_FLAGS, etha_io->addr + MMIS1); /* Submit C22 access to PHY */ val = MPSM_PSME | (pop << 13) | (regad << 8) | (phyad << 3); if (!read) val |= data << 16; - writel(val, etha->addr + MPSM); + writel(val, etha_io->addr + MPSM); - ret = readl_poll_sleep_timeout(etha->addr + MPSM, pval, + ret = readl_poll_sleep_timeout(etha_io->addr + MPSM, pval, !(pval & MPSM_PSME), RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); @@ -385,45 +397,45 @@ static int rswitch_mii_access_c22(struct rswitch_etha *etha, bool read, return 0; /* Read data */ - ret = (readl(etha->addr + MPSM) & MPSM_PRD_MASK) >> 16; + ret = (readl(etha_io->addr + MPSM) & MPSM_PRD_MASK) >> 16; /* Clear read completion flag */ - setbits_le32(etha->addr + MMIS1, MMIS1_PRACS); + setbits_le32(etha_io->addr + MMIS1, MMIS1_PRACS); return ret; } -static int rswitch_mii_access_c45(struct rswitch_etha *etha, bool read, +static int rswitch_mii_access_c45(struct rswitch_etha_io *etha_io, bool read, int phyad, int devad, int regad, int data) { u32 pval, val; int ret; /* Set Station Management Mode : Clause 45 */ - setbits_le32(etha->addr + MPSM, MPSM_MFF_C45); + setbits_le32(etha_io->addr + MPSM, MPSM_MFF_C45); /* Clear completion flags */ - writel(MMIS1_CLEAR_FLAGS, etha->addr + MMIS1); + writel(MMIS1_CLEAR_FLAGS, etha_io->addr + MMIS1); /* Submit address to PHY (MDIO_ADDR_C45 << 13) */ val = MPSM_PSME | MPSM_MFF_C45 | (devad << 8) | (phyad << 3); - writel((regad << 16) | val, etha->addr + MPSM); + writel((regad << 16) | val, etha_io->addr + MPSM); - ret = readl_poll_sleep_timeout(etha->addr + MMIS1, pval, + ret = readl_poll_sleep_timeout(etha_io->addr + MMIS1, pval, pval & MMIS1_PAACS, RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); if (ret) return ret; /* Clear address completion flag */ - setbits_le32(etha->addr + MMIS1, MMIS1_PAACS); + setbits_le32(etha_io->addr + MMIS1, MMIS1_PAACS); /* Read/Write PHY register */ if (read) { val |= MDIO_READ_C45 << 13; - writel(val, etha->addr + MPSM); + writel(val, etha_io->addr + MPSM); - ret = readl_poll_sleep_timeout(etha->addr + MMIS1, pval, + ret = readl_poll_sleep_timeout(etha_io->addr + MMIS1, pval, pval & MMIS1_PRACS, RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); @@ -431,16 +443,16 @@ static int rswitch_mii_access_c45(struct rswitch_etha *etha, bool read, return ret; /* Read data */ - ret = (readl(etha->addr + MPSM) & MPSM_PRD_MASK) >> 16; + ret = (readl(etha_io->addr + MPSM) & MPSM_PRD_MASK) >> 16; /* Clear read completion flag */ - setbits_le32(etha->addr + MMIS1, MMIS1_PRACS); + setbits_le32(etha_io->addr + MMIS1, MMIS1_PRACS); } else { val |= MDIO_WRITE_C45 << 13; val |= data << 16; - writel(val, etha->addr + MPSM); + writel(val, etha_io->addr + MPSM); - ret = readl_poll_sleep_timeout(etha->addr + MMIS1, pval, + ret = readl_poll_sleep_timeout(etha_io->addr + MMIS1, pval, pval & MMIS1_PWACS, RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); @@ -453,32 +465,33 @@ static int rswitch_mii_read_c45(struct mii_dev *miidev, int phyad, int devad, in { struct rswitch_port_priv *priv = miidev->priv; struct rswitch_etha *etha = &priv->etha; + struct rswitch_etha_io *etha_mii = ða->mii; int val; /* Change to disable mode */ - rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE); + rswitch_etha_change_mode(priv, etha_mii, EAMC_OPC_DISABLE); /* Change to config mode */ - rswitch_etha_change_mode(priv, EAMC_OPC_CONFIG); + rswitch_etha_change_mode(priv, etha_mii, EAMC_OPC_CONFIG); /* Enable Station Management clock */ - clrsetbits_le32(etha->addr + MPIC, + clrsetbits_le32(etha_mii->addr + MPIC, MPIC_PSMCS_MASK | MPIC_PSMHT_MASK, - MPIC_MDC_CLK_SET); + priv->drv_data->mpid_mdc_clk); /* Access PHY register */ if (devad != MDIO_DEVAD_NONE) /* Definitelly C45 */ - val = rswitch_mii_access_c45(etha, true, phyad, devad, regad, 0); + val = rswitch_mii_access_c45(etha_mii, true, phyad, devad, regad, 0); else if (etha->phydev->is_c45) /* C22 access to C45 PHY */ - val = rswitch_mii_access_c45(etha, true, phyad, 1, regad, 0); + val = rswitch_mii_access_c45(etha_mii, true, phyad, 1, regad, 0); else - val = rswitch_mii_access_c22(etha, true, phyad, regad, 0); + val = rswitch_mii_access_c22(etha_mii, true, phyad, regad, 0); /* Disable Station Management Clock */ - clrbits_le32(etha->addr + MPIC, MPIC_PSMCS_MASK); + clrbits_le32(etha_mii->addr + MPIC, MPIC_PSMCS_MASK); /* Change to disable mode */ - rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE); + rswitch_etha_change_mode(priv, etha_mii, EAMC_OPC_DISABLE); return val; } @@ -487,45 +500,46 @@ int rswitch_mii_write_c45(struct mii_dev *miidev, int phyad, int devad, int rega { struct rswitch_port_priv *priv = miidev->priv; struct rswitch_etha *etha = &priv->etha; + struct rswitch_etha_io *etha_mii = ða->mii; /* Change to disable mode */ - rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE); + rswitch_etha_change_mode(priv, etha_mii, EAMC_OPC_DISABLE); /* Change to config mode */ - rswitch_etha_change_mode(priv, EAMC_OPC_CONFIG); + rswitch_etha_change_mode(priv, etha_mii, EAMC_OPC_CONFIG); /* Enable Station Management clock */ - clrsetbits_le32(etha->addr + MPIC, + clrsetbits_le32(etha_mii->addr + MPIC, MPIC_PSMCS_MASK | MPIC_PSMHT_MASK, - MPIC_MDC_CLK_SET); + priv->drv_data->mpid_mdc_clk); /* Access PHY register */ if (devad != MDIO_DEVAD_NONE) /* Definitelly C45 */ - rswitch_mii_access_c45(etha, false, phyad, devad, regad, data); + rswitch_mii_access_c45(etha_mii, false, phyad, devad, regad, data); else if (etha->phydev->is_c45) /* C22 access to C45 PHY */ - rswitch_mii_access_c45(etha, false, phyad, 1, regad, data); + rswitch_mii_access_c45(etha_mii, false, phyad, 1, regad, data); else - rswitch_mii_access_c22(etha, false, phyad, regad, data); + rswitch_mii_access_c22(etha_mii, false, phyad, regad, data); /* Disable Station Management Clock */ - clrbits_le32(etha->addr + MPIC, MPIC_PSMCS_MASK); + clrbits_le32(etha_mii->addr + MPIC, MPIC_PSMCS_MASK); /* Change to disable mode */ - rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE); + rswitch_etha_change_mode(priv, etha_mii, EAMC_OPC_DISABLE); return 0; } -static int rswitch_check_link(struct rswitch_etha *etha) +static int rswitch_check_link(struct rswitch_etha_io *etha_serdes) { u32 pval; int ret; /* Request Link Verification */ - writel(MLVC_PLV, etha->addr + MLVC); + writel(MLVC_PLV, etha_serdes->addr + MLVC); /* Complete Link Verification */ - ret = readl_poll_sleep_timeout(etha->addr + MLVC, pval, + ret = readl_poll_sleep_timeout(etha_serdes->addr + MLVC, pval, !(pval & MLVC_PLV), RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); if (ret) { @@ -538,16 +552,21 @@ static int rswitch_check_link(struct rswitch_etha *etha) static int rswitch_reset(struct rswitch_port_priv *priv) { + struct rswitch_drv_data *drv_data = priv->drv_data; int ret; - setbits_le32(priv->addr + RRC, RRC_RR); - clrbits_le32(priv->addr + RRC, RRC_RR); + setbits_le32(priv->addr + drv_data->coma_offset + RRC, RRC_RR); + clrbits_le32(priv->addr + drv_data->coma_offset + RRC, RRC_RR); ret = rswitch_gwca_change_mode(priv, GWMC_OPC_DISABLE); if (ret) return ret; - ret = rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE); + ret = rswitch_etha_change_mode(priv, &priv->etha.serdes, EAMC_OPC_DISABLE); + if (ret) + return ret; + + ret = rswitch_etha_change_mode(priv, &priv->etha.mii, EAMC_OPC_DISABLE); if (ret) return ret; @@ -609,7 +628,7 @@ static void rswitch_rx_desc_init(struct rswitch_port_priv *priv) priv->rx_desc_index = 0; for (i = 0; i < RSWITCH_NUM_RX_DESC; i++) { - priv->rx_desc[i].data.die_dt = DT_EEMPTY; + priv->rx_desc[i].data.die_dt = DT_FEMPTY; priv->rx_desc[i].data.info_ds = PKTSIZE_ALIGN; packet_addr = (uintptr_t)priv->rx_desc[i].packet; priv->rx_desc[i].data.dptrl = lower_32_bits(packet_addr); @@ -638,20 +657,26 @@ static void rswitch_rx_desc_init(struct rswitch_port_priv *priv) static void rswitch_clock_enable(struct rswitch_port_priv *priv) { + struct rswitch_drv_data *drv_data = priv->drv_data; struct rswitch_etha *etha = &priv->etha; struct rswitch_gwca *gwca = &priv->gwca; + int etha_index = etha->serdes.index; - setbits_le32(priv->addr + RCEC, BIT(etha->index) | BIT(gwca->index) | RCEC_RCE); + setbits_le32(priv->addr + drv_data->coma_offset + RCEC, + BIT(etha_index) | BIT(gwca->index) | RCEC_RCE); } static int rswitch_bpool_init(struct rswitch_port_priv *priv) { + struct rswitch_drv_data *drv_data = priv->drv_data; u32 pval; - writel(CABPIRM_BPIOG, priv->addr + CABPIRM); + writel(CABPIRM_BPIOG, priv->addr + drv_data->coma_offset + + CABPIRM + drv_data->cabpirm_offset); - return readl_poll_sleep_timeout(priv->addr + CABPIRM, pval, - pval & CABPIRM_BPR, + return readl_poll_sleep_timeout(priv->addr + drv_data->coma_offset + + CABPIRM + drv_data->cabpirm_offset, + pval, pval & CABPIRM_BPR, RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); } @@ -659,34 +684,39 @@ static void rswitch_mfwd_init(struct rswitch_port_priv *priv) { struct rswitch_etha *etha = &priv->etha; struct rswitch_gwca *gwca = &priv->gwca; + int gwca_index = HW_INDEX_TO_GWCA(gwca->index, priv->drv_data->ports); + int etha_index = etha->serdes.index; - writel(FWPC0_DEFAULT, priv->addr + FWPC0(etha->index)); + writel(FWPC0_DEFAULT, priv->addr + FWPC0(etha_index)); writel(FWPC0_DEFAULT, priv->addr + FWPC0(gwca->index)); writel(RSWITCH_RX_CHAIN_INDEX, - priv->addr + FWPBFCSDC(HW_INDEX_TO_GWCA(gwca->index), etha->index)); + priv->addr + FWPBFCSDC(priv->drv_data->fwpbfcsdc_offset, + gwca_index, etha_index, + priv->drv_data->etha_incr)); writel(BIT(gwca->index), - priv->addr + FWPBFC(etha->index)); + priv->addr + FWPBFC(etha_index)); - writel(BIT(etha->index), + writel(BIT(etha_index), priv->addr + FWPBFC(gwca->index)); } static void rswitch_rmac_init(struct rswitch_etha *etha) { + struct rswitch_etha_io *etha_serdes = ða->serdes; unsigned char *mac = etha->enetaddr; /* Set MAC address */ - writel((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5], - etha->addr + MRMAC1); + writel((mac[0] << 8) | mac[1], etha_serdes->addr + MRMAC0); - writel((mac[0] << 8) | mac[1], etha->addr + MRMAC0); + writel((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5], + etha_serdes->addr + MRMAC1); /* Set MIIx */ - writel(MPIC_PIS_GMII | MPIC_LSC_1000, etha->addr + MPIC); + writel(MPIC_PIS_GMII | MPIC_LSC_1000, etha_serdes->addr + MPIC); - writel(0x07E707E7, etha->addr + MRAFC); + writel(0x07E707E7, etha_serdes->addr + MRAFC); } static int rswitch_gwca_mcast_table_reset(struct rswitch_gwca *gwca) @@ -735,11 +765,17 @@ static int rswitch_gwca_init(struct rswitch_port_priv *priv) /* Setting flow */ writel(GWVCC_VEM_SC_TAG, gwca->addr + GWVCC); writel(0, gwca->addr + GWTTFC); - writel(upper_32_bits((uintptr_t)priv->bat_desc) & GWDCBAC0_DCBAUP, gwca->addr + GWDCBAC0); - writel(lower_32_bits((uintptr_t)priv->bat_desc), gwca->addr + GWDCBAC1); + writel(upper_32_bits((uintptr_t)priv->bat_desc) & GWDCBAC0_DCBAUP, + gwca->addr + GWDCBAC0 + priv->drv_data->gwdcbac_offset); + writel(lower_32_bits((uintptr_t)priv->bat_desc), + gwca->addr + GWDCBAC1 + priv->drv_data->gwdcbac_offset); writel(GWDCC_DQT | GWDCC_BALR, gwca->addr + GWDCC(RSWITCH_TX_CHAIN_INDEX)); writel(GWDCC_BALR, gwca->addr + GWDCC(RSWITCH_RX_CHAIN_INDEX)); + /* Enable Under Switch Minimum Frame Size Padding */ + if (priv->drv_data->is_rsw3) + writel(GWCKSC_USMFSPE, gwca->addr + GWCKSC); + ret = rswitch_gwca_change_mode(priv, GWMC_OPC_DISABLE); if (ret) return ret; @@ -751,13 +787,13 @@ static int rswitch_gwca_init(struct rswitch_port_priv *priv) return 0; } -static int rswitch_etha_tas_ram_reset(struct rswitch_etha *etha) +static int rswitch_etha_tas_ram_reset(struct rswitch_etha_io *etha_serdes) { u32 pval; - writel(EATASRIRM_TASRIOG, etha->addr + EATASRIRM); + writel(EATASRIRM_TASRIOG, etha_serdes->addr + EATASRIRM); - return readl_poll_sleep_timeout(etha->addr + EATASRIRM, pval, + return readl_poll_sleep_timeout(etha_serdes->addr + EATASRIRM, pval, pval & EATASRIRM_TASRR, RSWITCH_SLEEP_US, RSWITCH_TIMEOUT_US); } @@ -765,35 +801,43 @@ static int rswitch_etha_tas_ram_reset(struct rswitch_etha *etha) static int rswitch_etha_init(struct rswitch_port_priv *priv) { struct rswitch_etha *etha = &priv->etha; + struct rswitch_etha_io *etha_serdes = ða->serdes; int ret; u32 prio; - ret = rswitch_etha_change_mode(priv, EAMC_OPC_DISABLE); + ret = rswitch_etha_change_mode(priv, etha_serdes, EAMC_OPC_DISABLE); if (ret) return ret; - ret = rswitch_etha_change_mode(priv, EAMC_OPC_CONFIG); + ret = rswitch_etha_change_mode(priv, etha_serdes, EAMC_OPC_CONFIG); if (ret) return ret; - ret = rswitch_etha_tas_ram_reset(etha); + ret = rswitch_etha_tas_ram_reset(etha_serdes); if (ret) return ret; /* Setting flow */ - writel(0, etha->addr + EATTFC); + writel(0, etha_serdes->addr + EATTFC); for (prio = 0; prio < RSWITCH_MAX_CTAG_PCP; prio++) - writel(EATDQDC_DQD, etha->addr + EATDQDC(prio)); + writel(EATDQDC_DQD, etha_serdes->addr + EATDQDC(prio)); rswitch_rmac_init(etha); - ret = rswitch_etha_change_mode(priv, EAMC_OPC_OPERATION); + if (etha->xpcs) { + if (etha_serdes->index >= 5 && etha_serdes->index <= 7) + writel(MIOC_BIT3_SET, etha_serdes->addr + MIOC); + else + printf("RSW: Invalid port %d\n", etha_serdes->index); + } + + ret = rswitch_etha_change_mode(priv, etha_serdes, EAMC_OPC_OPERATION); if (ret) return ret; /* Link Verification */ - ret = rswitch_check_link(etha); + ret = rswitch_check_link(etha_serdes); if (ret) return ret; @@ -958,13 +1002,14 @@ static int rswitch_write_hwaddr(struct udevice *dev) { struct rswitch_port_priv *priv = dev_get_priv(dev); struct rswitch_etha *etha = &priv->etha; + struct rswitch_etha_io *etha_serdes = ða->serdes; struct eth_pdata *pdata = dev_get_plat(dev); unsigned char *mac = pdata->enetaddr; writel((mac[2] << 24) | (mac[3] << 16) | (mac[4] << 8) | mac[5], - etha->addr + MRMAC1); + etha_serdes->addr + MRMAC1); - writel((mac[0] << 8) | mac[1], etha->addr + MRMAC0); + writel((mac[0] << 8) | mac[1], etha_serdes->addr + MRMAC0); return 0; } @@ -1005,19 +1050,29 @@ static int rswitch_port_probe(struct udevice *dev) int ret; priv->addr = rpriv->addr; + priv->drv_data = (void *)dev_get_driver_data(dev->parent); + + ret = generic_phy_get_by_index(dev, 0, &priv->serdes); + if (ret) + return ret; + + if (priv->drv_data->is_rsw3) { + etha->xpcs = device_is_compatible(priv->serdes.dev, + "renesas,r8a78000-ether-pcs"); + } etha->enetaddr = pdata->enetaddr; - etha->index = dev_read_u32_default(dev, "reg", 0); - etha->addr = priv->addr + RSWITCH_ETHA_OFFSET + etha->index * RSWITCH_ETHA_SIZE; + etha->mii.index = dev_read_u32_default(dev, "reg", 0); + etha->serdes.index = priv->serdes.id; + etha->mii.addr = priv->addr + priv->drv_data->etha_offset + + etha->mii.index * RSWITCH_ETHA_SIZE; + etha->serdes.addr = priv->addr + priv->drv_data->etha_offset + + etha->serdes.index * RSWITCH_ETHA_SIZE; gwca->index = 1; - gwca->addr = priv->addr + RSWITCH_GWCA_OFFSET + gwca->index * RSWITCH_GWCA_SIZE; - gwca->index = GWCA_TO_HW_INDEX(gwca->index); - - ret = generic_phy_get_by_index(dev, 0, &priv->serdes); - if (ret) - return ret; + gwca->addr = priv->addr + priv->drv_data->gwca_offset + gwca->index * RSWITCH_GWCA_SIZE; + gwca->index = GWCA_TO_HW_INDEX(gwca->index, priv->drv_data->ports); /* Toggle the reset so we can access the PHYs */ ret = rswitch_reset(priv); @@ -1109,13 +1164,11 @@ static int rswitch_probe(struct udevice *dev) if (!priv->addr) return -EINVAL; - priv->rsw_clk = devm_clk_get(dev, NULL); - if (IS_ERR(priv->rsw_clk)) { - ret = PTR_ERR(priv->rsw_clk); + ret = clk_get_bulk(dev, &priv->rsw_clk); + if (ret < 0) goto err_map; - } - ret = clk_prepare_enable(priv->rsw_clk); + ret = clk_enable_bulk(&priv->rsw_clk); if (ret) goto err_map; @@ -1130,7 +1183,7 @@ static int rswitch_remove(struct udevice *dev) { struct rswitch_priv *priv = dev_get_plat(dev); - clk_disable_unprepare(priv->rsw_clk); + clk_disable_bulk(&priv->rsw_clk); unmap_physmem(priv->addr, MAP_NOCACHE); return 0; @@ -1166,8 +1219,34 @@ static int rswitch_bind(struct udevice *parent) return 0; } +static const struct rswitch_drv_data r8a779f0_drv_data = { + .ports = 3, + .coma_offset = 0x9000, + .etha_offset = 0xa000, + .gwca_offset = 0x10000, + .mpid_mdc_clk = 0x06050000, + .etha_incr = 0x10, + .gwdcbac_offset = 0x0, + .fwpbfcsdc_offset = 0x0, + .cabpirm_offset = 0x0, +}; + +static const struct rswitch_drv_data r8a78000_drv_data = { + .ports = 13, + .coma_offset = 0x1c000, + .etha_offset = 0x1d000, + .gwca_offset = 0x37000, + .mpid_mdc_clk = 0x060c0000, + .etha_incr = 0x20, + .gwdcbac_offset = 0x50, + .fwpbfcsdc_offset = 0xfc, + .cabpirm_offset = 0x20, + .is_rsw3 = true, +}; + static const struct udevice_id rswitch_ids[] = { - { .compatible = "renesas,r8a779f0-ether-switch" }, + { .compatible = "renesas,r8a779f0-ether-switch", .data = (ulong)&r8a779f0_drv_data }, + { .compatible = "renesas,r8a78000-ether-switch3", .data = (ulong)&r8a78000_drv_data }, { } }; diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index 8433e7db265..41c52f56d7a 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -57,10 +57,9 @@ #define TX_TOTAL_BUFSIZE (CFG_ETH_BUFSIZE * CFG_TX_DESCR_NUM) #define RX_TOTAL_BUFSIZE (CFG_ETH_BUFSIZE * CFG_RX_DESCR_NUM) -#define H3_EPHY_DEFAULT_VALUE 0x58000 -#define H3_EPHY_DEFAULT_MASK GENMASK(31, 15) #define H3_EPHY_ADDR_SHIFT 20 #define REG_PHY_ADDR_MASK GENMASK(4, 0) +#define H3_EPHY_CLK_SEL BIT(18) /* 1: 24MHz, 0: 25MHz */ #define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */ #define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */ #define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */ @@ -176,6 +175,7 @@ struct sun8i_eth_pdata { u32 reset_delays[3]; int tx_delay_ps; int rx_delay_ps; + bool leds_active_low; }; static int sun8i_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) @@ -287,34 +287,24 @@ static void sun8i_adjust_link(struct emac_eth_dev *priv, writel(v, priv->mac_reg + EMAC_CTL0); } -static u32 sun8i_emac_set_syscon_ephy(struct emac_eth_dev *priv, u32 reg) +static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata, + struct emac_eth_dev *priv) { + u32 reg = 0; + if (priv->use_internal_phy) { /* H3 based SoC's that has an Internal 100MBit PHY * needs to be configured and powered up before use */ - reg &= ~H3_EPHY_DEFAULT_MASK; - reg |= H3_EPHY_DEFAULT_VALUE; reg |= priv->phyaddr << H3_EPHY_ADDR_SHIFT; - reg &= ~H3_EPHY_SHUTDOWN; - return reg | H3_EPHY_SELECT; - } - - /* This is to select External Gigabit PHY on those boards with - * an internal PHY. Does not hurt on other SoCs. Linux does - * it as well. - */ - return reg & ~H3_EPHY_SELECT; -} + reg |= H3_EPHY_CLK_SEL; + reg |= H3_EPHY_SELECT; -static int sun8i_emac_set_syscon(struct sun8i_eth_pdata *pdata, - struct emac_eth_dev *priv) -{ - u32 reg; - - reg = readl(priv->sysctl_reg); - - reg = sun8i_emac_set_syscon_ephy(priv, reg); + if (pdata->leds_active_low) + reg |= H3_EPHY_LED_POL; + } else { + reg |= H3_EPHY_SHUTDOWN; + } reg &= ~(SC_ETCS_MASK | SC_EPIT); if (priv->variant->support_rmii) @@ -859,6 +849,10 @@ static int sun8i_emac_eth_of_to_plat(struct udevice *dev) printf("%s: Invalid RX delay value %d\n", __func__, sun8i_pdata->rx_delay_ps); + sun8i_pdata->leds_active_low = + fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), + "allwinner,leds-active-low"); + if (fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), "snps,reset-active-low")) reset_flags |= GPIOD_ACTIVE_LOW; diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c index 2aa7e5e3a30..7a88f76fd09 100644 --- a/drivers/net/ti/am65-cpsw-nuss.c +++ b/drivers/net/ti/am65-cpsw-nuss.c @@ -234,14 +234,11 @@ out: #define AM65_GMII_SEL_MODE_RGMII 2 #define AM65_GMII_SEL_MODE_SGMII 3 -#define AM65_GMII_SEL_RGMII_IDMODE BIT(4) - static int am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv, phy_interface_t phy_mode) { struct udevice *dev = priv->dev; u32 offset, reg, phandle; - bool rgmii_id = false; fdt_addr_t gmii_sel; u32 mode = 0; ofnode node; @@ -278,12 +275,6 @@ static int am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv, mode = AM65_GMII_SEL_MODE_RGMII; break; - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_TXID: - mode = AM65_GMII_SEL_MODE_RGMII; - rgmii_id = true; - break; - case PHY_INTERFACE_MODE_SGMII: mode = AM65_GMII_SEL_MODE_SGMII; break; @@ -298,9 +289,6 @@ static int am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv, break; }; - if (rgmii_id) - mode |= AM65_GMII_SEL_RGMII_IDMODE; - reg = mode; dev_dbg(dev, "gmii_sel PHY mode: %u, new gmii_sel: %08x\n", phy_mode, reg); @@ -630,7 +618,7 @@ static int am65_cpsw_phy_init(struct udevice *dev) u32 supported = PHY_GBIT_FEATURES; int ret = 0; - phydev = dm_eth_phy_connect(dev); + phydev = dm_eth_phy_connect_interface(dev, pdata->phy_interface); if (!phydev) { dev_err(dev, "phy_connect() failed\n"); return -ENODEV; @@ -657,9 +645,28 @@ static int am65_cpsw_ofdata_parse_phy(struct udevice *dev) dev_read_u32(dev, "reg", &priv->port_id); pdata->phy_interface = dev_read_phy_mode(dev); - if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) { + + /* CPSW controllers supported by this driver have a fixed internal TX + * delay in RGMII mode. Fix up PHY mode to account for this and warn + * about Device Trees that claim to have a TX delay on the PCB. + */ + switch (pdata->phy_interface) { + case PHY_INTERFACE_MODE_RGMII_ID: + pdata->phy_interface = PHY_INTERFACE_MODE_RGMII_RXID; + break; + case PHY_INTERFACE_MODE_RGMII_TXID: + pdata->phy_interface = PHY_INTERFACE_MODE_RGMII; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_RXID: + dev_warn(dev, + "RGMII mode without internal TX delay unsupported; please fix your Device Tree\n"); + break; + case PHY_INTERFACE_MODE_NA: dev_err(dev, "Invalid PHY mode, port %u\n", priv->port_id); return -EINVAL; + default: + break; } dev_read_u32(dev, "max-speed", (u32 *)&pdata->max_speed); diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c index 22e119370c8..fb48feb4469 100644 --- a/drivers/net/xilinx_axi_emac.c +++ b/drivers/net/xilinx_axi_emac.c @@ -619,11 +619,11 @@ static int axiemac_start(struct udevice *dev) #endif rx_bd.cntrl = sizeof(rxframe); /* Flush the last BD so DMA core could see the updates */ - flush_cache((phys_addr_t)&rx_bd, sizeof(rx_bd)); + flush_cache((phys_addr_t)(uintptr_t)&rx_bd, sizeof(rx_bd)); /* It is necessary to flush rxframe because if you don't do it * then cache can contain uninitialized data */ - flush_cache((phys_addr_t)&rxframe, sizeof(rxframe)); + flush_cache((phys_addr_t)(uintptr_t)&rxframe, sizeof(rxframe)); /* Start the hardware */ temp = readl(&priv->dmarx->control); @@ -675,7 +675,7 @@ static int axiemac_send(struct udevice *dev, void *ptr, int len) } /* Flush packet to main memory to be trasfered by DMA */ - flush_cache((phys_addr_t)ptr, len); + flush_cache((phys_addr_t)(uintptr_t)ptr, len); /* Setup Tx BD */ memset(&tx_bd, 0, sizeof(tx_bd)); @@ -691,7 +691,7 @@ static int axiemac_send(struct udevice *dev, void *ptr, int len) XAXIDMA_BD_CTRL_TXEOF_MASK; /* Flush the last BD so DMA core could see the updates */ - flush_cache((phys_addr_t)&tx_bd, sizeof(tx_bd)); + flush_cache((phys_addr_t)(uintptr_t)&tx_bd, sizeof(tx_bd)); if (readl(&priv->dmatx->status) & XAXIDMA_HALTED_MASK) { u32 temp; @@ -791,11 +791,11 @@ static int axiemac_free_pkt(struct udevice *dev, uchar *packet, int length) rx_bd.cntrl = sizeof(rxframe); /* Write bd to HW */ - flush_cache((phys_addr_t)&rx_bd, sizeof(rx_bd)); + flush_cache((phys_addr_t)(uintptr_t)&rx_bd, sizeof(rx_bd)); /* It is necessary to flush rxframe because if you don't do it * then cache will contain previous packet */ - flush_cache((phys_addr_t)&rxframe, sizeof(rxframe)); + flush_cache((phys_addr_t)(uintptr_t)&rxframe, sizeof(rxframe)); /* Rx BD is ready - start again */ axienet_dma_write(&rx_bd, &priv->dmarx->tail); @@ -831,10 +831,10 @@ static int axi_emac_probe(struct udevice *dev) struct axidma_priv *priv = dev_get_priv(dev); int ret; - priv->iobase = (struct axi_regs *)pdata->iobase; + priv->iobase = (struct axi_regs *)(uintptr_t)pdata->iobase; priv->dmatx = plat->dmatx; /* RX channel offset is 0x30 */ - priv->dmarx = (struct axidma_reg *)((phys_addr_t)priv->dmatx + 0x30); + priv->dmarx = (struct axidma_reg *)((uintptr_t)priv->dmatx + 0x30); priv->mactype = plat->mactype; if (priv->mactype == EMAC_1G) { diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 703e22479d2..407b022508c 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -162,7 +162,9 @@ struct zynq_gem_regs { u32 idr; /* 0x2c - Interrupt Disable reg */ u32 reserved3; u32 phymntnc; /* 0x34 - Phy Maintaince reg */ - u32 reserved4[18]; + u32 reserved4[6]; + u32 hsmaccfg; /* 0x50 - HS MAC Config reg */ + u32 reserved5[11]; u32 hashl; /* 0x80 - Hash Low address reg */ u32 hashh; /* 0x84 - Hash High address reg */ #define LADDR_LOW 0 @@ -185,6 +187,10 @@ struct zynq_gem_regs { u32 upper_txqbase; /* 0x4C8 - Upper tx_q base addr */ u32 reserved11[2]; u32 upper_rxqbase; /* 0x4D4 - Upper rx_q base addr */ + u32 reserved13[362]; + u32 usxctrlreg; /* 0xA80 - Usx Control reg */ + u32 reserved14; + u32 usxstatusreg; /* 0xA88 - Usx Status reg */ }; /* BD descriptors */ @@ -209,6 +215,27 @@ struct emac_bd { /* Setup the first free TX descriptor */ #define TX_FREE_DESC 2 +#define HS_SPEED_1000M 1 +#define HS_SPEED_2500M 2 +#define HS_SPEED_5000M 3 +#define HS_SPEED_10000M 4 +#define MACB_SERDES_RATE_5G_2G5_1G 0 +#define MACB_SERDES_RATE_10G 1 +#define USX_BLOCK_LOCK BIT(0) +#define TX_SCR_BYPASS BIT(8) +#define RX_SCR_BYPASS BIT(9) +#define RX_SYNC_RESET BIT(2) +#define SPEED_5000 5000 +#define TX_EN BIT(1) +#define SIGNAL_OK BIT(0) +#define ENABLE_HS_MAC BIT(31) +#define PCSSEL BIT(11) +#define HS_MAC_SPEED_MASK 0x3 +#define USX_CONFIG_SERDES_RATE_MASK 0x3 +#define USX_CONFIG_SERDES_RATE_SHIFT 12 +#define USX_CONFIG_SPEED_MASK 0x3 +#define USX_CONFIG_SPEED_SHIFT 14 + /* Initialized, rxbd_current, rx_first_buf must be 0 after init */ struct zynq_gem_priv { struct emac_bd *tx_bd; @@ -391,9 +418,11 @@ static int zynq_phy_init(struct udevice *dev) static int zynq_gem_init(struct udevice *dev) { - u32 i, nwconfig, nwcfg; int ret; + u32 i, nwconfig, nwcfg, ctrl, ncr; unsigned long clk_rate = 0; + unsigned long speed_val, serdes_rate, config; + unsigned long clear_speed_val_mask, clear_serdes_rate_mask; struct zynq_gem_priv *priv = dev_get_priv(dev); struct zynq_gem_regs *regs = priv->iobase; struct zynq_gem_regs *regs_mdio = priv->mdiobase; @@ -499,6 +528,67 @@ static int zynq_gem_init(struct udevice *dev) nwconfig = ZYNQ_GEM_NWCFG_INIT; + if (device_is_compatible(dev, "amd,versal2-10gbe")) { + if (priv->interface == PHY_INTERFACE_MODE_10GBASER) { + ctrl = readl(®s->nwcfg); + ctrl |= PCSSEL; + writel(ctrl, ®s->nwcfg); + ncr = readl(®s->nwctrl); + ncr |= ENABLE_HS_MAC; + writel(ncr, ®s->nwctrl); + } + switch (priv->phydev->speed) { + case SPEED_1000: + speed_val = HS_SPEED_1000M; + serdes_rate = MACB_SERDES_RATE_5G_2G5_1G; + break; + case SPEED_2500: + speed_val = HS_SPEED_2500M; + serdes_rate = MACB_SERDES_RATE_5G_2G5_1G; + break; + case SPEED_5000: + speed_val = HS_SPEED_5000M; + serdes_rate = MACB_SERDES_RATE_5G_2G5_1G; + break; + case SPEED_10000: + speed_val = HS_SPEED_10000M; + serdes_rate = MACB_SERDES_RATE_10G; + break; + default: + printf("Specified speed not supported =%d\n", priv->phydev->speed); + break; + } + + config = readl(®s->hsmaccfg); + config = (config & ~HS_MAC_SPEED_MASK) | speed_val; + writel(config, ®s->hsmaccfg); + + config = readl(®s->usxctrlreg); + config |= SIGNAL_OK; + clear_serdes_rate_mask = ~(USX_CONFIG_SERDES_RATE_MASK << + USX_CONFIG_SERDES_RATE_SHIFT); + config = (config & clear_serdes_rate_mask) | + serdes_rate << USX_CONFIG_SERDES_RATE_SHIFT; + + clear_speed_val_mask = ~(USX_CONFIG_SPEED_MASK << + USX_CONFIG_SPEED_SHIFT); + config = (config & clear_speed_val_mask) | + speed_val << USX_CONFIG_SPEED_SHIFT; + config &= ~(TX_SCR_BYPASS | RX_SCR_BYPASS); + config |= RX_SYNC_RESET; + writel(config, ®s->usxctrlreg); + + mdelay(250); + config &= ~(RX_SYNC_RESET); + config |= (TX_EN); + writel(config, ®s->usxctrlreg); + + ret = wait_for_bit_le32(®s->usxstatusreg, USX_BLOCK_LOCK, + true, 20000, true); + if (ret) + printf("usx block lock failed\n"); + } + /* * Set SGMII enable PCS selection only if internal PCS/PMA * core is used and interface is SGMII. @@ -997,6 +1087,7 @@ static int zynq_gem_of_to_plat(struct udevice *dev) } static const struct udevice_id zynq_gem_ids[] = { + { .compatible = "amd,versal2-10gbe" }, { .compatible = "xlnx,versal-gem", .data = RXCLK_EN }, { .compatible = "cdns,versal-gem", .data = RXCLK_EN }, { .compatible = "xlnx,zynqmp-gem" }, diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 6c2cda1a966..ea9868425d0 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -333,12 +333,6 @@ config PCIE_IMX bool "i.MX PCIe support" depends on ARCH_MX6 -config PCIE_INTEL_FPGA - bool "Intel FPGA PCIe support" - help - Say Y here if you want to enable PCIe controller support on Intel - FPGA, example Stratix 10. - config PCIE_IPROC bool "Iproc PCIe support" help diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index a0420e733ed..98f3c226f63 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -40,7 +40,6 @@ obj-$(CONFIG_PCIE_LAYERSCAPE_GEN4) += pcie_layerscape_gen4.o \ pcie_layerscape_fixup_common.o obj-$(CONFIG_PCI_XILINX) += pcie_xilinx.o obj-$(CONFIG_PCI_PHYTIUM) += pcie_phytium.o -obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o obj-$(CONFIG_PCIE_DW_COMMON) += pcie_dw_common.o obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o diff --git a/drivers/pci/pci-rcar-gen4.c b/drivers/pci/pci-rcar-gen4.c index 41f0d958447..e165271f58c 100644 --- a/drivers/pci/pci-rcar-gen4.c +++ b/drivers/pci/pci-rcar-gen4.c @@ -243,7 +243,7 @@ static int rcar_gen4_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable clrbits_le32(rcar->app_base + PCIERSTCTRL1, APP_HOLD_PHY_RST); - ret = readl_poll_timeout(rcar->phy_base + 0x0f8, val, !(val & BIT(18)), 10000); + ret = readl_poll_timeout(rcar->phy_base + 0x0f8, val, val & BIT(18), 10000); if (ret < 0) return ret; @@ -306,6 +306,8 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar) if (ret) goto err_unprepare; + mdelay(1); + setbits_le32(rcar->app_base + PCIEMSR0, DEVICE_TYPE_RC | ((rcar->num_lanes < 4) ? BIFUR_MOD_SET_ON : 0)); @@ -314,6 +316,9 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar) if (ret) goto err_unprepare; + reset_status(&rcar->pwr_rst); + mdelay(1); + rcar_gen4_pcie_additional_common_init(rcar); return 0; @@ -472,6 +477,10 @@ static int rcar_gen4_pcie_probe(struct udevice *dev) if (!rcar_gen4_pcie_link_up(rcar)) { printf("PCIE-%d: Link down\n", dev_seq(dev)); + rcar_gen4_pcie_ltssm_control(rcar, false); + dm_gpio_set_value(&rcar->pe_rst, 1); + reset_assert(&rcar->pwr_rst); + clk_disable_unprepare(rcar->ref_clk); return -ENODEV; } @@ -489,6 +498,26 @@ static int rcar_gen4_pcie_probe(struct udevice *dev) } /** + * rcar_gen4_pcie_remove() - Stop the PCIe bus active link + * @dev: A pointer to the device being operated on + * + * Stop an active link on the PCIe bus and deconfigure the controller. + * + * Return: 0 on success, else -ENODEV + */ +static int rcar_gen4_pcie_remove(struct udevice *dev) +{ + struct rcar_gen4_pcie *rcar = dev_get_priv(dev); + + rcar_gen4_pcie_ltssm_control(rcar, false); + dm_gpio_set_value(&rcar->pe_rst, 1); + reset_assert(&rcar->pwr_rst); + clk_disable_unprepare(rcar->ref_clk); + + return 0; +} + +/** * rcar_gen4_pcie_of_to_plat() - Translate from DT to device state * * @dev: A pointer to the device being operated on @@ -561,5 +590,7 @@ U_BOOT_DRIVER(rcar_gen4_pcie) = { .ops = &rcar_gen4_pcie_ops, .of_to_plat = rcar_gen4_pcie_of_to_plat, .probe = rcar_gen4_pcie_probe, + .remove = rcar_gen4_pcie_remove, .priv_auto = sizeof(struct rcar_gen4_pcie), + .flags = DM_FLAG_ACTIVE_DMA, }; diff --git a/drivers/pci/pci_mvebu.c b/drivers/pci/pci_mvebu.c index 77815513b76..3985bd59607 100644 --- a/drivers/pci/pci_mvebu.c +++ b/drivers/pci/pci_mvebu.c @@ -763,6 +763,7 @@ static int mvebu_pcie_bind(struct udevice *parent) pcie->mem.start = mem.start; pcie->mem.end = mem.start + SZ_128M - 1; mem.start += SZ_128M; + mem.end = mem.start + SZ_128M - 1; } else { printf("%s: unable to assign mbus window for mem\n", pcie->name); pcie->mem.start = 0; @@ -773,6 +774,7 @@ static int mvebu_pcie_bind(struct udevice *parent) pcie->io.start = io.start; pcie->io.end = io.start + SZ_64K - 1; io.start += SZ_64K; + io.end = io.start + SZ_64K - 1; } else { printf("%s: unable to assign mbus window for io\n", pcie->name); pcie->io.start = 0; diff --git a/drivers/pci/pcie_intel_fpga.c b/drivers/pci/pcie_intel_fpga.c deleted file mode 100644 index 959fd369086..00000000000 --- a/drivers/pci/pcie_intel_fpga.c +++ /dev/null @@ -1,434 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel FPGA PCIe host controller driver - * - * Copyright (C) 2013-2018 Intel Corporation. All rights reserved - * - */ - -#include <dm.h> -#include <pci.h> -#include <asm/global_data.h> -#include <asm/io.h> -#include <dm/device_compat.h> -#include <linux/bitops.h> -#include <linux/delay.h> - -#define RP_TX_REG0 0x2000 -#define RP_TX_CNTRL 0x2004 -#define RP_TX_SOP BIT(0) -#define RP_TX_EOP BIT(1) -#define RP_RXCPL_STATUS 0x200C -#define RP_RXCPL_SOP BIT(0) -#define RP_RXCPL_EOP BIT(1) -#define RP_RXCPL_REG 0x2008 -#define P2A_INT_STATUS 0x3060 -#define P2A_INT_STS_ALL 0xf -#define P2A_INT_ENABLE 0x3070 -#define RP_CAP_OFFSET 0x70 - -/* TLP configuration type 0 and 1 */ -#define TLP_FMTTYPE_CFGRD0 0x04 /* Configuration Read Type 0 */ -#define TLP_FMTTYPE_CFGWR0 0x44 /* Configuration Write Type 0 */ -#define TLP_FMTTYPE_CFGRD1 0x05 /* Configuration Read Type 1 */ -#define TLP_FMTTYPE_CFGWR1 0x45 /* Configuration Write Type 1 */ -#define TLP_PAYLOAD_SIZE 0x01 -#define TLP_READ_TAG 0x1d -#define TLP_WRITE_TAG 0x10 -#define RP_DEVFN 0 - -#define RP_CFG_ADDR(pcie, reg) \ - ((pcie->hip_base) + (reg) + (1 << 20)) -#define RP_SECONDARY(pcie) \ - readb(RP_CFG_ADDR(pcie, PCI_SECONDARY_BUS)) -#define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn)) - -#define TLP_CFGRD_DW0(pcie, bus) \ - ((((bus > RP_SECONDARY(pcie)) ? TLP_FMTTYPE_CFGRD1 \ - : TLP_FMTTYPE_CFGRD0) << 24) | \ - TLP_PAYLOAD_SIZE) - -#define TLP_CFGWR_DW0(pcie, bus) \ - ((((bus > RP_SECONDARY(pcie)) ? TLP_FMTTYPE_CFGWR1 \ - : TLP_FMTTYPE_CFGWR0) << 24) | \ - TLP_PAYLOAD_SIZE) - -#define TLP_CFG_DW1(pcie, tag, be) \ - (((TLP_REQ_ID(pcie->first_busno, RP_DEVFN)) << 16) | (tag << 8) | (be)) -#define TLP_CFG_DW2(bus, dev, fn, offset) \ - (((bus) << 24) | ((dev) << 19) | ((fn) << 16) | (offset)) - -#define TLP_COMP_STATUS(s) (((s) >> 13) & 7) -#define TLP_BYTE_COUNT(s) (((s) >> 0) & 0xfff) -#define TLP_HDR_SIZE 3 -#define TLP_LOOP 20000 -#define DWORD_MASK 3 - -#define IS_ROOT_PORT(pcie, bdf) \ - ((PCI_BUS(bdf) == pcie->first_busno) ? true : false) - -/** - * struct intel_fpga_pcie - Intel FPGA PCIe controller state - * @bus: Pointer to the PCI bus - * @cra_base: The base address of CRA register space - * @hip_base: The base address of Rootport configuration space - * @first_busno: This driver supports multiple PCIe controllers. - * first_busno stores the bus number of the PCIe root-port - * number which may vary depending on the PCIe setup. - */ -struct intel_fpga_pcie { - struct udevice *bus; - void __iomem *cra_base; - void __iomem *hip_base; - int first_busno; -}; - -/** - * Intel FPGA PCIe port uses BAR0 of RC's configuration space as the - * translation from PCI bus to native BUS. Entire DDR region is mapped - * into PCIe space using these registers, so it can be reached by DMA from - * EP devices. - * The BAR0 of bridge should be hidden during enumeration to avoid the - * sizing and resource allocation by PCIe core. - */ -static bool intel_fpga_pcie_hide_rc_bar(struct intel_fpga_pcie *pcie, - pci_dev_t bdf, int offset) -{ - if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) == 0 && - PCI_FUNC(bdf) == 0 && offset == PCI_BASE_ADDRESS_0) - return true; - - return false; -} - -static inline void cra_writel(struct intel_fpga_pcie *pcie, const u32 value, - const u32 reg) -{ - writel(value, pcie->cra_base + reg); -} - -static inline u32 cra_readl(struct intel_fpga_pcie *pcie, const u32 reg) -{ - return readl(pcie->cra_base + reg); -} - -static bool intel_fpga_pcie_link_up(struct intel_fpga_pcie *pcie) -{ - return !!(readw(RP_CFG_ADDR(pcie, RP_CAP_OFFSET + PCI_EXP_LNKSTA)) - & PCI_EXP_LNKSTA_DLLLA); -} - -static bool intel_fpga_pcie_addr_valid(struct intel_fpga_pcie *pcie, - pci_dev_t bdf) -{ - /* If there is no link, then there is no device */ - if (!IS_ROOT_PORT(pcie, bdf) && !intel_fpga_pcie_link_up(pcie)) - return false; - - /* access only one slot on each root port */ - if (IS_ROOT_PORT(pcie, bdf) && PCI_DEV(bdf) > 0) - return false; - - if ((PCI_BUS(bdf) == pcie->first_busno + 1) && PCI_DEV(bdf) > 0) - return false; - - return true; -} - -static void tlp_write_tx(struct intel_fpga_pcie *pcie, u32 reg0, u32 ctrl) -{ - cra_writel(pcie, reg0, RP_TX_REG0); - cra_writel(pcie, ctrl, RP_TX_CNTRL); -} - -static int tlp_read_packet(struct intel_fpga_pcie *pcie, u32 *value) -{ - int i; - u32 ctrl; - u32 comp_status; - u32 dw[4]; - u32 count = 0; - - for (i = 0; i < TLP_LOOP; i++) { - ctrl = cra_readl(pcie, RP_RXCPL_STATUS); - if (!(ctrl & RP_RXCPL_SOP)) - continue; - - /* read first DW */ - dw[count++] = cra_readl(pcie, RP_RXCPL_REG); - - /* Poll for EOP */ - for (i = 0; i < TLP_LOOP; i++) { - ctrl = cra_readl(pcie, RP_RXCPL_STATUS); - dw[count++] = cra_readl(pcie, RP_RXCPL_REG); - if (ctrl & RP_RXCPL_EOP) { - comp_status = TLP_COMP_STATUS(dw[1]); - if (comp_status) { - *value = pci_get_ff(PCI_SIZE_32); - return 0; - } - - if (value && - TLP_BYTE_COUNT(dw[1]) == sizeof(u32) && - count >= 3) - *value = dw[3]; - - return 0; - } - } - - udelay(5); - } - - dev_err(pcie->dev, "read TLP packet timed out\n"); - return -ENODEV; -} - -static void tlp_write_packet(struct intel_fpga_pcie *pcie, u32 *headers, - u32 data) -{ - tlp_write_tx(pcie, headers[0], RP_TX_SOP); - - tlp_write_tx(pcie, headers[1], 0); - - tlp_write_tx(pcie, headers[2], 0); - - tlp_write_tx(pcie, data, RP_TX_EOP); -} - -static int tlp_cfg_dword_read(struct intel_fpga_pcie *pcie, pci_dev_t bdf, - int offset, u8 byte_en, u32 *value) -{ - u32 headers[TLP_HDR_SIZE]; - u8 busno = PCI_BUS(bdf); - - headers[0] = TLP_CFGRD_DW0(pcie, busno); - headers[1] = TLP_CFG_DW1(pcie, TLP_READ_TAG, byte_en); - headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset); - - tlp_write_packet(pcie, headers, 0); - - return tlp_read_packet(pcie, value); -} - -static int tlp_cfg_dword_write(struct intel_fpga_pcie *pcie, pci_dev_t bdf, - int offset, u8 byte_en, u32 value) -{ - u32 headers[TLP_HDR_SIZE]; - u8 busno = PCI_BUS(bdf); - - headers[0] = TLP_CFGWR_DW0(pcie, busno); - headers[1] = TLP_CFG_DW1(pcie, TLP_WRITE_TAG, byte_en); - headers[2] = TLP_CFG_DW2(busno, PCI_DEV(bdf), PCI_FUNC(bdf), offset); - - tlp_write_packet(pcie, headers, value); - - return tlp_read_packet(pcie, NULL); -} - -int intel_fpga_rp_conf_addr(const struct udevice *bus, pci_dev_t bdf, - uint offset, void **paddress) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - *paddress = RP_CFG_ADDR(pcie, offset); - - return 0; -} - -static int intel_fpga_pcie_rp_rd_conf(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong *valuep, - enum pci_size_t size) -{ - return pci_generic_mmap_read_config(bus, intel_fpga_rp_conf_addr, - bdf, offset, valuep, size); -} - -static int intel_fpga_pcie_rp_wr_conf(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong value, - enum pci_size_t size) -{ - int ret; - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - ret = pci_generic_mmap_write_config(bus, intel_fpga_rp_conf_addr, - bdf, offset, value, size); - if (!ret) { - /* Monitor changes to PCI_PRIMARY_BUS register on root port - * and update local copy of root bus number accordingly. - */ - if (offset == PCI_PRIMARY_BUS) - pcie->first_busno = (u8)(value); - } - - return ret; -} - -static u8 pcie_get_byte_en(uint offset, enum pci_size_t size) -{ - switch (size) { - case PCI_SIZE_8: - return 1 << (offset & 3); - case PCI_SIZE_16: - return 3 << (offset & 3); - default: - return 0xf; - } -} - -static int _pcie_intel_fpga_read_config(struct intel_fpga_pcie *pcie, - pci_dev_t bdf, uint offset, - ulong *valuep, enum pci_size_t size) -{ - int ret; - u32 data; - u8 byte_en; - - /* Uses memory mapped method to read rootport config registers */ - if (IS_ROOT_PORT(pcie, bdf)) - return intel_fpga_pcie_rp_rd_conf(pcie->bus, bdf, - offset, valuep, size); - - byte_en = pcie_get_byte_en(offset, size); - ret = tlp_cfg_dword_read(pcie, bdf, offset & ~DWORD_MASK, - byte_en, &data); - if (ret) - return ret; - - dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08x)\n", - offset, size, data); - *valuep = pci_conv_32_to_size(data, offset, size); - - return 0; -} - -static int _pcie_intel_fpga_write_config(struct intel_fpga_pcie *pcie, - pci_dev_t bdf, uint offset, - ulong value, enum pci_size_t size) -{ - u32 data; - u8 byte_en; - - dev_dbg(pcie->dev, "PCIE CFG write: (b.d.f)=(%02d.%02d.%02d)\n", - PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n", - offset, size, value); - - /* Uses memory mapped method to read rootport config registers */ - if (IS_ROOT_PORT(pcie, bdf)) - return intel_fpga_pcie_rp_wr_conf(pcie->bus, bdf, offset, - value, size); - - byte_en = pcie_get_byte_en(offset, size); - data = pci_conv_size_to_32(0, value, offset, size); - - return tlp_cfg_dword_write(pcie, bdf, offset & ~DWORD_MASK, - byte_en, data); -} - -static int pcie_intel_fpga_read_config(const struct udevice *bus, pci_dev_t bdf, - uint offset, ulong *valuep, - enum pci_size_t size) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - dev_dbg(pcie->dev, "PCIE CFG read: (b.d.f)=(%02d.%02d.%02d)\n", - PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - - if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset)) { - *valuep = (u32)pci_get_ff(size); - return 0; - } - - if (!intel_fpga_pcie_addr_valid(pcie, bdf)) { - *valuep = (u32)pci_get_ff(size); - return 0; - } - - return _pcie_intel_fpga_read_config(pcie, bdf, offset, valuep, size); -} - -static int pcie_intel_fpga_write_config(struct udevice *bus, pci_dev_t bdf, - uint offset, ulong value, - enum pci_size_t size) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(bus); - - if (intel_fpga_pcie_hide_rc_bar(pcie, bdf, offset)) - return 0; - - if (!intel_fpga_pcie_addr_valid(pcie, bdf)) - return 0; - - return _pcie_intel_fpga_write_config(pcie, bdf, offset, value, - size); -} - -static int pcie_intel_fpga_probe(struct udevice *dev) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(dev); - - pcie->bus = pci_get_controller(dev); - pcie->first_busno = dev_seq(dev); - - /* clear all interrupts */ - cra_writel(pcie, P2A_INT_STS_ALL, P2A_INT_STATUS); - /* disable all interrupts */ - cra_writel(pcie, 0, P2A_INT_ENABLE); - - return 0; -} - -static int pcie_intel_fpga_of_to_plat(struct udevice *dev) -{ - struct intel_fpga_pcie *pcie = dev_get_priv(dev); - struct fdt_resource reg_res; - int node = dev_of_offset(dev); - int ret; - - DECLARE_GLOBAL_DATA_PTR; - - ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names", - "Cra", ®_res); - if (ret) { - dev_err(dev, "resource \"Cra\" not found\n"); - return ret; - } - - pcie->cra_base = map_physmem(reg_res.start, - fdt_resource_size(®_res), - MAP_NOCACHE); - - ret = fdt_get_named_resource(gd->fdt_blob, node, "reg", "reg-names", - "Hip", ®_res); - if (ret) { - dev_err(dev, "resource \"Hip\" not found\n"); - return ret; - } - - pcie->hip_base = map_physmem(reg_res.start, - fdt_resource_size(®_res), - MAP_NOCACHE); - - return 0; -} - -static const struct dm_pci_ops pcie_intel_fpga_ops = { - .read_config = pcie_intel_fpga_read_config, - .write_config = pcie_intel_fpga_write_config, -}; - -static const struct udevice_id pcie_intel_fpga_ids[] = { - { .compatible = "altr,pcie-root-port-2.0" }, - {}, -}; - -U_BOOT_DRIVER(pcie_intel_fpga) = { - .name = "pcie_intel_fpga", - .id = UCLASS_PCI, - .of_match = pcie_intel_fpga_ids, - .ops = &pcie_intel_fpga_ops, - .of_to_plat = pcie_intel_fpga_of_to_plat, - .probe = pcie_intel_fpga_probe, - .priv_auto = sizeof(struct intel_fpga_pcie), -}; diff --git a/drivers/pci_endpoint/pcie_cdns_ti_ep.c b/drivers/pci_endpoint/pcie_cdns_ti_ep.c index 661b6ba5b55..021bd73a383 100644 --- a/drivers/pci_endpoint/pcie_cdns_ti_ep.c +++ b/drivers/pci_endpoint/pcie_cdns_ti_ep.c @@ -20,6 +20,7 @@ #include <regmap.h> #include <syscon.h> #include <pci_ep.h> +#include <linux/delay.h> #include "pcie-cadence.h" @@ -90,15 +91,26 @@ static int pcie_cdns_reset(struct udevice *dev, struct power_domain *pci_pwrdmn) dev_err(dev, "failed to power on: %d\n", ret); return ret; } - + mdelay(1); return 0; } static int pcie_cdns_config_serdes(struct udevice *dev) { + int ret; + + if (CONFIG_IS_ENABLED(MUX_MMIO)) { + struct udevice *mux; + + ret = uclass_get_device_by_seq(UCLASS_MUX, 0, &mux); + if (ret) { + dev_err(dev, "unable to get mux\n"); + return ret; + } + } + if (CONFIG_IS_ENABLED(PHY_CADENCE_TORRENT)) { struct phy serdes; - int ret = 7; ret = generic_phy_get_by_name(dev, "pcie-phy", &serdes); if (ret != 0 && ret != -EBUSY) { @@ -263,9 +275,11 @@ static int pcie_cdns_ti_ep_probe(struct udevice *dev) struct pcie_cdns_ti_ep *pcie = dev_get_priv(dev); struct pcie_cdns_ti_ep_data *data; struct power_domain pci_pwrdmn; + struct cdns_pcie pcie_dev; struct clk *clk; int ret; + pcie_dev.reg_base = pcie->reg_base; pcie->dev = dev; data = (struct pcie_cdns_ti_ep_data *)dev_get_driver_data(dev); if (!data) @@ -316,6 +330,13 @@ static int pcie_cdns_ti_ep_probe(struct udevice *dev) return ret; } + /* + * Disable all the functions except function 0 (anyway BIT(0) is + * hardwired to 1). This is required to avoid RC from enumerating + * those functions which are not even configured. + */ + cdns_pcie_writel(&pcie_dev, CDNS_PCIE_LM_EP_FUNC_CFG, BIT(0)); + return 0; } @@ -377,11 +398,19 @@ static const struct pcie_cdns_ti_ep_data am64_pcie_ep_data = { .max_lanes = 1, }; +static const struct pcie_cdns_ti_ep_data j784s4_pcie_ep_data = { + .max_lanes = 4, +}; + static const struct udevice_id pcie_cdns_ti_ep_ids[] = { { .compatible = "ti,am64-pcie-ep", .data = (ulong)&am64_pcie_ep_data, }, + { + .compatible = "ti,j784s4-pcie-ep", + .data = (ulong)&j784s4_pcie_ep_data, + }, {}, }; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index d36a5f00ef8..420d7c7a44d 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -289,11 +289,19 @@ config PHY_NPCM_USB Support the USB PHY in NPCM SoCs config PHY_IMX8MQ_USB - bool "NXP i.MX8MQ/i.MX8MP/i.MX95 USB PHY Driver" + bool "NXP i.MX8MQ/i.MX8MP/i.MX95/i.MX94 USB PHY Driver" depends on PHY - depends on IMX8MQ || IMX8MP || IMX95 + depends on IMX8MQ || IMX8MP || IMX95 || IMX94 help - Support the USB3.0 PHY in NXP i.MX8MQ, i.MX8MP, and i.MX95 SoC + Support the USB3.0 PHY in NXP i.MX8MQ, i.MX8MP, i.MX95, and i.MX94 SoCs. + +config SPL_PHY_IMX8MQ_USB + bool "Enable NXP i.MX8MQ/i.MX8MP/i.MX95/i.MX94 USB3.0 PHY Driver in SPL" + depends on SPL_PHY + depends on IMX8MQ || IMX8MP || IMX95 || IMX94 + help + Enable support for the USB3.0 PHY in NXP i.MX8MQ, i.MX8MP, i.MX95, and + i.MX94 SoCs in SPL. config PHY_IMX8M_PCIE bool "NXP i.MX8MM/i.MX8MP PCIe PHY Driver" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 98c1ef8683b..5a6df0ecfeb 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -38,7 +38,7 @@ obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o obj-$(CONFIG_PHY_EXYNOS_USBDRD) += phy-exynos-usbdrd.o obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-usb.o -obj-$(CONFIG_PHY_IMX8MQ_USB) += phy-imx8mq-usb.o +obj-$(CONFIG_$(PHASE_)PHY_IMX8MQ_USB) += phy-imx8mq-usb.o obj-$(CONFIG_PHY_IMX8M_PCIE) += phy-imx8m-pcie.o obj-$(CONFIG_PHY_XILINX_ZYNQMP) += phy-zynqmp.o obj-y += cadence/ diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig index b5f69c0a96d..c66197de143 100644 --- a/drivers/phy/marvell/Kconfig +++ b/drivers/phy/marvell/Kconfig @@ -1,5 +1,6 @@ config MVEBU_COMPHY_SUPPORT bool "ComPhy SerDes driver" + depends on ARMADA_3700 || ARMADA_8K help Choose this option to add support for Comphy driver. diff --git a/drivers/phy/qcom/Kconfig b/drivers/phy/qcom/Kconfig index 61e5e2fca41..0dd69f7ffd0 100644 --- a/drivers/phy/qcom/Kconfig +++ b/drivers/phy/qcom/Kconfig @@ -1,8 +1,8 @@ config MSM8916_USB_PHY - bool "Qualcomm MSM8916 USB PHY support" - depends on PHY + bool + select PHY help - Support the USB PHY in msm8916 + Support the Qualcomm MSM8916 USB PHY This PHY is found on qualcomm dragonboard410c development board. diff --git a/drivers/phy/qcom/phy-qcom-qmp-ufs.c b/drivers/phy/qcom/phy-qcom-qmp-ufs.c index f3c606847fb..907f34744eb 100644 --- a/drivers/phy/qcom/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qcom/phy-qcom-qmp-ufs.c @@ -221,6 +221,36 @@ static const struct qmp_ufs_init_tbl sm8150_ufsphy_hs_g4_rx[] = { QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0x3c), }; +static const struct qmp_ufs_init_tbl sm7150_ufsphy_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_LVL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_TERM_BW, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x81), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x59), +}; + +static const struct qmp_ufs_init_tbl sm7150_ufsphy_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SIGDET_CTRL2, 0x6f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_SMALL_AMP_DRV_LVL, 0x02), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SYM_RESYNC_CTRL, 0x03), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_TX_MID_TERM_CTRL1, 0x43), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_SIGDET_CTRL1, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_RX_MIN_HIBERN8_TIME, 0xff), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_UFS_MULTI_LANE_CTRL1, 0x02), +}; + static const struct qmp_ufs_init_tbl sm8150_ufsphy_serdes[] = { QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0xd9), QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x11), @@ -1018,6 +1048,36 @@ static const struct qmp_ufs_cfg sm8150_ufsphy_cfg = { .no_pcs_sw_reset = false, }; +static const struct qmp_ufs_cfg sm7150_ufsphy_cfg = { + .lanes = 1, + + .offsets = &qmp_ufs_offsets, + + .tbls = { + .serdes = sdm845_ufsphy_serdes, + .serdes_num = ARRAY_SIZE(sdm845_ufsphy_serdes), + .tx = sdm845_ufsphy_tx, + .tx_num = ARRAY_SIZE(sdm845_ufsphy_tx), + .rx = sm7150_ufsphy_rx, + .rx_num = ARRAY_SIZE(sm7150_ufsphy_rx), + .pcs = sm7150_ufsphy_pcs, + .pcs_num = ARRAY_SIZE(sm7150_ufsphy_pcs), + }, + .tbls_hs_b = { + .serdes = sdm845_ufsphy_hs_b_serdes, + .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes), + }, + .clk_list = sdm845_ufs_phy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), + .vreg_list = qmp_ufs_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_ufs_vreg_l), + .reset_list = qmp_ufs_reset_l, + .num_resets = ARRAY_SIZE(qmp_ufs_reset_l), + .regs = ufsphy_v3_regs_layout, + + .no_pcs_sw_reset = true, +}; + static const struct qmp_ufs_cfg sm8250_ufsphy_cfg = { .lanes = 2, @@ -1593,6 +1653,8 @@ static struct phy_ops qmp_ufs_ops = { static const struct udevice_id qmp_ufs_ids[] = { { .compatible = "qcom,sa8775p-qmp-ufs-phy", .data = (ulong)&sa8775p_ufsphy_cfg, }, { .compatible = "qcom,sdm845-qmp-ufs-phy", .data = (ulong)&sdm845_ufsphy_cfg }, + { .compatible = "qcom,sm6350-qmp-ufs-phy", .data = (ulong)&sdm845_ufsphy_cfg }, + { .compatible = "qcom,sm7150-qmp-ufs-phy", .data = (ulong)&sm7150_ufsphy_cfg }, { .compatible = "qcom,sm8150-qmp-ufs-phy", .data = (ulong)&sm8150_ufsphy_cfg }, { .compatible = "qcom,sm8250-qmp-ufs-phy", .data = (ulong)&sm8250_ufsphy_cfg }, { .compatible = "qcom,qcs8300-qmp-ufs-phy", .data = (ulong)&sa8775p_ufsphy_cfg }, diff --git a/drivers/phy/renesas/Kconfig b/drivers/phy/renesas/Kconfig index 0efb0f8f337..affbee0500c 100644 --- a/drivers/phy/renesas/Kconfig +++ b/drivers/phy/renesas/Kconfig @@ -7,3 +7,15 @@ config PHY_R8A779F0_ETHERNET_SERDES depends on RCAR_64 && PHY help Support for Ethernet SERDES found on Renesas R-Car S4-8 SoCs. + +config PHY_R8A78000_ETHERNET_PCS + tristate "Renesas R-Car X5H Ethernet PCS driver" + depends on RCAR_64 && PHY + help + Support for Ethernet PCS found on Renesas R-Car X5H SoCs. + +config PHY_R8A78000_MP_PHY + tristate "Renesas R-Car X5H Multi-Protocol PHY driver" + depends on RCAR_64 && PHY + help + Support for Multi-Protocol PHY on Renesas R-Car X5H SoCs. diff --git a/drivers/phy/renesas/Makefile b/drivers/phy/renesas/Makefile index fd6b8d964e5..12585c21f58 100644 --- a/drivers/phy/renesas/Makefile +++ b/drivers/phy/renesas/Makefile @@ -1 +1,3 @@ obj-$(CONFIG_PHY_R8A779F0_ETHERNET_SERDES) += r8a779f0-ether-serdes.o +obj-$(CONFIG_PHY_R8A78000_ETHERNET_PCS) += r8a78000-ether-pcs.o +obj-$(CONFIG_PHY_R8A78000_MP_PHY) += r8a78000-mp-phy.o diff --git a/drivers/phy/renesas/r8a78000-ether-pcs.c b/drivers/phy/renesas/r8a78000-ether-pcs.c new file mode 100644 index 00000000000..6343f89313a --- /dev/null +++ b/drivers/phy/renesas/r8a78000-ether-pcs.c @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Renesas Ethernet PCS Device Driver + * + * Based on the Renesas Ethernet SERDES driver and updated for PCS support. + * + * Copyright (C) 2025 Renesas Electronics Corporation + */ + +#include <asm/io.h> +#include <clk-uclass.h> +#include <clk.h> +#include <div64.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <dm/lists.h> +#include <dm/of_access.h> +#include <generic-phy.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <log.h> +#include <reset.h> +#include <syscon.h> + +#define R8A78000_ETH_PCS_NUM 8 +#define R8A78000_ETH_PCS_OFFSET 0x0400 +#define R8A78000_ETH_PCS_BANK_SELECT 0x03fc +#define R8A78000_ETH_PCS_TIMEOUT_US 100000 +#define R8A78000_ETH_PCS_NUM_RETRY_LINKUP 8 + +struct r8a78000_eth_pcs_drv_data; +struct r8a78000_eth_pcs_channel { + struct r8a78000_eth_pcs_drv_data *dd; + struct phy *phy; + void __iomem *addr; + phy_interface_t phy_interface; + int speed; + int index; +}; + +struct r8a78000_eth_pcs_drv_data { + void __iomem *addr; + struct reset_ctl_bulk reset; + struct phy mpphy; + struct r8a78000_eth_pcs_channel channel[R8A78000_ETH_PCS_NUM]; + struct clk_bulk clks; +}; + +/* + * The datasheet describes initialization procedure without any information + * about registers' name/bits. So, this is all black magic to initialize + * the hardware. + */ +static void r8a78000_eth_pcs_write32(void __iomem *addr, u32 offs, u32 bank, u32 data) +{ + writel(bank, addr + R8A78000_ETH_PCS_BANK_SELECT); + writel(data, addr + offs); +} + +static int +r8a78000_eth_pcs_reg_wait(struct r8a78000_eth_pcs_channel *channel, + u32 offs, u32 bank, u32 mask, u32 expected) +{ + u32 val = 0; + int ret; + + writel(bank, channel->addr + R8A78000_ETH_PCS_BANK_SELECT); + + ret = readl_poll_timeout(channel->addr + offs, val, + (val & mask) == expected, + R8A78000_ETH_PCS_TIMEOUT_US); + if (ret) + dev_dbg(channel->phy->dev, + "%s: index %d, offs %x, bank %x, mask %x, expected %x\n", + __func__, channel->index, offs, bank, mask, expected); + + return ret; +} + +static int +r8a78000_eth_pcs_init_ram(struct r8a78000_eth_pcs_channel *channel, struct phy *mpphy) +{ + int ret; + + ret = r8a78000_eth_pcs_reg_wait(channel, 0x026c, 0x180, BIT(0), 0x01); + if (ret) + return ret; + + r8a78000_eth_pcs_write32(channel->addr, 0x026c, 0x180, 0x03); + + ret = generic_phy_power_on(mpphy); + if (ret) + return ret; + + ret = r8a78000_eth_pcs_reg_wait(channel, 0x0000, 0x300, BIT(15), 0); + if (ret) + return ret; + + return 0; +} + +static int +r8a78000_eth_pcs_common_setting(struct r8a78000_eth_pcs_channel *channel) +{ + int ret; + + switch (channel->phy_interface) { + case PHY_INTERFACE_MODE_SGMII: + r8a78000_eth_pcs_write32(channel->addr, 0x001c, 0x300, 0x0001); + r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x380, 0x2000); + r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x1f00, 0x0140); + r8a78000_eth_pcs_write32(channel->addr, 0x0258, 0x180, 0x0018); + r8a78000_eth_pcs_write32(channel->addr, 0x01dc, 0x180, 0x000d); + r8a78000_eth_pcs_write32(channel->addr, 0x00f8, 0x180, 0x0016); + r8a78000_eth_pcs_write32(channel->addr, 0x0248, 0x180, 0x0016); + r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x300, 0x0c40); + + ret = r8a78000_eth_pcs_reg_wait(channel, 0x0040, 0x380, GENMASK(4, 2), 0x06 << 2); + if (ret) + return ret; + + r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x300, 0x0440); + + ret = r8a78000_eth_pcs_reg_wait(channel, 0x0040, 0x380, GENMASK(4, 2), 0x04 << 2); + if (ret) + return ret; + + r8a78000_eth_pcs_write32(channel->addr, 0x0014, 0x380, 0x0050); + r8a78000_eth_pcs_write32(channel->addr, 0x00d8, 0x180, 0x3000); + r8a78000_eth_pcs_write32(channel->addr, 0x00dc, 0x180, 0x0000); + + return 0; + case PHY_INTERFACE_MODE_USXGMII: + r8a78000_eth_pcs_write32(channel->addr, 0x001c, 0x300, 0x0000); + r8a78000_eth_pcs_write32(channel->addr, 0x001c, 0x380, 0x0000); + r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x380, 0x2200); + r8a78000_eth_pcs_write32(channel->addr, 0x0258, 0x180, 0x0018); + r8a78000_eth_pcs_write32(channel->addr, 0x01dc, 0x180, 0x000d); + r8a78000_eth_pcs_write32(channel->addr, 0x00f8, 0x180, 0x001b); + r8a78000_eth_pcs_write32(channel->addr, 0x0248, 0x180, 0x001b); + r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x300, 0x0c40); + + ret = r8a78000_eth_pcs_reg_wait(channel, 0x0040, 0x380, GENMASK(4, 2), 0x06 << 2); + if (ret) + return ret; + + r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x300, 0x0440); + + ret = r8a78000_eth_pcs_reg_wait(channel, 0x0040, 0x380, GENMASK(4, 2), 0x04 << 2); + if (ret) + return ret; + + r8a78000_eth_pcs_write32(channel->addr, 0x0014, 0x380, 0x0050); + r8a78000_eth_pcs_write32(channel->addr, 0x00d8, 0x180, 0x1800); + r8a78000_eth_pcs_write32(channel->addr, 0x00dc, 0x180, 0x0012); + + ret = r8a78000_eth_pcs_reg_wait(channel, 0x0080, 0x180, BIT(12), BIT(12)); + if (ret) + return ret; + + r8a78000_eth_pcs_write32(channel->addr, 0x0170, 0x180, 0x1000); + + ret = r8a78000_eth_pcs_reg_wait(channel, 0x0260, 0x180, BIT(12), BIT(12)); + if (ret) + return ret; + + r8a78000_eth_pcs_write32(channel->addr, 0x0170, 0x180, 0x0000); + + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int +r8a78000_eth_pcs_chan_setting(struct r8a78000_eth_pcs_channel *channel) +{ + int ret; + + switch (channel->phy_interface) { + case PHY_INTERFACE_MODE_SGMII: + /* For AN_ON */ + r8a78000_eth_pcs_write32(channel->addr, 0x0004, 0x1f80, 0x0005); + r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x1f80, 0x2200); + r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x1f00, 0x3140); + + ret = r8a78000_eth_pcs_reg_wait(channel, 0x0008, 0x1f80, BIT(0), BIT(0)); + if (ret) + return ret; + + break; + case PHY_INTERFACE_MODE_USXGMII: + /* For AN_ON */ + r8a78000_eth_pcs_write32(channel->addr, 0x0004, 0x1f80, 0x0001); + r8a78000_eth_pcs_write32(channel->addr, 0x0028, 0x1f80, 0x0001); + r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x1f80, 0x2008); + r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x1f00, 0x3140); + + ret = r8a78000_eth_pcs_reg_wait(channel, 0x0008, 0x1f80, BIT(0), BIT(0)); + if (ret) + return ret; + + r8a78000_eth_pcs_write32(channel->addr, 0x0008, 0x1f80, 0x0000); + + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int +r8a78000_eth_pcs_chan_speed(struct r8a78000_eth_pcs_channel *channel) +{ + int ret; + + switch (channel->phy_interface) { + case PHY_INTERFACE_MODE_SGMII: + /* Do nothing */ + break; + case PHY_INTERFACE_MODE_USXGMII: + if (channel->speed == 10000) + r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x1f00, 0x2140); + else if (channel->speed == 2500) + r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x1f00, 0x0120); + else + return -EOPNOTSUPP; + + r8a78000_eth_pcs_write32(channel->addr, 0x0000, 0x380, 0x2600); + + ret = r8a78000_eth_pcs_reg_wait(channel, 0x0000, 0x380, BIT(10), 0); + if (ret) + return ret; + + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int r8a78000_eth_pcs_monitor_linkup(struct r8a78000_eth_pcs_channel *channel) +{ + int i, ret; + + for (i = 0; i < R8A78000_ETH_PCS_NUM_RETRY_LINKUP; i++) { + ret = r8a78000_eth_pcs_reg_wait(channel, 0x0004, 0x300, + BIT(2), BIT(2)); + if (!ret) + break; + + /* restart */ + r8a78000_eth_pcs_write32(channel->addr, 0x0144, 0x180, 0x0010); + udelay(1); + r8a78000_eth_pcs_write32(channel->addr, 0x0144, 0x180, 0x0000); + } + + return ret; +} + +static int r8a78000_eth_pcs_init(struct phy *p) +{ + struct r8a78000_eth_pcs_drv_data *dd = dev_get_priv(p->dev); + struct r8a78000_eth_pcs_channel *channel = dd->channel + p->id; + int ret; + + ret = generic_phy_init(&dd->mpphy); + if (ret) { + dev_dbg(channel->phy->dev, "XPCS: Failed to init MPPHY\n"); + return ret; + } + + ret = r8a78000_eth_pcs_init_ram(channel, &dd->mpphy); + if (ret) + return ret; + + ret = r8a78000_eth_pcs_common_setting(channel); + + return ret; +} + +static int r8a78000_eth_pcs_hw_init_late(struct r8a78000_eth_pcs_channel *channel) +{ + int ret; + + ret = r8a78000_eth_pcs_chan_setting(channel); + if (ret) + return ret; + + ret = r8a78000_eth_pcs_chan_speed(channel); + if (ret) + return ret; + + r8a78000_eth_pcs_write32(channel->addr, 0x03c0, 0x380, 0x0000); + + r8a78000_eth_pcs_write32(channel->addr, 0x03d0, 0x380, 0x0000); + + return r8a78000_eth_pcs_monitor_linkup(channel); +} + +static int r8a78000_eth_pcs_power_on(struct phy *p) +{ + struct r8a78000_eth_pcs_drv_data *dd = dev_get_priv(p->dev); + struct r8a78000_eth_pcs_channel *channel = dd->channel + p->id; + + return r8a78000_eth_pcs_hw_init_late(channel); +} + +static int r8a78000_eth_pcs_set_mode(struct phy *p, enum phy_mode mode, + int submode) +{ + struct r8a78000_eth_pcs_drv_data *dd = dev_get_priv(p->dev); + struct r8a78000_eth_pcs_channel *channel = dd->channel + p->id; + + if (mode != PHY_MODE_ETHERNET) + return -EOPNOTSUPP; + + switch (submode) { + case PHY_INTERFACE_MODE_GMII: + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_USXGMII: + channel->phy_interface = submode; + return 0; + default: + return -EOPNOTSUPP; + } +} + +static int r8a78000_eth_pcs_set_speed(struct phy *p, int speed) +{ + struct r8a78000_eth_pcs_drv_data *dd = dev_get_priv(p->dev); + struct r8a78000_eth_pcs_channel *channel = dd->channel + p->id; + + channel->speed = speed; + + return 0; +} + +static int r8a78000_eth_pcs_of_xlate(struct phy *phy, + struct ofnode_phandle_args *args) +{ + if (args->args_count < 1) + return -ENODEV; + + if (args->args[0] >= R8A78000_ETH_PCS_NUM) + return -ENODEV; + + phy->id = args->args[0]; + + return 0; +} + +static const struct phy_ops r8a78000_eth_pcs_ops = { + .init = r8a78000_eth_pcs_init, + .power_on = r8a78000_eth_pcs_power_on, + .set_mode = r8a78000_eth_pcs_set_mode, + .set_speed = r8a78000_eth_pcs_set_speed, + .of_xlate = r8a78000_eth_pcs_of_xlate, +}; + +static const struct udevice_id r8a78000_eth_pcs_of_table[] = { + { .compatible = "renesas,r8a78000-ether-pcs", }, + { } +}; + +static int r8a78000_eth_pcs_probe(struct udevice *dev) +{ + struct r8a78000_eth_pcs_drv_data *dd = dev_get_priv(dev); + int i, ret; + + dd->addr = dev_read_addr_ptr(dev); + if (!dd->addr) + return -EINVAL; + + ret = reset_get_bulk(dev, &dd->reset); + if (ret) + return ret; + + ret = clk_get_bulk(dev, &dd->clks); + if (ret < 0) + goto err_clk_get; + + ret = clk_enable_bulk(&dd->clks); + if (ret) + goto err_clk_enable; + + reset_assert_bulk(&dd->reset); + reset_deassert_bulk(&dd->reset); + + ret = generic_phy_get_by_index(dev, 0, &dd->mpphy); + if (ret) + goto err_phy_get; + + for (i = 0; i < R8A78000_ETH_PCS_NUM; i++) { + struct r8a78000_eth_pcs_channel *channel = &dd->channel[i]; + + channel->addr = dd->addr + R8A78000_ETH_PCS_OFFSET * i; + channel->dd = dd; + channel->index = i; + } + + return 0; + +err_phy_get: + clk_disable_bulk(&dd->clks); +err_clk_enable: + clk_release_bulk(&dd->clks); +err_clk_get: + reset_release_bulk(&dd->reset); + return ret; +} + +U_BOOT_DRIVER(r8a78000_eth_pcs_driver_platform) = { + .name = "r8a78000_eth_pcs", + .id = UCLASS_PHY, + .of_match = r8a78000_eth_pcs_of_table, + .probe = r8a78000_eth_pcs_probe, + .ops = &r8a78000_eth_pcs_ops, + .priv_auto = sizeof(struct r8a78000_eth_pcs_drv_data), +}; diff --git a/drivers/phy/renesas/r8a78000-mp-phy.c b/drivers/phy/renesas/r8a78000-mp-phy.c new file mode 100644 index 00000000000..fba130a65a1 --- /dev/null +++ b/drivers/phy/renesas/r8a78000-mp-phy.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Renesas Multi-Protocol PHY device driver + * + * Copyright (C) 2025 Renesas Electronics Corporation + */ + +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <generic-phy.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <reset.h> + +/* Common registers */ +#define MPPHY_CMNCNT1 0x80000 +#define MPPHY_CMNCNT2 0x80004 +#define MPPHY_PCS0REG1 0x85000 +#define MPPHY_PCS0REG5 0x85010 + +/* Channel register base and offsets */ +#define MPPHY_CHAN_BASE(ch) (0x81000 + (ch) * 0x1000) +#define MPPHY_PXTEST_OFFSET 0x00C +#define MPPHY_RXCNT_OFFSET 0x038 +#define MPPHY_SRAMCNT_OFFSET 0x040 +#define MPPHY_REFCLK_OFFSET 0x014 +#define MPPHY_CNTXT1_OFFSET 0x004 +#define MPPHY_CNTXT2_OFFSET 0x008 +#define MPPHY_TXREQ_OFFSET 0x044 + +/* Channel specific registers */ +#define MPPHY_PXTEST(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_PXTEST_OFFSET) +#define MPPHY_PXRXCNT(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_RXCNT_OFFSET) +#define MPPHY_PXSRAMCNT(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_SRAMCNT_OFFSET) +#define MPPHY_PXREFCLK(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_REFCLK_OFFSET) +#define MPPHY_PXCNTXT1(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_CNTXT1_OFFSET) +#define MPPHY_PXCNTXT2(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_CNTXT2_OFFSET) +#define MPPHY_PXTXREQ(ch) (MPPHY_CHAN_BASE(ch) + MPPHY_TXREQ_OFFSET) + +/* Channel enable bit masks for MPPHY_CMNCNT1 register */ +#define MPPHY_CMNCNT1_CH_MASK(ch) (0xFF << ((ch) * 8)) + +/* Channel enable bits for MPPHY_CMNCNT1 register */ +#define MPPHY_CMNCNT1_CH_EN(ch) ((ch) == 0 ? BIT(1) : BIT((ch) * 8)) + +/* PCS0REG5 register mask and values for each channel */ +#define MPPHY_PCS0REG5_CH(ch) (0x03 << (24 + (ch) * 2)) + +/* PCS0REG1 register bits */ +#define MPPHY_PCS0REG1_VAL 0x00010000 + +/* PXTEST register bit */ +#define MPPHY_PXTEST_BIT BIT(0) + +/* PXRXCNT register reset value */ +#define MPPHY_PXRXCNT_RESET_VAL 0x202 + +/* PXSRAMCNT register bits */ +#define MPPHY_PXSRAMCNT_BYPASS BIT(0) +#define MPPHY_PXSRAMCNT_BIT3 BIT(3) +#define BOOTLOAD_BYPASS_MODE 0x3 +#define SRAM_BYPASS_MODE 0xc +#define SRAM_EXT_LD_DONE 0x10 +#define SRAM_INIT_DONE 0x20 + +#define SRAM_CONTROL_SET_BIT \ + (BOOTLOAD_BYPASS_MODE | SRAM_BYPASS_MODE | \ + SRAM_EXT_LD_DONE | SRAM_INIT_DONE) + +/* CMNCNT1/2 clock settings */ +#define MPPHY_CMNCNT2_CLK_CH(ch) (0x30003 << ((ch) * 4)) + +/* PXREFCLK register value */ +#define MPPHY_PXREFCLK_VAL 0x35 + +/* PXTXREQ register value */ +#define MPPHY_PXTXREQ_VAL 0x8 + +/* Context settings */ +#define MPPHY_CNTXT1_VALUE 0x02010002 +#define MPPHY_CNTXT2_VALUE 0x02020202 /* For channels 1-3 */ +#define MPPHY_CNTXT2_CH0_VALUE 0x02020201 /* Special for channel 0 */ + +/* struct mpphy_priv - Private data for the MPPHY driver */ +struct mp_phy_priv { + struct phy *phy; + struct clk_bulk clks; + struct reset_ctl_bulk resets; + void __iomem *base; +}; + +static int mp_phy_init(struct phy *phy) +{ + struct mp_phy_priv *priv = dev_get_priv(phy->dev); + + if (phy->id > 3) { + printf("Invalid channel ID: %ld\n", phy->id); + return -EINVAL; + } + + clrsetbits_le32(priv->base + MPPHY_CMNCNT1, MPPHY_CMNCNT1_CH_MASK(phy->id), + MPPHY_CMNCNT1_CH_EN(phy->id)); + setbits_le32(priv->base + MPPHY_PCS0REG5, MPPHY_PCS0REG5_CH(phy->id)); + setbits_le32(priv->base + MPPHY_PCS0REG1, MPPHY_PCS0REG1_VAL); + setbits_le32(priv->base + MPPHY_PXTEST(phy->id), MPPHY_PXTEST_BIT); + clrbits_le32(priv->base + MPPHY_PCS0REG5, MPPHY_PCS0REG5_CH(phy->id)); + clrbits_le32(priv->base + MPPHY_PCS0REG1, MPPHY_PCS0REG1_VAL); + clrbits_le32(priv->base + MPPHY_PXTEST(phy->id), MPPHY_PXTEST_BIT); + + /* Set PHY RX/TX reset and SRAM bypass mode */ + writel(MPPHY_PXRXCNT_RESET_VAL, priv->base + MPPHY_PXRXCNT(phy->id)); + writel(MPPHY_PXSRAMCNT_BYPASS, priv->base + MPPHY_PXSRAMCNT(phy->id)); + setbits_le32(priv->base + MPPHY_PXSRAMCNT(phy->id), MPPHY_PXSRAMCNT_BIT3); + + /* Clock supply settings */ + setbits_le32(priv->base + MPPHY_CMNCNT2, MPPHY_CMNCNT2_CLK_CH(phy->id)); + + setbits_le32(priv->base + MPPHY_PXREFCLK(phy->id), MPPHY_PXREFCLK_VAL); + + /* Release PHY RX/TX reset */ + writel(0x0, priv->base + MPPHY_PXRXCNT(phy->id)); + + /* Setting Context Restore Registers and select PHY2/PHY3 protocol */ + writel(MPPHY_CNTXT1_VALUE, priv->base + MPPHY_PXCNTXT1(phy->id)); + writel((phy->id == 0) ? MPPHY_CNTXT2_CH0_VALUE : MPPHY_CNTXT2_VALUE, + priv->base + MPPHY_PXCNTXT2(phy->id)); + writel(MPPHY_PXTXREQ_VAL, priv->base + MPPHY_PXTXREQ(phy->id)); + + return 0; +} + +static int mp_phy_late_init(struct phy *phy) +{ + struct mp_phy_priv *priv = dev_get_priv(phy->dev); + + writel(SRAM_CONTROL_SET_BIT, priv->base + MPPHY_PXSRAMCNT(phy->id)); + + return 0; +} + +static int mp_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + /* Current source code only supports Ethernet */ + if (mode != PHY_MODE_ETHERNET) + return -EOPNOTSUPP; + + return 0; +} + +static int mp_phy_of_xlate(struct phy *phy, struct ofnode_phandle_args *args) +{ + if (args->args_count > 2) + return -EINVAL; + + /* Set channel ID from first argument if available */ + if (args->args_count) + phy->id = args->args[0]; + else + phy->id = 0; + + return 0; +} + +static const struct phy_ops mp_phy_ops = { + .init = mp_phy_init, + .power_on = mp_phy_late_init, + .set_mode = mp_phy_set_mode, + .of_xlate = mp_phy_of_xlate, +}; + +static int mp_phy_probe(struct udevice *dev) +{ + struct mp_phy_priv *priv = dev_get_priv(dev); + int ret; + + /* Get base address from device tree */ + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -EINVAL; + + ret = clk_get_bulk(dev, &priv->clks); + if (ret < 0) + return ret; + + ret = clk_enable_bulk(&priv->clks); + if (ret) + goto err_clk_enable; + + ret = reset_get_bulk(dev, &priv->resets); + if (ret) + goto err_reset_get; + + ret = reset_assert_bulk(&priv->resets); + if (ret) + goto err_reset_assert; + + ret = reset_deassert_bulk(&priv->resets); + if (ret) + goto err_reset_assert; + + return 0; + +err_reset_assert: + reset_release_bulk(&priv->resets); +err_reset_get: + clk_disable_bulk(&priv->clks); +err_clk_enable: + clk_release_bulk(&priv->clks); + return ret; +} + +static const struct udevice_id mp_phy_ids[] = { + { .compatible = "renesas,r8a78000-multi-protocol-phy" }, + { } +}; + +U_BOOT_DRIVER(renesas_mpphy) = { + .name = "renesas_mpphy", + .id = UCLASS_PHY, + .of_match = mp_phy_ids, + .probe = mp_phy_probe, + .ops = &mp_phy_ops, + .priv_auto = sizeof(struct mp_phy_priv), +}; diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 6e2d4bc2b05..eaf68d18f3a 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -1180,6 +1180,7 @@ static int j721e_wiz_probe(struct udevice *dev) ofnode node; struct regmap *regmap; u32 num_lanes; + bool already_configured = false; node = get_child_by_name(dev, "serdes"); @@ -1243,15 +1244,6 @@ static int j721e_wiz_probe(struct udevice *dev) goto err_addr_to_resource; } - for (i = 0; i < wiz->num_lanes; i++) { - regmap_field_read(wiz->p_enable[i], &val); - if (val & (P_ENABLE | P_ENABLE_FORCE)) { - dev_err(dev, "SERDES already configured\n"); - rc = -EBUSY; - goto err_addr_to_resource; - } - } - rc = j721e_wiz_bind_of_clocks(wiz); if (rc) { dev_err(dev, "Failed to bind clocks\n"); @@ -1270,10 +1262,21 @@ static int j721e_wiz_probe(struct udevice *dev) goto err_addr_to_resource; } - rc = wiz_init(wiz); - if (rc) { - dev_err(dev, "WIZ initialization failed\n"); - goto err_addr_to_resource; + for (i = 0; i < wiz->num_lanes; i++) { + regmap_field_read(wiz->p_enable[i], &val); + if (val & (P_ENABLE | P_ENABLE_FORCE)) { + dev_info(dev, "SERDES already configured, skipping wiz initialization\n"); + already_configured = true; + break; + } + } + + if (!already_configured) { + rc = wiz_init(wiz); + if (rc) { + dev_err(dev, "WIZ initialization failed\n"); + goto err_addr_to_resource; + } } return 0; diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index babf1bccc96..7dbaf966f93 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -117,8 +117,26 @@ int meson_gpio_get(struct udevice *dev, unsigned int offset) struct meson_pinctrl *priv = dev_get_priv(dev->parent); unsigned int reg, bit; int ret; + enum gpio_func_t direction; + enum meson_reg_type reg_type; - ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_IN, ®, + direction = meson_gpio_get_direction(dev, offset); + + switch (direction) { + case GPIOF_INPUT: + reg_type = REG_IN; + break; + + case GPIOF_OUTPUT: + reg_type = REG_OUT; + break; + + default: + dev_warn(dev, "Failed to get current direction of Pin %u\n", offset); + return -EINVAL; + } + + ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, reg_type, ®, &bit); if (ret) return ret; diff --git a/drivers/pinctrl/nxp/pinctrl-imx-scmi.c b/drivers/pinctrl/nxp/pinctrl-imx-scmi.c index aed47be337d..781835c6852 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx-scmi.c +++ b/drivers/pinctrl/nxp/pinctrl-imx-scmi.c @@ -16,6 +16,7 @@ #include "pinctrl-imx.h" #define DAISY_OFFSET_IMX95 0x408 +#define DAISY_OFFSET_IMX94 0x608 /* SCMI pin control types */ #define PINCTRL_TYPE_MUX 192 @@ -133,6 +134,8 @@ static int imx_scmi_pinctrl_probe(struct udevice *dev) if (IS_ENABLED(CONFIG_IMX95)) priv->daisy_offset = DAISY_OFFSET_IMX95; + else if (IS_ENABLED(CONFIG_IMX94)) + priv->daisy_offset = DAISY_OFFSET_IMX94; else return -EINVAL; @@ -141,7 +144,7 @@ static int imx_scmi_pinctrl_probe(struct udevice *dev) static int imx_scmi_pinctrl_bind(struct udevice *dev) { - if (IS_ENABLED(CONFIG_IMX95)) + if (IS_ENABLED(CONFIG_IMX95) || IS_ENABLED(CONFIG_IMX94)) return 0; return -ENODEV; diff --git a/drivers/pinctrl/pinctrl-zynqmp.c b/drivers/pinctrl/pinctrl-zynqmp.c index 665b76a7d4d..7c11ac4c8b8 100644 --- a/drivers/pinctrl/pinctrl-zynqmp.c +++ b/drivers/pinctrl/pinctrl-zynqmp.c @@ -127,7 +127,8 @@ static int zynqmp_pm_query_data(enum pm_query_id qid, u32 arg1, u32 arg2, u32 *o int ret; u32 ret_payload[PAYLOAD_ARG_CNT]; - ret = xilinx_pm_request(PM_QUERY_DATA, qid, arg1, arg2, 0, ret_payload); + ret = xilinx_pm_request(PM_QUERY_DATA, qid, arg1, arg2, 0, 0, + 0, ret_payload); if (ret) return ret; @@ -142,7 +143,8 @@ static int zynqmp_pm_pinctrl_get_config(const u32 pin, const u32 param, u32 *val u32 ret_payload[PAYLOAD_ARG_CNT]; /* Get config for the pin */ - ret = xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_GET, pin, param, 0, 0, ret_payload); + ret = xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_GET, pin, param, 0, 0, 0, + 0, ret_payload); if (ret) { printf("%s failed\n", __func__); return ret; @@ -164,14 +166,15 @@ static int zynqmp_pm_pinctrl_set_config(const u32 pin, const u32 param, u32 valu } /* Request the pin first */ - ret = xilinx_pm_request(PM_PINCTRL_REQUEST, pin, 0, 0, 0, NULL); + ret = xilinx_pm_request(PM_PINCTRL_REQUEST, pin, 0, 0, 0, 0, 0, NULL); if (ret) { printf("%s: pin request failed\n", __func__); return ret; } /* Set config for the pin */ - ret = xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_SET, pin, param, value, 0, NULL); + ret = xilinx_pm_request(PM_PINCTRL_CONFIG_PARAM_SET, pin, param, value, + 0, 0, 0, NULL); if (ret) { printf("%s failed\n", __func__); return ret; @@ -186,7 +189,7 @@ static int zynqmp_pinctrl_get_function_groups(u32 fid, u32 index, u16 *groups) u32 ret_payload[PAYLOAD_ARG_CNT]; ret = xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_FUNCTION_GROUPS, - fid, index, 0, ret_payload); + fid, index, 0, 0, 0, ret_payload); if (ret) { printf("%s failed\n", __func__); return ret; @@ -242,7 +245,7 @@ static int zynqmp_pinctrl_get_pin_groups(u32 pin, u32 index, u16 *groups) u32 ret_payload[PAYLOAD_ARG_CNT]; ret = xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_PIN_GROUPS, - pin, index, 0, ret_payload); + pin, index, 0, 0, 0, ret_payload); if (ret) { printf("%s failed to get pin groups\n", __func__); return ret; @@ -313,13 +316,13 @@ static int zynqmp_pinctrl_probe(struct udevice *dev) for (i = 0; i < priv->nfuncs; i++) { /* Get function name for the function and fill */ xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_FUNCTION_NAME, - i, 0, 0, ret_payload); + i, 0, 0, 0, 0, ret_payload); memcpy((void *)priv->funcs[i].name, ret_payload, MAX_FUNC_NAME_LEN); /* And fill number of groups available for certain function */ xilinx_pm_request(PM_QUERY_DATA, PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS, - i, 0, 0, ret_payload); + i, 0, 0, 0, 0, ret_payload); priv->funcs[i].ngroups = ret_payload[1]; priv->ngroups += priv->funcs[i].ngroups; @@ -370,7 +373,8 @@ static int zynqmp_pinmux_set(struct udevice *dev, unsigned int selector, int ret; /* Request the pin first */ - ret = xilinx_pm_request(PM_PINCTRL_REQUEST, selector, 0, 0, 0, NULL); + ret = xilinx_pm_request(PM_PINCTRL_REQUEST, selector, 0, 0, 0, 0, + 0, NULL); if (ret) { printf("%s: pin request failed\n", __func__); return ret; @@ -378,7 +382,7 @@ static int zynqmp_pinmux_set(struct udevice *dev, unsigned int selector, /* Set the pin function */ ret = xilinx_pm_request(PM_PINCTRL_SET_FUNCTION, selector, func_selector, - 0, 0, NULL); + 0, 0, 0, 0, NULL); if (ret) { printf("%s: Failed to set pinmux function\n", __func__); return ret; diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 21f81b66099..320aba33347 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -68,6 +68,13 @@ config PINCTRL_QCOM_SC7280 help Say Y here to enable support for pinctrl on the Snapdragon SC7280 SoC, +config PINCTRL_QCOM_SDM670 + bool "Qualcomm SDM670 Pinctrl" + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the Snapdragon SDM670 SoC, + as well as the associated GPIO driver. + config PINCTRL_QCOM_SDM660 bool "Qualcomm SDM630/660 Pinctrl" select PINCTRL_QCOM @@ -89,6 +96,19 @@ config PINCTRL_QCOM_SM6115 Say Y here to enable support for pinctrl on the Snapdragon SM6115 SoC, as well as the associated GPIO driver. +config PINCTRL_QCOM_SM6350 + bool "Qualcomm SM6350 Pinctrl" + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the Snapdragon SM6350 SoC, + +config PINCTRL_QCOM_SM7150 + bool "Qualcomm SM7150 GCC" + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the Snapdragon SM7150 SoC, + as well as the associated GPIO driver. + config PINCTRL_QCOM_SM8150 bool "Qualcomm SM8150 Pinctrl" select PINCTRL_QCOM diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 6cb53838e71..06582ac2068 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -13,8 +13,11 @@ obj-$(CONFIG_PINCTRL_QCOM_QCS404) += pinctrl-qcs404.o obj-$(CONFIG_PINCTRL_QCOM_SA8775P) += pinctrl-sa8775p.o obj-$(CONFIG_PINCTRL_QCOM_SC7280) += pinctrl-sc7280.o obj-$(CONFIG_PINCTRL_QCOM_SDM660) += pinctrl-sdm660.o +obj-$(CONFIG_PINCTRL_QCOM_SDM670) += pinctrl-sdm670.o obj-$(CONFIG_PINCTRL_QCOM_SDM845) += pinctrl-sdm845.o obj-$(CONFIG_PINCTRL_QCOM_SM6115) += pinctrl-sm6115.o +obj-$(CONFIG_PINCTRL_QCOM_SM6350) += pinctrl-sm6350.o +obj-$(CONFIG_PINCTRL_QCOM_SM7150) += pinctrl-sm7150.o obj-$(CONFIG_PINCTRL_QCOM_SM8150) += pinctrl-sm8150.o obj-$(CONFIG_PINCTRL_QCOM_SM8250) += pinctrl-sm8250.o obj-$(CONFIG_PINCTRL_QCOM_SM8550) += pinctrl-sm8550.o diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280.c b/drivers/pinctrl/qcom/pinctrl-sc7280.c index fe87947fbbf..d62b2cc6fb6 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc7280.c +++ b/drivers/pinctrl/qcom/pinctrl-sc7280.c @@ -10,10 +10,6 @@ #include "pinctrl-qcom.h" -#define WEST 0x00000000 -#define SOUTH 0x00400000 -#define NORTH 0x00800000 - #define MAX_PIN_NAME_LEN 32 static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); @@ -47,7 +43,7 @@ static const struct pinctrl_function msm_pinctrl_functions[] = { } static const struct msm_special_pin_data sc7280_special_pins_data[] = { - [0] = UFS_RESET("ufs_reset", SOUTH + 0xbe000), + [0] = UFS_RESET("ufs_reset", 0xbe000), [1] = SDC_PINGROUP("sdc1_rclk", 0xb3004, 0, 6), [2] = SDC_PINGROUP("sdc1_clk", 0xb3000, 13, 6), [3] = SDC_PINGROUP("sdc1_cmd", 0xb3000, 11, 3), diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670.c b/drivers/pinctrl/qcom/pinctrl-sdm670.c new file mode 100644 index 00000000000..830fe7d826f --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sdm670.c @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Qualcomm SDM670 pinctrl + * + * (C) Copyright 2025 David Wronek <david.wronek@mainlining.org> + */ + +#include <dm.h> +#include "pinctrl-qcom.h" + +#define NORTH 0x00500000 +#define SOUTH 0x00900000 +#define WEST 0x00100000 + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +static const struct pinctrl_function sdm670_pinctrl_functions[] = { + { "gpio", 0 }, + { "blsp_uart2", 3 }, /* gpio 4 and 5, used for debug uart */ +}; + +static const unsigned int sdm670_pin_offsets[] = { + [0] = SOUTH, + [1] = SOUTH, + [2] = SOUTH, + [3] = SOUTH, + [4] = NORTH, + [5] = NORTH, + [6] = NORTH, + [7] = NORTH, + [8] = WEST, + [9] = WEST, + [10] = NORTH, + [11] = NORTH, + [12] = SOUTH, + [13] = WEST, + [14] = WEST, + [15] = WEST, + [16] = WEST, + [17] = WEST, + [18] = WEST, + [19] = WEST, + [20] = WEST, + [21] = WEST, + [22] = WEST, + [23] = WEST, + [24] = WEST, + [25] = WEST, + [26] = WEST, + [27] = WEST, + [28] = WEST, + [29] = WEST, + [30] = WEST, + [31] = WEST, + [32] = WEST, + [33] = WEST, + [34] = WEST, + [35] = NORTH, + [36] = NORTH, + [37] = NORTH, + [38] = NORTH, + [39] = NORTH, + [40] = NORTH, + [41] = SOUTH, + [42] = SOUTH, + [43] = SOUTH, + [44] = SOUTH, + [45] = SOUTH, + [46] = SOUTH, + [47] = SOUTH, + [48] = SOUTH, + [49] = NORTH, + [50] = NORTH, + [51] = NORTH, + [52] = NORTH, + [53] = NORTH, + [54] = NORTH, + [55] = NORTH, + [56] = NORTH, + [57] = NORTH, + [65] = NORTH, + [66] = NORTH, + [67] = NORTH, + [68] = NORTH, + [75] = NORTH, + [76] = NORTH, + [77] = NORTH, + [78] = NORTH, + [79] = NORTH, + [80] = NORTH, + [81] = NORTH, + [82] = NORTH, + [83] = NORTH, + [84] = NORTH, + [85] = SOUTH, + [86] = SOUTH, + [87] = SOUTH, + [88] = SOUTH, + [89] = SOUTH, + [90] = SOUTH, + [91] = SOUTH, + [92] = SOUTH, + [93] = SOUTH, + [94] = SOUTH, + [95] = SOUTH, + [96] = SOUTH, + [97] = WEST, + [98] = WEST, + [99] = NORTH, + [100] = WEST, + [101] = WEST, + [102] = WEST, + [103] = WEST, + [105] = NORTH, + [106] = NORTH, + [107] = NORTH, + [108] = NORTH, + [109] = NORTH, + [110] = NORTH, + [111] = NORTH, + [112] = NORTH, + [113] = NORTH, + [114] = WEST, + [115] = WEST, + [116] = SOUTH, + [117] = NORTH, + [118] = NORTH, + [119] = NORTH, + [120] = NORTH, + [121] = NORTH, + [122] = NORTH, + [123] = NORTH, + [124] = NORTH, + [125] = NORTH, + [126] = NORTH, + [127] = WEST, + [128] = WEST, + [129] = WEST, + [130] = WEST, + [131] = WEST, + [132] = WEST, + [133] = NORTH, + [134] = NORTH, + [135] = WEST, + [136] = WEST, + [137] = WEST, + [138] = WEST, + [139] = WEST, + [140] = WEST, + [141] = WEST, + [142] = WEST, + [143] = WEST, + [144] = SOUTH, + [145] = SOUTH, + [146] = WEST, + [147] = WEST, + [148] = WEST, + [149] = WEST, +}; + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ +{ \ + .name = pg_name, \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ +} + +#define UFS_RESET(pg_name, offset) \ +{ \ + .name = pg_name, \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ +} + +static const struct msm_special_pin_data sdm670_special_pins_data[] = { + UFS_RESET("ufs_reset", 0x99d000), + SDC_QDSD_PINGROUP("sdc1_rclk", NORTH + 0x99000, 15, 0), + SDC_QDSD_PINGROUP("sdc1_clk", NORTH + 0x99000, 13, 6), + SDC_QDSD_PINGROUP("sdc1_cmd", NORTH + 0x99000, 11, 3), + SDC_QDSD_PINGROUP("sdc1_data", NORTH + 0x99000, 9, 0), + SDC_QDSD_PINGROUP("sdc2_clk", NORTH + 0x9a000, 14, 6), + SDC_QDSD_PINGROUP("sdc2_cmd", NORTH + 0x9a000, 11, 3), + SDC_QDSD_PINGROUP("sdc2_data", NORTH + 0x9a000, 9, 0), +}; + +static const char *sdm670_get_function_name(struct udevice *dev, unsigned int selector) +{ + return sdm670_pinctrl_functions[selector].name; +} + +static const char *sdm670_get_pin_name(struct udevice *dev, unsigned int selector) +{ + if (selector >= 150 && selector <= 157) + snprintf(pin_name, MAX_PIN_NAME_LEN, + sdm670_special_pins_data[selector - 150].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + + return pin_name; +} + +static int sdm670_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector) +{ + if (selector >= 0 && selector < ARRAY_SIZE(sdm670_pinctrl_functions)) + return sdm670_pinctrl_functions[selector].val; + return -EINVAL; +} + +struct msm_pinctrl_data sdm670_data = { + .pin_data = { + .pin_offsets = sdm670_pin_offsets, + .pin_count = ARRAY_SIZE(sdm670_pin_offsets) + ARRAY_SIZE(sdm670_special_pins_data), + .special_pins_start = 150, + .special_pins_data = sdm670_special_pins_data, + }, + .functions_count = ARRAY_SIZE(sdm670_pinctrl_functions), + .get_function_name = sdm670_get_function_name, + .get_function_mux = sdm670_get_function_mux, + .get_pin_name = sdm670_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { + .compatible = "qcom,sdm670-tlmm", + .data = (ulong)&sdm670_data + }, + { /* Sentinel */ } +}; + +U_BOOT_DRIVER(pinctrl_ssdm670) = { + .name = "pinctrl_sdm670", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops = &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, +}; diff --git a/drivers/pinctrl/qcom/pinctrl-sm6350.c b/drivers/pinctrl/qcom/pinctrl-sm6350.c new file mode 100644 index 00000000000..1cbed77b55f --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sm6350.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Qualcomm sm6350 pinctrl + * + * (C) Copyright 2024 Linaro Ltd. + * (C) Copyright 2025 Luca Weiss <luca.weiss@fairphone.com> + * + */ + +#include <dm.h> + +#include "pinctrl-qcom.h" + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +static const struct pinctrl_function msm_pinctrl_functions[] = { + {"qup13_f2", 1}, + {"gpio", 0}, +}; + +#define SDC_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = pg_name, \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + } + +#define UFS_RESET(pg_name, offset) \ + { \ + .name = pg_name, \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + } + +static const struct msm_special_pin_data sm6350_special_pins_data[] = { + [0] = UFS_RESET("ufs_reset", 0xae000), + [1] = SDC_PINGROUP("sdc1_rclk", 0xa1000, 15, 0), + [2] = SDC_PINGROUP("sdc1_clk", 0xa0000, 13, 6), + [3] = SDC_PINGROUP("sdc1_cmd", 0xa0000, 11, 3), + [4] = SDC_PINGROUP("sdc1_data", 0xa0000, 9, 0), + [5] = SDC_PINGROUP("sdc2_clk", 0xa2000, 14, 6), + [6] = SDC_PINGROUP("sdc2_cmd", 0xa2000, 11, 3), + [7] = SDC_PINGROUP("sdc2_data", 0xa2000, 9, 0), +}; + +static const char *sm6350_get_function_name(struct udevice *dev, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].name; +} + +static const char *sm6350_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + if (selector >= 156 && selector <= 163) + snprintf(pin_name, MAX_PIN_NAME_LEN, + sm6350_special_pins_data[selector - 156].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + + return pin_name; +} + +static int sm6350_get_function_mux(__maybe_unused unsigned int pin, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].val; +} + +static struct msm_pinctrl_data sm6350_data = { + .pin_data = { + .pin_count = 164, + .special_pins_start = 156, + .special_pins_data = sm6350_special_pins_data, + }, + .functions_count = ARRAY_SIZE(msm_pinctrl_functions), + .get_function_name = sm6350_get_function_name, + .get_function_mux = sm6350_get_function_mux, + .get_pin_name = sm6350_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,sm6350-tlmm", .data = (ulong)&sm6350_data }, + { /* Sentinel */ } +}; + +U_BOOT_DRIVER(pinctrl_sm6350) = { + .name = "pinctrl_sm6350", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops = &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, +}; diff --git a/drivers/pinctrl/qcom/pinctrl-sm7150.c b/drivers/pinctrl/qcom/pinctrl-sm7150.c new file mode 100644 index 00000000000..435ba39b1db --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sm7150.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Pinctrl driver for Qualcomm SM7150 + * + * (C) Copyright 2025 Danila Tikhonov <danila@jiaxyga.com> + * (C) Copyright 2025 Jens Reidel <adrian@mainlining.org> + * + * Based on Linux Kernel driver + */ + +#include <dm.h> + +#include "pinctrl-qcom.h" + +#define WEST 0x00000000 +#define NORTH 0x00400000 +#define SOUTH 0x00800000 + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +static const struct pinctrl_function msm_pinctrl_functions[] = { + { "qup12", 1 }, + { "gpio", 0 }, + { "sdc2_clk", 0 } /* special pin GPIO124 */ +}; + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = pg_name, \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + } + +#define UFS_RESET(pg_name, offset) \ + { \ + .name = pg_name, \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + } + +static const struct msm_special_pin_data msm_special_pins_data[] = { + [0] = UFS_RESET("ufs_reset", 0x9f000), + [1] = SDC_QDSD_PINGROUP("sdc1_rclk", WEST + 0x9a000, 15, 0), + [2] = SDC_QDSD_PINGROUP("sdc1_clk", WEST + 0x9a000, 13, 6), + [3] = SDC_QDSD_PINGROUP("sdc1_cmd", WEST + 0x9a000, 11, 3), + [4] = SDC_QDSD_PINGROUP("sdc1_data", WEST + 0x9a000, 9, 0), + [5] = SDC_QDSD_PINGROUP("sdc2_clk", SOUTH + 0x98000, 14, 6), + [6] = SDC_QDSD_PINGROUP("sdc2_cmd", SOUTH + 0x98000, 11, 3), + [7] = SDC_QDSD_PINGROUP("sdc2_data", SOUTH + 0x98000, 9, 0), +}; + +static const unsigned int sm7150_pin_offsets[] = { + [0] = SOUTH, [1] = SOUTH, [2] = SOUTH, [3] = SOUTH, + [4] = NORTH, [5] = NORTH, [6] = NORTH, [7] = NORTH, + [8] = NORTH, [9] = NORTH, [10] = NORTH, [11] = NORTH, + [12] = SOUTH, [13] = SOUTH, [14] = SOUTH, [15] = SOUTH, + [16] = SOUTH, [17] = SOUTH, [18] = SOUTH, [19] = SOUTH, + [20] = SOUTH, [21] = SOUTH, [22] = SOUTH, [23] = SOUTH, + [24] = SOUTH, [25] = SOUTH, [26] = SOUTH, [27] = SOUTH, + [28] = SOUTH, [29] = NORTH, [30] = SOUTH, [31] = WEST, + [32] = NORTH, [33] = NORTH, [34] = SOUTH, [35] = SOUTH, + [36] = SOUTH, [37] = SOUTH, [38] = SOUTH, [39] = SOUTH, + [40] = SOUTH, [41] = SOUTH, [42] = NORTH, [43] = NORTH, + [44] = NORTH, [45] = NORTH, [46] = NORTH, [47] = NORTH, + [48] = WEST, [49] = WEST, [50] = WEST, [51] = WEST, + [52] = WEST, [53] = WEST, [54] = WEST, [55] = WEST, + [56] = WEST, [57] = WEST, [58] = WEST, [59] = NORTH, + [60] = NORTH, [61] = NORTH, [62] = NORTH, [63] = NORTH, + [64] = NORTH, [65] = NORTH, [66] = NORTH, [67] = NORTH, + [68] = NORTH, [69] = NORTH, [70] = NORTH, [71] = NORTH, + [72] = NORTH, [73] = NORTH, [74] = WEST, [75] = WEST, + [76] = WEST, [77] = WEST, [78] = WEST, [79] = WEST, + [80] = WEST, [81] = WEST, [82] = WEST, [83] = WEST, + [84] = WEST, [85] = WEST, [86] = NORTH, [87] = NORTH, + [88] = NORTH, [89] = NORTH, [90] = NORTH, [91] = NORTH, + [92] = NORTH, [93] = NORTH, [94] = SOUTH, [95] = WEST, + [96] = WEST, [97] = WEST, [98] = WEST, [99] = WEST, + [100] = WEST, [101] = NORTH, [102] = NORTH, [103] = NORTH, + [104] = WEST, [105] = NORTH, [106] = NORTH, [107] = WEST, + [108] = SOUTH, [109] = SOUTH, [110] = NORTH, [111] = NORTH, + [112] = NORTH, [113] = NORTH, [114] = NORTH, [115] = NORTH, + [116] = NORTH, [117] = NORTH, [118] = NORTH, +}; + +static const char *sm7150_get_function_name(struct udevice *dev, unsigned int selector) +{ + return msm_pinctrl_functions[selector].name; +} + +static const char *sm7150_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + if (selector >= 119 && selector <= 126) + snprintf(pin_name, MAX_PIN_NAME_LEN, + msm_special_pins_data[selector - 119].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + + return pin_name; +} + +static int sm7150_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector) +{ + return msm_pinctrl_functions[selector].val; +} + +static struct msm_pinctrl_data sm7150_data = { + .pin_data = { + .pin_offsets = sm7150_pin_offsets, + .pin_count = 126, + .special_pins_start = 119, + .special_pins_data = msm_special_pins_data, + }, + .functions_count = ARRAY_SIZE(msm_pinctrl_functions), + .get_function_name = sm7150_get_function_name, + .get_function_mux = sm7150_get_function_mux, + .get_pin_name = sm7150_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,sm7150-tlmm", .data = (ulong)&sm7150_data }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(pinctrl_sm7150) = { + .name = "pinctrl_sm7150", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops = &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, +}; diff --git a/drivers/pinctrl/renesas/Kconfig b/drivers/pinctrl/renesas/Kconfig index 560f7275454..ac40b31dbfa 100644 --- a/drivers/pinctrl/renesas/Kconfig +++ b/drivers/pinctrl/renesas/Kconfig @@ -53,28 +53,28 @@ config PINCTRL_PFC_R8A7794 Support pin multiplexing control on Renesas R-Car Gen2 R8A7794 SoCs. config PINCTRL_PFC_R8A774A1 - bool "Renesas RZ/G2 R8A774A1 pin control driver" - depends on PINCTRL_PFC - help - Support pin multiplexing control on Renesas RZ/G2M R8A774A1 SoCs. + bool "Renesas RZ/G2 R8A774A1 pin control driver" + depends on PINCTRL_PFC + help + Support pin multiplexing control on Renesas RZ/G2M R8A774A1 SoCs. config PINCTRL_PFC_R8A774B1 - bool "Renesas RZ/G2 R8A774B1 pin control driver" - depends on PINCTRL_PFC - help - Support pin multiplexing control on Renesas RZ/G2N R8A774B1 SoCs. + bool "Renesas RZ/G2 R8A774B1 pin control driver" + depends on PINCTRL_PFC + help + Support pin multiplexing control on Renesas RZ/G2N R8A774B1 SoCs. config PINCTRL_PFC_R8A774C0 - bool "Renesas RZ/G2 R8A774C0 pin control driver" - depends on PINCTRL_PFC - help - Support pin multiplexing control on Renesas RZ/G2E R8A774C0 SoCs. + bool "Renesas RZ/G2 R8A774C0 pin control driver" + depends on PINCTRL_PFC + help + Support pin multiplexing control on Renesas RZ/G2E R8A774C0 SoCs. config PINCTRL_PFC_R8A774E1 - bool "Renesas RZ/G2 R8A774E1 pin control driver" - depends on PINCTRL_PFC - help - Support pin multiplexing control on Renesas RZ/G2H R8A774E1 SoCs. + bool "Renesas RZ/G2 R8A774E1 pin control driver" + depends on PINCTRL_PFC + help + Support pin multiplexing control on Renesas RZ/G2H R8A774E1 SoCs. config PINCTRL_PFC_R8A77951 bool "Renesas R-Car Gen3 R8A7795 pin control driver" @@ -148,6 +148,12 @@ config PINCTRL_PFC_R8A779H0 help Support pin multiplexing control on Renesas R-Car Gen4 R8A779H0 SoCs. +config PINCTRL_PFC_R8A78000 + bool "Renesas R-Car Gen5 R8A78000 pin control driver" + depends on PINCTRL_PFC + help + Support pin multiplexing control on Renesas R-Car Gen5 R8A78000 SoCs. + config PINCTRL_RZA1 bool "Renesas RZ/A1 R7S72100 pin control driver" depends on CPU_RZA1 diff --git a/drivers/pinctrl/renesas/Makefile b/drivers/pinctrl/renesas/Makefile index a5810dc0f10..f9ac5eabf09 100644 --- a/drivers/pinctrl/renesas/Makefile +++ b/drivers/pinctrl/renesas/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_PINCTRL_PFC_R8A779A0) += pfc-r8a779a0.o obj-$(CONFIG_PINCTRL_PFC_R8A779F0) += pfc-r8a779f0.o obj-$(CONFIG_PINCTRL_PFC_R8A779G0) += pfc-r8a779g0.o obj-$(CONFIG_PINCTRL_PFC_R8A779H0) += pfc-r8a779h0.o +obj-$(CONFIG_PINCTRL_PFC_R8A78000) += pfc-r8a78000.o obj-$(CONFIG_PINCTRL_RZA1) += pinctrl-rza1.o obj-$(CONFIG_PINCTRL_RZN1) += pinctrl-rzn1.o obj-$(CONFIG_PINCTRL_RZG2L) += rzg2l-pfc.o diff --git a/drivers/pinctrl/renesas/pfc-r8a7790.c b/drivers/pinctrl/renesas/pfc-r8a7790.c index 4d6ce06cf16..e986c9fd6c1 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7790.c +++ b/drivers/pinctrl/renesas/pfc-r8a7790.c @@ -6186,6 +6186,7 @@ static const struct sh_pfc_soc_operations r8a7790_pfc_ops = { .pin_to_pocctrl = r8a7790_pin_to_pocctrl, .get_bias = rcar_pinmux_get_bias, .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; #ifdef CONFIG_PINCTRL_PFC_R8A7742 diff --git a/drivers/pinctrl/renesas/pfc-r8a7791.c b/drivers/pinctrl/renesas/pfc-r8a7791.c index c6d761bb378..90dedd02b69 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7791.c +++ b/drivers/pinctrl/renesas/pfc-r8a7791.c @@ -6936,6 +6936,7 @@ static const struct sh_pfc_soc_operations r8a7791_pfc_ops = { .pin_to_pocctrl = r8a7791_pin_to_pocctrl, .get_bias = rcar_pinmux_get_bias, .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; #ifdef CONFIG_PINCTRL_PFC_R8A7743 diff --git a/drivers/pinctrl/renesas/pfc-r8a7792.c b/drivers/pinctrl/renesas/pfc-r8a7792.c index d2ff1d9d1a6..fa44028724b 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7792.c +++ b/drivers/pinctrl/renesas/pfc-r8a7792.c @@ -3145,6 +3145,7 @@ static const struct pinmux_bias_reg pinmux_bias_regs[] = { static const struct sh_pfc_soc_operations r8a7792_pfc_ops = { .get_bias = rcar_pinmux_get_bias, .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; const struct sh_pfc_soc_info r8a7792_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-r8a7794.c b/drivers/pinctrl/renesas/pfc-r8a7794.c index a1fa1776bae..1ee932f9c2e 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7794.c +++ b/drivers/pinctrl/renesas/pfc-r8a7794.c @@ -5887,6 +5887,7 @@ static const struct sh_pfc_soc_operations r8a7794_pfc_ops = { .pin_to_pocctrl = r8a7794_pin_to_pocctrl, .get_bias = rcar_pinmux_get_bias, .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; #ifdef CONFIG_PINCTRL_PFC_R8A7745 diff --git a/drivers/pinctrl/renesas/pfc-r8a77951.c b/drivers/pinctrl/renesas/pfc-r8a77951.c index 8ddcbfbbd64..99b90e6df0d 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77951.c +++ b/drivers/pinctrl/renesas/pfc-r8a77951.c @@ -6184,6 +6184,7 @@ static const struct sh_pfc_soc_operations r8a77951_pfc_ops = { .pin_to_pocctrl = r8a77951_pin_to_pocctrl, .get_bias = rcar_pinmux_get_bias, .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; #ifdef CONFIG_PINCTRL_PFC_R8A774E1 diff --git a/drivers/pinctrl/renesas/pfc-r8a7796.c b/drivers/pinctrl/renesas/pfc-r8a7796.c index 7bc9fb709ea..a587dfb89d4 100644 --- a/drivers/pinctrl/renesas/pfc-r8a7796.c +++ b/drivers/pinctrl/renesas/pfc-r8a7796.c @@ -6137,6 +6137,7 @@ static const struct sh_pfc_soc_operations r8a7796_pfc_ops = { .pin_to_pocctrl = r8a7796_pin_to_pocctrl, .get_bias = rcar_pinmux_get_bias, .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; #ifdef CONFIG_PINCTRL_PFC_R8A774A1 diff --git a/drivers/pinctrl/renesas/pfc-r8a77965.c b/drivers/pinctrl/renesas/pfc-r8a77965.c index 97fde005de6..9049d762a59 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77965.c +++ b/drivers/pinctrl/renesas/pfc-r8a77965.c @@ -6378,6 +6378,7 @@ static const struct sh_pfc_soc_operations r8a77965_pfc_ops = { .pin_to_pocctrl = r8a77965_pin_to_pocctrl, .get_bias = rcar_pinmux_get_bias, .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; #ifdef CONFIG_PINCTRL_PFC_R8A774B1 diff --git a/drivers/pinctrl/renesas/pfc-r8a77970.c b/drivers/pinctrl/renesas/pfc-r8a77970.c index 3a0a310c5fe..c4fc6c8e09c 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77970.c +++ b/drivers/pinctrl/renesas/pfc-r8a77970.c @@ -2567,6 +2567,7 @@ static const struct sh_pfc_soc_operations r8a77970_pfc_ops = { .pin_to_pocctrl = r8a77970_pin_to_pocctrl, .get_bias = rcar_pinmux_get_bias, .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; const struct sh_pfc_soc_info r8a77970_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-r8a77980.c b/drivers/pinctrl/renesas/pfc-r8a77980.c index 59f4bdde202..8fd7e165bbe 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77980.c +++ b/drivers/pinctrl/renesas/pfc-r8a77980.c @@ -3084,6 +3084,7 @@ static const struct sh_pfc_soc_operations r8a77980_pfc_ops = { .pin_to_pocctrl = r8a77980_pin_to_pocctrl, .get_bias = rcar_pinmux_get_bias, .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; const struct sh_pfc_soc_info r8a77980_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-r8a77990.c b/drivers/pinctrl/renesas/pfc-r8a77990.c index 75b7429bc0d..3607a559c6d 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77990.c +++ b/drivers/pinctrl/renesas/pfc-r8a77990.c @@ -5336,6 +5336,7 @@ static const struct sh_pfc_soc_operations r8a77990_pfc_ops = { .pin_to_pocctrl = r8a77990_pin_to_pocctrl, .get_bias = rcar_pinmux_get_bias, .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; #ifdef CONFIG_PINCTRL_PFC_R8A774C0 diff --git a/drivers/pinctrl/renesas/pfc-r8a77995.c b/drivers/pinctrl/renesas/pfc-r8a77995.c index 6fe2d743418..8f2bda5d6d3 100644 --- a/drivers/pinctrl/renesas/pfc-r8a77995.c +++ b/drivers/pinctrl/renesas/pfc-r8a77995.c @@ -3210,6 +3210,7 @@ static const struct sh_pfc_soc_operations r8a77995_pfc_ops = { .pin_to_pocctrl = r8a77995_pin_to_pocctrl, .get_bias = r8a77995_pinmux_get_bias, .set_bias = r8a77995_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; const struct sh_pfc_soc_info r8a77995_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-r8a779a0.c b/drivers/pinctrl/renesas/pfc-r8a779a0.c index 39690bd5d07..82d39a3b366 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779a0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779a0.c @@ -4382,6 +4382,7 @@ static const struct sh_pfc_soc_operations r8a779a0_pfc_ops = { .pin_to_pocctrl = r8a779a0_pin_to_pocctrl, .get_bias = rcar_pinmux_get_bias, .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; const struct sh_pfc_soc_info r8a779a0_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-r8a779f0.c b/drivers/pinctrl/renesas/pfc-r8a779f0.c index 2b629135f69..78659eaa187 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779f0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779f0.c @@ -2094,6 +2094,7 @@ static const struct sh_pfc_soc_operations r8a779f0_pfc_ops = { .pin_to_pocctrl = r8a779f0_pin_to_pocctrl, .get_bias = rcar_pinmux_get_bias, .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; const struct sh_pfc_soc_info r8a779f0_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-r8a779g0.c b/drivers/pinctrl/renesas/pfc-r8a779g0.c index f411be8b879..c63adedd297 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779g0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779g0.c @@ -354,7 +354,7 @@ #define IP1SR2_3_0 FM(TPU0TO0_A) FM(CANFD6_RX) F_(0, 0) FM(TCLK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_7_4 FM(CAN_CLK) FM(FXR_TXENA_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_11_8 FM(CANFD0_TX) FM(FXR_TXENB_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_15_12 FM(CANFD0_RX) FM(STPWT_EXTFXR) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_15_12 FM(CANFD0_RX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_19_16 FM(CANFD2_TX) FM(TPU0TO2_A) F_(0, 0) FM(TCLK3_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_23_20 FM(CANFD2_RX) FM(TPU0TO3_A) FM(PWM1_B) FM(TCLK4_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_27_24 FM(CANFD3_TX) F_(0, 0) FM(PWM2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -473,55 +473,55 @@ #define IP0SR6_7_4 FM(AVB1_MAGIC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR6_11_8 FM(AVB1_MDC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR6_15_12 FM(AVB1_PHY_INT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR6_19_16 FM(AVB1_LINK) FM(AVB1_MII_TX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR6_23_20 FM(AVB1_AVTP_MATCH) FM(AVB1_MII_RX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR6_27_24 FM(AVB1_TXC) FM(AVB1_MII_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR6_31_28 FM(AVB1_TX_CTL) FM(AVB1_MII_TX_EN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR6_19_16 FM(AVB1_LINK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR6_23_20 FM(AVB1_AVTP_MATCH) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR6_27_24 FM(AVB1_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR6_31_28 FM(AVB1_TX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP1SR6 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP1SR6_3_0 FM(AVB1_RXC) FM(AVB1_MII_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_7_4 FM(AVB1_RX_CTL) FM(AVB1_MII_RX_DV) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_11_8 FM(AVB1_AVTP_PPS) FM(AVB1_MII_COL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_15_12 FM(AVB1_AVTP_CAPTURE) FM(AVB1_MII_CRS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_19_16 FM(AVB1_TD1) FM(AVB1_MII_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_23_20 FM(AVB1_TD0) FM(AVB1_MII_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_27_24 FM(AVB1_RD1) FM(AVB1_MII_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_31_28 FM(AVB1_RD0) FM(AVB1_MII_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_3_0 FM(AVB1_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_7_4 FM(AVB1_RX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_11_8 FM(AVB1_AVTP_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_15_12 FM(AVB1_AVTP_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_19_16 FM(AVB1_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_23_20 FM(AVB1_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_27_24 FM(AVB1_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_31_28 FM(AVB1_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP2SR6 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP2SR6_3_0 FM(AVB1_TD2) FM(AVB1_MII_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR6_7_4 FM(AVB1_RD2) FM(AVB1_MII_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR6_11_8 FM(AVB1_TD3) FM(AVB1_MII_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR6_15_12 FM(AVB1_RD3) FM(AVB1_MII_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR6_3_0 FM(AVB1_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR6_7_4 FM(AVB1_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR6_11_8 FM(AVB1_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR6_15_12 FM(AVB1_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP2SR6_19_16 FM(AVB1_TXCREFCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* SR7 */ /* IP0SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP0SR7_3_0 FM(AVB0_AVTP_PPS) FM(AVB0_MII_COL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_7_4 FM(AVB0_AVTP_CAPTURE) FM(AVB0_MII_CRS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) FM(AVB0_MII_RX_ER) FM(CC5_OSCOUT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_15_12 FM(AVB0_TD3) FM(AVB0_MII_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_19_16 FM(AVB0_LINK) FM(AVB0_MII_TX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_3_0 FM(AVB0_AVTP_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_7_4 FM(AVB0_AVTP_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_15_12 FM(AVB0_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_19_16 FM(AVB0_LINK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_23_20 FM(AVB0_PHY_INT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_27_24 FM(AVB0_TD2) FM(AVB0_MII_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_31_28 FM(AVB0_TD1) FM(AVB0_MII_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_27_24 FM(AVB0_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_31_28 FM(AVB0_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP1SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP1SR7_3_0 FM(AVB0_RD3) FM(AVB0_MII_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR7_3_0 FM(AVB0_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR7_7_4 FM(AVB0_TXCREFCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR7_11_8 FM(AVB0_MAGIC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR7_15_12 FM(AVB0_TD0) FM(AVB0_MII_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR7_19_16 FM(AVB0_RD2) FM(AVB0_MII_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR7_15_12 FM(AVB0_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR7_19_16 FM(AVB0_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR7_23_20 FM(AVB0_MDC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR7_27_24 FM(AVB0_MDIO) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR7_31_28 FM(AVB0_TXC) FM(AVB0_MII_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR7_31_28 FM(AVB0_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP2SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP2SR7_3_0 FM(AVB0_TX_CTL) FM(AVB0_MII_TX_EN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR7_7_4 FM(AVB0_RD1) FM(AVB0_MII_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR7_11_8 FM(AVB0_RD0) FM(AVB0_MII_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR7_15_12 FM(AVB0_RXC) FM(AVB0_MII_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR7_19_16 FM(AVB0_RX_CTL) FM(AVB0_MII_RX_DV) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_3_0 FM(AVB0_TX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_7_4 FM(AVB0_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_11_8 FM(AVB0_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_15_12 FM(AVB0_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_19_16 FM(AVB0_RX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* SR8 */ /* IP0SR8 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ @@ -927,7 +927,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1SR2_11_8, FXR_TXENB_N_B), PINMUX_IPSR_GPSR(IP1SR2_15_12, CANFD0_RX), - PINMUX_IPSR_GPSR(IP1SR2_15_12, STPWT_EXTFXR), PINMUX_IPSR_GPSR(IP1SR2_19_16, CANFD2_TX), PINMUX_IPSR_GPSR(IP1SR2_19_16, TPU0TO2_A), @@ -1078,118 +1077,85 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP0SR6_15_12, AVB1_PHY_INT), PINMUX_IPSR_GPSR(IP0SR6_19_16, AVB1_LINK), - PINMUX_IPSR_GPSR(IP0SR6_19_16, AVB1_MII_TX_ER), PINMUX_IPSR_GPSR(IP0SR6_23_20, AVB1_AVTP_MATCH), - PINMUX_IPSR_GPSR(IP0SR6_23_20, AVB1_MII_RX_ER), PINMUX_IPSR_GPSR(IP0SR6_27_24, AVB1_TXC), - PINMUX_IPSR_GPSR(IP0SR6_27_24, AVB1_MII_TXC), PINMUX_IPSR_GPSR(IP0SR6_31_28, AVB1_TX_CTL), - PINMUX_IPSR_GPSR(IP0SR6_31_28, AVB1_MII_TX_EN), /* IP1SR6 */ PINMUX_IPSR_GPSR(IP1SR6_3_0, AVB1_RXC), - PINMUX_IPSR_GPSR(IP1SR6_3_0, AVB1_MII_RXC), PINMUX_IPSR_GPSR(IP1SR6_7_4, AVB1_RX_CTL), - PINMUX_IPSR_GPSR(IP1SR6_7_4, AVB1_MII_RX_DV), PINMUX_IPSR_GPSR(IP1SR6_11_8, AVB1_AVTP_PPS), - PINMUX_IPSR_GPSR(IP1SR6_11_8, AVB1_MII_COL), PINMUX_IPSR_GPSR(IP1SR6_15_12, AVB1_AVTP_CAPTURE), - PINMUX_IPSR_GPSR(IP1SR6_15_12, AVB1_MII_CRS), PINMUX_IPSR_GPSR(IP1SR6_19_16, AVB1_TD1), - PINMUX_IPSR_GPSR(IP1SR6_19_16, AVB1_MII_TD1), PINMUX_IPSR_GPSR(IP1SR6_23_20, AVB1_TD0), - PINMUX_IPSR_GPSR(IP1SR6_23_20, AVB1_MII_TD0), PINMUX_IPSR_GPSR(IP1SR6_27_24, AVB1_RD1), - PINMUX_IPSR_GPSR(IP1SR6_27_24, AVB1_MII_RD1), PINMUX_IPSR_GPSR(IP1SR6_31_28, AVB1_RD0), - PINMUX_IPSR_GPSR(IP1SR6_31_28, AVB1_MII_RD0), /* IP2SR6 */ PINMUX_IPSR_GPSR(IP2SR6_3_0, AVB1_TD2), - PINMUX_IPSR_GPSR(IP2SR6_3_0, AVB1_MII_TD2), PINMUX_IPSR_GPSR(IP2SR6_7_4, AVB1_RD2), - PINMUX_IPSR_GPSR(IP2SR6_7_4, AVB1_MII_RD2), PINMUX_IPSR_GPSR(IP2SR6_11_8, AVB1_TD3), - PINMUX_IPSR_GPSR(IP2SR6_11_8, AVB1_MII_TD3), PINMUX_IPSR_GPSR(IP2SR6_15_12, AVB1_RD3), - PINMUX_IPSR_GPSR(IP2SR6_15_12, AVB1_MII_RD3), PINMUX_IPSR_GPSR(IP2SR6_19_16, AVB1_TXCREFCLK), /* IP0SR7 */ PINMUX_IPSR_GPSR(IP0SR7_3_0, AVB0_AVTP_PPS), - PINMUX_IPSR_GPSR(IP0SR7_3_0, AVB0_MII_COL), PINMUX_IPSR_GPSR(IP0SR7_7_4, AVB0_AVTP_CAPTURE), - PINMUX_IPSR_GPSR(IP0SR7_7_4, AVB0_MII_CRS), PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_AVTP_MATCH), - PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_MII_RX_ER), - PINMUX_IPSR_GPSR(IP0SR7_11_8, CC5_OSCOUT), PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_TD3), - PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_MII_TD3), PINMUX_IPSR_GPSR(IP0SR7_19_16, AVB0_LINK), - PINMUX_IPSR_GPSR(IP0SR7_19_16, AVB0_MII_TX_ER), PINMUX_IPSR_GPSR(IP0SR7_23_20, AVB0_PHY_INT), PINMUX_IPSR_GPSR(IP0SR7_27_24, AVB0_TD2), - PINMUX_IPSR_GPSR(IP0SR7_27_24, AVB0_MII_TD2), PINMUX_IPSR_GPSR(IP0SR7_31_28, AVB0_TD1), - PINMUX_IPSR_GPSR(IP0SR7_31_28, AVB0_MII_TD1), /* IP1SR7 */ PINMUX_IPSR_GPSR(IP1SR7_3_0, AVB0_RD3), - PINMUX_IPSR_GPSR(IP1SR7_3_0, AVB0_MII_RD3), PINMUX_IPSR_GPSR(IP1SR7_7_4, AVB0_TXCREFCLK), PINMUX_IPSR_GPSR(IP1SR7_11_8, AVB0_MAGIC), PINMUX_IPSR_GPSR(IP1SR7_15_12, AVB0_TD0), - PINMUX_IPSR_GPSR(IP1SR7_15_12, AVB0_MII_TD0), PINMUX_IPSR_GPSR(IP1SR7_19_16, AVB0_RD2), - PINMUX_IPSR_GPSR(IP1SR7_19_16, AVB0_MII_RD2), PINMUX_IPSR_GPSR(IP1SR7_23_20, AVB0_MDC), PINMUX_IPSR_GPSR(IP1SR7_27_24, AVB0_MDIO), PINMUX_IPSR_GPSR(IP1SR7_31_28, AVB0_TXC), - PINMUX_IPSR_GPSR(IP1SR7_31_28, AVB0_MII_TXC), /* IP2SR7 */ PINMUX_IPSR_GPSR(IP2SR7_3_0, AVB0_TX_CTL), - PINMUX_IPSR_GPSR(IP2SR7_3_0, AVB0_MII_TX_EN), PINMUX_IPSR_GPSR(IP2SR7_7_4, AVB0_RD1), - PINMUX_IPSR_GPSR(IP2SR7_7_4, AVB0_MII_RD1), PINMUX_IPSR_GPSR(IP2SR7_11_8, AVB0_RD0), - PINMUX_IPSR_GPSR(IP2SR7_11_8, AVB0_MII_RD0), PINMUX_IPSR_GPSR(IP2SR7_15_12, AVB0_RXC), - PINMUX_IPSR_GPSR(IP2SR7_15_12, AVB0_MII_RXC), PINMUX_IPSR_GPSR(IP2SR7_19_16, AVB0_RX_CTL), - PINMUX_IPSR_GPSR(IP2SR7_19_16, AVB0_MII_RX_DV), /* IP0SR8 */ PINMUX_IPSR_MSEL(IP0SR8_3_0, SCL0, SEL_SCL0_0), @@ -4490,6 +4456,7 @@ static const struct sh_pfc_soc_operations r8a779g0_pin_ops = { .pin_to_pocctrl = r8a779g0_pin_to_pocctrl, .get_bias = rcar_pinmux_get_bias, .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; const struct sh_pfc_soc_info r8a779g0_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-r8a779h0.c b/drivers/pinctrl/renesas/pfc-r8a779h0.c index 87af037a8d3..2c6c901f3a4 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779h0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779h0.c @@ -342,7 +342,7 @@ #define IP1SR2_3_0 FM(TPU0TO0_A) F_(0, 0) F_(0, 0) FM(TCLK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_7_4 FM(CAN_CLK) FM(FXR_TXENA_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_11_8 FM(CANFD0_TX) FM(FXR_TXENB_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_15_12 FM(CANFD0_RX) FM(STPWT_EXTFXR) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_15_12 FM(CANFD0_RX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_19_16 FM(CANFD2_TX) FM(TPU0TO2_A) F_(0, 0) FM(TCLK3_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_23_20 FM(CANFD2_RX) FM(TPU0TO3_A) FM(PWM1_B) FM(TCLK4_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_27_24 FM(CANFD3_TX) F_(0, 0) FM(PWM2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -481,7 +481,7 @@ /* IP0SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ #define IP0SR7_3_0 FM(AVB0_AVTP_PPS) FM(AVB0_MII_COL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_7_4 FM(AVB0_AVTP_CAPTURE) FM(AVB0_MII_CRS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) FM(AVB0_MII_RX_ER) FM(CC5_OSCOUT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) FM(AVB0_MII_RX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_15_12 FM(AVB0_TD3) FM(AVB0_MII_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_19_16 FM(AVB0_LINK) FM(AVB0_MII_TX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_23_20 FM(AVB0_PHY_INT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -868,7 +868,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1SR2_11_8, FXR_TXENB_N_B), PINMUX_IPSR_GPSR(IP1SR2_15_12, CANFD0_RX), - PINMUX_IPSR_GPSR(IP1SR2_15_12, STPWT_EXTFXR), PINMUX_IPSR_GPSR(IP1SR2_19_16, CANFD2_TX), PINMUX_IPSR_GPSR(IP1SR2_19_16, TPU0TO2_A), @@ -1126,7 +1125,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_AVTP_MATCH), PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_MII_RX_ER), - PINMUX_IPSR_GPSR(IP0SR7_11_8, CC5_OSCOUT), PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_TD3), PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_MII_TD3), @@ -4143,6 +4141,7 @@ static const struct sh_pfc_soc_operations r8a779h0_pin_ops = { .pin_to_pocctrl = r8a779h0_pin_to_pocctrl, .get_bias = rcar_pinmux_get_bias, .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar_pinconf_set_drive_strength, }; const struct sh_pfc_soc_info r8a779h0_pinmux_info = { diff --git a/drivers/pinctrl/renesas/pfc-r8a78000.c b/drivers/pinctrl/renesas/pfc-r8a78000.c new file mode 100644 index 00000000000..cb6a18ee229 --- /dev/null +++ b/drivers/pinctrl/renesas/pfc-r8a78000.c @@ -0,0 +1,5254 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * R8A78000 processor support - PFC hardware block. + * + * Copyright (C) 2025 Renesas Electronics Corp. + * + */ + +#include <dm.h> +#include <errno.h> +#include <bitfield.h> +#include <dm/pinctrl.h> +#include <linux/bitops.h> +#include <linux/kernel.h> + +#include "sh_pfc.h" + +#define CFG_FLAGS (SH_PFC_PIN_CFG_DRIVE_STRENGTH | SH_PFC_PIN_CFG_PULL_UP_DOWN) + +#define CPU_ALL_GP(fn, sfx) \ + PORT_GP_CFG_28(0, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_22(1, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_29(2, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_17(3, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_16(4, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_23(5, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_31(6, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_31(7, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_16(8, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_1(8, 26, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_1(8, 27, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_1(8, 28, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_1(8, 29, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_1(8, 30, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_1(8, 31, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_17(9, fn, sfx, CFG_FLAGS), \ + PORT_GP_CFG_14(10, fn, sfx, CFG_FLAGS) + +/* + * F_() : just information + * FM() : macro for FN_xxx / xxx_MARK + */ + +/* GPSR0 */ +#define GPSR0_27 F_(DP2_HOTPLUG, GRP0_27_FUNC) +#define GPSR0_26 F_(DP1_HOTPLUG, GRP0_26_FUNC) +#define GPSR0_25 F_(DP0_HOTPLUG, GRP0_25_FUNC) +#define GPSR0_24 F_(MSIOF1_SS2_A, GRP0_24_FUNC) +#define GPSR0_23 F_(MSIOF1_SS1_A, GRP0_23_FUNC) +#define GPSR0_22 F_(MSIOF1_SYNC_A, GRP0_22_FUNC) +#define GPSR0_21 F_(MSIOF1_RXD_A, GRP0_21_FUNC) +#define GPSR0_20 F_(MSIOF1_TXD_A, GRP0_20_FUNC) +#define GPSR0_19 F_(MSIOF1_SCK_A, GRP0_19_FUNC) +#define GPSR0_18 F_(MSIOF0_SS2, GRP0_18_FUNC) +#define GPSR0_17 F_(MSIOF0_SS1, GRP0_17_FUNC) +#define GPSR0_16 F_(MSIOF0_SYNC, GRP0_16_FUNC) +#define GPSR0_15 F_(MSIOF0_RXD, GRP0_15_FUNC) +#define GPSR0_14 F_(MSIOF0_TXD, GRP0_14_FUNC) +#define GPSR0_13 F_(MSIOF0_SCK, GRP0_13_FUNC) +#define GPSR0_12 F_(RXDB_EXTFXR_A, GRP0_12_FUNC) +#define GPSR0_11 F_(FXR_TXENB_N_A, GRP0_11_FUNC) +#define GPSR0_10 F_(FXR_TXDB_A, GRP0_10_FUNC) +#define GPSR0_9 F_(RXDA_EXTFXR_A, GRP0_9_FUNC) +#define GPSR0_8 F_(FXR_TXENA_N_A, GRP0_8_FUNC) +#define GPSR0_7 F_(FXR_TXDA_A, GRP0_7_FUNC) +#define GPSR0_6 F_(CLK_EXTFXR_A, GRP0_6_FUNC) +#define GPSR0_5 F_(FXR_CLKOUT2_A, GRP0_5_FUNC) +#define GPSR0_4 F_(FXR_CLKOUT1_A, GRP0_4_FUNC) +#define GPSR0_3 F_(STPWT_EXTFXR_A, GRP0_3_FUNC) +#define GPSR0_2 F_(GP0_02, GRP0_2_FUNC) +#define GPSR0_1 F_(GP0_01, GRP0_1_FUNC) +#define GPSR0_0 F_(GP0_00, GRP0_0_FUNC) + +/* GPSR1 */ +#define GPSR1_21 F_(RLIN33TX, GRP1_21_FUNC) +#define GPSR1_20 F_(RLIN33RX_INTP19, GRP1_20_FUNC) +#define GPSR1_19 F_(RLIN32TX, GRP1_19_FUNC) +#define GPSR1_18 F_(RLIN32RX_INTP18, GRP1_18_FUNC) +#define GPSR1_17 F_(RLIN31TX, GRP1_17_FUNC) +#define GPSR1_16 F_(RLIN31RX_INTP17, GRP1_16_FUNC) +#define GPSR1_15 F_(RLIN30TX, GRP1_15_FUNC) +#define GPSR1_14 F_(RLIN30RX_INTP16, GRP1_14_FUNC) +#define GPSR1_13 F_(CAN6TX, GRP1_13_FUNC) +#define GPSR1_12 F_(CAN6RX_INTP6, GRP1_12_FUNC) +#define GPSR1_11 F_(CAN5TX, GRP1_11_FUNC) +#define GPSR1_10 F_(CAN5RX_INTP5, GRP1_10_FUNC) +#define GPSR1_9 F_(CAN4TX, GRP1_9_FUNC) +#define GPSR1_8 F_(CAN4RX_INTP4, GRP1_8_FUNC) +#define GPSR1_7 F_(CAN3TX, GRP1_7_FUNC) +#define GPSR1_6 F_(CAN3RX_INTP3, GRP1_6_FUNC) +#define GPSR1_5 F_(CAN2TX, GRP1_5_FUNC) +#define GPSR1_4 F_(CAN2RX_INTP2, GRP1_4_FUNC) +#define GPSR1_3 F_(CAN1TX, GRP1_3_FUNC) +#define GPSR1_2 F_(CAN1RX_INTP1, GRP1_2_FUNC) +#define GPSR1_1 F_(CAN0TX, GRP1_1_FUNC) +#define GPSR1_0 F_(CAN0RX_INTP0, GRP1_0_FUNC) + +/* GPSR2 */ +#define GPSR2_28 F_(INTP34_B, GRP2_28_FUNC) +#define GPSR2_27 F_(TAUD1O3, GRP2_27_FUNC) +#define GPSR2_26 F_(TAUD1O2, GRP2_26_FUNC) +#define GPSR2_25 F_(TAUD1O1, GRP2_25_FUNC) +#define GPSR2_24 F_(TAUD1O0, GRP2_24_FUNC) +#define GPSR2_23 F_(EXTCLK0O_B, GRP2_23_FUNC) +#define GPSR2_22 F_(AVS1, GRP2_22_FUNC) +#define GPSR2_21 F_(AVS0, GRP2_21_FUNC) +#define GPSR2_20 F_(SDA0, GRP2_20_FUNC) +#define GPSR2_19 F_(SCL0, GRP2_19_FUNC) +#define GPSR2_18 F_(INTP33_B, GRP2_18_FUNC) +#define GPSR2_17 F_(INTP32_B, GRP2_17_FUNC) +#define GPSR2_16 F_(CAN_CLK, GRP2_16_FUNC) +#define GPSR2_15 F_(CAN15TX_B, GRP2_15_FUNC) +#define GPSR2_14 F_(CAN15RX_INTP15_B, GRP2_14_FUNC) +#define GPSR2_13 F_(CAN14TX_B, GRP2_13_FUNC) +#define GPSR2_12 F_(CAN14RX_INTP14_B, GRP2_12_FUNC) +#define GPSR2_11 F_(CAN13TX_B, GRP2_11_FUNC) +#define GPSR2_10 F_(CAN13RX_INTP13_B, GRP2_10_FUNC) +#define GPSR2_9 F_(CAN12TX_B, GRP2_9_FUNC) +#define GPSR2_8 F_(CAN12RX_INTP12_B, GRP2_8_FUNC) +#define GPSR2_7 F_(RLIN37TX_B, GRP2_7_FUNC) +#define GPSR2_6 F_(RLIN37RX_INTP23_B, GRP2_6_FUNC) +#define GPSR2_5 F_(RLIN36TX_B, GRP2_5_FUNC) +#define GPSR2_4 F_(RLIN36RX_INTP22_B, GRP2_4_FUNC) +#define GPSR2_3 F_(RLIN35TX_B, GRP2_3_FUNC) +#define GPSR2_2 F_(RLIN35RX_INTP21_B, GRP2_2_FUNC) +#define GPSR2_1 F_(RLIN34TX_B, GRP2_1_FUNC) +#define GPSR2_0 F_(RLIN34RX_INTP20_B, GRP2_0_FUNC) + +/* GPSR3 */ +#define GPSR3_16 F_(ERRORIN_N, GRP3_16_FUNC) +#define GPSR3_15 F_(ERROROUT_N, GRP3_15_FUNC) +#define GPSR3_14 F_(QSPI1_SSL, GRP3_14_FUNC) +#define GPSR3_13 F_(QSPI1_IO3, GRP3_13_FUNC) +#define GPSR3_12 F_(QSPI1_IO2, GRP3_12_FUNC) +#define GPSR3_11 F_(QSPI1_MISO_IO1, GRP3_11_FUNC) +#define GPSR3_10 F_(QSPI1_MOSI_IO0, GRP3_10_FUNC) +#define GPSR3_9 F_(QSPI1_SPCLK, GRP3_9_FUNC) +#define GPSR3_8 F_(RPC_INT_N, GRP3_8_FUNC) +#define GPSR3_7 F_(RPC_WP_N, GRP3_7_FUNC) +#define GPSR3_6 F_(RPC_RESET_N, GRP3_6_FUNC) +#define GPSR3_5 F_(QSPI0_SSL, GRP3_5_FUNC) +#define GPSR3_4 F_(QSPI0_IO3, GRP3_4_FUNC) +#define GPSR3_3 F_(QSPI0_IO2, GRP3_3_FUNC) +#define GPSR3_2 F_(QSPI0_MISO_IO1, GRP3_2_FUNC) +#define GPSR3_1 F_(QSPI0_MOSI_IO0, GRP3_1_FUNC) +#define GPSR3_0 F_(QSPI0_SPCLK, GRP3_0_FUNC) + +/* GPSR4 */ +#define GPSR4_15 F_(PCIE61_CLKREQ_N, GRP4_15_FUNC) +#define GPSR4_14 F_(PCIE60_CLKREQ_N, GRP4_14_FUNC) +#define GPSR4_13 F_(ERRORIN_N, GRP4_13_FUNC) +#define GPSR4_12 F_(SD0_CD, GRP4_12_FUNC) +#define GPSR4_11 F_(SD0_WP, GRP4_11_FUNC) +#define GPSR4_10 F_(MMC0_DS, GRP4_10_FUNC) +#define GPSR4_9 F_(MMC0_D7, GRP4_9_FUNC) +#define GPSR4_8 F_(MMC0_D6, GRP4_8_FUNC) +#define GPSR4_7 F_(MMC0_D5, GRP4_7_FUNC) +#define GPSR4_6 F_(MMC0_D4, GRP4_6_FUNC) +#define GPSR4_5 F_(MMC0_SD_D3, GRP4_5_FUNC) +#define GPSR4_4 F_(MMC0_SD_D2, GRP4_4_FUNC) +#define GPSR4_3 F_(MMC0_SD_D1, GRP4_3_FUNC) +#define GPSR4_2 F_(MMC0_SD_D0, GRP4_2_FUNC) +#define GPSR4_1 F_(MMC0_SD_CMD, GRP4_1_FUNC) +#define GPSR4_0 F_(MMC0_SD_CLK, GRP4_0_FUNC) + +/* GPSR5 */ +#define GPSR5_22 F_(TPU0TO3, GRP5_22_FUNC) +#define GPSR5_21 F_(TPU0TO2, GRP5_21_FUNC) +#define GPSR5_20 F_(TPU0TO1, GRP5_20_FUNC) +#define GPSR5_19 F_(TPU0TO0, GRP5_19_FUNC) +#define GPSR5_18 F_(TCLK4, GRP5_18_FUNC) +#define GPSR5_17 F_(TCLK3, GRP5_17_FUNC) +#define GPSR5_16 F_(TCLK2, GRP5_16_FUNC) +#define GPSR5_15 F_(TCLK1, GRP5_15_FUNC) +#define GPSR5_14 F_(IRQ3_A, GRP5_14_FUNC) +#define GPSR5_13 F_(IRQ2_A, GRP5_13_FUNC) +#define GPSR5_12 F_(IRQ1_A, GRP5_12_FUNC) +#define GPSR5_11 F_(IRQ0_A, GRP5_11_FUNC) +#define GPSR5_10 F_(HSCK1, GRP5_10_FUNC) +#define GPSR5_9 F_(HCTS1_N, GRP5_9_FUNC) +#define GPSR5_8 F_(HRTS1_N, GRP5_8_FUNC) +#define GPSR5_7 F_(HRX1, GRP5_7_FUNC) +#define GPSR5_6 F_(HTX1, GRP5_6_FUNC) +#define GPSR5_5 F_(SCIF_CLK, GRP5_5_FUNC) +#define GPSR5_4 F_(HSCK0, GRP5_4_FUNC) +#define GPSR5_3 F_(HCTS0_N, GRP5_3_FUNC) +#define GPSR5_2 F_(HRTS0_N, GRP5_2_FUNC) +#define GPSR5_1 F_(HRX0, GRP5_1_FUNC) +#define GPSR5_0 F_(HTX0, GRP5_0_FUNC) + +/* GPSR6 */ +#define GPSR6_30 F_(AUDIO1_CLKOUT1, GRP6_30_FUNC) +#define GPSR6_29 F_(AUDIO1_CLKOUT0, GRP6_29_FUNC) +#define GPSR6_28 F_(SSI2_SD, GRP6_28_FUNC) +#define GPSR6_27 F_(SSI2_WS, GRP6_27_FUNC) +#define GPSR6_26 F_(SSI2_SCK, GRP6_26_FUNC) +#define GPSR6_25 F_(AUDIO0_CLKOUT3, GRP6_25_FUNC) +#define GPSR6_24 F_(AUDIO0_CLKOUT2, GRP6_24_FUNC) +#define GPSR6_23 F_(SSI1_SD, GRP6_23_FUNC) +#define GPSR6_22 F_(SSI1_WS, GRP6_22_FUNC) +#define GPSR6_21 F_(SSI1_SCK, GRP6_21_FUNC) +#define GPSR6_20 F_(AUDIO0_CLKOUT1, GRP6_20_FUNC) +#define GPSR6_19 F_(AUDIO0_CLKOUT0, GRP6_19_FUNC) +#define GPSR6_18 F_(SSI0_SD, GRP6_18_FUNC) +#define GPSR6_17 F_(SSI0_WS, GRP6_17_FUNC) +#define GPSR6_16 F_(SSI0_SCK, GRP6_16_FUNC) +#define GPSR6_15 F_(MSIOF4_SS2_B, GRP6_15_FUNC) +#define GPSR6_14 F_(MSIOF4_SS1_B, GRP6_14_FUNC) +#define GPSR6_13 F_(MSIOF4_SYNC_B, GRP6_13_FUNC) +#define GPSR6_12 F_(MSIOF4_RXD_B, GRP6_12_FUNC) +#define GPSR6_11 F_(MSIOF4_TXD_B, GRP6_11_FUNC) +#define GPSR6_10 F_(MSIOF4_SCK_B, GRP6_10_FUNC) +#define GPSR6_9 F_(MSIOF7_SS2_A, GRP6_9_FUNC) +#define GPSR6_8 F_(MSIOF7_SS1_A, GRP6_8_FUNC) +#define GPSR6_7 F_(MSIOF7_SYNC_A, GRP6_7_FUNC) +#define GPSR6_6 F_(MSIOF7_RXD_A, GRP6_6_FUNC) +#define GPSR6_5 F_(MSIOF7_TXD_A, GRP6_5_FUNC) +#define GPSR6_4 F_(MSIOF7_SCK_A, GRP6_4_FUNC) +#define GPSR6_3 F_(RIF6_CLK, GRP6_3_FUNC) +#define GPSR6_2 F_(RIF6_SYNC, GRP6_2_FUNC) +#define GPSR6_1 F_(RIF6_D1, GRP6_1_FUNC) +#define GPSR6_0 F_(RIF6_D0, GRP6_0_FUNC) + +/* GPSR7 */ +#define GPSR7_30 F_(MSIOF6_SS2_B, GRP7_30_FUNC) +#define GPSR7_29 F_(MSIOF6_SS1_B, GRP7_29_FUNC) +#define GPSR7_28 F_(MSIOF6_SYNC_B, GRP7_28_FUNC) +#define GPSR7_27 F_(MSIOF6_RXD_B, GRP7_27_FUNC) +#define GPSR7_26 F_(MSIOF6_TXD_B, GRP7_26_FUNC) +#define GPSR7_25 F_(MSIOF6_SCK_B, GRP7_25_FUNC) +#define GPSR7_24 F_(MSIOF5_SS2, GRP7_24_FUNC) +#define GPSR7_23 F_(MSIOF5_SS1, GRP7_23_FUNC) +#define GPSR7_22 F_(MSIOF5_SYNC, GRP7_22_FUNC) +#define GPSR7_21 F_(MSIOF5_RXD, GRP7_21_FUNC) +#define GPSR7_20 F_(MSIOF5_TXD, GRP7_20_FUNC) +#define GPSR7_19 F_(GP07_19, GRP7_19_FUNC) +#define GPSR7_18 F_(GP07_18, GRP7_18_FUNC) +#define GPSR7_17 F_(MSIOF5_SCK, GRP7_17_FUNC) +#define GPSR7_16 F_(AUDIO_CLKC_A, GRP7_16_FUNC) +#define GPSR7_15 F_(SSI6_SD, GRP7_15_FUNC) +#define GPSR7_14 F_(SSI6_WS, GRP7_14_FUNC) +#define GPSR7_13 F_(SSI6_SCK, GRP7_13_FUNC) +#define GPSR7_12 F_(AUDIO_CLKB_A, GRP7_12_FUNC) +#define GPSR7_11 F_(SSI5_SD, GRP7_11_FUNC) +#define GPSR7_10 F_(SSI5_WS, GRP7_10_FUNC) +#define GPSR7_9 F_(SSI5_SCK, GRP7_9_FUNC) +#define GPSR7_8 F_(AUDIO_CLKA_A, GRP7_8_FUNC) +#define GPSR7_7 F_(SSI4_SD, GRP7_7_FUNC) +#define GPSR7_6 F_(SSI4_WS, GRP7_6_FUNC) +#define GPSR7_5 F_(SSI4_SCK, GRP7_5_FUNC) +#define GPSR7_4 F_(AUDIO1_CLKOUT3, GRP7_4_FUNC) +#define GPSR7_3 F_(AUDIO1_CLKOUT2, GRP7_3_FUNC) +#define GPSR7_2 F_(SSI3_SD, GRP7_2_FUNC) +#define GPSR7_1 F_(SSI3_WS, GRP7_1_FUNC) +#define GPSR7_0 F_(SSI3_SCK, GRP7_0_FUNC) + +/* GPSR8 */ +#define GPSR8_31 F_(S3DA2, GRP8_31_FUNC) +#define GPSR8_30 F_(S3CL2, GRP8_30_FUNC) +#define GPSR8_29 F_(S3DA1, GRP8_29_FUNC) +#define GPSR8_28 F_(S3CL1, GRP8_28_FUNC) +#define GPSR8_27 F_(S3DA0, GRP8_27_FUNC) +#define GPSR8_26 F_(S3CL0, GRP8_26_FUNC) +#define GPSR8_15 F_(SDA8, GRP8_15_FUNC) +#define GPSR8_14 F_(SCL8, GRP8_14_FUNC) +#define GPSR8_13 F_(SDA7, GRP8_13_FUNC) +#define GPSR8_12 F_(SCL7, GRP8_12_FUNC) +#define GPSR8_11 F_(SDA6, GRP8_11_FUNC) +#define GPSR8_10 F_(SCL6, GRP8_10_FUNC) +#define GPSR8_9 F_(SDA5, GRP8_9_FUNC) +#define GPSR8_8 F_(SCL5, GRP8_8_FUNC) +#define GPSR8_7 F_(SDA4, GRP8_7_FUNC) +#define GPSR8_6 F_(SCL4, GRP8_6_FUNC) +#define GPSR8_5 F_(SDA3, GRP8_5_FUNC) +#define GPSR8_4 F_(SCL3, GRP8_4_FUNC) +#define GPSR8_3 F_(SDA2, GRP8_3_FUNC) +#define GPSR8_2 F_(SCL2, GRP8_2_FUNC) +#define GPSR8_1 F_(SDA1, GRP8_1_FUNC) +#define GPSR8_0 F_(SCL1, GRP8_0_FUNC) + +/* GPSR9 */ +#define GPSR9_16 F_(RSW3_MATCH, GRP9_16_FUNC) +#define GPSR9_15 F_(RSW3_CAPTURE, GRP9_15_FUNC) +#define GPSR9_14 F_(RSW3_PPS, GRP9_14_FUNC) +#define GPSR9_13 F_(ETH10G0_PHYINT, GRP9_13_FUNC) +#define GPSR9_12 F_(ETH10G0_LINK, GRP9_12_FUNC) +#define GPSR9_11 F_(ETH10G0_MDC, GRP9_11_FUNC) +#define GPSR9_10 F_(ETH10G0_MDIO, GRP9_10_FUNC) +#define GPSR9_9 F_(ETH25G0_PHYINT, GRP9_9_FUNC) +#define GPSR9_8 F_(ETH25G0_LINK, GRP9_8_FUNC) +#define GPSR9_7 F_(ETH25G0_MDC, GRP9_7_FUNC) +#define GPSR9_6 F_(ETH25G0_MDIO, GRP9_6_FUNC) +#define GPSR9_5 F_(ETHES4_MATCH, GRP9_5_FUNC) +#define GPSR9_4 F_(ETHES4_CAPTURE, GRP9_4_FUNC) +#define GPSR9_3 F_(ETHES4_PPS, GRP9_3_FUNC) +#define GPSR9_2 F_(ETHES0_MATCH, GRP9_2_FUNC) +#define GPSR9_1 F_(ETHES0_CAPTURE, GRP9_1_FUNC) +#define GPSR9_0 F_(ETHES0_PPS, GRP9_0_FUNC) + +/* GPSR10 */ +#define GPSR10_13 F_(PCIE41_CLKREQ_N, GRP10_13_FUNC) +#define GPSR10_12 F_(PCIE40_CLKREQ_N, GRP10_12_FUNC) +#define GPSR10_11 F_(USB3_VBUS_VALID, GRP10_11_FUNC) +#define GPSR10_10 F_(USB3_OVC, GRP10_10_FUNC) +#define GPSR10_9 F_(USB3_PWEN, GRP10_9_FUNC) +#define GPSR10_8 F_(USB2_VBUS_VALID, GRP10_8_FUNC) +#define GPSR10_7 F_(USB2_OVC, GRP10_7_FUNC) +#define GPSR10_6 F_(USB2_PWEN, GRP10_6_FUNC) +#define GPSR10_5 F_(USB1_VBUS_VALID, GRP10_5_FUNC) +#define GPSR10_4 F_(USB1_OVC, GRP10_4_FUNC) +#define GPSR10_3 F_(USB1_PWEN, GRP10_3_FUNC) +#define GPSR10_2 F_(USB0_VBUS_VALID, GRP10_2_FUNC) +#define GPSR10_1 F_(USB0_OVC, GRP10_1_FUNC) +#define GPSR10_0 F_(USB0_PWEN, GRP10_0_FUNC) + +/* Group0 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define GRP0_27_FUNC FM(DP2_HOTPLUG) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_26_FUNC FM(DP1_HOTPLUG) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_25_FUNC FM(DP0_HOTPLUG) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_24_FUNC FM(MSIOF1_SS2_A) FM(TAUD0O13) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_23_FUNC FM(MSIOF1_SS1_A) FM(TAUD0O12) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_22_FUNC FM(MSIOF1_SYNC_A) FM(TAUD0O11) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_21_FUNC FM(MSIOF1_RXD_A) FM(TAUD0O10) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_20_FUNC FM(MSIOF1_TXD_A) FM(TAUD0O9) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_19_FUNC FM(MSIOF1_SCK_A) FM(TAUD0O8) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_18_FUNC FM(MSIOF0_SS2) FM(TAUD0O7) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_17_FUNC FM(MSIOF0_SS1) FM(TAUD0O6) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_16_FUNC FM(MSIOF0_SYNC) FM(TAUD0O5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_15_FUNC FM(MSIOF0_RXD) FM(TAUD0O4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_14_FUNC FM(MSIOF0_TXD) FM(TAUD0O3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_13_FUNC FM(MSIOF0_SCK) FM(TAUD0O2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_12_FUNC FM(RXDB_EXTFXR_A) FM(CAN11TX) FM(RLIN311TX) FM(RTCA0OUT_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_11_FUNC FM(FXR_TXENB_N_A) FM(CAN11RX_INTP11) FM(RLIN311RX_INTP27) FM(EXTCLK0O_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_10_FUNC FM(FXR_TXDB_A) FM(CAN10TX) FM(RLIN310TX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_9_FUNC FM(RXDA_EXTFXR_A) FM(CAN10RX_INTP10) FM(RLIN310RX_INTP26) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_8_FUNC FM(FXR_TXENA_N_A) FM(CAN9TX) FM(RLIN39TX) FM(TAUD1O15) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_7_FUNC FM(FXR_TXDA_A) FM(CAN9RX_INTP9) FM(RLIN39RX_INTP25) FM(TAUD1O14) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_6_FUNC FM(CLK_EXTFXR_A) FM(CAN8TX) FM(RLIN38TX) FM(TAUD1O13) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_5_FUNC FM(FXR_CLKOUT2_A) FM(CAN8RX_INTP8) FM(RLIN38RX_INTP24) FM(TAUD1O12) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_4_FUNC FM(FXR_CLKOUT1_A) FM(CAN7TX) FM(RLIN315TX_A) FM(TAUD1O11) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_3_FUNC FM(STPWT_EXTFXR_A) FM(CAN7RX_INTP7) FM(RLIN315RX_INTP31_A) FM(TAUD1O10) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_2_FUNC F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_1_FUNC F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP0_0_FUNC F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) + +/* Group1 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define GRP1_21_FUNC FM(RLIN33TX) FM(TAUJ1I3_TAUJ1O3) FM(CAN15TX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_20_FUNC FM(RLIN33RX_INTP19) FM(TAUJ1I2_TAUJ1O2) FM(CAN15RX_INTP15_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_19_FUNC FM(RLIN32TX) FM(TAUJ1I1_TAUJ1O1) FM(CAN14TX_A) FM(NMI1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_18_FUNC FM(RLIN32RX_INTP18) FM(TAUJ1I0_TAUJ1O0) FM(CAN14RX_INTP14_A) FM(INTP34_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_17_FUNC FM(RLIN31TX) FM(TAUJ3I3_TAUJ3O3) FM(CAN13TX_A) FM(INTP33_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_16_FUNC FM(RLIN31RX_INTP17) FM(TAUJ3I2_TAUJ3O2) FM(CAN13RX_INTP13_A) FM(INTP32_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_15_FUNC FM(RLIN30TX) FM(TAUJ3I1_TAUJ3O1) FM(CAN12TX_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_14_FUNC FM(RLIN30RX_INTP16) FM(TAUJ3I0_TAUJ3O0) FM(CAN12RX_INTP12_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_13_FUNC FM(CAN6TX) FM(RLIN314TX_A) FM(TAUD1O9) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_12_FUNC FM(CAN6RX_INTP6) FM(RLIN314RX_INTP30_A) FM(TAUD1O8) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_11_FUNC FM(CAN5TX) FM(RLIN313TX_A) FM(MSIOF3_SS2) FM(RXDB_EXTFXR_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_10_FUNC FM(CAN5RX_INTP5) FM(RLIN313RX_INTP29_A) FM(MSIOF3_SS1) FM(FXR_TXENB_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_9_FUNC FM(CAN4TX) FM(RLIN312TX_A) FM(MSIOF3_SYNC) FM(FXR_TXDB_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_8_FUNC FM(CAN4RX_INTP4) FM(RLIN312RX_INTP28_A) FM(MSIOF3_RXD) FM(RXDA_EXTFXR_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_7_FUNC FM(CAN3TX) FM(RLIN37TX_A) FM(MSIOF3_TXD) FM(FXR_TXENA_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_6_FUNC FM(CAN3RX_INTP3) FM(RLIN37RX_INTP23_A) FM(MSIOF3_SCK) FM(FXR_TXDA_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_5_FUNC FM(CAN2TX) FM(RLIN36TX_A) FM(MSIOF2_SS2) FM(CLK_EXTFXR_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_4_FUNC FM(CAN2RX_INTP2) FM(RLIN36RX_INTP22_A) FM(MSIOF2_SS1) FM(FXR_CLKOUT2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_3_FUNC FM(CAN1TX) FM(RLIN35TX_A) FM(MSIOF2_SYNC) FM(FXR_CLKOUT1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_2_FUNC FM(CAN1RX_INTP1) FM(RLIN35RX_INTP21_A) FM(MSIOF2_RXD) FM(STPWT_EXTFXR_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_1_FUNC FM(CAN0TX) FM(RLIN34TX_A) FM(MSIOF2_TXD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP1_0_FUNC FM(CAN0RX_INTP0) FM(RLIN34RX_INTP20_A) FM(MSIOF2_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) + +/* Group2 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define GRP2_28_FUNC FM(INTP34_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_27_FUNC FM(TAUD1O3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_26_FUNC FM(TAUD1O2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_25_FUNC FM(TAUD1O1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_24_FUNC FM(TAUD1O0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_23_FUNC FM(EXTCLK0O_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_22_FUNC FM(AVS1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_21_FUNC FM(AVS0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_20_FUNC FM(SDA0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_19_FUNC FM(SCL0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_18_FUNC FM(INTP33_B) FM(TAUD0O1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_17_FUNC FM(INTP32_B) FM(TAUD0O0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_16_FUNC FM(CAN_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_15_FUNC FM(CAN15TX_B) FM(RLIN315TX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_14_FUNC FM(CAN15RX_B_INTP15) FM(RLIN315RX_INTP31_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_13_FUNC FM(CAN14TX_B) FM(RLIN314TX_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_12_FUNC FM(CAN14RX_B_INTP14) FM(RLIN314RX_INTP30_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_11_FUNC FM(CAN13TX_B) FM(RLIN313TX) F_(0, 0) FM(CANXL1_TX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_10_FUNC FM(CAN13RX_B_INTP13) FM(RLIN313RX_INTP29_B) F_(0, 0) FM(CANXL1_RX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_9_FUNC FM(CAN12TX_B) FM(RLIN312TX) FM(TAUD1O7) FM(CANXL0_TX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_8_FUNC FM(CAN12RX_B_INTP12) FM(RLIN312RX_INTP28_B) FM(TAUD1O6) FM(CANXL0_RX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_7_FUNC FM(RLIN37TX_B) FM(RTCA0OUT_B) FM(TAUD1O5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_6_FUNC FM(RLIN37RX_B_INTP23) F_(0, 0) FM(TAUD1O4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_5_FUNC FM(RLIN36TX_B) FM(MSIOF1_SS2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_4_FUNC FM(RLIN36RX_B_INTP22) FM(MSIOF1_SS1_B) F_(0, 0) FM(CTIACK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_3_FUNC FM(RLIN35TX_B) FM(MSIOF1_SYN_B) F_(0, 0) FM(CTIREQ) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_2_FUNC FM(RLIN35RX_B_INTP21) FM(MSIOF1_RXD_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_1_FUNC FM(RLIN34TX_B) FM(MSIOF1_TXD_B) FM(TAUD0O15) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP2_0_FUNC FM(RLIN34RX_B_INTP20) FM(MSIOF1_SCK_B) FM(TAUD0O14) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) + + +/* Group3 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define GRP3_16_FUNC FM(ERRORIN0_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_15_FUNC FM(ERROROUT_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_14_FUNC FM(QSPI1_SSL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_13_FUNC FM(QSPI1_IO3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_12_FUNC FM(QSPI1_IO2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_11_FUNC FM(QSPI1_MISO_IO1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_10_FUNC FM(QSPI1_MOSI_IO0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_9_FUNC FM(QSPI1_SPCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_8_FUNC FM(RPC_INT_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_7_FUNC FM(RPC_WP_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_6_FUNC FM(RPC_RESET_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_5_FUNC FM(QSPI0_SSL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_4_FUNC FM(QSPI0_IO3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_3_FUNC FM(QSPI0_IO2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_2_FUNC FM(QSPI0_MISO_IO1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_1_FUNC FM(QSPI0_MOSI_IO0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP3_0_FUNC FM(QSPI0_SPCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) + +/* Group4 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define GRP4_15_FUNC FM(PCIE61_CLKREQ_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_14_FUNC FM(PCIE60_CLKREQ_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_13_FUNC FM(ERRORIN1_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_12_FUNC FM(SD0_CD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_11_FUNC FM(SD0_WP) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_10_FUNC FM(MMC0_DS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_9_FUNC FM(MMC0_D7) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_8_FUNC FM(MMC0_D6) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_7_FUNC FM(MMC0_D5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_6_FUNC FM(MMC0_D4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_5_FUNC FM(MMC0_SD_D3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_4_FUNC FM(MMC0_SD_D2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_3_FUNC FM(MMC0_SD_D1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_2_FUNC FM(MMC0_SD_D0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_1_FUNC FM(MMC0_SD_CMD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP4_0_FUNC FM(MMC0_SD_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) + +/* Group5 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define GRP5_22_FUNC FM(TPU0TO3) FM(SSI9_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_21_FUNC FM(TPU0TO2) FM(SSI9_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_20_FUNC FM(TPU0TO1) FM(PWM5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_19_FUNC FM(TPU0TO0) FM(PWM4) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_18_FUNC FM(TCLK4) FM(PWM3) FM(SSI19_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_17_FUNC FM(TCLK3) FM(PWM2) FM(SSI19_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_16_FUNC FM(TCLK2) FM(PWM1) FM(SSI19_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_15_FUNC FM(TCLK1) FM(PWM0_A) FM(SSI18_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_14_FUNC FM(IRQ3_A) F_(0, 0) F_(0, 0) FM(RIF7_D1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_13_FUNC FM(IRQ2_A) FM(SSI17_SD) F_(0, 0) FM(RIF7_D0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_12_FUNC FM(IRQ1_A) FM(SSI17_WS) F_(0, 0) FM(RIF7_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_11_FUNC FM(IRQ0_A) FM(SSI17_SCK) F_(0, 0) FM(RIF7_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_10_FUNC FM(HSCK1) FM(SCK1) FM(SSI13_SCK) FM(RIF0_CLK_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_9_FUNC FM(HCTS1_N) FM(CTS1_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_8_FUNC FM(HRTS1_N) FM(RTS1_N) FM(RIF0_SYNC_B) FM(SSI16_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_7_FUNC FM(HRX1) FM(RX1) F_(0, 0) FM(SSI16_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_6_FUNC FM(HTX1) FM(TX1) F_(0, 0) FM(SSI16_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_5_FUNC FM(SCIF_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_4_FUNC FM(HSCK0) FM(SCK0) F_(0, 0) FM(SSI15_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_3_FUNC FM(HCTS0_N) FM(CTS0_N) FM(IRQ1_B) FM(SSI15_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_2_FUNC FM(HRTS0_N) FM(RTS0_N) FM(IRQ0_B) FM(SSI15_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_1_FUNC FM(HRX0) FM(RX0) FM(SSI13_SD) FM(RIF0_D1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP5_0_FUNC FM(HTX0) FM(TX0) FM(SSI13_WS) FM(RIF0_D0_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) + +/* Group6 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define GRP6_30_FUNC FM(AUDIO1_CLKOUT1) FM(MSIOF7_RXD_B) FM(RIF5_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_29_FUNC FM(AUDIO1_CLKOUT0) FM(MSIOF7_TXD_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_28_FUNC FM(SSI2_SD) FM(MSIOF7_SCK_B) FM(RIF5_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_27_FUNC FM(SSI2_WS) F_(0, 0) FM(RIF1_D1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_26_FUNC FM(SSI2_SCK) F_(0, 0) FM(RIF1_D0_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_25_FUNC FM(AUDIO0_CLKOUT3) F_(0, 0) FM(RIF1_CLK_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_24_FUNC FM(AUDIO0_CLKOUT2) F_(0, 0) FM(RIF2_D1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_23_FUNC FM(SSI1_SD) F_(0, 0) FM(HCTS3_N) FM(CTS3_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_22_FUNC FM(SSI1_WS) F_(0, 0) FM(HRTS3_N) FM(RTS3_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_21_FUNC FM(SSI1_SCK) FM(MSIOF4_SS2_A) FM(HSCK3) FM(SCK3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_20_FUNC FM(AUDIO0_CLKOUT1) FM(MSIOF4_SS1_A) FM(RIF2_D0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_19_FUNC FM(AUDIO0_CLKOUT0) FM(MSIOF4_SYNC_A) FM(RIF2_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_18_FUNC FM(SSI0_SD) FM(MSIOF4_RXD_A) FM(HRX3) FM(RX3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_17_FUNC FM(SSI0_WS) FM(MSIOF4_TXD_A) FM(HTX3) FM(TX3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_16_FUNC FM(SSI0_SCK) FM(MSIOF4_SCK_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_15_FUNC FM(MSIOF4_SS2_B) FM(SSI14_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_14_FUNC FM(MSIOF4_SS1_B) FM(SSI12_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_13_FUNC FM(MSIOF4_SYNC_B) FM(SSI12_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_12_FUNC FM(MSIOF4_RXD_B) F_(0, 0) FM(AUDIO_CLKC_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_11_FUNC FM(MSIOF4_TXD_B) FM(SSI12_SCK) F_(0, 0) FM(RIF1_SYNC_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_10_FUNC FM(MSIOF4_SCK_B) F_(0, 0) FM(AUDIO_CLKB_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_9_FUNC FM(MSIOF7_SS2_A) FM(SSI14_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_8_FUNC FM(MSIOF7_SS1_A) FM(SSI14_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_7_FUNC FM(MSIOF7_SYNC_A) FM(RIF1_D1_B) FM(SSI11_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_6_FUNC FM(MSIOF7_RXD_A) FM(RIF1_D0_B) FM(SSI11_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_5_FUNC FM(MSIOF7_TXD_A) FM(RIF1_SYNC_B) FM(SSI11_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_4_FUNC FM(MSIOF7_SCK_A) FM(RIF1_CLK_B) FM(AUDIO_CLKA_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_3_FUNC FM(RIF6_CLK) FM(SSI10_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_2_FUNC FM(RIF6_SYNC) FM(SSI10_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_1_FUNC FM(RIF6_D1) FM(SSI10_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP6_0_FUNC FM(RIF6_D0) FM(SSI9_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) + +/* Group7 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define GRP7_30_FUNC FM(MSIOF6_SS2_B) FM(HRX2_B) FM(RX4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_29_FUNC FM(MSIOF6_SS1_B) FM(SSI7_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_28_FUNC FM(MSIOF6_SYNC_B) FM(SSI7_WS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_27_FUNC FM(MSIOF6_RXD_B) FM(SSI7_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_26_FUNC FM(MSIOF6_TXD_B) FM(HTX2_B) FM(TX4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_25_FUNC FM(MSIOF6_SCK_B) FM(SSI8_SD) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_24_FUNC FM(MSIOF5_SS2) FM(HCTS2_N_B) FM(CTS4_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_23_FUNC FM(MSIOF5_SS1) FM(RIF0_SYNC_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_22_FUNC FM(MSIOF5_SYNC) FM(HRTS2_N_B) FM(RTS4_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_21_FUNC FM(MSIOF5_RXD) FM(RIF0_D1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_20_FUNC FM(MSIOF5_TXD) FM(HSCK2_B) FM(SCK4_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_19_FUNC F_(0, 0) FM(MSIOF6_SS2_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_18_FUNC F_(0, 0) FM(MSIOF6_SS1_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_17_FUNC FM(MSIOF5_SCK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_16_FUNC FM(AUDIO_CLKC_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_15_FUNC FM(SSI6_SD) FM(MSIOF6_RXD_A) FM(RIF4_D1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_14_FUNC FM(SSI6_WS) FM(MSIOF6_TXD_A) FM(RIF4_D0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_13_FUNC FM(SSI6_SCK) FM(MSIOF6_SCK_A) FM(RIF4_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_12_FUNC FM(AUDIO_CLKB_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_11_FUNC FM(SSI5_SD) FM(MSIOF6_SYNC_A) FM(RIF4_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_10_FUNC FM(SSI5_WS) FM(RIF3_SYNC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_9_FUNC FM(SSI5_SCK) FM(RIF3_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_8_FUNC FM(AUDIO_CLKA_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_7_FUNC FM(SSI4_SD) FM(RIF3_D1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_6_FUNC FM(SSI4_WS) FM(RIF3_D0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_5_FUNC FM(SSI4_SCK) FM(RIF2_CLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_4_FUNC FM(AUDIO1_CLKOUT3) FM(RIF0_D0_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_3_FUNC FM(AUDIO1_CLKOUT2) FM(RIF0_CLK_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_2_FUNC FM(SSI3_SD) FM(MSIOF7_SS2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_1_FUNC FM(SSI3_WS) FM(MSIOF7_SS1_B) FM(RIF5_D1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP7_0_FUNC FM(SSI3_SCK) FM(MSIOF7_SYNC_B) FM(RIF5_D0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) + +/* Group8 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define GRP8_31_FUNC FM(S3DA2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_30_FUNC FM(S3CL2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_29_FUNC FM(S3DA1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_28_FUNC FM(S3CL1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_27_FUNC FM(S3DA0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_26_FUNC FM(S3CL0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_15_FUNC FM(SDA8) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_14_FUNC FM(SCL8) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_13_FUNC FM(SDA7) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_12_FUNC FM(SCL7) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_11_FUNC FM(SDA6) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_10_FUNC FM(SCL6) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_9_FUNC FM(SDA5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_8_FUNC FM(SCL5) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_7_FUNC FM(SDA4) FM(HCTS2_N_A) FM(CTS4_N_A) FM(PWM7_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_6_FUNC FM(SCL4) FM(HRTS2_N_A) FM(RTS4_N_A) FM(PWM9_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_5_FUNC FM(SDA3) FM(HRX2_A) FM(RX4_A) FM(PWM8_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_4_FUNC FM(SCL3) FM(HTX2_A) FM(TX4_A) FM(PWM6_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_3_FUNC FM(SDA2) FM(HSCK2_A) FM(SCK4_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_2_FUNC FM(SCL2) FM(PWM0_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_1_FUNC FM(SDA1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP8_0_FUNC FM(SCL1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) + +/* Group9 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define GRP9_16_FUNC FM(RSW3_MATCH) F_(0, 0) F_(0, 0) FM(PWM9_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_15_FUNC FM(RSW3_CAPTURE) F_(0, 0) F_(0, 0) FM(PWM8_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_14_FUNC FM(RSW3_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_13_FUNC FM(ETH10G0_PHYINT) FM(ETH10G1_PHYINT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_12_FUNC FM(ETH10G0_LINK) FM(ETH10G1_LINK) F_(0, 0) FM(PWM7_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_11_FUNC FM(ETH10G0_MDC) FM(ETH10G1_MDC) F_(0, 0) FM(IRQ3_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_10_FUNC FM(ETH10G0_MDIO) FM(ETH10G1_MDIO) F_(0, 0) FM(IRQ2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_9_FUNC FM(ETH25G0_PHYINT) FM(ETH25G1_PHYINT) FM(ETH25G2_PHYINT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_8_FUNC FM(ETH25G0_LINK) FM(ETH25G1_LINK) FM(ETH25G2_LINK) FM(PWM6_A) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_7_FUNC FM(ETH25G0_MDC) FM(ETH25G1_MDC) FM(ETH25G2_MDC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_6_FUNC FM(ETH25G0_MDIO) FM(ETH25G1_MDIO) FM(ETH25G2_MDIO) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_5_FUNC FM(ETHES4_MATCH) FM(ETHES5_MATCH) FM(ETHES6_MATCH) FM(ETHES7_MATCH) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_4_FUNC FM(ETHES4_CAPTURE) FM(ETHES5_CAPTURE) FM(ETHES6_CAPTURE) FM(ETHES7_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_3_FUNC FM(ETHES4_PPS) FM(ETHES5_PPS) FM(ETHES6_PPS) FM(ETHES7_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_2_FUNC FM(ETHES0_MATCH) FM(ETHES1_MATCH) FM(ETHES2_MATCH) FM(ETHES3_MATCH) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_1_FUNC FM(ETHES0_CAPTURE) FM(ETHES1_CAPTURE) FM(ETHES2_CAPTURE) FM(ETHES3_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP9_0_FUNC FM(ETHES0_PPS) FM(ETHES1_PPS) FM(ETHES2_PPS) FM(ETHES3_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) + +/* Group10 Functions */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ +#define GRP10_13_FUNC FM(PCIE41_CLKREQ_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP10_12_FUNC FM(PCIE40_CLKREQ_N) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP10_11_FUNC FM(USB3_VBUS_VALID) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP10_10_FUNC FM(USB3_OVC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP10_9_FUNC FM(USB3_PWEN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP10_8_FUNC FM(USB2_VBUS_VALID) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP10_7_FUNC FM(USB2_OVC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP10_6_FUNC FM(USB2_PWEN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP10_5_FUNC FM(USB1_VBUS_VALID) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP10_4_FUNC FM(USB1_OVC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP10_3_FUNC FM(USB1_PWEN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP10_2_FUNC FM(USB0_VBUS_VALID) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP10_1_FUNC FM(USB0_OVC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define GRP10_0_FUNC FM(USB0_PWEN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) + +#define PINMUX_GPSR \ +/* GPSR0 */ /* GPSR1 */ /* GPSR2 */ /* GPSR3 */ /* GPSR4 */ /* GPSR5 */ /* GPSR6 */ /* GPSR7 */ /* GPSR8 */ /* GPSR9 */ /* GPSR10 */ \ + GPSR8_31 \ + GPSR6_30 GPSR7_30 GPSR8_30 \ + GPSR6_29 GPSR7_29 GPSR8_29 \ + GPSR2_28 GPSR6_28 GPSR7_28 GPSR8_28 \ +GPSR0_27 GPSR2_27 GPSR6_27 GPSR7_27 GPSR8_27 \ +GPSR0_26 GPSR2_26 GPSR6_26 GPSR7_26 GPSR8_26 \ +GPSR0_25 GPSR2_25 GPSR6_25 GPSR7_25 \ +GPSR0_24 GPSR2_24 GPSR6_24 GPSR7_24 \ +GPSR0_23 GPSR2_23 GPSR6_23 GPSR7_23 \ +GPSR0_22 GPSR2_22 GPSR5_22 GPSR6_22 GPSR7_22 \ +GPSR0_21 GPSR1_21 GPSR2_21 GPSR5_21 GPSR6_21 GPSR7_21 \ +GPSR0_20 GPSR1_20 GPSR2_20 GPSR5_20 GPSR6_20 GPSR7_20 \ +GPSR0_19 GPSR1_19 GPSR2_19 GPSR5_19 GPSR6_19 GPSR7_19 \ +GPSR0_18 GPSR1_18 GPSR2_18 GPSR5_18 GPSR6_18 GPSR7_18 \ +GPSR0_17 GPSR1_17 GPSR2_17 GPSR5_17 GPSR6_17 GPSR7_17 \ +GPSR0_16 GPSR1_16 GPSR2_16 GPSR3_16 GPSR5_16 GPSR6_16 GPSR7_16 GPSR9_16 \ +GPSR0_15 GPSR1_15 GPSR2_15 GPSR3_15 GPSR4_15 GPSR5_15 GPSR6_15 GPSR7_15 GPSR8_15 GPSR9_15 \ +GPSR0_14 GPSR1_14 GPSR2_14 GPSR3_14 GPSR4_14 GPSR5_14 GPSR6_14 GPSR7_14 GPSR8_14 GPSR9_14 \ +GPSR0_13 GPSR1_13 GPSR2_13 GPSR3_13 GPSR4_13 GPSR5_13 GPSR6_13 GPSR7_13 GPSR8_13 GPSR9_13 GPSR4_13 \ +GPSR0_12 GPSR1_12 GPSR2_12 GPSR3_12 GPSR4_12 GPSR5_12 GPSR6_12 GPSR7_12 GPSR8_12 GPSR9_12 GPSR4_12 \ +GPSR0_11 GPSR1_11 GPSR2_11 GPSR3_11 GPSR4_11 GPSR5_11 GPSR6_11 GPSR7_11 GPSR8_11 GPSR9_11 GPSR4_11 \ +GPSR0_10 GPSR1_10 GPSR2_10 GPSR3_10 GPSR4_10 GPSR5_10 GPSR6_10 GPSR7_10 GPSR8_10 GPSR9_10 GPSR4_10 \ +GPSR0_9 GPSR1_9 GPSR2_9 GPSR3_9 GPSR4_9 GPSR5_9 GPSR6_9 GPSR7_9 GPSR8_9 GPSR9_9 GPSR4_9 \ +GPSR0_8 GPSR1_8 GPSR2_8 GPSR3_8 GPSR4_8 GPSR5_8 GPSR6_8 GPSR7_8 GPSR8_8 GPSR9_8 GPSR4_8 \ +GPSR0_7 GPSR1_7 GPSR2_7 GPSR3_7 GPSR4_7 GPSR5_7 GPSR6_7 GPSR7_7 GPSR8_7 GPSR9_7 GPSR4_7 \ +GPSR0_6 GPSR1_6 GPSR2_6 GPSR3_6 GPSR4_6 GPSR5_6 GPSR6_6 GPSR7_6 GPSR8_6 GPSR9_6 GPSR4_6 \ +GPSR0_5 GPSR1_5 GPSR2_5 GPSR3_5 GPSR4_5 GPSR5_5 GPSR6_5 GPSR7_5 GPSR8_5 GPSR9_5 GPSR4_5 \ +GPSR0_4 GPSR1_4 GPSR2_4 GPSR3_4 GPSR4_4 GPSR5_4 GPSR6_4 GPSR7_4 GPSR8_4 GPSR9_4 GPSR4_4 \ +GPSR0_3 GPSR1_3 GPSR2_3 GPSR3_3 GPSR4_3 GPSR5_3 GPSR6_3 GPSR7_3 GPSR8_3 GPSR9_3 GPSR4_3 \ +GPSR0_2 GPSR1_2 GPSR2_2 GPSR3_2 GPSR4_2 GPSR5_2 GPSR6_2 GPSR7_2 GPSR8_2 GPSR9_2 GPSR4_2 \ +GPSR0_1 GPSR1_1 GPSR2_1 GPSR3_1 GPSR4_1 GPSR5_1 GPSR6_1 GPSR7_1 GPSR8_1 GPSR9_1 GPSR4_1 \ +GPSR0_0 GPSR1_0 GPSR2_0 GPSR3_0 GPSR4_0 GPSR5_0 GPSR6_0 GPSR7_0 GPSR8_0 GPSR9_0 GPSR4_0 + +/* GRP0_FUNC */ +#define GRP0_FUNC \ +FM(GRP0_27_FUNC) GRP0_27_FUNC \ +FM(GRP0_26_FUNC) GRP0_26_FUNC \ +FM(GRP0_25_FUNC) GRP0_25_FUNC \ +FM(GRP0_24_FUNC) GRP0_24_FUNC \ +FM(GRP0_23_FUNC) GRP0_23_FUNC \ +FM(GRP0_22_FUNC) GRP0_22_FUNC \ +FM(GRP0_21_FUNC) GRP0_21_FUNC \ +FM(GRP0_20_FUNC) GRP0_20_FUNC \ +FM(GRP0_19_FUNC) GRP0_19_FUNC \ +FM(GRP0_18_FUNC) GRP0_18_FUNC \ +FM(GRP0_17_FUNC) GRP0_17_FUNC \ +FM(GRP0_16_FUNC) GRP0_16_FUNC \ +FM(GRP0_15_FUNC) GRP0_15_FUNC \ +FM(GRP0_14_FUNC) GRP0_14_FUNC \ +FM(GRP0_13_FUNC) GRP0_13_FUNC \ +FM(GRP0_12_FUNC) GRP0_12_FUNC \ +FM(GRP0_11_FUNC) GRP0_11_FUNC \ +FM(GRP0_10_FUNC) GRP0_10_FUNC \ +FM(GRP0_9_FUNC) GRP0_9_FUNC \ +FM(GRP0_8_FUNC) GRP0_8_FUNC \ +FM(GRP0_7_FUNC) GRP0_7_FUNC \ +FM(GRP0_6_FUNC) GRP0_6_FUNC \ +FM(GRP0_5_FUNC) GRP0_5_FUNC \ +FM(GRP0_4_FUNC) GRP0_4_FUNC \ +FM(GRP0_3_FUNC) GRP0_3_FUNC \ +FM(GRP0_2_FUNC) GRP0_2_FUNC \ +FM(GRP0_1_FUNC) GRP0_1_FUNC \ +FM(GRP0_0_FUNC) GRP0_0_FUNC + +/* GRP1_FUNC */ +#define GRP1_FUNC \ +FM(GRP1_21_FUNC) GRP1_21_FUNC \ +FM(GRP1_20_FUNC) GRP1_20_FUNC \ +FM(GRP1_19_FUNC) GRP1_19_FUNC \ +FM(GRP1_18_FUNC) GRP1_18_FUNC \ +FM(GRP1_17_FUNC) GRP1_17_FUNC \ +FM(GRP1_16_FUNC) GRP1_16_FUNC \ +FM(GRP1_15_FUNC) GRP1_15_FUNC \ +FM(GRP1_14_FUNC) GRP1_14_FUNC \ +FM(GRP1_13_FUNC) GRP1_13_FUNC \ +FM(GRP1_12_FUNC) GRP1_12_FUNC \ +FM(GRP1_11_FUNC) GRP1_11_FUNC \ +FM(GRP1_10_FUNC) GRP1_10_FUNC \ +FM(GRP1_9_FUNC) GRP1_9_FUNC \ +FM(GRP1_8_FUNC) GRP1_8_FUNC \ +FM(GRP1_7_FUNC) GRP1_7_FUNC \ +FM(GRP1_6_FUNC) GRP1_6_FUNC \ +FM(GRP1_5_FUNC) GRP1_5_FUNC \ +FM(GRP1_4_FUNC) GRP1_4_FUNC \ +FM(GRP1_3_FUNC) GRP1_3_FUNC \ +FM(GRP1_2_FUNC) GRP1_2_FUNC \ +FM(GRP1_1_FUNC) GRP1_1_FUNC \ +FM(GRP1_0_FUNC) GRP1_0_FUNC + +/* GRP2_FUNC */ +#define GRP2_FUNC \ +FM(GRP2_28_FUNC) GRP2_28_FUNC \ +FM(GRP2_27_FUNC) GRP2_27_FUNC \ +FM(GRP2_26_FUNC) GRP2_26_FUNC \ +FM(GRP2_25_FUNC) GRP2_25_FUNC \ +FM(GRP2_24_FUNC) GRP2_24_FUNC \ +FM(GRP2_23_FUNC) GRP2_23_FUNC \ +FM(GRP2_22_FUNC) GRP2_22_FUNC \ +FM(GRP2_21_FUNC) GRP2_21_FUNC \ +FM(GRP2_20_FUNC) GRP2_20_FUNC \ +FM(GRP2_19_FUNC) GRP2_19_FUNC \ +FM(GRP2_18_FUNC) GRP2_18_FUNC \ +FM(GRP2_17_FUNC) GRP2_17_FUNC \ +FM(GRP2_16_FUNC) GRP2_16_FUNC \ +FM(GRP2_15_FUNC) GRP2_15_FUNC \ +FM(GRP2_14_FUNC) GRP2_14_FUNC \ +FM(GRP2_13_FUNC) GRP2_13_FUNC \ +FM(GRP2_12_FUNC) GRP2_12_FUNC \ +FM(GRP2_11_FUNC) GRP2_11_FUNC \ +FM(GRP2_10_FUNC) GRP2_10_FUNC \ +FM(GRP2_9_FUNC) GRP2_9_FUNC \ +FM(GRP2_8_FUNC) GRP2_8_FUNC \ +FM(GRP2_7_FUNC) GRP2_7_FUNC \ +FM(GRP2_6_FUNC) GRP2_6_FUNC \ +FM(GRP2_5_FUNC) GRP2_5_FUNC \ +FM(GRP2_4_FUNC) GRP2_4_FUNC \ +FM(GRP2_3_FUNC) GRP2_3_FUNC \ +FM(GRP2_2_FUNC) GRP2_2_FUNC \ +FM(GRP2_1_FUNC) GRP2_1_FUNC \ +FM(GRP2_0_FUNC) GRP2_0_FUNC + +/* GRP3_FUNC */ +#define GRP3_FUNC \ +FM(GRP3_16_FUNC) GRP3_16_FUNC \ +FM(GRP3_15_FUNC) GRP3_15_FUNC \ +FM(GRP3_14_FUNC) GRP3_14_FUNC \ +FM(GRP3_13_FUNC) GRP3_13_FUNC \ +FM(GRP3_12_FUNC) GRP3_12_FUNC \ +FM(GRP3_11_FUNC) GRP3_11_FUNC \ +FM(GRP3_10_FUNC) GRP3_10_FUNC \ +FM(GRP3_9_FUNC) GRP3_9_FUNC \ +FM(GRP3_8_FUNC) GRP3_8_FUNC \ +FM(GRP3_7_FUNC) GRP3_7_FUNC \ +FM(GRP3_6_FUNC) GRP3_6_FUNC \ +FM(GRP3_5_FUNC) GRP3_5_FUNC \ +FM(GRP3_4_FUNC) GRP3_4_FUNC \ +FM(GRP3_3_FUNC) GRP3_3_FUNC \ +FM(GRP3_2_FUNC) GRP3_2_FUNC \ +FM(GRP3_1_FUNC) GRP3_1_FUNC \ +FM(GRP3_0_FUNC) GRP3_0_FUNC + +/* GRP4_FUNC */ +#define GRP4_FUNC \ +FM(GRP4_15_FUNC) GRP4_15_FUNC \ +FM(GRP4_14_FUNC) GRP4_14_FUNC \ +FM(GRP4_13_FUNC) GRP4_13_FUNC \ +FM(GRP4_12_FUNC) GRP4_12_FUNC \ +FM(GRP4_11_FUNC) GRP4_11_FUNC \ +FM(GRP4_10_FUNC) GRP4_10_FUNC \ +FM(GRP4_9_FUNC) GRP4_9_FUNC \ +FM(GRP4_8_FUNC) GRP4_8_FUNC \ +FM(GRP4_7_FUNC) GRP4_7_FUNC \ +FM(GRP4_6_FUNC) GRP4_6_FUNC \ +FM(GRP4_5_FUNC) GRP4_5_FUNC \ +FM(GRP4_4_FUNC) GRP4_4_FUNC \ +FM(GRP4_3_FUNC) GRP4_3_FUNC \ +FM(GRP4_2_FUNC) GRP4_2_FUNC \ +FM(GRP4_1_FUNC) GRP4_1_FUNC \ +FM(GRP4_0_FUNC) GRP4_0_FUNC + +/* GRP5_FUNC */ +#define GRP5_FUNC \ +FM(GRP5_22_FUNC) GRP5_22_FUNC \ +FM(GRP5_21_FUNC) GRP5_21_FUNC \ +FM(GRP5_20_FUNC) GRP5_20_FUNC \ +FM(GRP5_19_FUNC) GRP5_19_FUNC \ +FM(GRP5_18_FUNC) GRP5_18_FUNC \ +FM(GRP5_17_FUNC) GRP5_17_FUNC \ +FM(GRP5_16_FUNC) GRP5_16_FUNC \ +FM(GRP5_15_FUNC) GRP5_15_FUNC \ +FM(GRP5_14_FUNC) GRP5_14_FUNC \ +FM(GRP5_13_FUNC) GRP5_13_FUNC \ +FM(GRP5_12_FUNC) GRP5_12_FUNC \ +FM(GRP5_11_FUNC) GRP5_11_FUNC \ +FM(GRP5_10_FUNC) GRP5_10_FUNC \ +FM(GRP5_9_FUNC) GRP5_9_FUNC \ +FM(GRP5_8_FUNC) GRP5_8_FUNC \ +FM(GRP5_7_FUNC) GRP5_7_FUNC \ +FM(GRP5_6_FUNC) GRP5_6_FUNC \ +FM(GRP5_5_FUNC) GRP5_5_FUNC \ +FM(GRP5_4_FUNC) GRP5_4_FUNC \ +FM(GRP5_3_FUNC) GRP5_3_FUNC \ +FM(GRP5_2_FUNC) GRP5_2_FUNC \ +FM(GRP5_1_FUNC) GRP5_1_FUNC \ +FM(GRP5_0_FUNC) GRP5_0_FUNC + +/* GRP6_FUNC */ +#define GRP6_FUNC \ +FM(GRP6_30_FUNC) GRP6_30_FUNC \ +FM(GRP6_29_FUNC) GRP6_29_FUNC \ +FM(GRP6_28_FUNC) GRP6_28_FUNC \ +FM(GRP6_27_FUNC) GRP6_27_FUNC \ +FM(GRP6_26_FUNC) GRP6_26_FUNC \ +FM(GRP6_25_FUNC) GRP6_25_FUNC \ +FM(GRP6_24_FUNC) GRP6_24_FUNC \ +FM(GRP6_23_FUNC) GRP6_23_FUNC \ +FM(GRP6_22_FUNC) GRP6_22_FUNC \ +FM(GRP6_21_FUNC) GRP6_21_FUNC \ +FM(GRP6_20_FUNC) GRP6_20_FUNC \ +FM(GRP6_19_FUNC) GRP6_19_FUNC \ +FM(GRP6_18_FUNC) GRP6_18_FUNC \ +FM(GRP6_17_FUNC) GRP6_17_FUNC \ +FM(GRP6_16_FUNC) GRP6_16_FUNC \ +FM(GRP6_15_FUNC) GRP6_15_FUNC \ +FM(GRP6_14_FUNC) GRP6_14_FUNC \ +FM(GRP6_13_FUNC) GRP6_13_FUNC \ +FM(GRP6_12_FUNC) GRP6_12_FUNC \ +FM(GRP6_11_FUNC) GRP6_11_FUNC \ +FM(GRP6_10_FUNC) GRP6_10_FUNC \ +FM(GRP6_9_FUNC) GRP6_9_FUNC \ +FM(GRP6_8_FUNC) GRP6_8_FUNC \ +FM(GRP6_7_FUNC) GRP6_7_FUNC \ +FM(GRP6_6_FUNC) GRP6_6_FUNC \ +FM(GRP6_5_FUNC) GRP6_5_FUNC \ +FM(GRP6_4_FUNC) GRP6_4_FUNC \ +FM(GRP6_3_FUNC) GRP6_3_FUNC \ +FM(GRP6_2_FUNC) GRP6_2_FUNC \ +FM(GRP6_1_FUNC) GRP6_1_FUNC \ +FM(GRP6_0_FUNC) GRP6_0_FUNC + +/* GRP7_FUNC */ +#define GRP7_FUNC \ +FM(GRP7_30_FUNC) GRP7_30_FUNC \ +FM(GRP7_29_FUNC) GRP7_29_FUNC \ +FM(GRP7_28_FUNC) GRP7_28_FUNC \ +FM(GRP7_27_FUNC) GRP7_27_FUNC \ +FM(GRP7_26_FUNC) GRP7_26_FUNC \ +FM(GRP7_25_FUNC) GRP7_25_FUNC \ +FM(GRP7_24_FUNC) GRP7_24_FUNC \ +FM(GRP7_23_FUNC) GRP7_23_FUNC \ +FM(GRP7_22_FUNC) GRP7_22_FUNC \ +FM(GRP7_21_FUNC) GRP7_21_FUNC \ +FM(GRP7_20_FUNC) GRP7_20_FUNC \ +FM(GRP7_19_FUNC) GRP7_19_FUNC \ +FM(GRP7_18_FUNC) GRP7_18_FUNC \ +FM(GRP7_17_FUNC) GRP7_17_FUNC \ +FM(GRP7_16_FUNC) GRP7_16_FUNC \ +FM(GRP7_15_FUNC) GRP7_15_FUNC \ +FM(GRP7_14_FUNC) GRP7_14_FUNC \ +FM(GRP7_13_FUNC) GRP7_13_FUNC \ +FM(GRP7_12_FUNC) GRP7_12_FUNC \ +FM(GRP7_11_FUNC) GRP7_11_FUNC \ +FM(GRP7_10_FUNC) GRP7_10_FUNC \ +FM(GRP7_9_FUNC) GRP7_9_FUNC \ +FM(GRP7_8_FUNC) GRP7_8_FUNC \ +FM(GRP7_7_FUNC) GRP7_7_FUNC \ +FM(GRP7_6_FUNC) GRP7_6_FUNC \ +FM(GRP7_5_FUNC) GRP7_5_FUNC \ +FM(GRP7_4_FUNC) GRP7_4_FUNC \ +FM(GRP7_3_FUNC) GRP7_3_FUNC \ +FM(GRP7_2_FUNC) GRP7_2_FUNC \ +FM(GRP7_1_FUNC) GRP7_1_FUNC \ +FM(GRP7_0_FUNC) GRP7_0_FUNC + +/* GRP8_FUNC */ +#define GRP8_FUNC \ +FM(GRP8_31_FUNC) GRP8_31_FUNC \ +FM(GRP8_30_FUNC) GRP8_30_FUNC \ +FM(GRP8_29_FUNC) GRP8_29_FUNC \ +FM(GRP8_28_FUNC) GRP8_28_FUNC \ +FM(GRP8_27_FUNC) GRP8_27_FUNC \ +FM(GRP8_26_FUNC) GRP8_26_FUNC \ +FM(GRP8_15_FUNC) GRP8_15_FUNC \ +FM(GRP8_14_FUNC) GRP8_14_FUNC \ +FM(GRP8_13_FUNC) GRP8_13_FUNC \ +FM(GRP8_12_FUNC) GRP8_12_FUNC \ +FM(GRP8_11_FUNC) GRP8_11_FUNC \ +FM(GRP8_10_FUNC) GRP8_10_FUNC \ +FM(GRP8_9_FUNC) GRP8_9_FUNC \ +FM(GRP8_8_FUNC) GRP8_8_FUNC \ +FM(GRP8_7_FUNC) GRP8_7_FUNC \ +FM(GRP8_6_FUNC) GRP8_6_FUNC \ +FM(GRP8_5_FUNC) GRP8_5_FUNC \ +FM(GRP8_4_FUNC) GRP8_4_FUNC \ +FM(GRP8_3_FUNC) GRP8_3_FUNC \ +FM(GRP8_2_FUNC) GRP8_2_FUNC \ +FM(GRP8_1_FUNC) GRP8_1_FUNC \ +FM(GRP8_0_FUNC) GRP8_0_FUNC + +/* GRP9_FUNC */ +#define GRP9_FUNC \ +FM(GRP9_16_FUNC) GRP9_16_FUNC \ +FM(GRP9_15_FUNC) GRP9_15_FUNC \ +FM(GRP9_14_FUNC) GRP9_14_FUNC \ +FM(GRP9_13_FUNC) GRP9_13_FUNC \ +FM(GRP9_12_FUNC) GRP9_12_FUNC \ +FM(GRP9_11_FUNC) GRP9_11_FUNC \ +FM(GRP9_10_FUNC) GRP9_10_FUNC \ +FM(GRP9_9_FUNC) GRP9_9_FUNC \ +FM(GRP9_8_FUNC) GRP9_8_FUNC \ +FM(GRP9_7_FUNC) GRP9_7_FUNC \ +FM(GRP9_6_FUNC) GRP9_6_FUNC \ +FM(GRP9_5_FUNC) GRP9_5_FUNC \ +FM(GRP9_4_FUNC) GRP9_4_FUNC \ +FM(GRP9_3_FUNC) GRP9_3_FUNC \ +FM(GRP9_2_FUNC) GRP9_2_FUNC \ +FM(GRP9_1_FUNC) GRP9_1_FUNC \ +FM(GRP9_0_FUNC) GRP9_0_FUNC + +/* GRP10_FUNC */ +#define GRP10_FUNC \ +FM(GRP10_13_FUNC) GRP10_13_FUNC \ +FM(GRP10_12_FUNC) GRP10_12_FUNC \ +FM(GRP10_11_FUNC) GRP10_11_FUNC \ +FM(GRP10_10_FUNC) GRP10_10_FUNC \ +FM(GRP10_9_FUNC) GRP10_9_FUNC \ +FM(GRP10_8_FUNC) GRP10_8_FUNC \ +FM(GRP10_7_FUNC) GRP10_7_FUNC \ +FM(GRP10_6_FUNC) GRP10_6_FUNC \ +FM(GRP10_5_FUNC) GRP10_5_FUNC \ +FM(GRP10_4_FUNC) GRP10_4_FUNC \ +FM(GRP10_3_FUNC) GRP10_3_FUNC \ +FM(GRP10_2_FUNC) GRP10_2_FUNC \ +FM(GRP10_1_FUNC) GRP10_1_FUNC \ +FM(GRP10_0_FUNC) GRP10_0_FUNC + +/* Mux all groups functions */ +#define PINMUX_GRP_FUNC \ +GRP0_FUNC \ +GRP1_FUNC \ +GRP2_FUNC \ +GRP3_FUNC \ +GRP4_FUNC \ +GRP5_FUNC \ +GRP6_FUNC \ +GRP7_FUNC \ +GRP8_FUNC \ +GRP9_FUNC \ +GRP10_FUNC + +#define GP_ALTSEL(id, bank, pin) \ +GP##bank##_ALTSEL##id##_##pin##_0, \ +GP##bank##_ALTSEL##id##_##pin##_1, + +#define GP_ALTSEL_TYPE(id, bank) \ + GP_ALTSEL(id, bank, 31) \ + GP_ALTSEL(id, bank, 30) \ + GP_ALTSEL(id, bank, 29) \ + GP_ALTSEL(id, bank, 28) \ + GP_ALTSEL(id, bank, 27) \ + GP_ALTSEL(id, bank, 26) \ + GP_ALTSEL(id, bank, 25) \ + GP_ALTSEL(id, bank, 24) \ + GP_ALTSEL(id, bank, 23) \ + GP_ALTSEL(id, bank, 22) \ + GP_ALTSEL(id, bank, 21) \ + GP_ALTSEL(id, bank, 20) \ + GP_ALTSEL(id, bank, 19) \ + GP_ALTSEL(id, bank, 18) \ + GP_ALTSEL(id, bank, 17) \ + GP_ALTSEL(id, bank, 16) \ + GP_ALTSEL(id, bank, 15) \ + GP_ALTSEL(id, bank, 14) \ + GP_ALTSEL(id, bank, 13) \ + GP_ALTSEL(id, bank, 12) \ + GP_ALTSEL(id, bank, 11) \ + GP_ALTSEL(id, bank, 10) \ + GP_ALTSEL(id, bank, 9) \ + GP_ALTSEL(id, bank, 8) \ + GP_ALTSEL(id, bank, 7) \ + GP_ALTSEL(id, bank, 6) \ + GP_ALTSEL(id, bank, 5) \ + GP_ALTSEL(id, bank, 4) \ + GP_ALTSEL(id, bank, 3) \ + GP_ALTSEL(id, bank, 2) \ + GP_ALTSEL(id, bank, 1) \ + GP_ALTSEL(id, bank, 0) + +#define GP_ALTSEL0(bank) GP_ALTSEL_TYPE(0, bank) +#define GP_ALTSEL1(bank) GP_ALTSEL_TYPE(1, bank) +#define GP_ALTSEL2(bank) GP_ALTSEL_TYPE(2, bank) +#define GP_ALTSEL3(bank) GP_ALTSEL_TYPE(3, bank) + +#define PINMUX_ALTSEL \ +GP_ALTSEL0(0) GP_ALTSEL0(1) GP_ALTSEL0(2) GP_ALTSEL0(3) GP_ALTSEL0(4) GP_ALTSEL0(5) GP_ALTSEL0(6) GP_ALTSEL0(7) GP_ALTSEL0(8) GP_ALTSEL0(9) GP_ALTSEL0(10) \ +GP_ALTSEL1(0) GP_ALTSEL1(1) GP_ALTSEL1(2) GP_ALTSEL1(3) GP_ALTSEL1(4) GP_ALTSEL1(5) GP_ALTSEL1(6) GP_ALTSEL1(7) GP_ALTSEL1(8) GP_ALTSEL1(9) GP_ALTSEL1(10) \ +GP_ALTSEL2(0) GP_ALTSEL2(1) GP_ALTSEL2(2) GP_ALTSEL2(3) GP_ALTSEL2(4) GP_ALTSEL2(5) GP_ALTSEL2(6) GP_ALTSEL2(7) GP_ALTSEL2(8) GP_ALTSEL2(9) GP_ALTSEL2(10) \ +GP_ALTSEL3(0) GP_ALTSEL3(1) GP_ALTSEL3(2) GP_ALTSEL3(3) GP_ALTSEL3(4) GP_ALTSEL3(5) GP_ALTSEL3(6) GP_ALTSEL3(7) GP_ALTSEL3(8) GP_ALTSEL3(9) GP_ALTSEL3(10) + +/* GP1_MODSEL */ /* 0 */ /* 1 */ +#define GP1_MODSEL_21 FM(SEL_TAUJ13_OUTPUT) FM(SEL_TAUJ13_INPUT) +#define GP1_MODSEL_20 FM(SEL_TAUJ12_OUTPUT) FM(SEL_TAUJ12_INPUT) +#define GP1_MODSEL_19 FM(SEL_TAUJ11_OUTPUT) FM(SEL_TAUJ11_INPUT) +#define GP1_MODSEL_18 FM(SEL_TAUJ10_OUTPUT) FM(SEL_TAUJ10_INPUT) +#define GP1_MODSEL_17 FM(SEL_TAUJ33_OUTPUT) FM(SEL_TAUJ33_INPUT) +#define GP1_MODSEL_16 FM(SEL_TAUJ32_OUTPUT) FM(SEL_TAUJ32_INPUT) +#define GP1_MODSEL_15 FM(SEL_TAUJ31_OUTPUT) FM(SEL_TAUJ31_INPUT) +#define GP1_MODSEL_14 FM(SEL_TAUJ30_OUTPUT) FM(SEL_TAUJ30_INPUT) + +#define GP1_MODSEL \ +GP1_MODSEL_21 \ +GP1_MODSEL_20 \ +GP1_MODSEL_19 \ +GP1_MODSEL_18 \ +GP1_MODSEL_17 \ +GP1_MODSEL_16 \ +GP1_MODSEL_15 \ +GP1_MODSEL_14 + +/* GP2_MODSEL */ /* 0 */ /* 1 */ +#define GP2_MODSEL_20 FM(SEL_SDA0_0) FM(SEL_SDA0_1) +#define GP2_MODSEL_19 FM(SEL_SCL0_0) FM(SEL_SCL0_1) + +#define GP2_MODSEL \ +GP2_MODSEL_20 \ +GP2_MODSEL_19 + +/* GP8_MODSEL */ /* 0 */ /* 1 */ +#define GP8_MODSEL_15 FM(SEL_SDA8_0) FM(SEL_SDA8_1) +#define GP8_MODSEL_14 FM(SEL_SCL8_0) FM(SEL_SCL8_1) +#define GP8_MODSEL_13 FM(SEL_SDA7_0) FM(SEL_SDA7_1) +#define GP8_MODSEL_12 FM(SEL_SCL7_0) FM(SEL_SCL7_1) +#define GP8_MODSEL_11 FM(SEL_SDA6_0) FM(SEL_SDA6_1) +#define GP8_MODSEL_10 FM(SEL_SCL6_0) FM(SEL_SCL6_1) +#define GP8_MODSEL_9 FM(SEL_SDA5_0) FM(SEL_SDA5_1) +#define GP8_MODSEL_8 FM(SEL_SCL5_0) FM(SEL_SCL5_1) +#define GP8_MODSEL_7 FM(SEL_SDA4_0) FM(SEL_SDA4_1) +#define GP8_MODSEL_6 FM(SEL_SCL4_0) FM(SEL_SCL4_1) +#define GP8_MODSEL_5 FM(SEL_SDA3_0) FM(SEL_SDA3_1) +#define GP8_MODSEL_4 FM(SEL_SCL3_0) FM(SEL_SCL3_1) +#define GP8_MODSEL_3 FM(SEL_SDA2_0) FM(SEL_SDA2_1) +#define GP8_MODSEL_2 FM(SEL_SCL2_0) FM(SEL_SCL2_1) +#define GP8_MODSEL_1 FM(SEL_SDA1_0) FM(SEL_SDA1_1) +#define GP8_MODSEL_0 FM(SEL_SCL1_0) FM(SEL_SCL1_1) + +#define GP8_MODSEL \ +GP8_MODSEL_15 \ +GP8_MODSEL_14 \ +GP8_MODSEL_13 \ +GP8_MODSEL_12 \ +GP8_MODSEL_11 \ +GP8_MODSEL_10 \ +GP8_MODSEL_9 \ +GP8_MODSEL_8 \ +GP8_MODSEL_7 \ +GP8_MODSEL_6 \ +GP8_MODSEL_5 \ +GP8_MODSEL_4 \ +GP8_MODSEL_3 \ +GP8_MODSEL_2 \ +GP8_MODSEL_1 \ +GP8_MODSEL_0 + +#define PINMUX_MODSELS \ +GP8_MODSEL \ +GP2_MODSEL \ +GP1_MODSEL + +enum { + PINMUX_RESERVED = 0, + + PINMUX_DATA_BEGIN, + GP_ALL(DATA), + PINMUX_DATA_END, + +#define F_(x, y) +#define FM(x) FN_##x, + PINMUX_FUNCTION_BEGIN, + GP_ALL(FN), + PINMUX_GPSR + PINMUX_GRP_FUNC + PINMUX_ALTSEL + PINMUX_MODSELS + PINMUX_FUNCTION_END, +#undef F_ +#undef FM + +#define F_(x, y) +#define FM(x) x##_MARK, + PINMUX_MARK_BEGIN, + PINMUX_GPSR + PINMUX_GRP_FUNC + PINMUX_MODSELS + PINMUX_MARK_END, +#undef F_ +#undef FM +}; + +#define GP_ALTSEL_FUNC_0(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_0, \ + GP##bank##_ALTSEL1_##pin##_0, \ + GP##bank##_ALTSEL2_##pin##_0, \ + GP##bank##_ALTSEL3_##pin##_0 + +#define GP_ALTSEL_FUNC_1(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_1, \ + GP##bank##_ALTSEL1_##pin##_0, \ + GP##bank##_ALTSEL2_##pin##_0, \ + GP##bank##_ALTSEL3_##pin##_0 + +#define GP_ALTSEL_FUNC_2(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_0, \ + GP##bank##_ALTSEL1_##pin##_1, \ + GP##bank##_ALTSEL2_##pin##_0, \ + GP##bank##_ALTSEL3_##pin##_0 + +#define GP_ALTSEL_FUNC_3(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_1, \ + GP##bank##_ALTSEL1_##pin##_1, \ + GP##bank##_ALTSEL2_##pin##_0, \ + GP##bank##_ALTSEL3_##pin##_0 + +#define GP_ALTSEL_FUNC_4(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_0, \ + GP##bank##_ALTSEL1_##pin##_0, \ + GP##bank##_ALTSEL2_##pin##_1, \ + GP##bank##_ALTSEL3_##pin##_0 + +#define GP_ALTSEL_FUNC_5(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_1, \ + GP##bank##_ALTSEL1_##pin##_0, \ + GP##bank##_ALTSEL2_##pin##_1, \ + GP##bank##_ALTSEL3_##pin##_0 + +#define GP_ALTSEL_FUNC_6(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_0, \ + GP##bank##_ALTSEL1_##pin##_1, \ + GP##bank##_ALTSEL2_##pin##_1, \ + GP##bank##_ALTSEL3_##pin##_0 + +#define GP_ALTSEL_FUNC_7(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_1, \ + GP##bank##_ALTSEL1_##pin##_1, \ + GP##bank##_ALTSEL2_##pin##_1, \ + GP##bank##_ALTSEL3_##pin##_0 + +#define GP_ALTSEL_FUNC_8(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_0, \ + GP##bank##_ALTSEL1_##pin##_0, \ + GP##bank##_ALTSEL2_##pin##_0, \ + GP##bank##_ALTSEL3_##pin##_1 + +#define GP_ALTSEL_FUNC_9(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_1, \ + GP##bank##_ALTSEL1_##pin##_0, \ + GP##bank##_ALTSEL2_##pin##_0, \ + GP##bank##_ALTSEL3_##pin##_1 + +#define GP_ALTSEL_FUNC_10(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_0, \ + GP##bank##_ALTSEL1_##pin##_1, \ + GP##bank##_ALTSEL2_##pin##_0, \ + GP##bank##_ALTSEL3_##pin##_1 + +#define GP_ALTSEL_FUNC_11(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_1, \ + GP##bank##_ALTSEL1_##pin##_1, \ + GP##bank##_ALTSEL2_##pin##_0, \ + GP##bank##_ALTSEL3_##pin##_1 + +#define GP_ALTSEL_FUNC_12(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_0, \ + GP##bank##_ALTSEL1_##pin##_0, \ + GP##bank##_ALTSEL2_##pin##_1, \ + GP##bank##_ALTSEL3_##pin##_1 + +#define GP_ALTSEL_FUNC_13(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_1, \ + GP##bank##_ALTSEL1_##pin##_0, \ + GP##bank##_ALTSEL2_##pin##_1, \ + GP##bank##_ALTSEL3_##pin##_1 + +#define GP_ALTSEL_FUNC_14(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_0, \ + GP##bank##_ALTSEL1_##pin##_1, \ + GP##bank##_ALTSEL2_##pin##_1, \ + GP##bank##_ALTSEL3_##pin##_1 + +#define GP_ALTSEL_FUNC_15(bank, pin) \ + GP##bank##_ALTSEL0_##pin##_1, \ + GP##bank##_ALTSEL1_##pin##_1, \ + GP##bank##_ALTSEL2_##pin##_1, \ + GP##bank##_ALTSEL3_##pin##_1 + +#define GP_ALTSEL_FUNC(bank, pin, func) \ + GP_ALTSEL_FUNC_##func(bank, pin) + +/* GP0 ALTSEL function 0 */ +#define ALT_DP2_HOTPLUG GP_ALTSEL_FUNC(0, 27, 0) +#define ALT_DP1_HOTPLUG GP_ALTSEL_FUNC(0, 26, 0) +#define ALT_DP0_HOTPLUG GP_ALTSEL_FUNC(0, 25, 0) +#define ALT_MSIOF1_SS2_A GP_ALTSEL_FUNC(0, 24, 0) +#define ALT_MSIOF1_SS1_A GP_ALTSEL_FUNC(0, 23, 0) +#define ALT_MSIOF1_SYNC_A GP_ALTSEL_FUNC(0, 22, 0) +#define ALT_MSIOF1_RXD_A GP_ALTSEL_FUNC(0, 21, 0) +#define ALT_MSIOF1_TXD_A GP_ALTSEL_FUNC(0, 20, 0) +#define ALT_MSIOF1_SCK_A GP_ALTSEL_FUNC(0, 19, 0) +#define ALT_MSIOF0_SS2 GP_ALTSEL_FUNC(0, 18, 0) +#define ALT_MSIOF0_SS1 GP_ALTSEL_FUNC(0, 17, 0) +#define ALT_MSIOF0_SYNC GP_ALTSEL_FUNC(0, 16, 0) +#define ALT_MSIOF0_RXD GP_ALTSEL_FUNC(0, 15, 0) +#define ALT_MSIOF0_TXD GP_ALTSEL_FUNC(0, 14, 0) +#define ALT_MSIOF0_SCK GP_ALTSEL_FUNC(0, 13, 0) +#define ALT_RXDB_EXTFXR_A GP_ALTSEL_FUNC(0, 12, 0) +#define ALT_FXR_TXENB_N_A GP_ALTSEL_FUNC(0, 11, 0) +#define ALT_FXR_TXDB_A GP_ALTSEL_FUNC(0, 10, 0) +#define ALT_RXDA_EXTFXR_A GP_ALTSEL_FUNC(0, 9, 0) +#define ALT_FXR_TXENA_N_A GP_ALTSEL_FUNC(0, 8, 0) +#define ALT_FXR_TXDA_A GP_ALTSEL_FUNC(0, 7, 0) +#define ALT_CLK_EXTFXR_A GP_ALTSEL_FUNC(0, 6, 0) +#define ALT_FXR_CLKOUT2_A GP_ALTSEL_FUNC(0, 5, 0) +#define ALT_FXR_CLKOUT1_A GP_ALTSEL_FUNC(0, 4, 0) +#define ALT_STPWT_EXTFXR_A GP_ALTSEL_FUNC(0, 3, 0) + +/* GP0 ALTSEL function 1 */ +#define ALT_TAUD0O13 GP_ALTSEL_FUNC(0, 24, 1) +#define ALT_TAUD0O12 GP_ALTSEL_FUNC(0, 23, 1) +#define ALT_TAUD0O11 GP_ALTSEL_FUNC(0, 22, 1) +#define ALT_TAUD0O10 GP_ALTSEL_FUNC(0, 21, 1) +#define ALT_TAUD0O9 GP_ALTSEL_FUNC(0, 20, 1) +#define ALT_TAUD0O8 GP_ALTSEL_FUNC(0, 19, 1) +#define ALT_TAUD0O7 GP_ALTSEL_FUNC(0, 18, 1) +#define ALT_TAUD0O6 GP_ALTSEL_FUNC(0, 17, 1) +#define ALT_TAUD0O5 GP_ALTSEL_FUNC(0, 16, 1) +#define ALT_TAUD0O4 GP_ALTSEL_FUNC(0, 15, 1) +#define ALT_TAUD0O3 GP_ALTSEL_FUNC(0, 14, 1) +#define ALT_TAUD0O2 GP_ALTSEL_FUNC(0, 13, 1) +#define ALT_CAN11TX GP_ALTSEL_FUNC(0, 12, 1) +#define ALT_CAN11RX_INTP11 GP_ALTSEL_FUNC(0, 11, 1) +#define ALT_CAN10TX GP_ALTSEL_FUNC(0, 10, 1) +#define ALT_CAN10RX_INTP10 GP_ALTSEL_FUNC(0, 9, 1) +#define ALT_CAN9TX GP_ALTSEL_FUNC(0, 8, 1) +#define ALT_CAN9RX_INTP9 GP_ALTSEL_FUNC(0, 7, 1) +#define ALT_CAN8TX GP_ALTSEL_FUNC(0, 6, 1) +#define ALT_CAN8RX_INTP8 GP_ALTSEL_FUNC(0, 5, 1) +#define ALT_CAN7TX GP_ALTSEL_FUNC(0, 4, 1) +#define ALT_CAN7RX_INTP7 GP_ALTSEL_FUNC(0, 3, 1) + +/* GP0 ALTSEL function 2 */ +#define ALT_RLIN311TX GP_ALTSEL_FUNC(0, 12, 2) +#define ALT_RLIN311RX_INTP27 GP_ALTSEL_FUNC(0, 11, 2) +#define ALT_RLIN310TX GP_ALTSEL_FUNC(0, 10, 2) +#define ALT_RLIN310RX_INTP26 GP_ALTSEL_FUNC(0, 9, 2) +#define ALT_RLIN39TX GP_ALTSEL_FUNC(0, 8, 2) +#define ALT_RLIN39RX_INTP25 GP_ALTSEL_FUNC(0, 7, 2) +#define ALT_RLIN38TX GP_ALTSEL_FUNC(0, 6, 2) +#define ALT_RLIN38RX_INTP24 GP_ALTSEL_FUNC(0, 5, 2) +#define ALT_RLIN315TX_A GP_ALTSEL_FUNC(0, 4, 2) +#define ALT_RLIN315RX_INTP31_A GP_ALTSEL_FUNC(0, 3, 2) + +/* GP0 ALTSEL function 3 */ +#define ALT_RTCA0OUT_A GP_ALTSEL_FUNC(0, 12, 3) +#define ALT_EXTCLK0O_A GP_ALTSEL_FUNC(0, 11, 3) +#define ALT_TAUD1O15 GP_ALTSEL_FUNC(0, 8, 3) +#define ALT_TAUD1O14 GP_ALTSEL_FUNC(0, 7, 3) +#define ALT_TAUD1O13 GP_ALTSEL_FUNC(0, 6, 3) +#define ALT_TAUD1O12 GP_ALTSEL_FUNC(0, 5, 3) +#define ALT_TAUD1O11 GP_ALTSEL_FUNC(0, 4, 3) +#define ALT_TAUD1O10 GP_ALTSEL_FUNC(0, 3, 3) + +/* GP1 ALTSEL function 0 */ +#define ALT_RLIN33TX GP_ALTSEL_FUNC(1, 21, 0) +#define ALT_RLIN33RX_INTP19 GP_ALTSEL_FUNC(1, 20, 0) +#define ALT_RLIN32TX GP_ALTSEL_FUNC(1, 19, 0) +#define ALT_RLIN32RX_INTP18 GP_ALTSEL_FUNC(1, 18, 0) +#define ALT_RLIN31TX GP_ALTSEL_FUNC(1, 17, 0) +#define ALT_RLIN31RX_INTP17 GP_ALTSEL_FUNC(1, 16, 0) +#define ALT_RLIN30TX GP_ALTSEL_FUNC(1, 15, 0) +#define ALT_RLIN30RX_INTP16 GP_ALTSEL_FUNC(1, 14, 0) +#define ALT_CAN6TX GP_ALTSEL_FUNC(1, 13, 0) +#define ALT_CAN6RX_INTP6 GP_ALTSEL_FUNC(1, 12, 0) +#define ALT_CAN5TX GP_ALTSEL_FUNC(1, 11, 0) +#define ALT_CAN5RX_INTP5 GP_ALTSEL_FUNC(1, 10, 0) +#define ALT_CAN4TX GP_ALTSEL_FUNC(1, 9, 0) +#define ALT_CAN4RX_INTP4 GP_ALTSEL_FUNC(1, 8, 0) +#define ALT_CAN3TX GP_ALTSEL_FUNC(1, 7, 0) +#define ALT_CAN3RX_INTP3 GP_ALTSEL_FUNC(1, 6, 0) +#define ALT_CAN2TX GP_ALTSEL_FUNC(1, 5, 0) +#define ALT_CAN2RX_INTP2 GP_ALTSEL_FUNC(1, 4, 0) +#define ALT_CAN1TX GP_ALTSEL_FUNC(1, 3, 0) +#define ALT_CAN1RX_INTP1 GP_ALTSEL_FUNC(1, 2, 0) +#define ALT_CAN0TX GP_ALTSEL_FUNC(1, 1, 0) +#define ALT_CAN0RX_INTP0 GP_ALTSEL_FUNC(1, 0, 0) + +/* GP1 ALTSEL function 1 */ +#define ALT_TAUJ1I3_TAUJ1O3 GP_ALTSEL_FUNC(1, 21, 1) +#define ALT_TAUJ1I2_TAUJ1O2 GP_ALTSEL_FUNC(1, 20, 1) +#define ALT_TAUJ1I1_TAUJ1O1 GP_ALTSEL_FUNC(1, 19, 1) +#define ALT_TAUJ1I0_TAUJ1O0 GP_ALTSEL_FUNC(1, 18, 1) +#define ALT_TAUJ3I3_TAUJ3O3 GP_ALTSEL_FUNC(1, 17, 1) +#define ALT_TAUJ3I2_TAUJ3O2 GP_ALTSEL_FUNC(1, 16, 1) +#define ALT_TAUJ3I1_TAUJ3O1 GP_ALTSEL_FUNC(1, 15, 1) +#define ALT_TAUJ3I0_TAUJ3O0 GP_ALTSEL_FUNC(1, 14, 1) +#define ALT_RLIN314TX_A GP_ALTSEL_FUNC(1, 13, 1) +#define ALT_RLIN314RX_INTP30_A GP_ALTSEL_FUNC(1, 12, 1) +#define ALT_RLIN313TX_A GP_ALTSEL_FUNC(1, 11, 1) +#define ALT_RLIN313RX_INTP29_A GP_ALTSEL_FUNC(1, 10, 1) +#define ALT_RLIN312TX_A GP_ALTSEL_FUNC(1, 9, 1) +#define ALT_RLIN312RX_INTP28_A GP_ALTSEL_FUNC(1, 8, 1) +#define ALT_RLIN37TX_A GP_ALTSEL_FUNC(1, 7, 1) +#define ALT_RLIN37RX_INTP23_A GP_ALTSEL_FUNC(1, 6, 1) +#define ALT_RLIN36TX_A GP_ALTSEL_FUNC(1, 5, 1) +#define ALT_RLIN36RX_INTP22_A GP_ALTSEL_FUNC(1, 4, 1) +#define ALT_RLIN35TX_A GP_ALTSEL_FUNC(1, 3, 1) +#define ALT_RLIN35RX_INTP21_A GP_ALTSEL_FUNC(1, 2, 1) +#define ALT_RLIN34TX_A GP_ALTSEL_FUNC(1, 1, 1) +#define ALT_RLIN34RX_INTP20_A GP_ALTSEL_FUNC(1, 0, 1) + +/* GP1 ALTSEL function 2 */ +#define ALT_CAN15TX_A GP_ALTSEL_FUNC(1, 21, 2) +#define ALT_CAN15RX_INTP15_A GP_ALTSEL_FUNC(1, 20, 2) +#define ALT_CAN14TX_A GP_ALTSEL_FUNC(1, 19, 2) +#define ALT_CAN14RX_INTP14_A GP_ALTSEL_FUNC(1, 18, 2) +#define ALT_CAN13TX_A GP_ALTSEL_FUNC(1, 17, 2) +#define ALT_CAN13RX_INTP13_A GP_ALTSEL_FUNC(1, 16, 2) +#define ALT_CAN12TX_A GP_ALTSEL_FUNC(1, 15, 2) +#define ALT_CAN12RX_INTP12_A GP_ALTSEL_FUNC(1, 14, 2) +#define ALT_TAUD1O9 GP_ALTSEL_FUNC(1, 13, 2) +#define ALT_TAUD1O8 GP_ALTSEL_FUNC(1, 12, 2) +#define ALT_MSIOF3_SS2 GP_ALTSEL_FUNC(1, 11, 2) +#define ALT_MSIOF3_SS1 GP_ALTSEL_FUNC(1, 10, 2) +#define ALT_MSIOF3_SYNC GP_ALTSEL_FUNC(1, 9, 2) +#define ALT_MSIOF3_RXD GP_ALTSEL_FUNC(1, 8, 2) +#define ALT_MSIOF3_TXD GP_ALTSEL_FUNC(1, 7, 2) +#define ALT_MSIOF3_SCK GP_ALTSEL_FUNC(1, 6, 2) +#define ALT_MSIOF2_SS2 GP_ALTSEL_FUNC(1, 5, 2) +#define ALT_MSIOF2_SS1 GP_ALTSEL_FUNC(1, 4, 2) +#define ALT_MSIOF2_SYNC GP_ALTSEL_FUNC(1, 3, 2) +#define ALT_MSIOF2_RXD GP_ALTSEL_FUNC(1, 2, 2) +#define ALT_MSIOF2_TXD GP_ALTSEL_FUNC(1, 1, 2) +#define ALT_MSIOF2_SCK GP_ALTSEL_FUNC(1, 0, 2) + +/* GP1 ALTSEL function 3 */ +#define ALT_NMI1_A GP_ALTSEL_FUNC(1, 19, 3) +#define ALT_INTP34_A GP_ALTSEL_FUNC(1, 18, 3) +#define ALT_INTP33_A GP_ALTSEL_FUNC(1, 17, 3) +#define ALT_INTP32_A GP_ALTSEL_FUNC(1, 16, 3) +#define ALT_RXDB_EXTFXR_B GP_ALTSEL_FUNC(1, 11, 3) +#define ALT_FXR_TXENB_N_B GP_ALTSEL_FUNC(1, 10, 3) +#define ALT_FXR_TXDB_B GP_ALTSEL_FUNC(1, 9, 3) +#define ALT_RXDA_EXTFXR_B GP_ALTSEL_FUNC(1, 8, 3) +#define ALT_FXR_TXENA_N_B GP_ALTSEL_FUNC(1, 7, 3) +#define ALT_FXR_TXDA_B GP_ALTSEL_FUNC(1, 6, 3) +#define ALT_CLK_EXTFXR_B GP_ALTSEL_FUNC(1, 5, 3) +#define ALT_FXR_CLKOUT2_B GP_ALTSEL_FUNC(1, 4, 3) +#define ALT_FXR_CLKOUT1_B GP_ALTSEL_FUNC(1, 3, 3) +#define ALT_STPWT_EXTFXR_B GP_ALTSEL_FUNC(1, 2, 3) + +/* GP2 ALTSEL function 0 */ +#define ALT_INTP34_B GP_ALTSEL_FUNC(2, 28, 0) +#define ALT_TAUD1O3 GP_ALTSEL_FUNC(2, 27, 0) +#define ALT_TAUD1O2 GP_ALTSEL_FUNC(2, 26, 0) +#define ALT_TAUD1O1 GP_ALTSEL_FUNC(2, 25, 0) +#define ALT_TAUD1O0 GP_ALTSEL_FUNC(2, 24, 0) +#define ALT_EXTCLK0O_B GP_ALTSEL_FUNC(2, 23, 0) +#define ALT_AVS1 GP_ALTSEL_FUNC(2, 22, 0) +#define ALT_AVS0 GP_ALTSEL_FUNC(2, 21, 0) +#define ALT_SDA0 GP_ALTSEL_FUNC(2, 20, 0) +#define ALT_SCL0 GP_ALTSEL_FUNC(2, 19, 0) +#define ALT_INTP33_B GP_ALTSEL_FUNC(2, 18, 0) +#define ALT_INTP32_B GP_ALTSEL_FUNC(2, 17, 0) +#define ALT_CAN_CLK GP_ALTSEL_FUNC(2, 16, 0) +#define ALT_CAN15TX_B GP_ALTSEL_FUNC(2, 15, 0) +#define ALT_CAN15RX_B_INTP15 GP_ALTSEL_FUNC(2, 14, 0) +#define ALT_CAN14TX_B GP_ALTSEL_FUNC(2, 13, 0) +#define ALT_CAN14RX_B_INTP14 GP_ALTSEL_FUNC(2, 12, 0) +#define ALT_CAN13TX_B GP_ALTSEL_FUNC(2, 11, 0) +#define ALT_CAN13RX_B_INTP13 GP_ALTSEL_FUNC(2, 10, 0) +#define ALT_CAN12TX_B GP_ALTSEL_FUNC(2, 9, 0) +#define ALT_CAN12RX_B_INTP12 GP_ALTSEL_FUNC(2, 8, 0) +#define ALT_RLIN37TX_B GP_ALTSEL_FUNC(2, 7, 0) +#define ALT_RLIN37RX_B_INTP23 GP_ALTSEL_FUNC(2, 6, 0) +#define ALT_RLIN36TX_B GP_ALTSEL_FUNC(2, 5, 0) +#define ALT_RLIN36RX_B_INTP22 GP_ALTSEL_FUNC(2, 4, 0) +#define ALT_RLIN35TX_B GP_ALTSEL_FUNC(2, 3, 0) +#define ALT_RLIN35RX_B_INTP21 GP_ALTSEL_FUNC(2, 2, 0) +#define ALT_RLIN34TX_B GP_ALTSEL_FUNC(2, 1, 0) +#define ALT_RLIN34RX_B_INTP20 GP_ALTSEL_FUNC(2, 0, 0) + +/* GP2 ALTSEL function 1 */ +#define ALT_TAUD0O1 GP_ALTSEL_FUNC(2, 18, 1) +#define ALT_TAUD0O0 GP_ALTSEL_FUNC(2, 17, 1) +#define ALT_RLIN315TX_B GP_ALTSEL_FUNC(2, 15, 1) +#define ALT_RLIN315RX_INTP31_B GP_ALTSEL_FUNC(2, 14, 1) +#define ALT_RLIN314TX_B GP_ALTSEL_FUNC(2, 13, 1) +#define ALT_RLIN314RX_INTP30_B GP_ALTSEL_FUNC(2, 12, 1) +#define ALT_RLIN313TX GP_ALTSEL_FUNC(2, 11, 1) +#define ALT_RLIN313RX_INTP29_B GP_ALTSEL_FUNC(2, 10, 1) +#define ALT_RLIN312TX GP_ALTSEL_FUNC(2, 9, 1) +#define ALT_RLIN312RX_INTP28_B GP_ALTSEL_FUNC(2, 8, 1) +#define ALT_RTCA0OUT_B GP_ALTSEL_FUNC(2, 7, 1) +#define ALT_MSIOF1_SS2_B GP_ALTSEL_FUNC(2, 5, 1) +#define ALT_MSIOF1_SS1_B GP_ALTSEL_FUNC(2, 4, 1) +#define ALT_MSIOF1_SYN_B GP_ALTSEL_FUNC(2, 3, 1) +#define ALT_MSIOF1_RXD_B GP_ALTSEL_FUNC(2, 2, 1) +#define ALT_MSIOF1_TXD_B GP_ALTSEL_FUNC(2, 1, 1) +#define ALT_MSIOF1_SCK_B GP_ALTSEL_FUNC(2, 0, 1) + +/* GP2 ALTSEL function 2 */ +#define ALT_TAUD1O7 GP_ALTSEL_FUNC(2, 9, 2) +#define ALT_TAUD1O6 GP_ALTSEL_FUNC(2, 8, 2) +#define ALT_TAUD1O5 GP_ALTSEL_FUNC(2, 7, 2) +#define ALT_TAUD1O4 GP_ALTSEL_FUNC(2, 6, 2) +#define ALT_TAUD0O15 GP_ALTSEL_FUNC(2, 1, 2) +#define ALT_TAUD0O14 GP_ALTSEL_FUNC(2, 0, 2) + +/* GP2 ALTSEL function 3 */ +#define ALT_CANXL1_TX GP_ALTSEL_FUNC(2, 11, 3) +#define ALT_CANXL1_RX GP_ALTSEL_FUNC(2, 10, 3) +#define ALT_CANXL0_TX GP_ALTSEL_FUNC(2, 9, 3) +#define ALT_CANXL0_RX GP_ALTSEL_FUNC(2, 8, 3) +#define ALT_CTIACK GP_ALTSEL_FUNC(2, 4, 3) +#define ALT_CTIREQ GP_ALTSEL_FUNC(2, 3, 3) + +/* GP3 ALTSEL function 0 */ +#define ALT_ERRORIN0_N GP_ALTSEL_FUNC(3, 16, 0) +#define ALT_ERROROUT_N GP_ALTSEL_FUNC(3, 15, 0) +#define ALT_QSPI1_SSL GP_ALTSEL_FUNC(3, 14, 0) +#define ALT_QSPI1_IO3 GP_ALTSEL_FUNC(3, 13, 0) +#define ALT_QSPI1_IO2 GP_ALTSEL_FUNC(3, 12, 0) +#define ALT_QSPI1_MISO_IO1 GP_ALTSEL_FUNC(3, 11, 0) +#define ALT_QSPI1_MOSI_IO0 GP_ALTSEL_FUNC(3, 10, 0) +#define ALT_QSPI1_SPCLK GP_ALTSEL_FUNC(3, 9, 0) +#define ALT_RPC_INT_N GP_ALTSEL_FUNC(3, 8, 0) +#define ALT_RPC_WP_N GP_ALTSEL_FUNC(3, 7, 0) +#define ALT_RPC_RESET_N GP_ALTSEL_FUNC(3, 6, 0) +#define ALT_QSPI0_SSL GP_ALTSEL_FUNC(3, 5, 0) +#define ALT_QSPI0_IO3 GP_ALTSEL_FUNC(3, 4, 0) +#define ALT_QSPI0_IO2 GP_ALTSEL_FUNC(3, 3, 0) +#define ALT_QSPI0_MISO_IO1 GP_ALTSEL_FUNC(3, 2, 0) +#define ALT_QSPI0_MOSI_IO0 GP_ALTSEL_FUNC(3, 1, 0) +#define ALT_QSPI0_SPCLK GP_ALTSEL_FUNC(3, 0, 0) + +/* GP4 ALTSEL function 0 */ +#define ALT_PCIE61_CLKREQ_N GP_ALTSEL_FUNC(4, 15, 0) +#define ALT_PCIE60_CLKREQ_N GP_ALTSEL_FUNC(4, 14, 0) +#define ALT_ERRORIN1_N GP_ALTSEL_FUNC(4, 13, 0) +#define ALT_SD0_CD GP_ALTSEL_FUNC(4, 12, 0) +#define ALT_SD0_WP GP_ALTSEL_FUNC(4, 11, 0) +#define ALT_MMC0_DS GP_ALTSEL_FUNC(4, 10, 0) +#define ALT_MMC0_D7 GP_ALTSEL_FUNC(4, 9, 0) +#define ALT_MMC0_D6 GP_ALTSEL_FUNC(4, 8, 0) +#define ALT_MMC0_D5 GP_ALTSEL_FUNC(4, 7, 0) +#define ALT_MMC0_D4 GP_ALTSEL_FUNC(4, 6, 0) +#define ALT_MMC0_SD_D3 GP_ALTSEL_FUNC(4, 5, 0) +#define ALT_MMC0_SD_D2 GP_ALTSEL_FUNC(4, 4, 0) +#define ALT_MMC0_SD_D1 GP_ALTSEL_FUNC(4, 3, 0) +#define ALT_MMC0_SD_D0 GP_ALTSEL_FUNC(4, 2, 0) +#define ALT_MMC0_SD_CMD GP_ALTSEL_FUNC(4, 1, 0) +#define ALT_MMC0_SD_CLK GP_ALTSEL_FUNC(4, 0, 0) + +/* GP5 ALTSEL function 0 */ +#define ALT_TPU0TO3 GP_ALTSEL_FUNC(5, 22, 0) +#define ALT_TPU0TO2 GP_ALTSEL_FUNC(5, 21, 0) +#define ALT_TPU0TO1 GP_ALTSEL_FUNC(5, 20, 0) +#define ALT_TPU0TO0 GP_ALTSEL_FUNC(5, 19, 0) +#define ALT_TCLK4 GP_ALTSEL_FUNC(5, 18, 0) +#define ALT_TCLK3 GP_ALTSEL_FUNC(5, 17, 0) +#define ALT_TCLK2 GP_ALTSEL_FUNC(5, 16, 0) +#define ALT_TCLK1 GP_ALTSEL_FUNC(5, 15, 0) +#define ALT_IRQ3_A GP_ALTSEL_FUNC(5, 14, 0) +#define ALT_IRQ2_A GP_ALTSEL_FUNC(5, 13, 0) +#define ALT_IRQ1_A GP_ALTSEL_FUNC(5, 12, 0) +#define ALT_IRQ0_A GP_ALTSEL_FUNC(5, 11, 0) +#define ALT_HSCK1 GP_ALTSEL_FUNC(5, 10, 0) +#define ALT_HCTS1_N GP_ALTSEL_FUNC(5, 9, 0) +#define ALT_HRTS1_N GP_ALTSEL_FUNC(5, 8, 0) +#define ALT_HRX1 GP_ALTSEL_FUNC(5, 7, 0) +#define ALT_HTX1 GP_ALTSEL_FUNC(5, 6, 0) +#define ALT_SCIF_CLK GP_ALTSEL_FUNC(5, 5, 0) +#define ALT_HSCK0 GP_ALTSEL_FUNC(5, 4, 0) +#define ALT_HCTS0_N GP_ALTSEL_FUNC(5, 3, 0) +#define ALT_HRTS0_N GP_ALTSEL_FUNC(5, 2, 0) +#define ALT_HRX0 GP_ALTSEL_FUNC(5, 1, 0) +#define ALT_HTX0 GP_ALTSEL_FUNC(5, 0, 0) + +/* GP5 ALTSEL function 1 */ +#define ALT_SSI9_WS GP_ALTSEL_FUNC(5, 22, 1) +#define ALT_SSI9_SCK GP_ALTSEL_FUNC(5, 21, 1) +#define ALT_PWM5 GP_ALTSEL_FUNC(5, 20, 1) +#define ALT_PWM4 GP_ALTSEL_FUNC(5, 19, 1) +#define ALT_PWM3 GP_ALTSEL_FUNC(5, 18, 1) +#define ALT_PWM2 GP_ALTSEL_FUNC(5, 17, 1) +#define ALT_PWM1 GP_ALTSEL_FUNC(5, 16, 1) +#define ALT_PWM0_A GP_ALTSEL_FUNC(5, 15, 1) +#define ALT_SSI17_SD GP_ALTSEL_FUNC(5, 13, 1) +#define ALT_SSI17_WS GP_ALTSEL_FUNC(5, 12, 1) +#define ALT_SSI17_SCK GP_ALTSEL_FUNC(5, 11, 1) +#define ALT_SCK1 GP_ALTSEL_FUNC(5, 10, 1) +#define ALT_CTS1_N GP_ALTSEL_FUNC(5, 9, 1) +#define ALT_RTS1_N GP_ALTSEL_FUNC(5, 8, 1) +#define ALT_RX1 GP_ALTSEL_FUNC(5, 7, 1) +#define ALT_TX1 GP_ALTSEL_FUNC(5, 6, 1) +#define ALT_SCK0 GP_ALTSEL_FUNC(5, 4, 1) +#define ALT_CTS0_N GP_ALTSEL_FUNC(5, 3, 1) +#define ALT_RTS0_N GP_ALTSEL_FUNC(5, 2, 1) +#define ALT_RX0 GP_ALTSEL_FUNC(5, 1, 1) +#define ALT_TX0 GP_ALTSEL_FUNC(5, 0, 1) + +/* GP5 ALTSEL function 2 */ +#define ALT_SSI19_SD GP_ALTSEL_FUNC(5, 18, 2) +#define ALT_SSI19_WS GP_ALTSEL_FUNC(5, 17, 2) +#define ALT_SSI19_SCK GP_ALTSEL_FUNC(5, 16, 2) +#define ALT_SSI18_SD GP_ALTSEL_FUNC(5, 15, 2) +#define ALT_SSI13_SCK GP_ALTSEL_FUNC(5, 10, 2) +#define ALT_RIF0_SYNC_B GP_ALTSEL_FUNC(5, 8, 2) +#define ALT_IRQ1_B GP_ALTSEL_FUNC(5, 3, 2) +#define ALT_IRQ0_B GP_ALTSEL_FUNC(5, 2, 2) +#define ALT_SSI13_SD GP_ALTSEL_FUNC(5, 1, 2) +#define ALT_SSI13_WS GP_ALTSEL_FUNC(5, 0, 2) + +/* GP5 ALTSEL function 3*/ +#define ALT_RIF7_D1 GP_ALTSEL_FUNC(5, 14, 3) +#define ALT_RIF7_D0 GP_ALTSEL_FUNC(5, 13, 3) +#define ALT_RIF7_SYNC GP_ALTSEL_FUNC(5, 12, 3) +#define ALT_RIF7_CLK GP_ALTSEL_FUNC(5, 11, 3) +#define ALT_RIF0_CLK_B GP_ALTSEL_FUNC(5, 10, 3) +#define ALT_SSI16_SD GP_ALTSEL_FUNC(5, 8, 3) +#define ALT_SSI16_WS GP_ALTSEL_FUNC(5, 7, 3) +#define ALT_SSI16_SCK GP_ALTSEL_FUNC(5, 6, 3) +#define ALT_SSI15_SD GP_ALTSEL_FUNC(5, 4, 3) +#define ALT_SSI15_WS GP_ALTSEL_FUNC(5, 3, 3) +#define ALT_SSI15_SCK GP_ALTSEL_FUNC(5, 2, 3) +#define ALT_RIF0_D1_B GP_ALTSEL_FUNC(5, 1, 3) +#define ALT_RIF0_D0_B GP_ALTSEL_FUNC(5, 0, 3) + +/* GP6 ALTSEL function 0 */ +#define ALT_AUDIO1_CLKOUT1 GP_ALTSEL_FUNC(6, 30, 0) +#define ALT_AUDIO1_CLKOUT0 GP_ALTSEL_FUNC(6, 29, 0) +#define ALT_SSI2_SD GP_ALTSEL_FUNC(6, 28, 0) +#define ALT_SSI2_WS GP_ALTSEL_FUNC(6, 27, 0) +#define ALT_SSI2_SCK GP_ALTSEL_FUNC(6, 26, 0) +#define ALT_AUDIO0_CLKOUT3 GP_ALTSEL_FUNC(6, 25, 0) +#define ALT_AUDIO0_CLKOUT2 GP_ALTSEL_FUNC(6, 24, 0) +#define ALT_SSI1_SD GP_ALTSEL_FUNC(6, 23, 0) +#define ALT_SSI1_WS GP_ALTSEL_FUNC(6, 22, 0) +#define ALT_SSI1_SCK GP_ALTSEL_FUNC(6, 21, 0) +#define ALT_AUDIO0_CLKOUT1 GP_ALTSEL_FUNC(6, 20, 0) +#define ALT_AUDIO0_CLKOUT0 GP_ALTSEL_FUNC(6, 19, 0) +#define ALT_SSI0_SD GP_ALTSEL_FUNC(6, 18, 0) +#define ALT_SSI0_WS GP_ALTSEL_FUNC(6, 17, 0) +#define ALT_SSI0_SCK GP_ALTSEL_FUNC(6, 16, 0) +#define ALT_MSIOF4_SS2_B GP_ALTSEL_FUNC(6, 15, 0) +#define ALT_MSIOF4_SS1_B GP_ALTSEL_FUNC(6, 14, 0) +#define ALT_MSIOF4_SYNC_B GP_ALTSEL_FUNC(6, 13, 0) +#define ALT_MSIOF4_RXD_B GP_ALTSEL_FUNC(6, 12, 0) +#define ALT_MSIOF4_TXD_B GP_ALTSEL_FUNC(6, 11, 0) +#define ALT_MSIOF4_SCK_B GP_ALTSEL_FUNC(6, 10, 0) +#define ALT_MSIOF7_SS2_A GP_ALTSEL_FUNC(6, 9, 0) +#define ALT_MSIOF7_SS1_A GP_ALTSEL_FUNC(6, 8, 0) +#define ALT_MSIOF7_SYNC_A GP_ALTSEL_FUNC(6, 7, 0) +#define ALT_MSIOF7_RXD_A GP_ALTSEL_FUNC(6, 6, 0) +#define ALT_MSIOF7_TXD_A GP_ALTSEL_FUNC(6, 5, 0) +#define ALT_MSIOF7_SCK_A GP_ALTSEL_FUNC(6, 4, 0) +#define ALT_RIF6_CLK GP_ALTSEL_FUNC(6, 3, 0) +#define ALT_RIF6_SYNC GP_ALTSEL_FUNC(6, 2, 0) +#define ALT_RIF6_D1 GP_ALTSEL_FUNC(6, 1, 0) +#define ALT_RIF6_D0 GP_ALTSEL_FUNC(6, 0, 0) + +/* GP6 ALTSEL function 1 */ +#define ALT_MSIOF7_RXD_B GP_ALTSEL_FUNC(6, 30, 1) +#define ALT_MSIOF7_TXD_B GP_ALTSEL_FUNC(6, 29, 1) +#define ALT_MSIOF7_SCK_B GP_ALTSEL_FUNC(6, 28, 1) +#define ALT_MSIOF4_SS2_A GP_ALTSEL_FUNC(6, 21, 1) +#define ALT_MSIOF4_SS1_A GP_ALTSEL_FUNC(6, 20, 1) +#define ALT_MSIOF4_SYNC_A GP_ALTSEL_FUNC(6, 19, 1) +#define ALT_MSIOF4_RXD_A GP_ALTSEL_FUNC(6, 18, 1) +#define ALT_MSIOF4_TXD_A GP_ALTSEL_FUNC(6, 17, 1) +#define ALT_MSIOF4_SCK_A GP_ALTSEL_FUNC(6, 16, 1) +#define ALT_SSI14_SD GP_ALTSEL_FUNC(6, 15, 1) +#define ALT_SSI12_SD GP_ALTSEL_FUNC(6, 14, 1) +#define ALT_SSI12_WS GP_ALTSEL_FUNC(6, 13, 1) +#define ALT_SSI12_SCK GP_ALTSEL_FUNC(6, 11, 1) +#define ALT_SSI14_WS GP_ALTSEL_FUNC(6, 9, 1) +#define ALT_SSI14_SCK GP_ALTSEL_FUNC(6, 8, 1) +#define ALT_RIF1_D1_B GP_ALTSEL_FUNC(6, 7, 1) +#define ALT_RIF1_D0_B GP_ALTSEL_FUNC(6, 6, 1) +#define ALT_RIF1_SYNC_B GP_ALTSEL_FUNC(6, 5, 1) +#define ALT_RIF1_CLK_B GP_ALTSEL_FUNC(6, 4, 1) +#define ALT_SSI10_SD GP_ALTSEL_FUNC(6, 3, 1) +#define ALT_SSI10_WS GP_ALTSEL_FUNC(6, 2, 1) +#define ALT_SSI10_SCK GP_ALTSEL_FUNC(6, 1, 1) +#define ALT_SSI9_SD GP_ALTSEL_FUNC(6, 0, 1) + +/* GP6 ALTSEL function 2 */ +#define ALT_RIF5_CLK GP_ALTSEL_FUNC(6, 30, 2) +#define ALT_RIF5_SYNC GP_ALTSEL_FUNC(6, 28, 2) +#define ALT_RIF1_D1_A GP_ALTSEL_FUNC(6, 27, 2) +#define ALT_RIF1_D0_A GP_ALTSEL_FUNC(6, 26, 2) +#define ALT_RIF1_CLK_A GP_ALTSEL_FUNC(6, 25, 2) +#define ALT_RIF2_D1 GP_ALTSEL_FUNC(6, 24, 2) +#define ALT_HCTS3_N GP_ALTSEL_FUNC(6, 23, 2) +#define ALT_HRTS3_N GP_ALTSEL_FUNC(6, 22, 2) +#define ALT_HSCK3 GP_ALTSEL_FUNC(6, 21, 2) +#define ALT_RIF2_D0 GP_ALTSEL_FUNC(6, 20, 2) +#define ALT_RIF2_SYNC GP_ALTSEL_FUNC(6, 19, 2) +#define ALT_HRX3 GP_ALTSEL_FUNC(6, 18, 2) +#define ALT_HTX3 GP_ALTSEL_FUNC(6, 17, 2) +#define ALT_AUDIO_CLKC_B GP_ALTSEL_FUNC(6, 12, 2) +#define ALT_AUDIO_CLKB_B GP_ALTSEL_FUNC(6, 10, 2) +#define ALT_SSI11_SD GP_ALTSEL_FUNC(6, 7, 2) +#define ALT_SSI11_WS GP_ALTSEL_FUNC(6, 6, 2) +#define ALT_SSI11_SCK GP_ALTSEL_FUNC(6, 5, 2) +#define ALT_AUDIO_CLKA_B GP_ALTSEL_FUNC(6, 4, 2) + +/* GP6 ALTSEL function 3 */ +#define ALT_CTS3_N GP_ALTSEL_FUNC(6, 22, 3) +#define ALT_RTS3_N GP_ALTSEL_FUNC(6, 22, 3) +#define ALT_SCK3 GP_ALTSEL_FUNC(6, 21, 3) +#define ALT_RX3 GP_ALTSEL_FUNC(6, 18, 3) +#define ALT_TX3 GP_ALTSEL_FUNC(6, 17, 3) +#define ALT_RIF1_SYNC_A GP_ALTSEL_FUNC(6, 11, 3) + +/* GP7 ALTSEL function 0 */ +#define ALT_MSIOF6_SS2_B GP_ALTSEL_FUNC(7, 30, 0) +#define ALT_MSIOF6_SS1_B GP_ALTSEL_FUNC(7, 29, 0) +#define ALT_MSIOF6_SYNC_B GP_ALTSEL_FUNC(7, 28, 0) +#define ALT_MSIOF6_RXD_B GP_ALTSEL_FUNC(7, 27, 0) +#define ALT_MSIOF6_TXD_B GP_ALTSEL_FUNC(7, 26, 0) +#define ALT_MSIOF6_SCK_B GP_ALTSEL_FUNC(7, 25, 0) +#define ALT_MSIOF5_SS2 GP_ALTSEL_FUNC(7, 24, 0) +#define ALT_MSIOF5_SS1 GP_ALTSEL_FUNC(7, 23, 0) +#define ALT_MSIOF5_SYNC GP_ALTSEL_FUNC(7, 22, 0) +#define ALT_MSIOF5_RXD GP_ALTSEL_FUNC(7, 21, 0) +#define ALT_MSIOF5_TXD GP_ALTSEL_FUNC(7, 20, 0) +#define ALT_MSIOF5_SCK GP_ALTSEL_FUNC(7, 17, 0) +#define ALT_AUDIO_CLKC_A GP_ALTSEL_FUNC(7, 16, 0) +#define ALT_SSI6_SD GP_ALTSEL_FUNC(7, 15, 0) +#define ALT_SSI6_WS GP_ALTSEL_FUNC(7, 14, 0) +#define ALT_SSI6_SCK GP_ALTSEL_FUNC(7, 13, 0) +#define ALT_AUDIO_CLKB_A GP_ALTSEL_FUNC(7, 12, 0) +#define ALT_SSI5_SD GP_ALTSEL_FUNC(7, 11, 0) +#define ALT_SSI5_WS GP_ALTSEL_FUNC(7, 10, 0) +#define ALT_SSI5_SCK GP_ALTSEL_FUNC(7, 9, 0) +#define ALT_AUDIO_CLKA_A GP_ALTSEL_FUNC(7, 8, 0) +#define ALT_SSI4_SD GP_ALTSEL_FUNC(7, 7, 0) +#define ALT_SSI4_WS GP_ALTSEL_FUNC(7, 6, 0) +#define ALT_SSI4_SCK GP_ALTSEL_FUNC(7, 5, 0) +#define ALT_AUDIO1_CLKOUT3 GP_ALTSEL_FUNC(7, 4, 0) +#define ALT_AUDIO1_CLKOUT2 GP_ALTSEL_FUNC(7, 3, 0) +#define ALT_SSI3_SD GP_ALTSEL_FUNC(7, 2, 0) +#define ALT_SSI3_WS GP_ALTSEL_FUNC(7, 1, 0) +#define ALT_SSI3_SCK GP_ALTSEL_FUNC(7, 0, 0) + +/* GP7 ALTSEL function 1 */ +#define ALT_HRX2_B GP_ALTSEL_FUNC(7, 30, 1) +#define ALT_SSI7_SD GP_ALTSEL_FUNC(7, 29, 1) +#define ALT_SSI7_WS GP_ALTSEL_FUNC(7, 28, 1) +#define ALT_SSI7_SCK GP_ALTSEL_FUNC(7, 27, 1) +#define ALT_HTX2_B GP_ALTSEL_FUNC(7, 26, 1) +#define ALT_SSI8_SD GP_ALTSEL_FUNC(7, 25, 1) +#define ALT_HCTS2_N_B GP_ALTSEL_FUNC(7, 24, 1) +#define ALT_RIF0_SYNC_A GP_ALTSEL_FUNC(7, 23, 1) +#define ALT_HRTS2_N_B GP_ALTSEL_FUNC(7, 22, 1) +#define ALT_RIF0_D1_A GP_ALTSEL_FUNC(7, 21, 1) +#define ALT_HSCK2_B GP_ALTSEL_FUNC(7, 20, 1) +#define ALT_MSIOF6_SS2_A GP_ALTSEL_FUNC(7, 19, 1) +#define ALT_MSIOF6_SS1_A GP_ALTSEL_FUNC(7, 18, 1) +#define ALT_MSIOF6_RXD_A GP_ALTSEL_FUNC(7, 15, 1) +#define ALT_MSIOF6_TXD_A GP_ALTSEL_FUNC(7, 14, 1) +#define ALT_MSIOF6_SCK_A GP_ALTSEL_FUNC(7, 13, 1) +#define ALT_MSIOF6_SYNC_A GP_ALTSEL_FUNC(7, 11, 1) +#define ALT_RIF3_SYNC GP_ALTSEL_FUNC(7, 10, 1) +#define ALT_RIF3_CLK GP_ALTSEL_FUNC(7, 9, 1) +#define ALT_RIF3_D1 GP_ALTSEL_FUNC(7, 7, 1) +#define ALT_RIF3_D0 GP_ALTSEL_FUNC(7, 6, 1) +#define ALT_RIF2_CLK GP_ALTSEL_FUNC(7, 5, 1) +#define ALT_RIF0_D0_A GP_ALTSEL_FUNC(7, 4, 1) +#define ALT_RIF0_CLK_A GP_ALTSEL_FUNC(7, 3, 1) +#define ALT_MSIOF7_SS2_B GP_ALTSEL_FUNC(7, 2, 1) +#define ALT_MSIOF7_SS1_B GP_ALTSEL_FUNC(7, 1, 1) +#define ALT_MSIOF7_SYNC_B GP_ALTSEL_FUNC(7, 0, 1) + +/* GP7 ALTSEL function 2 */ +#define ALT_RX4_B GP_ALTSEL_FUNC(7, 30, 2) +#define ALT_TX4_B GP_ALTSEL_FUNC(7, 26, 2) +#define ALT_CTS4_N_B GP_ALTSEL_FUNC(7, 24, 2) +#define ALT_RTS4_N_B GP_ALTSEL_FUNC(7, 22, 2) +#define ALT_SCK4_B GP_ALTSEL_FUNC(7, 20, 2) +#define ALT_RIF4_D1 GP_ALTSEL_FUNC(7, 15, 2) +#define ALT_RIF4_D0 GP_ALTSEL_FUNC(7, 14, 2) +#define ALT_RIF4_SYNC GP_ALTSEL_FUNC(7, 13, 2) +#define ALT_RIF4_CLK GP_ALTSEL_FUNC(7, 11, 2) +#define ALT_RIF5_D1 GP_ALTSEL_FUNC(7, 1, 2) +#define ALT_RIF5_D0 GP_ALTSEL_FUNC(7, 0, 2) + +/* GP8 ALTSEL function 0 */ +#define ALT_S3DA2 GP_ALTSEL_FUNC(8, 31, 0) +#define ALT_S3CL2 GP_ALTSEL_FUNC(8, 30, 0) +#define ALT_S3DA1 GP_ALTSEL_FUNC(8, 29, 0) +#define ALT_S3CL1 GP_ALTSEL_FUNC(8, 28, 0) +#define ALT_S3DA0 GP_ALTSEL_FUNC(8, 27, 0) +#define ALT_S3CL0 GP_ALTSEL_FUNC(8, 26, 0) +#define ALT_SDA8 GP_ALTSEL_FUNC(8, 15, 0) +#define ALT_SCL8 GP_ALTSEL_FUNC(8, 14, 0) +#define ALT_SDA7 GP_ALTSEL_FUNC(8, 13, 0) +#define ALT_SCL7 GP_ALTSEL_FUNC(8, 12, 0) +#define ALT_SDA6 GP_ALTSEL_FUNC(8, 11, 0) +#define ALT_SCL6 GP_ALTSEL_FUNC(8, 10, 0) +#define ALT_SDA5 GP_ALTSEL_FUNC(8, 9, 0) +#define ALT_SCL5 GP_ALTSEL_FUNC(8, 8, 0) +#define ALT_SDA4 GP_ALTSEL_FUNC(8, 7, 0) +#define ALT_SCL4 GP_ALTSEL_FUNC(8, 6, 0) +#define ALT_SDA3 GP_ALTSEL_FUNC(8, 5, 0) +#define ALT_SCL3 GP_ALTSEL_FUNC(8, 4, 0) +#define ALT_SDA2 GP_ALTSEL_FUNC(8, 3, 0) +#define ALT_SCL2 GP_ALTSEL_FUNC(8, 2, 0) +#define ALT_SDA1 GP_ALTSEL_FUNC(8, 1, 0) +#define ALT_SCL1 GP_ALTSEL_FUNC(8, 0, 0) + +/* GP8 ALTSEL function 1 */ +#define ALT_HCTS2_N_A GP_ALTSEL_FUNC(8, 7, 1) +#define ALT_HRTS2_N_A GP_ALTSEL_FUNC(8, 6, 1) +#define ALT_HRX2_A GP_ALTSEL_FUNC(8, 5, 1) +#define ALT_HTX2_A GP_ALTSEL_FUNC(8, 4, 1) +#define ALT_HSCK2_A GP_ALTSEL_FUNC(8, 3, 1) +#define ALT_PWM0_B GP_ALTSEL_FUNC(8, 2, 1) + +/* GP8 ALTSEL function 2 */ +#define ALT_CTS4_N_A GP_ALTSEL_FUNC(8, 7, 2) +#define ALT_RTS4_N_A GP_ALTSEL_FUNC(8, 6, 2) +#define ALT_RX4_A GP_ALTSEL_FUNC(8, 5, 2) +#define ALT_TX4_A GP_ALTSEL_FUNC(8, 4, 2) +#define ALT_SCK4_A GP_ALTSEL_FUNC(8, 3, 2) + +/* GP8 ALTSEL function 3 */ +#define ALT_PWM7_B GP_ALTSEL_FUNC(8, 7, 3) +#define ALT_PWM9_B GP_ALTSEL_FUNC(8, 6, 3) +#define ALT_PWM8_B GP_ALTSEL_FUNC(8, 5, 3) +#define ALT_PWM6_B GP_ALTSEL_FUNC(8, 4, 3) + +/* GP9 ALTSEL function 0 */ +#define ALT_RSW3_MATCH GP_ALTSEL_FUNC(9, 16, 0) +#define ALT_RSW3_CAPTURE GP_ALTSEL_FUNC(9, 15, 0) +#define ALT_RSW3_PPS GP_ALTSEL_FUNC(9, 14, 0) +#define ALT_ETH10G0_PHYINT GP_ALTSEL_FUNC(9, 13, 0) +#define ALT_ETH10G0_LINK GP_ALTSEL_FUNC(9, 12, 0) +#define ALT_ETH10G0_MDC GP_ALTSEL_FUNC(9, 11, 0) +#define ALT_ETH10G0_MDIO GP_ALTSEL_FUNC(9, 10, 0) +#define ALT_ETH25G0_PHYINT GP_ALTSEL_FUNC(9, 9, 0) +#define ALT_ETH25G0_LINK GP_ALTSEL_FUNC(9, 8, 0) +#define ALT_ETH25G0_MDC GP_ALTSEL_FUNC(9, 7, 0) +#define ALT_ETH25G0_MDIO GP_ALTSEL_FUNC(9, 6, 0) +#define ALT_ETHES4_MATCH GP_ALTSEL_FUNC(9, 5, 0) +#define ALT_ETHES4_CAPTURE GP_ALTSEL_FUNC(9, 4, 0) +#define ALT_ETHES4_PPS GP_ALTSEL_FUNC(9, 3, 0) +#define ALT_ETHES0_MATCH GP_ALTSEL_FUNC(9, 2, 0) +#define ALT_ETHES0_CAPTURE GP_ALTSEL_FUNC(9, 1, 0) +#define ALT_ETHES0_PPS GP_ALTSEL_FUNC(9, 0, 0) + +/* GP9 ALTSEL function 1 */ +#define ALT_ETH10G1_PHYINT GP_ALTSEL_FUNC(9, 13, 1) +#define ALT_ETH10G1_LINK GP_ALTSEL_FUNC(9, 12, 1) +#define ALT_ETH10G1_MDC GP_ALTSEL_FUNC(9, 11, 1) +#define ALT_ETH10G1_MDIO GP_ALTSEL_FUNC(9, 10, 1) +#define ALT_ETH25G1_PHYINT GP_ALTSEL_FUNC(9, 9, 1) +#define ALT_ETH25G1_LINK GP_ALTSEL_FUNC(9, 8, 1) +#define ALT_ETH25G1_MDC GP_ALTSEL_FUNC(9, 7, 1) +#define ALT_ETH25G1_MDIO GP_ALTSEL_FUNC(9, 6, 1) +#define ALT_ETHES5_MATCH GP_ALTSEL_FUNC(9, 5, 1) +#define ALT_ETHES5_CAPTURE GP_ALTSEL_FUNC(9, 4, 1) +#define ALT_ETHES5_PPS GP_ALTSEL_FUNC(9, 3, 1) +#define ALT_ETHES1_MATCH GP_ALTSEL_FUNC(9, 2, 1) +#define ALT_ETHES1_CAPTURE GP_ALTSEL_FUNC(9, 1, 1) +#define ALT_ETHES1_PPS GP_ALTSEL_FUNC(9, 0, 1) + +/* GP9 ALTSEL function 2 */ +#define ALT_ETH25G2_PHYINT GP_ALTSEL_FUNC(9, 9, 2) +#define ALT_ETH25G2_LINK GP_ALTSEL_FUNC(9, 8, 2) +#define ALT_ETH25G2_MDC GP_ALTSEL_FUNC(9, 7, 2) +#define ALT_ETH25G2_MDIO GP_ALTSEL_FUNC(9, 6, 2) +#define ALT_ETHES6_MATCH GP_ALTSEL_FUNC(9, 5, 2) +#define ALT_ETHES6_CAPTURE GP_ALTSEL_FUNC(9, 4, 2) +#define ALT_ETHES6_PPS GP_ALTSEL_FUNC(9, 3, 2) +#define ALT_ETHES2_MATCH GP_ALTSEL_FUNC(9, 2, 2) +#define ALT_ETHES2_CAPTURE GP_ALTSEL_FUNC(9, 1, 2) +#define ALT_ETHES2_PPS GP_ALTSEL_FUNC(9, 0, 2) + +/* GP9 ALTSEL function 3 */ +#define ALT_PWM9_A GP_ALTSEL_FUNC(9, 16, 0) +#define ALT_PWM8_A GP_ALTSEL_FUNC(9, 15, 0) +#define ALT_PWM7_A GP_ALTSEL_FUNC(9, 12, 0) +#define ALT_IRQ3_B GP_ALTSEL_FUNC(9, 11, 0) +#define ALT_IRQ2_B GP_ALTSEL_FUNC(9, 10, 0) +#define ALT_PWM6_A GP_ALTSEL_FUNC(9, 8, 0) +#define ALT_ETHES7_MATCH GP_ALTSEL_FUNC(9, 5, 0) +#define ALT_ETHES7_CAPTURE GP_ALTSEL_FUNC(9, 4, 0) +#define ALT_ETHES7_PPS GP_ALTSEL_FUNC(9, 3, 0) +#define ALT_ETHES3_MATCH GP_ALTSEL_FUNC(9, 2, 0) +#define ALT_ETHES3_CAPTURE GP_ALTSEL_FUNC(9, 1, 0) +#define ALT_ETHES3_PPS GP_ALTSEL_FUNC(9, 0, 0) + +/* GP10 ALTSEL function 0 */ +#define ALT_PCIE41_CLKREQ_N GP_ALTSEL_FUNC(10, 13, 0) +#define ALT_PCIE40_CLKREQ_N GP_ALTSEL_FUNC(10, 12, 0) +#define ALT_USB3_VBUS_VALID GP_ALTSEL_FUNC(10, 11, 0) +#define ALT_USB3_OVC GP_ALTSEL_FUNC(10, 10, 0) +#define ALT_USB3_PWEN GP_ALTSEL_FUNC(10, 9, 0) +#define ALT_USB2_VBUS_VALID GP_ALTSEL_FUNC(10, 8, 0) +#define ALT_USB2_OVC GP_ALTSEL_FUNC(10, 7, 0) +#define ALT_USB2_PWEN GP_ALTSEL_FUNC(10, 6, 0) +#define ALT_USB1_VBUS_VALID GP_ALTSEL_FUNC(10, 5, 0) +#define ALT_USB1_OVC GP_ALTSEL_FUNC(10, 4, 0) +#define ALT_USB1_PWEN GP_ALTSEL_FUNC(10, 3, 0) +#define ALT_USB0_VBUS_VALID GP_ALTSEL_FUNC(10, 2, 0) +#define ALT_USB0_OVC GP_ALTSEL_FUNC(10, 1, 0) +#define ALT_USB0_PWEN GP_ALTSEL_FUNC(10, 0, 0) + +#define PINMUX_GFUNC_GPSR(grp_func, fn) \ +fn##_MARK, ALT_##fn, FN_##grp_func, 0 + +#define PINMUX_GFUNC_MSEL_GPSR(grp_func, fn, msel) \ +fn##_MARK, ALT_##fn, FN_##msel, FN_##grp_func, 0 + +#define PINMUX_GFUNC_MSELMARK_GPSR(grp_func, fn, msel) \ +msel##_MARK, ALT_##fn, FN_##msel, FN_##grp_func, 0 + +static const u16 pinmux_data[] = { + PINMUX_DATA_GP_ALL(), + + /* Group0 Functions */ + PINMUX_GFUNC_GPSR(GRP0_27_FUNC, DP2_HOTPLUG), + + PINMUX_GFUNC_GPSR(GRP0_26_FUNC, DP1_HOTPLUG), + + PINMUX_GFUNC_GPSR(GRP0_25_FUNC, DP0_HOTPLUG), + + PINMUX_GFUNC_GPSR(GRP0_24_FUNC, MSIOF1_SS2_A), + PINMUX_GFUNC_GPSR(GRP0_24_FUNC, TAUD0O13), + + PINMUX_GFUNC_GPSR(GRP0_23_FUNC, MSIOF1_SS1_A), + PINMUX_GFUNC_GPSR(GRP0_23_FUNC, TAUD0O12), + + PINMUX_GFUNC_GPSR(GRP0_22_FUNC, MSIOF1_SYNC_A), + PINMUX_GFUNC_GPSR(GRP0_22_FUNC, TAUD0O11), + + PINMUX_GFUNC_GPSR(GRP0_21_FUNC, MSIOF1_RXD_A), + PINMUX_GFUNC_GPSR(GRP0_21_FUNC, TAUD0O10), + + PINMUX_GFUNC_GPSR(GRP0_20_FUNC, MSIOF1_TXD_A), + PINMUX_GFUNC_GPSR(GRP0_20_FUNC, TAUD0O9), + + PINMUX_GFUNC_GPSR(GRP0_19_FUNC, MSIOF1_SCK_A), + PINMUX_GFUNC_GPSR(GRP0_19_FUNC, TAUD0O8), + + PINMUX_GFUNC_GPSR(GRP0_18_FUNC, MSIOF0_SS2), + PINMUX_GFUNC_GPSR(GRP0_18_FUNC, TAUD0O7), + + PINMUX_GFUNC_GPSR(GRP0_17_FUNC, MSIOF0_SS1), + PINMUX_GFUNC_GPSR(GRP0_17_FUNC, TAUD0O6), + + PINMUX_GFUNC_GPSR(GRP0_16_FUNC, MSIOF0_SYNC), + PINMUX_GFUNC_GPSR(GRP0_16_FUNC, TAUD0O5), + + PINMUX_GFUNC_GPSR(GRP0_15_FUNC, MSIOF0_RXD), + PINMUX_GFUNC_GPSR(GRP0_15_FUNC, TAUD0O4), + + PINMUX_GFUNC_GPSR(GRP0_14_FUNC, MSIOF0_TXD), + PINMUX_GFUNC_GPSR(GRP0_14_FUNC, TAUD0O3), + + PINMUX_GFUNC_GPSR(GRP0_13_FUNC, MSIOF0_SCK), + PINMUX_GFUNC_GPSR(GRP0_13_FUNC, TAUD0O2), + + PINMUX_GFUNC_GPSR(GRP0_12_FUNC, RXDB_EXTFXR_A), + PINMUX_GFUNC_GPSR(GRP0_12_FUNC, CAN11TX), + PINMUX_GFUNC_GPSR(GRP0_12_FUNC, RLIN311TX), + PINMUX_GFUNC_GPSR(GRP0_12_FUNC, RTCA0OUT_A), + + PINMUX_GFUNC_GPSR(GRP0_11_FUNC, FXR_TXENB_N_A), + PINMUX_GFUNC_GPSR(GRP0_11_FUNC, CAN11RX_INTP11), + PINMUX_GFUNC_GPSR(GRP0_11_FUNC, RLIN311RX_INTP27), + PINMUX_GFUNC_GPSR(GRP0_11_FUNC, EXTCLK0O_A), + + PINMUX_GFUNC_GPSR(GRP0_10_FUNC, FXR_TXDB_A), + PINMUX_GFUNC_GPSR(GRP0_10_FUNC, CAN10TX), + PINMUX_GFUNC_GPSR(GRP0_10_FUNC, RLIN310TX), + + PINMUX_GFUNC_GPSR(GRP0_9_FUNC, RXDA_EXTFXR_A), + PINMUX_GFUNC_GPSR(GRP0_9_FUNC, CAN10RX_INTP10), + PINMUX_GFUNC_GPSR(GRP0_9_FUNC, RLIN310RX_INTP26), + + PINMUX_GFUNC_GPSR(GRP0_8_FUNC, FXR_TXENA_N_A), + PINMUX_GFUNC_GPSR(GRP0_8_FUNC, CAN9TX), + PINMUX_GFUNC_GPSR(GRP0_8_FUNC, RLIN39TX), + PINMUX_GFUNC_GPSR(GRP0_8_FUNC, TAUD1O15), + + PINMUX_GFUNC_GPSR(GRP0_7_FUNC, FXR_TXDA_A), + PINMUX_GFUNC_GPSR(GRP0_7_FUNC, CAN9RX_INTP9), + PINMUX_GFUNC_GPSR(GRP0_7_FUNC, RLIN39RX_INTP25), + PINMUX_GFUNC_GPSR(GRP0_7_FUNC, TAUD1O14), + + PINMUX_GFUNC_GPSR(GRP0_6_FUNC, CLK_EXTFXR_A), + PINMUX_GFUNC_GPSR(GRP0_6_FUNC, CAN8TX), + PINMUX_GFUNC_GPSR(GRP0_6_FUNC, RLIN38TX), + PINMUX_GFUNC_GPSR(GRP0_6_FUNC, TAUD1O13), + + PINMUX_GFUNC_GPSR(GRP0_5_FUNC, FXR_CLKOUT2_A), + PINMUX_GFUNC_GPSR(GRP0_5_FUNC, CAN8RX_INTP8), + PINMUX_GFUNC_GPSR(GRP0_5_FUNC, RLIN38RX_INTP24), + PINMUX_GFUNC_GPSR(GRP0_5_FUNC, TAUD1O12), + + PINMUX_GFUNC_GPSR(GRP0_4_FUNC, FXR_CLKOUT1_A), + PINMUX_GFUNC_GPSR(GRP0_4_FUNC, CAN7TX), + PINMUX_GFUNC_GPSR(GRP0_4_FUNC, RLIN315TX_A), + PINMUX_GFUNC_GPSR(GRP0_4_FUNC, TAUD1O11), + + PINMUX_GFUNC_GPSR(GRP0_3_FUNC, STPWT_EXTFXR_A), + PINMUX_GFUNC_GPSR(GRP0_3_FUNC, CAN7RX_INTP7), + PINMUX_GFUNC_GPSR(GRP0_3_FUNC, RLIN315RX_INTP31_A), + PINMUX_GFUNC_GPSR(GRP0_3_FUNC, TAUD1O10), + + /* Group1 Functions */ + PINMUX_GFUNC_GPSR(GRP1_21_FUNC, RLIN33TX), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_21_FUNC, TAUJ1I3_TAUJ1O3, SEL_TAUJ13_OUTPUT), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_21_FUNC, TAUJ1I3_TAUJ1O3, SEL_TAUJ13_INPUT), + PINMUX_GFUNC_GPSR(GRP1_21_FUNC, CAN15TX_A), + + PINMUX_GFUNC_GPSR(GRP1_20_FUNC, RLIN33RX_INTP19), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_20_FUNC, TAUJ1I2_TAUJ1O2, SEL_TAUJ12_OUTPUT), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_20_FUNC, TAUJ1I2_TAUJ1O2, SEL_TAUJ12_INPUT), + PINMUX_GFUNC_GPSR(GRP1_20_FUNC, CAN15RX_INTP15_A), + + PINMUX_GFUNC_GPSR(GRP1_19_FUNC, RLIN32TX), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_19_FUNC, TAUJ1I1_TAUJ1O1, SEL_TAUJ11_OUTPUT), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_19_FUNC, TAUJ1I1_TAUJ1O1, SEL_TAUJ11_INPUT), + PINMUX_GFUNC_GPSR(GRP1_19_FUNC, CAN14TX_A), + PINMUX_GFUNC_GPSR(GRP1_19_FUNC, NMI1_A), + + PINMUX_GFUNC_GPSR(GRP1_18_FUNC, RLIN32RX_INTP18), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_18_FUNC, TAUJ1I0_TAUJ1O0, SEL_TAUJ10_OUTPUT), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_18_FUNC, TAUJ1I0_TAUJ1O0, SEL_TAUJ10_INPUT), + PINMUX_GFUNC_GPSR(GRP1_18_FUNC, CAN14RX_INTP14_A), + PINMUX_GFUNC_GPSR(GRP1_18_FUNC, INTP34_A), + + PINMUX_GFUNC_GPSR(GRP1_17_FUNC, RLIN31TX), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_17_FUNC, TAUJ3I3_TAUJ3O3, SEL_TAUJ33_OUTPUT), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_17_FUNC, TAUJ3I3_TAUJ3O3, SEL_TAUJ33_INPUT), + PINMUX_GFUNC_GPSR(GRP1_17_FUNC, CAN13TX_A), + PINMUX_GFUNC_GPSR(GRP1_17_FUNC, INTP33_A), + + PINMUX_GFUNC_GPSR(GRP1_16_FUNC, RLIN31RX_INTP17), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_16_FUNC, TAUJ3I2_TAUJ3O2, SEL_TAUJ32_OUTPUT), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_16_FUNC, TAUJ3I2_TAUJ3O2, SEL_TAUJ32_INPUT), + PINMUX_GFUNC_GPSR(GRP1_16_FUNC, CAN13RX_INTP13_A), + PINMUX_GFUNC_GPSR(GRP1_16_FUNC, INTP32_A), + + PINMUX_GFUNC_GPSR(GRP1_15_FUNC, RLIN30TX), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_15_FUNC, TAUJ3I1_TAUJ3O1, SEL_TAUJ31_OUTPUT), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_15_FUNC, TAUJ3I1_TAUJ3O1, SEL_TAUJ31_INPUT), + PINMUX_GFUNC_GPSR(GRP1_15_FUNC, CAN12TX_A), + + PINMUX_GFUNC_GPSR(GRP1_14_FUNC, RLIN30RX_INTP16), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_14_FUNC, TAUJ3I0_TAUJ3O0, SEL_TAUJ30_OUTPUT), + PINMUX_GFUNC_MSELMARK_GPSR(GRP1_14_FUNC, TAUJ3I0_TAUJ3O0, SEL_TAUJ30_INPUT), + PINMUX_GFUNC_GPSR(GRP1_14_FUNC, CAN12RX_INTP12_A), + + PINMUX_GFUNC_GPSR(GRP1_13_FUNC, CAN6TX), + PINMUX_GFUNC_GPSR(GRP1_13_FUNC, RLIN314TX_A), + PINMUX_GFUNC_GPSR(GRP1_13_FUNC, TAUD1O9), + + PINMUX_GFUNC_GPSR(GRP1_12_FUNC, CAN6RX_INTP6), + PINMUX_GFUNC_GPSR(GRP1_12_FUNC, RLIN314RX_INTP30_A), + PINMUX_GFUNC_GPSR(GRP1_12_FUNC, TAUD1O8), + + PINMUX_GFUNC_GPSR(GRP1_11_FUNC, CAN5TX), + PINMUX_GFUNC_GPSR(GRP1_11_FUNC, RLIN313TX_A), + PINMUX_GFUNC_GPSR(GRP1_11_FUNC, MSIOF3_SS2), + PINMUX_GFUNC_GPSR(GRP1_11_FUNC, RXDB_EXTFXR_B), + + PINMUX_GFUNC_GPSR(GRP1_10_FUNC, CAN5RX_INTP5), + PINMUX_GFUNC_GPSR(GRP1_10_FUNC, RLIN313RX_INTP29_A), + PINMUX_GFUNC_GPSR(GRP1_10_FUNC, MSIOF3_SS1), + PINMUX_GFUNC_GPSR(GRP1_10_FUNC, FXR_TXENB_N_B), + + PINMUX_GFUNC_GPSR(GRP1_9_FUNC, CAN4TX), + PINMUX_GFUNC_GPSR(GRP1_9_FUNC, RLIN312TX_A), + PINMUX_GFUNC_GPSR(GRP1_9_FUNC, MSIOF3_SYNC), + PINMUX_GFUNC_GPSR(GRP1_9_FUNC, FXR_TXDB_B), + + PINMUX_GFUNC_GPSR(GRP1_8_FUNC, CAN4RX_INTP4), + PINMUX_GFUNC_GPSR(GRP1_8_FUNC, RLIN312RX_INTP28_A), + PINMUX_GFUNC_GPSR(GRP1_8_FUNC, MSIOF3_RXD), + PINMUX_GFUNC_GPSR(GRP1_8_FUNC, RXDA_EXTFXR_B), + + PINMUX_GFUNC_GPSR(GRP1_7_FUNC, CAN3TX), + PINMUX_GFUNC_GPSR(GRP1_7_FUNC, RLIN37TX_A), + PINMUX_GFUNC_GPSR(GRP1_7_FUNC, MSIOF3_TXD), + PINMUX_GFUNC_GPSR(GRP1_7_FUNC, FXR_TXENA_N_B), + + PINMUX_GFUNC_GPSR(GRP1_6_FUNC, CAN3RX_INTP3), + PINMUX_GFUNC_GPSR(GRP1_6_FUNC, RLIN37RX_INTP23_A), + PINMUX_GFUNC_GPSR(GRP1_6_FUNC, MSIOF3_SCK), + PINMUX_GFUNC_GPSR(GRP1_6_FUNC, FXR_TXDA_B), + + PINMUX_GFUNC_GPSR(GRP1_5_FUNC, CAN2TX), + PINMUX_GFUNC_GPSR(GRP1_5_FUNC, RLIN36TX_A), + PINMUX_GFUNC_GPSR(GRP1_5_FUNC, MSIOF2_SS2), + PINMUX_GFUNC_GPSR(GRP1_5_FUNC, CLK_EXTFXR_B), + + PINMUX_GFUNC_GPSR(GRP1_4_FUNC, CAN2RX_INTP2), + PINMUX_GFUNC_GPSR(GRP1_4_FUNC, RLIN36RX_INTP22_A), + PINMUX_GFUNC_GPSR(GRP1_4_FUNC, MSIOF2_SS1), + PINMUX_GFUNC_GPSR(GRP1_4_FUNC, FXR_CLKOUT2_B), + + PINMUX_GFUNC_GPSR(GRP1_3_FUNC, CAN1TX), + PINMUX_GFUNC_GPSR(GRP1_3_FUNC, RLIN35TX_A), + PINMUX_GFUNC_GPSR(GRP1_3_FUNC, MSIOF2_SYNC), + PINMUX_GFUNC_GPSR(GRP1_3_FUNC, FXR_CLKOUT1_B), + + PINMUX_GFUNC_GPSR(GRP1_2_FUNC, CAN1RX_INTP1), + PINMUX_GFUNC_GPSR(GRP1_2_FUNC, RLIN35RX_INTP21_A), + PINMUX_GFUNC_GPSR(GRP1_2_FUNC, MSIOF2_RXD), + PINMUX_GFUNC_GPSR(GRP1_2_FUNC, STPWT_EXTFXR_B), + + PINMUX_GFUNC_GPSR(GRP1_1_FUNC, CAN0TX), + PINMUX_GFUNC_GPSR(GRP1_1_FUNC, RLIN34TX_A), + PINMUX_GFUNC_GPSR(GRP1_1_FUNC, MSIOF2_TXD), + + PINMUX_GFUNC_GPSR(GRP1_0_FUNC, CAN0RX_INTP0), + PINMUX_GFUNC_GPSR(GRP1_0_FUNC, RLIN34RX_INTP20_A), + PINMUX_GFUNC_GPSR(GRP1_0_FUNC, MSIOF2_SCK), + + /* Group2 Functions */ + PINMUX_GFUNC_GPSR(GRP2_28_FUNC, INTP34_B), + + PINMUX_GFUNC_GPSR(GRP2_27_FUNC, TAUD1O3), + + PINMUX_GFUNC_GPSR(GRP2_26_FUNC, TAUD1O2), + + PINMUX_GFUNC_GPSR(GRP2_25_FUNC, TAUD1O1), + + PINMUX_GFUNC_GPSR(GRP2_24_FUNC, TAUD1O0), + + PINMUX_GFUNC_GPSR(GRP2_23_FUNC, EXTCLK0O_B), + + PINMUX_GFUNC_GPSR(GRP2_22_FUNC, AVS1), + + PINMUX_GFUNC_GPSR(GRP2_21_FUNC, AVS0), + + PINMUX_GFUNC_MSEL_GPSR(GRP2_20_FUNC, SDA0, SEL_SDA0_1), + + PINMUX_GFUNC_MSEL_GPSR(GRP2_19_FUNC, SCL0, SEL_SCL0_1), + + PINMUX_GFUNC_GPSR(GRP2_18_FUNC, INTP33_B), + PINMUX_GFUNC_GPSR(GRP2_18_FUNC, TAUD0O1), + + PINMUX_GFUNC_GPSR(GRP2_17_FUNC, INTP32_B), + PINMUX_GFUNC_GPSR(GRP2_17_FUNC, TAUD0O0), + + PINMUX_GFUNC_GPSR(GRP2_16_FUNC, CAN_CLK), + + PINMUX_GFUNC_GPSR(GRP2_15_FUNC, CAN15TX_B), + PINMUX_GFUNC_GPSR(GRP2_15_FUNC, RLIN315TX_B), + + PINMUX_GFUNC_GPSR(GRP2_14_FUNC, CAN15RX_B_INTP15), + PINMUX_GFUNC_GPSR(GRP2_14_FUNC, RLIN315RX_INTP31_B), + + PINMUX_GFUNC_GPSR(GRP2_13_FUNC, CAN14TX_B), + PINMUX_GFUNC_GPSR(GRP2_13_FUNC, RLIN314TX_B), + + PINMUX_GFUNC_GPSR(GRP2_12_FUNC, CAN14RX_B_INTP14), + PINMUX_GFUNC_GPSR(GRP2_12_FUNC, RLIN314RX_INTP30_B), + + PINMUX_GFUNC_GPSR(GRP2_11_FUNC, CAN13TX_B), + PINMUX_GFUNC_GPSR(GRP2_11_FUNC, RLIN313TX), + PINMUX_GFUNC_GPSR(GRP2_11_FUNC, CANXL1_TX), + + PINMUX_GFUNC_GPSR(GRP2_10_FUNC, CAN13RX_B_INTP13), + PINMUX_GFUNC_GPSR(GRP2_10_FUNC, RLIN313RX_INTP29_B), + PINMUX_GFUNC_GPSR(GRP2_10_FUNC, CANXL1_RX), + + PINMUX_GFUNC_GPSR(GRP2_9_FUNC, CAN12TX_B), + PINMUX_GFUNC_GPSR(GRP2_9_FUNC, RLIN312TX), + PINMUX_GFUNC_GPSR(GRP2_9_FUNC, TAUD1O7), + PINMUX_GFUNC_GPSR(GRP2_9_FUNC, CANXL0_TX), + + PINMUX_GFUNC_GPSR(GRP2_8_FUNC, CAN12RX_B_INTP12), + PINMUX_GFUNC_GPSR(GRP2_8_FUNC, RLIN312RX_INTP28_B), + PINMUX_GFUNC_GPSR(GRP2_8_FUNC, TAUD1O6), + PINMUX_GFUNC_GPSR(GRP2_8_FUNC, CANXL0_RX), + + PINMUX_GFUNC_GPSR(GRP2_7_FUNC, RLIN37TX_B), + PINMUX_GFUNC_GPSR(GRP2_7_FUNC, RTCA0OUT_B), + PINMUX_GFUNC_GPSR(GRP2_7_FUNC, TAUD1O5), + + PINMUX_GFUNC_GPSR(GRP2_6_FUNC, RLIN37RX_B_INTP23), + PINMUX_GFUNC_GPSR(GRP2_6_FUNC, TAUD1O4), + + PINMUX_GFUNC_GPSR(GRP2_5_FUNC, RLIN36TX_B), + PINMUX_GFUNC_GPSR(GRP2_5_FUNC, MSIOF1_SS2_B), + + PINMUX_GFUNC_GPSR(GRP2_4_FUNC, RLIN36RX_B_INTP22), + PINMUX_GFUNC_GPSR(GRP2_4_FUNC, MSIOF1_SS1_B), + PINMUX_GFUNC_GPSR(GRP2_4_FUNC, CTIACK), + + PINMUX_GFUNC_GPSR(GRP2_3_FUNC, RLIN35TX_B), + PINMUX_GFUNC_GPSR(GRP2_3_FUNC, MSIOF1_SYN_B), + PINMUX_GFUNC_GPSR(GRP2_3_FUNC, CTIREQ), + + PINMUX_GFUNC_GPSR(GRP2_2_FUNC, RLIN35RX_B_INTP21), + PINMUX_GFUNC_GPSR(GRP2_2_FUNC, MSIOF1_RXD_B), + + PINMUX_GFUNC_GPSR(GRP2_1_FUNC, RLIN34TX_B), + PINMUX_GFUNC_GPSR(GRP2_1_FUNC, MSIOF1_TXD_B), + PINMUX_GFUNC_GPSR(GRP2_1_FUNC, TAUD0O15), + + PINMUX_GFUNC_GPSR(GRP2_0_FUNC, RLIN34RX_B_INTP20), + PINMUX_GFUNC_GPSR(GRP2_0_FUNC, MSIOF1_SCK_B), + PINMUX_GFUNC_GPSR(GRP2_0_FUNC, TAUD0O14), + + /* Group3 Functions */ + PINMUX_GFUNC_GPSR(GRP3_16_FUNC, ERRORIN0_N), + + PINMUX_GFUNC_GPSR(GRP3_15_FUNC, ERROROUT_N), + + PINMUX_GFUNC_GPSR(GRP3_14_FUNC, QSPI1_SSL), + + PINMUX_GFUNC_GPSR(GRP3_13_FUNC, QSPI1_IO3), + + PINMUX_GFUNC_GPSR(GRP3_12_FUNC, QSPI1_IO2), + + PINMUX_GFUNC_GPSR(GRP3_11_FUNC, QSPI1_MISO_IO1), + + PINMUX_GFUNC_GPSR(GRP3_10_FUNC, QSPI1_MOSI_IO0), + + PINMUX_GFUNC_GPSR(GRP3_9_FUNC, QSPI1_SPCLK), + + PINMUX_GFUNC_GPSR(GRP3_8_FUNC, RPC_INT_N), + + PINMUX_GFUNC_GPSR(GRP3_7_FUNC, RPC_WP_N), + + PINMUX_GFUNC_GPSR(GRP3_6_FUNC, RPC_RESET_N), + + PINMUX_GFUNC_GPSR(GRP3_5_FUNC, QSPI0_SSL), + + PINMUX_GFUNC_GPSR(GRP3_4_FUNC, QSPI0_IO3), + + PINMUX_GFUNC_GPSR(GRP3_3_FUNC, QSPI0_IO2), + + PINMUX_GFUNC_GPSR(GRP3_2_FUNC, QSPI0_MISO_IO1), + + PINMUX_GFUNC_GPSR(GRP3_1_FUNC, QSPI0_MOSI_IO0), + + PINMUX_GFUNC_GPSR(GRP3_0_FUNC, QSPI0_SPCLK), + + /* Group4 Functions */ + PINMUX_GFUNC_GPSR(GRP4_15_FUNC, PCIE61_CLKREQ_N), + + PINMUX_GFUNC_GPSR(GRP4_14_FUNC, PCIE60_CLKREQ_N), + + PINMUX_GFUNC_GPSR(GRP4_13_FUNC, ERRORIN1_N), + + PINMUX_GFUNC_GPSR(GRP4_12_FUNC, SD0_CD), + + PINMUX_GFUNC_GPSR(GRP4_11_FUNC, SD0_WP), + + PINMUX_GFUNC_GPSR(GRP4_10_FUNC, MMC0_DS), + + PINMUX_GFUNC_GPSR(GRP4_9_FUNC, MMC0_D7), + + PINMUX_GFUNC_GPSR(GRP4_8_FUNC, MMC0_D6), + + PINMUX_GFUNC_GPSR(GRP4_7_FUNC, MMC0_D5), + + PINMUX_GFUNC_GPSR(GRP4_6_FUNC, MMC0_D4), + + PINMUX_GFUNC_GPSR(GRP4_5_FUNC, MMC0_SD_D3), + + PINMUX_GFUNC_GPSR(GRP4_4_FUNC, MMC0_SD_D2), + + PINMUX_GFUNC_GPSR(GRP4_3_FUNC, MMC0_SD_D1), + + PINMUX_GFUNC_GPSR(GRP4_2_FUNC, MMC0_SD_D0), + + PINMUX_GFUNC_GPSR(GRP4_1_FUNC, MMC0_SD_CMD), + + PINMUX_GFUNC_GPSR(GRP4_0_FUNC, MMC0_SD_CLK), + + /* Group5 Functions */ + PINMUX_GFUNC_GPSR(GRP5_22_FUNC, TPU0TO3), + PINMUX_GFUNC_GPSR(GRP5_22_FUNC, SSI9_WS), + + PINMUX_GFUNC_GPSR(GRP5_21_FUNC, TPU0TO2), + PINMUX_GFUNC_GPSR(GRP5_21_FUNC, SSI9_SCK), + + PINMUX_GFUNC_GPSR(GRP5_20_FUNC, TPU0TO1), + PINMUX_GFUNC_GPSR(GRP5_20_FUNC, PWM5), + + PINMUX_GFUNC_GPSR(GRP5_19_FUNC, TPU0TO0), + PINMUX_GFUNC_GPSR(GRP5_19_FUNC, PWM4), + + PINMUX_GFUNC_GPSR(GRP5_18_FUNC, TCLK4), + PINMUX_GFUNC_GPSR(GRP5_18_FUNC, PWM3), + PINMUX_GFUNC_GPSR(GRP5_18_FUNC, SSI19_SD), + + PINMUX_GFUNC_GPSR(GRP5_17_FUNC, TCLK3), + PINMUX_GFUNC_GPSR(GRP5_17_FUNC, PWM2), + PINMUX_GFUNC_GPSR(GRP5_17_FUNC, SSI19_WS), + + PINMUX_GFUNC_GPSR(GRP5_16_FUNC, TCLK2), + PINMUX_GFUNC_GPSR(GRP5_16_FUNC, PWM1), + PINMUX_GFUNC_GPSR(GRP5_16_FUNC, SSI19_SCK), + + PINMUX_GFUNC_GPSR(GRP5_15_FUNC, TCLK1), + PINMUX_GFUNC_GPSR(GRP5_15_FUNC, PWM0_A), + PINMUX_GFUNC_GPSR(GRP5_15_FUNC, SSI18_SD), + + PINMUX_GFUNC_GPSR(GRP5_14_FUNC, IRQ3_A), + PINMUX_GFUNC_GPSR(GRP5_14_FUNC, RIF7_D1), + + PINMUX_GFUNC_GPSR(GRP5_13_FUNC, IRQ2_A), + PINMUX_GFUNC_GPSR(GRP5_13_FUNC, SSI17_SD), + PINMUX_GFUNC_GPSR(GRP5_13_FUNC, RIF7_D0), + + PINMUX_GFUNC_GPSR(GRP5_12_FUNC, IRQ1_A), + PINMUX_GFUNC_GPSR(GRP5_12_FUNC, SSI17_WS), + PINMUX_GFUNC_GPSR(GRP5_12_FUNC, RIF7_SYNC), + + PINMUX_GFUNC_GPSR(GRP5_11_FUNC, IRQ0_A), + PINMUX_GFUNC_GPSR(GRP5_11_FUNC, SSI17_SCK), + PINMUX_GFUNC_GPSR(GRP5_11_FUNC, RIF7_CLK), + + PINMUX_GFUNC_GPSR(GRP5_10_FUNC, HSCK1), + PINMUX_GFUNC_GPSR(GRP5_10_FUNC, SCK1), + PINMUX_GFUNC_GPSR(GRP5_10_FUNC, SSI13_SCK), + PINMUX_GFUNC_GPSR(GRP5_10_FUNC, RIF0_CLK_B), + + PINMUX_GFUNC_GPSR(GRP5_9_FUNC, HCTS1_N), + PINMUX_GFUNC_GPSR(GRP5_9_FUNC, CTS1_N), + + PINMUX_GFUNC_GPSR(GRP5_8_FUNC, HRTS1_N), + PINMUX_GFUNC_GPSR(GRP5_8_FUNC, RTS1_N), + PINMUX_GFUNC_GPSR(GRP5_8_FUNC, RIF0_SYNC_B), + PINMUX_GFUNC_GPSR(GRP5_8_FUNC, SSI16_SD), + + PINMUX_GFUNC_GPSR(GRP5_7_FUNC, HRX1), + PINMUX_GFUNC_GPSR(GRP5_7_FUNC, RX1), + PINMUX_GFUNC_GPSR(GRP5_7_FUNC, SSI16_WS), + + PINMUX_GFUNC_GPSR(GRP5_6_FUNC, HTX1), + PINMUX_GFUNC_GPSR(GRP5_6_FUNC, TX1), + PINMUX_GFUNC_GPSR(GRP5_6_FUNC, SSI16_SCK), + + PINMUX_GFUNC_GPSR(GRP5_5_FUNC, SCIF_CLK), + + PINMUX_GFUNC_GPSR(GRP5_4_FUNC, HSCK0), + PINMUX_GFUNC_GPSR(GRP5_4_FUNC, SCK0), + PINMUX_GFUNC_GPSR(GRP5_4_FUNC, SSI15_SD), + + PINMUX_GFUNC_GPSR(GRP5_3_FUNC, HCTS0_N), + PINMUX_GFUNC_GPSR(GRP5_3_FUNC, CTS0_N), + PINMUX_GFUNC_GPSR(GRP5_3_FUNC, IRQ1_B), + PINMUX_GFUNC_GPSR(GRP5_3_FUNC, SSI15_WS), + + PINMUX_GFUNC_GPSR(GRP5_2_FUNC, HRTS0_N), + PINMUX_GFUNC_GPSR(GRP5_2_FUNC, RTS0_N), + PINMUX_GFUNC_GPSR(GRP5_2_FUNC, IRQ0_B), + PINMUX_GFUNC_GPSR(GRP5_2_FUNC, SSI15_SCK), + + PINMUX_GFUNC_GPSR(GRP5_1_FUNC, HRX0), + PINMUX_GFUNC_GPSR(GRP5_1_FUNC, RX0), + PINMUX_GFUNC_GPSR(GRP5_1_FUNC, SSI13_SD), + PINMUX_GFUNC_GPSR(GRP5_1_FUNC, RIF0_D1_B), + + PINMUX_GFUNC_GPSR(GRP5_0_FUNC, HTX0), + PINMUX_GFUNC_GPSR(GRP5_0_FUNC, TX0), + PINMUX_GFUNC_GPSR(GRP5_0_FUNC, SSI13_WS), + PINMUX_GFUNC_GPSR(GRP5_0_FUNC, RIF0_D0_B), + + /* Group6 Functions */ + PINMUX_GFUNC_GPSR(GRP6_30_FUNC, AUDIO1_CLKOUT1), + PINMUX_GFUNC_GPSR(GRP6_30_FUNC, MSIOF7_RXD_B), + PINMUX_GFUNC_GPSR(GRP6_30_FUNC, RIF5_CLK), + + PINMUX_GFUNC_GPSR(GRP6_29_FUNC, AUDIO1_CLKOUT0), + PINMUX_GFUNC_GPSR(GRP6_29_FUNC, MSIOF7_TXD_B), + + PINMUX_GFUNC_GPSR(GRP6_28_FUNC, SSI2_SD), + PINMUX_GFUNC_GPSR(GRP6_28_FUNC, MSIOF7_SCK_B), + PINMUX_GFUNC_GPSR(GRP6_28_FUNC, RIF5_SYNC), + + PINMUX_GFUNC_GPSR(GRP6_27_FUNC, SSI2_WS), + PINMUX_GFUNC_GPSR(GRP6_27_FUNC, RIF1_D1_A), + + PINMUX_GFUNC_GPSR(GRP6_26_FUNC, SSI2_SCK), + PINMUX_GFUNC_GPSR(GRP6_26_FUNC, RIF1_D0_A), + + PINMUX_GFUNC_GPSR(GRP6_25_FUNC, AUDIO0_CLKOUT3), + PINMUX_GFUNC_GPSR(GRP6_25_FUNC, RIF1_CLK_A), + + PINMUX_GFUNC_GPSR(GRP6_24_FUNC, AUDIO0_CLKOUT2), + PINMUX_GFUNC_GPSR(GRP6_24_FUNC, RIF2_D1), + + PINMUX_GFUNC_GPSR(GRP6_23_FUNC, SSI1_SD), + PINMUX_GFUNC_GPSR(GRP6_23_FUNC, HCTS3_N), + PINMUX_GFUNC_GPSR(GRP6_23_FUNC, CTS3_N), + + PINMUX_GFUNC_GPSR(GRP6_22_FUNC, SSI1_WS), + PINMUX_GFUNC_GPSR(GRP6_22_FUNC, HRTS3_N), + PINMUX_GFUNC_GPSR(GRP6_22_FUNC, RTS3_N), + + PINMUX_GFUNC_GPSR(GRP6_21_FUNC, SSI1_SCK), + PINMUX_GFUNC_GPSR(GRP6_21_FUNC, MSIOF4_SS2_A), + PINMUX_GFUNC_GPSR(GRP6_21_FUNC, HSCK3), + PINMUX_GFUNC_GPSR(GRP6_21_FUNC, SCK3), + + PINMUX_GFUNC_GPSR(GRP6_20_FUNC, AUDIO0_CLKOUT1), + PINMUX_GFUNC_GPSR(GRP6_20_FUNC, MSIOF4_SS1_A), + PINMUX_GFUNC_GPSR(GRP6_20_FUNC, RIF2_D0), + + PINMUX_GFUNC_GPSR(GRP6_19_FUNC, AUDIO0_CLKOUT0), + PINMUX_GFUNC_GPSR(GRP6_19_FUNC, MSIOF4_SYNC_A), + PINMUX_GFUNC_GPSR(GRP6_19_FUNC, RIF2_SYNC), + + PINMUX_GFUNC_GPSR(GRP6_18_FUNC, SSI0_SD), + PINMUX_GFUNC_GPSR(GRP6_18_FUNC, MSIOF4_RXD_A), + PINMUX_GFUNC_GPSR(GRP6_18_FUNC, HRX3), + PINMUX_GFUNC_GPSR(GRP6_18_FUNC, RX3), + + PINMUX_GFUNC_GPSR(GRP6_17_FUNC, SSI0_WS), + PINMUX_GFUNC_GPSR(GRP6_17_FUNC, MSIOF4_TXD_A), + PINMUX_GFUNC_GPSR(GRP6_17_FUNC, HTX3), + PINMUX_GFUNC_GPSR(GRP6_17_FUNC, TX3), + + PINMUX_GFUNC_GPSR(GRP6_16_FUNC, SSI0_SCK), + PINMUX_GFUNC_GPSR(GRP6_16_FUNC, MSIOF4_SCK_A), + + PINMUX_GFUNC_GPSR(GRP6_15_FUNC, MSIOF4_SS2_B), + PINMUX_GFUNC_GPSR(GRP6_15_FUNC, SSI14_SD), + + PINMUX_GFUNC_GPSR(GRP6_14_FUNC, MSIOF4_SS1_B), + PINMUX_GFUNC_GPSR(GRP6_14_FUNC, SSI12_SD), + + PINMUX_GFUNC_GPSR(GRP6_13_FUNC, MSIOF4_SYNC_B), + PINMUX_GFUNC_GPSR(GRP6_13_FUNC, SSI12_WS), + + PINMUX_GFUNC_GPSR(GRP6_12_FUNC, MSIOF4_RXD_B), + PINMUX_GFUNC_GPSR(GRP6_12_FUNC, AUDIO_CLKC_B), + + PINMUX_GFUNC_GPSR(GRP6_11_FUNC, MSIOF4_TXD_B), + PINMUX_GFUNC_GPSR(GRP6_11_FUNC, SSI12_SCK), + PINMUX_GFUNC_GPSR(GRP6_11_FUNC, RIF1_SYNC_A), + + PINMUX_GFUNC_GPSR(GRP6_10_FUNC, MSIOF4_SCK_B), + PINMUX_GFUNC_GPSR(GRP6_10_FUNC, AUDIO_CLKB_B), + + PINMUX_GFUNC_GPSR(GRP6_9_FUNC, MSIOF7_SS2_A), + PINMUX_GFUNC_GPSR(GRP6_9_FUNC, SSI14_WS), + + PINMUX_GFUNC_GPSR(GRP6_8_FUNC, MSIOF7_SS1_A), + PINMUX_GFUNC_GPSR(GRP6_8_FUNC, SSI14_SCK), + + PINMUX_GFUNC_GPSR(GRP6_7_FUNC, MSIOF7_SYNC_A), + PINMUX_GFUNC_GPSR(GRP6_7_FUNC, RIF1_D1_B), + PINMUX_GFUNC_GPSR(GRP6_7_FUNC, SSI11_SD), + + PINMUX_GFUNC_GPSR(GRP6_6_FUNC, MSIOF7_RXD_A), + PINMUX_GFUNC_GPSR(GRP6_6_FUNC, RIF1_D0_B), + PINMUX_GFUNC_GPSR(GRP6_6_FUNC, SSI11_WS), + + PINMUX_GFUNC_GPSR(GRP6_5_FUNC, MSIOF7_TXD_A), + PINMUX_GFUNC_GPSR(GRP6_5_FUNC, RIF1_SYNC_B), + PINMUX_GFUNC_GPSR(GRP6_5_FUNC, SSI11_SCK), + + PINMUX_GFUNC_GPSR(GRP6_4_FUNC, MSIOF7_SCK_A), + PINMUX_GFUNC_GPSR(GRP6_4_FUNC, RIF1_CLK_B), + PINMUX_GFUNC_GPSR(GRP6_4_FUNC, AUDIO_CLKA_B), + + PINMUX_GFUNC_GPSR(GRP6_3_FUNC, RIF6_CLK), + PINMUX_GFUNC_GPSR(GRP6_3_FUNC, SSI10_SD), + + PINMUX_GFUNC_GPSR(GRP6_2_FUNC, RIF6_SYNC), + PINMUX_GFUNC_GPSR(GRP6_2_FUNC, SSI10_WS), + + PINMUX_GFUNC_GPSR(GRP6_1_FUNC, RIF6_D1), + PINMUX_GFUNC_GPSR(GRP6_1_FUNC, SSI10_SCK), + + PINMUX_GFUNC_GPSR(GRP6_0_FUNC, RIF6_D0), + PINMUX_GFUNC_GPSR(GRP6_0_FUNC, SSI9_SD), + + /* Group7 Functions */ + PINMUX_GFUNC_GPSR(GRP7_30_FUNC, MSIOF6_SS2_B), + PINMUX_GFUNC_GPSR(GRP7_30_FUNC, HRX2_B), + PINMUX_GFUNC_GPSR(GRP7_30_FUNC, RX4_B), + + PINMUX_GFUNC_GPSR(GRP7_29_FUNC, MSIOF6_SS1_B), + PINMUX_GFUNC_GPSR(GRP7_29_FUNC, SSI7_SD), + + PINMUX_GFUNC_GPSR(GRP7_28_FUNC, MSIOF6_SYNC_B), + PINMUX_GFUNC_GPSR(GRP7_28_FUNC, SSI7_WS), + + PINMUX_GFUNC_GPSR(GRP7_27_FUNC, MSIOF6_RXD_B), + PINMUX_GFUNC_GPSR(GRP7_27_FUNC, SSI7_SCK), + + PINMUX_GFUNC_GPSR(GRP7_26_FUNC, MSIOF6_TXD_B), + PINMUX_GFUNC_GPSR(GRP7_26_FUNC, HTX2_B), + PINMUX_GFUNC_GPSR(GRP7_26_FUNC, TX4_B), + + PINMUX_GFUNC_GPSR(GRP7_25_FUNC, MSIOF6_SCK_B), + PINMUX_GFUNC_GPSR(GRP7_25_FUNC, SSI8_SD), + + PINMUX_GFUNC_GPSR(GRP7_24_FUNC, MSIOF5_SS2), + PINMUX_GFUNC_GPSR(GRP7_24_FUNC, HCTS2_N_B), + PINMUX_GFUNC_GPSR(GRP7_24_FUNC, CTS4_N_B), + + PINMUX_GFUNC_GPSR(GRP7_23_FUNC, MSIOF5_SS1), + PINMUX_GFUNC_GPSR(GRP7_23_FUNC, RIF0_SYNC_A), + + PINMUX_GFUNC_GPSR(GRP7_22_FUNC, MSIOF5_SYNC), + PINMUX_GFUNC_GPSR(GRP7_22_FUNC, HRTS2_N_B), + PINMUX_GFUNC_GPSR(GRP7_22_FUNC, RTS4_N_B), + + PINMUX_GFUNC_GPSR(GRP7_21_FUNC, MSIOF5_RXD), + PINMUX_GFUNC_GPSR(GRP7_21_FUNC, RIF0_D1_A), + + PINMUX_GFUNC_GPSR(GRP7_20_FUNC, MSIOF5_TXD), + PINMUX_GFUNC_GPSR(GRP7_20_FUNC, HSCK2_B), + PINMUX_GFUNC_GPSR(GRP7_20_FUNC, SCK4_B), + + PINMUX_GFUNC_GPSR(GRP7_19_FUNC, MSIOF6_SS2_A), + + PINMUX_GFUNC_GPSR(GRP7_18_FUNC, MSIOF6_SS1_A), + + PINMUX_GFUNC_GPSR(GRP7_17_FUNC, MSIOF5_SCK), + + PINMUX_GFUNC_GPSR(GRP7_16_FUNC, AUDIO_CLKC_A), + + PINMUX_GFUNC_GPSR(GRP7_15_FUNC, SSI6_SD), + PINMUX_GFUNC_GPSR(GRP7_15_FUNC, MSIOF6_RXD_A), + PINMUX_GFUNC_GPSR(GRP7_15_FUNC, RIF4_D1), + + PINMUX_GFUNC_GPSR(GRP7_14_FUNC, SSI6_WS), + PINMUX_GFUNC_GPSR(GRP7_14_FUNC, MSIOF6_TXD_A), + PINMUX_GFUNC_GPSR(GRP7_14_FUNC, RIF4_D0), + + PINMUX_GFUNC_GPSR(GRP7_13_FUNC, SSI6_SCK), + PINMUX_GFUNC_GPSR(GRP7_13_FUNC, MSIOF6_SCK_A), + PINMUX_GFUNC_GPSR(GRP7_13_FUNC, RIF4_SYNC), + + PINMUX_GFUNC_GPSR(GRP7_12_FUNC, AUDIO_CLKB_A), + + PINMUX_GFUNC_GPSR(GRP7_11_FUNC, SSI5_SD), + PINMUX_GFUNC_GPSR(GRP7_11_FUNC, MSIOF6_SYNC_A), + PINMUX_GFUNC_GPSR(GRP7_11_FUNC, RIF4_CLK), + + PINMUX_GFUNC_GPSR(GRP7_10_FUNC, SSI5_WS), + PINMUX_GFUNC_GPSR(GRP7_10_FUNC, RIF3_SYNC), + + PINMUX_GFUNC_GPSR(GRP7_9_FUNC, SSI5_SCK), + PINMUX_GFUNC_GPSR(GRP7_9_FUNC, RIF3_CLK), + + PINMUX_GFUNC_GPSR(GRP7_8_FUNC, AUDIO_CLKA_A), + + PINMUX_GFUNC_GPSR(GRP7_7_FUNC, SSI4_SD), + PINMUX_GFUNC_GPSR(GRP7_7_FUNC, RIF3_D1), + + PINMUX_GFUNC_GPSR(GRP7_6_FUNC, SSI4_WS), + PINMUX_GFUNC_GPSR(GRP7_6_FUNC, RIF3_D0), + + PINMUX_GFUNC_GPSR(GRP7_5_FUNC, SSI4_SCK), + PINMUX_GFUNC_GPSR(GRP7_5_FUNC, RIF2_CLK), + + PINMUX_GFUNC_GPSR(GRP7_4_FUNC, AUDIO1_CLKOUT3), + PINMUX_GFUNC_GPSR(GRP7_4_FUNC, RIF0_D0_A), + + PINMUX_GFUNC_GPSR(GRP7_3_FUNC, AUDIO1_CLKOUT2), + PINMUX_GFUNC_GPSR(GRP7_3_FUNC, RIF0_CLK_A), + + PINMUX_GFUNC_GPSR(GRP7_2_FUNC, SSI3_SD), + PINMUX_GFUNC_GPSR(GRP7_2_FUNC, MSIOF7_SS2_B), + + PINMUX_GFUNC_GPSR(GRP7_1_FUNC, SSI3_WS), + PINMUX_GFUNC_GPSR(GRP7_1_FUNC, MSIOF7_SS1_B), + PINMUX_GFUNC_GPSR(GRP7_1_FUNC, RIF5_D1), + + PINMUX_GFUNC_GPSR(GRP7_0_FUNC, SSI3_SCK), + PINMUX_GFUNC_GPSR(GRP7_0_FUNC, MSIOF7_SYNC_B), + PINMUX_GFUNC_GPSR(GRP7_0_FUNC, RIF5_D0), + + /* Group8 Functions */ + PINMUX_GFUNC_GPSR(GRP8_31_FUNC, S3DA2), + + PINMUX_GFUNC_GPSR(GRP8_30_FUNC, S3CL2), + + PINMUX_GFUNC_GPSR(GRP8_29_FUNC, S3DA1), + + PINMUX_GFUNC_GPSR(GRP8_28_FUNC, S3CL1), + + PINMUX_GFUNC_GPSR(GRP8_27_FUNC, S3DA0), + + PINMUX_GFUNC_GPSR(GRP8_26_FUNC, S3CL0), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_15_FUNC, SDA8, SEL_SDA8_1), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_14_FUNC, SCL8, SEL_SCL8_1), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_13_FUNC, SDA7, SEL_SDA7_1), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_12_FUNC, SCL7, SEL_SCL7_1), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_11_FUNC, SDA6, SEL_SDA6_1), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_10_FUNC, SCL6, SEL_SCL6_1), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_9_FUNC, SDA5, SEL_SDA5_1), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_8_FUNC, SCL5, SEL_SCL5_1), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_7_FUNC, SDA4, SEL_SDA4_1), + PINMUX_GFUNC_GPSR(GRP8_7_FUNC, HCTS2_N_A), + PINMUX_GFUNC_GPSR(GRP8_7_FUNC, CTS4_N_A), + PINMUX_GFUNC_GPSR(GRP8_7_FUNC, PWM7_B), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_6_FUNC, SCL4, SEL_SCL4_1), + PINMUX_GFUNC_GPSR(GRP8_6_FUNC, HRTS2_N_A), + PINMUX_GFUNC_GPSR(GRP8_6_FUNC, RTS4_N_A), + PINMUX_GFUNC_GPSR(GRP8_6_FUNC, PWM9_B), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_5_FUNC, SDA3, SEL_SDA3_1), + PINMUX_GFUNC_GPSR(GRP8_5_FUNC, HRX2_A), + PINMUX_GFUNC_GPSR(GRP8_5_FUNC, RX4_A), + PINMUX_GFUNC_GPSR(GRP8_5_FUNC, PWM8_B), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_4_FUNC, SCL3, SEL_SCL3_1), + PINMUX_GFUNC_GPSR(GRP8_4_FUNC, HTX2_A), + PINMUX_GFUNC_GPSR(GRP8_4_FUNC, TX4_A), + PINMUX_GFUNC_GPSR(GRP8_4_FUNC, PWM6_B), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_3_FUNC, SDA2, SEL_SDA2_1), + PINMUX_GFUNC_GPSR(GRP8_3_FUNC, HSCK2_A), + PINMUX_GFUNC_GPSR(GRP8_3_FUNC, SCK4_A), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_2_FUNC, SCL2, SEL_SCL2_1), + PINMUX_GFUNC_GPSR(GRP8_2_FUNC, PWM0_B), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_1_FUNC, SDA1, SEL_SDA1_1), + + PINMUX_GFUNC_MSEL_GPSR(GRP8_0_FUNC, SCL1, SEL_SCL1_1), + + /* Group9 Functions */ + PINMUX_GFUNC_GPSR(GRP9_16_FUNC, RSW3_MATCH), + PINMUX_GFUNC_GPSR(GRP9_16_FUNC, PWM9_A), + + PINMUX_GFUNC_GPSR(GRP9_15_FUNC, RSW3_CAPTURE), + PINMUX_GFUNC_GPSR(GRP9_15_FUNC, PWM8_A), + + PINMUX_GFUNC_GPSR(GRP9_14_FUNC, RSW3_PPS), + + PINMUX_GFUNC_GPSR(GRP9_13_FUNC, ETH10G0_PHYINT), + PINMUX_GFUNC_GPSR(GRP9_13_FUNC, ETH10G1_PHYINT), + + PINMUX_GFUNC_GPSR(GRP9_12_FUNC, ETH10G0_LINK), + PINMUX_GFUNC_GPSR(GRP9_12_FUNC, ETH10G1_LINK), + PINMUX_GFUNC_GPSR(GRP9_12_FUNC, PWM7_A), + + PINMUX_GFUNC_GPSR(GRP9_11_FUNC, ETH10G0_MDC), + PINMUX_GFUNC_GPSR(GRP9_11_FUNC, ETH10G1_MDC), + PINMUX_GFUNC_GPSR(GRP9_11_FUNC, IRQ3_B), + + PINMUX_GFUNC_GPSR(GRP9_10_FUNC, ETH10G0_MDIO), + PINMUX_GFUNC_GPSR(GRP9_10_FUNC, ETH10G1_MDIO), + PINMUX_GFUNC_GPSR(GRP9_10_FUNC, IRQ2_B), + + PINMUX_GFUNC_GPSR(GRP9_9_FUNC, ETH25G0_PHYINT), + PINMUX_GFUNC_GPSR(GRP9_9_FUNC, ETH25G1_PHYINT), + PINMUX_GFUNC_GPSR(GRP9_9_FUNC, ETH25G2_PHYINT), + + PINMUX_GFUNC_GPSR(GRP9_8_FUNC, ETH25G0_LINK), + PINMUX_GFUNC_GPSR(GRP9_8_FUNC, ETH25G1_LINK), + PINMUX_GFUNC_GPSR(GRP9_8_FUNC, ETH25G2_LINK), + PINMUX_GFUNC_GPSR(GRP9_8_FUNC, PWM6_A), + + PINMUX_GFUNC_GPSR(GRP9_7_FUNC, ETH25G0_MDC), + PINMUX_GFUNC_GPSR(GRP9_7_FUNC, ETH25G1_MDC), + PINMUX_GFUNC_GPSR(GRP9_7_FUNC, ETH25G2_MDC), + + PINMUX_GFUNC_GPSR(GRP9_6_FUNC, ETH25G0_MDIO), + PINMUX_GFUNC_GPSR(GRP9_6_FUNC, ETH25G1_MDIO), + PINMUX_GFUNC_GPSR(GRP9_6_FUNC, ETH25G2_MDIO), + + PINMUX_GFUNC_GPSR(GRP9_5_FUNC, ETHES4_MATCH), + PINMUX_GFUNC_GPSR(GRP9_5_FUNC, ETHES5_MATCH), + PINMUX_GFUNC_GPSR(GRP9_5_FUNC, ETHES6_MATCH), + PINMUX_GFUNC_GPSR(GRP9_5_FUNC, ETHES7_MATCH), + + PINMUX_GFUNC_GPSR(GRP9_4_FUNC, ETHES4_CAPTURE), + PINMUX_GFUNC_GPSR(GRP9_4_FUNC, ETHES5_CAPTURE), + PINMUX_GFUNC_GPSR(GRP9_4_FUNC, ETHES6_CAPTURE), + PINMUX_GFUNC_GPSR(GRP9_4_FUNC, ETHES7_CAPTURE), + + PINMUX_GFUNC_GPSR(GRP9_3_FUNC, ETHES4_PPS), + PINMUX_GFUNC_GPSR(GRP9_3_FUNC, ETHES5_PPS), + PINMUX_GFUNC_GPSR(GRP9_3_FUNC, ETHES6_PPS), + PINMUX_GFUNC_GPSR(GRP9_3_FUNC, ETHES7_PPS), + + PINMUX_GFUNC_GPSR(GRP9_2_FUNC, ETHES0_MATCH), + PINMUX_GFUNC_GPSR(GRP9_2_FUNC, ETHES1_MATCH), + PINMUX_GFUNC_GPSR(GRP9_2_FUNC, ETHES2_MATCH), + PINMUX_GFUNC_GPSR(GRP9_2_FUNC, ETHES3_MATCH), + + PINMUX_GFUNC_GPSR(GRP9_1_FUNC, ETHES0_CAPTURE), + PINMUX_GFUNC_GPSR(GRP9_1_FUNC, ETHES1_CAPTURE), + PINMUX_GFUNC_GPSR(GRP9_1_FUNC, ETHES2_CAPTURE), + PINMUX_GFUNC_GPSR(GRP9_1_FUNC, ETHES3_CAPTURE), + + PINMUX_GFUNC_GPSR(GRP9_0_FUNC, ETHES0_PPS), + PINMUX_GFUNC_GPSR(GRP9_0_FUNC, ETHES1_PPS), + PINMUX_GFUNC_GPSR(GRP9_0_FUNC, ETHES2_PPS), + PINMUX_GFUNC_GPSR(GRP9_0_FUNC, ETHES3_PPS), + + /* Group10 Functions */ + PINMUX_GFUNC_GPSR(GRP10_13_FUNC, PCIE41_CLKREQ_N), + + PINMUX_GFUNC_GPSR(GRP10_12_FUNC, PCIE40_CLKREQ_N), + + PINMUX_GFUNC_GPSR(GRP10_11_FUNC, USB3_VBUS_VALID), + + PINMUX_GFUNC_GPSR(GRP10_10_FUNC, USB3_OVC), + + PINMUX_GFUNC_GPSR(GRP10_9_FUNC, USB3_PWEN), + + PINMUX_GFUNC_GPSR(GRP10_8_FUNC, USB2_VBUS_VALID), + + PINMUX_GFUNC_GPSR(GRP10_7_FUNC, USB2_OVC), + + PINMUX_GFUNC_GPSR(GRP10_6_FUNC, USB2_PWEN), + + PINMUX_GFUNC_GPSR(GRP10_5_FUNC, USB1_VBUS_VALID), + + PINMUX_GFUNC_GPSR(GRP10_4_FUNC, USB1_OVC), + + PINMUX_GFUNC_GPSR(GRP10_3_FUNC, USB1_PWEN), + + PINMUX_GFUNC_GPSR(GRP10_2_FUNC, USB0_VBUS_VALID), + + PINMUX_GFUNC_GPSR(GRP10_1_FUNC, USB0_OVC), + + PINMUX_GFUNC_GPSR(GRP10_0_FUNC, USB0_PWEN), + +}; + +/* + * Pins not associated with a GPIO port. + * TODO: Define for None GPIO pins. + */ +enum { + GP_ASSIGN_LAST(), + //NOGP_ALL(), +}; + +static const struct sh_pfc_pin pinmux_pins[] = { + PINMUX_GPIO_GP_ALL(), + // TODO: Define for None GPIO pins. + //PINMUX_NOGP_ALL(), +}; + +/* - HSCIF0 ----------------------------------------------------------------- */ +static const unsigned int hscif0_data_pins[] = { + /* HRX0, HTX0 */ + RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 0), +}; +static const unsigned int hscif0_data_mux[] = { + HRX0_MARK, HTX0_MARK, +}; +static const unsigned int hscif0_clk_pins[] = { + /* HSCK0 */ + RCAR_GP_PIN(5, 4), +}; +static const unsigned int hscif0_clk_mux[] = { + HSCK0_MARK, +}; +static const unsigned int hscif0_ctrl_pins[] = { + /* HRTS0_N, HCTS0_N */ + RCAR_GP_PIN(5, 2), RCAR_GP_PIN(5, 3), +}; +static const unsigned int hscif0_ctrl_mux[] = { + HRTS0_N_MARK, HCTS0_N_MARK, +}; + +/* - HSCIF1 ----------------------------------------------------------------- */ +static const unsigned int hscif1_data_pins[] = { + /* HRX1, HTX1 */ + RCAR_GP_PIN(5, 7), RCAR_GP_PIN(5, 6), +}; +static const unsigned int hscif1_data_mux[] = { + HRX1_MARK, HTX1_MARK, +}; +static const unsigned int hscif1_clk_pins[] = { + /* HSCK1 */ + RCAR_GP_PIN(5, 10), +}; +static const unsigned int hscif1_clk_mux[] = { + HSCK1_MARK, +}; +static const unsigned int hscif1_ctrl_pins[] = { + /* HRTS1_N, HCTS1_N */ + RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 9), +}; +static const unsigned int hscif1_ctrl_mux[] = { + HRTS1_N_MARK, HCTS1_N_MARK, +}; + +/* - HSCIF2 ----------------------------------------------------------------- */ +static const unsigned int hscif2_data_a_pins[] = { + /* HRX2_A, HTX2_A */ + RCAR_GP_PIN(8, 5), RCAR_GP_PIN(8, 4), +}; +static const unsigned int hscif2_data_a_mux[] = { + HRX2_A_MARK, HTX2_A_MARK, +}; +static const unsigned int hscif2_clk_a_pins[] = { + /* HSCK2_A */ + RCAR_GP_PIN(8, 3), +}; +static const unsigned int hscif2_clk_a_mux[] = { + HSCK2_A_MARK, +}; +static const unsigned int hscif2_ctrl_a_pins[] = { + /* HRTS2_A_N, HCTS2_A_N */ + RCAR_GP_PIN(8, 6), RCAR_GP_PIN(8, 7), +}; +static const unsigned int hscif2_ctrl_a_mux[] = { + HRTS2_N_A_MARK, HCTS2_N_A_MARK, +}; + +static const unsigned int hscif2_data_b_pins[] = { + /* HRX2_B, HTX2_B */ + RCAR_GP_PIN(7, 30), RCAR_GP_PIN(7, 26), +}; +static const unsigned int hscif2_data_b_mux[] = { + HRX2_B_MARK, HTX2_B_MARK, +}; +static const unsigned int hscif2_clk_b_pins[] = { + /* HSCK2_B */ + RCAR_GP_PIN(7, 20), +}; +static const unsigned int hscif2_clk_b_mux[] = { + HSCK2_B_MARK, +}; +static const unsigned int hscif2_ctrl_b_pins[] = { + /* HRTS2_B_N, HCTS2_B_N */ + RCAR_GP_PIN(7, 22), RCAR_GP_PIN(7, 24), +}; +static const unsigned int hscif2_ctrl_b_mux[] = { + HRTS2_N_B_MARK, HCTS2_N_B_MARK, +}; + +/* - HSCIF3 ----------------------------------------------------------------- */ +static const unsigned int hscif3_data_pins[] = { + /* HRX3, HTX3 */ + RCAR_GP_PIN(6, 18), RCAR_GP_PIN(8, 17), +}; +static const unsigned int hscif3_data_mux[] = { + HRX3_MARK, HTX3_MARK, +}; +static const unsigned int hscif3_clk_pins[] = { + /* HSCK3 */ + RCAR_GP_PIN(6, 21), +}; +static const unsigned int hscif3_clk_mux[] = { + HSCK3_MARK, +}; +static const unsigned int hscif3_ctrl_pins[] = { + /* HRTS3_N, HCTS3_N */ + RCAR_GP_PIN(6, 22), RCAR_GP_PIN(6, 23), +}; +static const unsigned int hscif3_ctrl_mux[] = { + HRTS3_N_MARK, HCTS3_N_MARK, +}; + +/* - SCIF0 ----------------------------------------------------------------- */ +static const unsigned int scif0_data_pins[] = { + /* RX0, TX0 */ + RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 0), +}; +static const unsigned int scif0_data_mux[] = { + RX0_MARK, TX0_MARK, +}; +static const unsigned int scif0_clk_pins[] = { + /* SCK0 */ + RCAR_GP_PIN(5, 4), +}; +static const unsigned int scif0_clk_mux[] = { + SCK0_MARK, +}; +static const unsigned int scif0_ctrl_pins[] = { + /* RTS0_N, CTS0_N */ + RCAR_GP_PIN(5, 2), RCAR_GP_PIN(5, 3), +}; +static const unsigned int scif0_ctrl_mux[] = { + RTS0_N_MARK, CTS0_N_MARK, +}; + +/* - SCIF1 ----------------------------------------------------------------- */ +static const unsigned int scif1_data_pins[] = { + /* RX1, TX1 */ + RCAR_GP_PIN(5, 7), RCAR_GP_PIN(5, 6), +}; +static const unsigned int scif1_data_mux[] = { + RX1_MARK, TX1_MARK, +}; +static const unsigned int scif1_clk_pins[] = { + /* SCK1 */ + RCAR_GP_PIN(5, 10), +}; +static const unsigned int scif1_clk_mux[] = { + SCK1_MARK, +}; +static const unsigned int scif1_ctrl_pins[] = { + /* RTS1_N, CTS1_N */ + RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 9), +}; +static const unsigned int scif1_ctrl_mux[] = { + RTS1_N_MARK, CTS1_N_MARK, +}; + +/* - SCIF3 ----------------------------------------------------------------- */ +static const unsigned int scif3_data_pins[] = { + /* RX3, TX3 */ + RCAR_GP_PIN(6, 18), RCAR_GP_PIN(8, 17), +}; +static const unsigned int scif3_data_mux[] = { + RX3_MARK, TX3_MARK, +}; +static const unsigned int scif3_clk_pins[] = { + /* SCK3 */ + RCAR_GP_PIN(6, 21), +}; +static const unsigned int scif3_clk_mux[] = { + SCK3_MARK, +}; +static const unsigned int scif3_ctrl_pins[] = { + /* RTS3_N, CTS3_N */ + RCAR_GP_PIN(6, 22), RCAR_GP_PIN(6, 23), +}; +static const unsigned int scif3_ctrl_mux[] = { + RTS3_N_MARK, CTS3_N_MARK, +}; + +/* - SCIF4 ----------------------------------------------------------------- */ +static const unsigned int scif4_data_a_pins[] = { + /* RX4_A, TX4_A */ + RCAR_GP_PIN(8, 5), RCAR_GP_PIN(8, 4), +}; +static const unsigned int scif4_data_a_mux[] = { + RX4_A_MARK, TX4_A_MARK, +}; +static const unsigned int scif4_clk_a_pins[] = { + /* SCK4_A */ + RCAR_GP_PIN(8, 3), +}; +static const unsigned int scif4_clk_a_mux[] = { + SCK4_A_MARK, +}; +static const unsigned int scif4_ctrl_a_pins[] = { + /* RTS4_A_N, CTS4_A_N */ + RCAR_GP_PIN(8, 6), RCAR_GP_PIN(8, 7), +}; +static const unsigned int scif4_ctrl_a_mux[] = { + RTS4_N_A_MARK, CTS4_N_A_MARK, +}; + +static const unsigned int scif4_data_b_pins[] = { + /* RX4_B, TX4_B */ + RCAR_GP_PIN(7, 30), RCAR_GP_PIN(7, 26), +}; +static const unsigned int scif4_data_b_mux[] = { + RX4_B_MARK, TX4_B_MARK, +}; +static const unsigned int scif4_clk_b_pins[] = { + /* SCK4_B */ + RCAR_GP_PIN(7, 20), +}; +static const unsigned int scif4_clk_b_mux[] = { + SCK4_B_MARK, +}; +static const unsigned int scif4_ctrl_b_pins[] = { + /* RTS4_B_N, CTS4_B_N */ + RCAR_GP_PIN(7, 22), RCAR_GP_PIN(7, 24), +}; +static const unsigned int scif4_ctrl_b_mux[] = { + RTS4_N_B_MARK, CTS4_N_B_MARK, +}; + +/* - SCIF Clock ------------------------------------------------------------- */ +static const unsigned int scif_clk_pins[] = { + /* SCIF_CLK */ + RCAR_GP_PIN(5, 5), +}; +static const unsigned int scif_clk_mux[] = { + SCIF_CLK_MARK, +}; + +/* - I2C0 ------------------------------------------------------------------- */ +static const unsigned int i2c0_pins[] = { + /* SDA0, SCL0 */ + RCAR_GP_PIN(2, 20), RCAR_GP_PIN(2, 19), +}; +static const unsigned int i2c0_mux[] = { + SDA0_MARK, SCL0_MARK, +}; + +/* - I2C1 ------------------------------------------------------------------- */ +static const unsigned int i2c1_pins[] = { + /* SDA1, SCL1 */ + RCAR_GP_PIN(8, 1), RCAR_GP_PIN(8, 0), +}; +static const unsigned int i2c1_mux[] = { + SDA1_MARK, SCL1_MARK, +}; + +/* - I2C2 ------------------------------------------------------------------- */ +static const unsigned int i2c2_pins[] = { + /* SDA2, SCL2 */ + RCAR_GP_PIN(8, 3), RCAR_GP_PIN(8, 2), +}; +static const unsigned int i2c2_mux[] = { + SDA2_MARK, SCL2_MARK, +}; + +/* - I2C3 ------------------------------------------------------------------- */ +static const unsigned int i2c3_pins[] = { + /* SDA3, SCL3 */ + RCAR_GP_PIN(8, 5), RCAR_GP_PIN(8, 4), +}; +static const unsigned int i2c3_mux[] = { + SDA3_MARK, SCL3_MARK, +}; + +/* - I2C4 ------------------------------------------------------------------- */ +static const unsigned int i2c4_pins[] = { + /* SDA4, SCL4 */ + RCAR_GP_PIN(8, 7), RCAR_GP_PIN(8, 6), +}; +static const unsigned int i2c4_mux[] = { + SDA4_MARK, SCL4_MARK, +}; + +/* - I2C5 ------------------------------------------------------------------- */ +static const unsigned int i2c5_pins[] = { + /* SDA5, SCL5 */ + RCAR_GP_PIN(8, 9), RCAR_GP_PIN(8, 8), +}; +static const unsigned int i2c5_mux[] = { + SDA5_MARK, SCL5_MARK, +}; + +/* - I2C6 ------------------------------------------------------------------- */ +static const unsigned int i2c6_pins[] = { + /* SDA6, SCL6 */ + RCAR_GP_PIN(8, 11), RCAR_GP_PIN(8, 10), +}; +static const unsigned int i2c6_mux[] = { + SDA6_MARK, SCL6_MARK, +}; + +/* - I2C7 ------------------------------------------------------------------- */ +static const unsigned int i2c7_pins[] = { + /* SDA7, SCL7 */ + RCAR_GP_PIN(8, 13), RCAR_GP_PIN(8, 12), +}; +static const unsigned int i2c7_mux[] = { + SDA7_MARK, SCL7_MARK, +}; + +/* - I2C8 ------------------------------------------------------------------- */ +static const unsigned int i2c8_pins[] = { + /* SDA8, SCL8 */ + RCAR_GP_PIN(8, 15), RCAR_GP_PIN(8, 14), +}; +static const unsigned int i2c8_mux[] = { + SDA8_MARK, SCL8_MARK, +}; + +/* - INTC-EX ---------------------------------------------------------------- */ +static const unsigned int intc_ex_irq0_pins[] = { + /* IRQ0_A, IRQ0_B */ + RCAR_GP_PIN(5, 11), RCAR_GP_PIN(5, 2), +}; +static const unsigned int intc_ex_irq0_mux[] = { + IRQ0_A_MARK, IRQ0_B_MARK, +}; +static const unsigned int intc_ex_irq1_pins[] = { + /* IRQ1_A, IRQ1_B */ + RCAR_GP_PIN(5, 12), RCAR_GP_PIN(5, 3), +}; +static const unsigned int intc_ex_irq1_mux[] = { + IRQ1_A_MARK, IRQ1_B_MARK, +}; +static const unsigned int intc_ex_irq2_pins[] = { + /* IRQ2_A, IRQ2_B */ + RCAR_GP_PIN(5, 13), RCAR_GP_PIN(9, 10), +}; +static const unsigned int intc_ex_irq2_mux[] = { + IRQ2_A_MARK, IRQ2_B_MARK, +}; +static const unsigned int intc_ex_irq3_pins[] = { + /* IRQ3_A, IRQ3_B */ + RCAR_GP_PIN(5, 14), RCAR_GP_PIN(9, 11), +}; +static const unsigned int intc_ex_irq3_mux[] = { + IRQ3_A_MARK, IRQ3_B_MARK, +}; + +/* - PCIE4 ------------------------------------------------------------------- */ +static const unsigned int pcie40_clkreq_n_pins[] = { + /* PCIE40_CLKREQ_N */ + RCAR_GP_PIN(10, 12), +}; + +static const unsigned int pcie40_clkreq_n_mux[] = { + PCIE40_CLKREQ_N_MARK, +}; + +static const unsigned int pcie41_clkreq_n_pins[] = { + /* PCIE41_CLKREQ_N */ + RCAR_GP_PIN(10, 13), +}; + +static const unsigned int pcie41_clkreq_n_mux[] = { + PCIE41_CLKREQ_N_MARK, +}; + +/* - PCIE6 ------------------------------------------------------------------- */ +static const unsigned int pcie60_clkreq_n_pins[] = { + /* PCIE60_CLKREQ_N */ + RCAR_GP_PIN(4, 14), +}; + +static const unsigned int pcie60_clkreq_n_mux[] = { + PCIE60_CLKREQ_N_MARK, +}; + +static const unsigned int pcie61_clkreq_n_pins[] = { + /* PCIE61_CLKREQ_N */ + RCAR_GP_PIN(4, 15), +}; + +static const unsigned int pcie61_clkreq_n_mux[] = { + PCIE61_CLKREQ_N_MARK, +}; + +/* - QSPI0 ------------------------------------------------------------------ */ +static const unsigned int qspi0_ctrl_pins[] = { + /* SPCLK, SSL */ + RCAR_GP_PIN(3, 0), RCAR_GP_PIN(3, 5), +}; +static const unsigned int qspi0_ctrl_mux[] = { + QSPI0_SPCLK_MARK, QSPI0_SSL_MARK, +}; +static const unsigned int qspi0_data_pins[] = { + /* MOSI_IO0, MISO_IO1, IO2, IO3 */ + RCAR_GP_PIN(3, 1), RCAR_GP_PIN(3, 2), + RCAR_GP_PIN(3, 3), RCAR_GP_PIN(3, 4), +}; +static const unsigned int qspi0_data_mux[] = { + QSPI0_MOSI_IO0_MARK, QSPI0_MISO_IO1_MARK, + QSPI0_IO2_MARK, QSPI0_IO3_MARK, +}; + +/* - QSPI1 ------------------------------------------------------------------ */ +static const unsigned int qspi1_ctrl_pins[] = { + /* SPCLK, SSL */ + RCAR_GP_PIN(3, 9), RCAR_GP_PIN(3, 14), +}; +static const unsigned int qspi1_ctrl_mux[] = { + QSPI1_SPCLK_MARK, QSPI1_SSL_MARK, +}; +static const unsigned int qspi1_data_pins[] = { + /* MOSI_IO0, MISO_IO1, IO2, IO3 */ + RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 11), + RCAR_GP_PIN(3, 12), RCAR_GP_PIN(3, 13), +}; +static const unsigned int qspi1_data_mux[] = { + QSPI1_MOSI_IO0_MARK, QSPI1_MISO_IO1_MARK, + QSPI1_IO2_MARK, QSPI1_IO3_MARK, +}; + +/* - SDHI/MMC0 --------------------------------------------------------------- */ +static const unsigned int mmc0_data_pins[] = { + /* MMC0_SD_D[0:3], MMC0_D[4:7] */ + RCAR_GP_PIN(4, 2), RCAR_GP_PIN(4, 3), + RCAR_GP_PIN(4, 4), RCAR_GP_PIN(4, 5), + RCAR_GP_PIN(4, 6), RCAR_GP_PIN(4, 7), + RCAR_GP_PIN(4, 8), RCAR_GP_PIN(4, 9), +}; +static const unsigned int mmc0_data_mux[] = { + MMC0_SD_D0_MARK, MMC0_SD_D1_MARK, + MMC0_SD_D2_MARK, MMC0_SD_D3_MARK, + MMC0_D4_MARK, MMC0_D5_MARK, + MMC0_D6_MARK, MMC0_D7_MARK, +}; +static const unsigned int mmc0_ctrl_pins[] = { + /* MMC0_SD_CLK, MMC0_SD_CMD */ + RCAR_GP_PIN(4, 0), RCAR_GP_PIN(4, 1), +}; +static const unsigned int mmc0_ctrl_mux[] = { + MMC0_SD_CLK_MARK, MMC0_SD_CMD_MARK, +}; +static const unsigned int mmc0_cd_pins[] = { + /* SD0_CD */ + RCAR_GP_PIN(4, 12), +}; +static const unsigned int mmc0_cd_mux[] = { + SD0_CD_MARK, +}; +static const unsigned int mmc0_wp_pins[] = { + /* SD0_WP */ + RCAR_GP_PIN(4, 11), +}; +static const unsigned int mmc0_wp_mux[] = { + SD0_WP_MARK, +}; +static const unsigned int mmc0_ds_pins[] = { + /* MMC0_DS */ + RCAR_GP_PIN(4, 10), +}; +static const unsigned int mmc0_ds_mux[] = { + MMC0_DS_MARK, +}; + +/* - RSW3 ------------------------------------------------------------------ */ +static const unsigned int rsw3_match_pins[] = { + /* RSW3_MATCH */ + RCAR_GP_PIN(9, 16), +}; +static const unsigned int rsw3_match_mux[] = { + RSW3_MATCH_MARK, +}; +static const unsigned int rsw3_capture_pins[] = { + /* RSW3_CAPTURE */ + RCAR_GP_PIN(9, 15), +}; +static const unsigned int rsw3_capture_mux[] = { + RSW3_CAPTURE_MARK, +}; +static const unsigned int rsw3_pps_pins[] = { + /* RSW3_PPS */ + RCAR_GP_PIN(9, 14), +}; +static const unsigned int rsw3_pps_mux[] = { + RSW3_PPS_MARK, +}; + +/* - TSN0 ------------------------------------------------ */ +static const unsigned int eth10g0_link_pins[] = { + /* ETH10G0_LINK */ + RCAR_GP_PIN(9, 12), +}; +static const unsigned int eth10g0_link_mux[] = { + ETH10G0_LINK_MARK, +}; +static const unsigned int eth10g0_phyint_pins[] = { + /* ETH10G0_PHYINT */ + RCAR_GP_PIN(9, 13), +}; +static const unsigned int eth10g0_phyint_mux[] = { + ETH10G0_PHYINT_MARK, +}; +static const unsigned int eth10g0_mdio_pins[] = { + /* ETH10G0_MDC, ETH10G0_MDIO */ + RCAR_GP_PIN(9, 11), RCAR_GP_PIN(9, 10), +}; +static const unsigned int eth10g0_mdio_mux[] = { + ETH10G0_MDC_MARK, ETH10G0_MDIO_MARK, +}; + +static const unsigned int eth25g0_link_pins[] = { + /* ETH25G0_LINK */ + RCAR_GP_PIN(9, 8), +}; +static const unsigned int eth25g0_link_mux[] = { + ETH25G0_LINK_MARK, +}; +static const unsigned int eth25g0_phyint_pins[] = { + /* ETH25G0_PHYINT */ + RCAR_GP_PIN(9, 9), +}; +static const unsigned int eth25g0_phyint_mux[] = { + ETH25G0_PHYINT_MARK, +}; +static const unsigned int eth25g0_mdio_pins[] = { + /* ETH25G0_MDC, ETH25G0_MDIO */ + RCAR_GP_PIN(9, 7), RCAR_GP_PIN(9, 6), +}; +static const unsigned int eth25g0_mdio_mux[] = { + ETH25G0_MDC_MARK, ETH25G0_MDIO_MARK, +}; + +/* - TSN1 ------------------------------------------------ */ +static const unsigned int eth10g1_link_pins[] = { + /* ETH10G1_LINK */ + RCAR_GP_PIN(9, 12), +}; +static const unsigned int eth10g1_link_mux[] = { + ETH10G1_LINK_MARK, +}; +static const unsigned int eth10g1_phyint_pins[] = { + /* ETH10G1_PHYINT */ + RCAR_GP_PIN(9, 13), +}; +static const unsigned int eth10g1_phyint_mux[] = { + ETH10G1_PHYINT_MARK, +}; +static const unsigned int eth10g1_mdio_pins[] = { + /* ETH10G1_MDC, ETH10G1_MDIO */ + RCAR_GP_PIN(9, 11), RCAR_GP_PIN(9, 10), +}; +static const unsigned int eth10g1_mdio_mux[] = { + ETH10G1_MDC_MARK, ETH10G1_MDIO_MARK, +}; + +static const unsigned int eth25g1_link_pins[] = { + /* ETH25G1_LINK */ + RCAR_GP_PIN(9, 8), +}; +static const unsigned int eth25g1_link_mux[] = { + ETH25G1_LINK_MARK, +}; +static const unsigned int eth25g1_phyint_pins[] = { + /* ETH25G1_PHYINT */ + RCAR_GP_PIN(9, 9), +}; +static const unsigned int eth25g1_phyint_mux[] = { + ETH25G1_PHYINT_MARK, +}; +static const unsigned int eth25g1_mdio_pins[] = { + /* ETH25G1_MDC, ETH25G1_MDIO */ + RCAR_GP_PIN(9, 7), RCAR_GP_PIN(9, 6), +}; +static const unsigned int eth25g1_mdio_mux[] = { + ETH25G1_MDC_MARK, ETH25G1_MDIO_MARK, +}; + +/* - TSN2 ------------------------------------------------ */ +static const unsigned int eth25g2_link_pins[] = { + /* ETH25G2_LINK */ + RCAR_GP_PIN(9, 8), +}; +static const unsigned int eth25g2_link_mux[] = { + ETH25G2_LINK_MARK, +}; +static const unsigned int eth25g2_phyint_pins[] = { + /* ETH25G2_PHYINT */ + RCAR_GP_PIN(9, 9), +}; +static const unsigned int eth25g2_phyint_mux[] = { + ETH25G2_PHYINT_MARK, +}; +static const unsigned int eth25g2_mdio_pins[] = { + /* ETH25G2_MDC, ETH25G2_MDIO */ + RCAR_GP_PIN(9, 7), RCAR_GP_PIN(9, 6), +}; +static const unsigned int eth25g2_mdio_mux[] = { + ETH25G2_MDC_MARK, ETH25G2_MDIO_MARK, +}; + +/* - gPTPa (TSN0) ---------------------------------------- */ +static const unsigned int ethes0_pps_pins[] = { + /* ETHES0_PPS */ + RCAR_GP_PIN(9, 0), +}; +static const unsigned int ethes0_pps_mux[] = { + ETHES0_PPS_MARK, +}; +static const unsigned int ethes0_capture_pins[] = { + /* ETHES0_CAPTURE */ + RCAR_GP_PIN(9, 1), +}; +static const unsigned int ethes0_capture_mux[] = { + ETHES0_CAPTURE_MARK, +}; +static const unsigned int ethes0_match_pins[] = { + /* ETHES0_MATCH */ + RCAR_GP_PIN(9, 2), +}; +static const unsigned int ethes0_match_mux[] = { + ETHES0_MATCH_MARK, +}; + +/* - gPTPb (TSN1-7) -------------------------------------- */ +static const unsigned int ethes1_pps_pins[] = { + /* ETHES1_PPS */ + RCAR_GP_PIN(9, 0), +}; +static const unsigned int ethes1_pps_mux[] = { + ETHES1_PPS_MARK, +}; +static const unsigned int ethes1_capture_pins[] = { + /* ETHES1_CAPTURE */ + RCAR_GP_PIN(9, 1), +}; +static const unsigned int ethes1_capture_mux[] = { + ETHES1_CAPTURE_MARK, +}; +static const unsigned int ethes1_match_pins[] = { + /* ETHES1_MATCH */ + RCAR_GP_PIN(9, 2), +}; +static const unsigned int ethes1_match_mux[] = { + ETHES1_MATCH_MARK, +}; + +static const unsigned int ethes2_pps_pins[] = { + /* ETHES2_PPS */ + RCAR_GP_PIN(9, 0), +}; +static const unsigned int ethes2_pps_mux[] = { + ETHES2_PPS_MARK, +}; +static const unsigned int ethes2_capture_pins[] = { + /* ETHES2_CAPTURE */ + RCAR_GP_PIN(9, 1), +}; +static const unsigned int ethes2_capture_mux[] = { + ETHES2_CAPTURE_MARK, +}; +static const unsigned int ethes2_match_pins[] = { + /* ETHES1_MATCH */ + RCAR_GP_PIN(9, 2), +}; +static const unsigned int ethes2_match_mux[] = { + ETHES2_MATCH_MARK, +}; + +static const unsigned int ethes3_pps_pins[] = { + /* ETHES3_PPS */ + RCAR_GP_PIN(9, 0), +}; +static const unsigned int ethes3_pps_mux[] = { + ETHES3_PPS_MARK, +}; +static const unsigned int ethes3_capture_pins[] = { + /* ETHES3_CAPTURE */ + RCAR_GP_PIN(9, 1), +}; +static const unsigned int ethes3_capture_mux[] = { + ETHES3_CAPTURE_MARK, +}; +static const unsigned int ethes3_match_pins[] = { + /* ETHES3_MATCH */ + RCAR_GP_PIN(9, 2), +}; +static const unsigned int ethes3_match_mux[] = { + ETHES3_MATCH_MARK, +}; + +static const unsigned int ethes4_pps_pins[] = { + /* ETHES4_PPS */ + RCAR_GP_PIN(9, 3), +}; +static const unsigned int ethes4_pps_mux[] = { + ETHES4_PPS_MARK, +}; +static const unsigned int ethes4_capture_pins[] = { + /* ETHES4_CAPTURE */ + RCAR_GP_PIN(9, 4), +}; +static const unsigned int ethes4_capture_mux[] = { + ETHES4_CAPTURE_MARK, +}; +static const unsigned int ethes4_match_pins[] = { + /* ETHES4_MATCH */ + RCAR_GP_PIN(9, 5), +}; +static const unsigned int ethes4_match_mux[] = { + ETHES4_MATCH_MARK, +}; + +static const unsigned int ethes5_pps_pins[] = { + /* ETHES5_PPS */ + RCAR_GP_PIN(9, 3), +}; +static const unsigned int ethes5_pps_mux[] = { + ETHES5_PPS_MARK, +}; +static const unsigned int ethes5_capture_pins[] = { + /* ETHES5_CAPTURE */ + RCAR_GP_PIN(9, 4), +}; +static const unsigned int ethes5_capture_mux[] = { + ETHES5_CAPTURE_MARK, +}; +static const unsigned int ethes5_match_pins[] = { + /* ETHES5_MATCH */ + RCAR_GP_PIN(9, 5), +}; +static const unsigned int ethes5_match_mux[] = { + ETHES5_MATCH_MARK, +}; + +static const unsigned int ethes6_pps_pins[] = { + /* ETHES6_PPS */ + RCAR_GP_PIN(9, 3), +}; +static const unsigned int ethes6_pps_mux[] = { + ETHES6_PPS_MARK, +}; +static const unsigned int ethes6_capture_pins[] = { + /* ETHES6_CAPTURE */ + RCAR_GP_PIN(9, 4), +}; +static const unsigned int ethes6_capture_mux[] = { + ETHES6_CAPTURE_MARK, +}; +static const unsigned int ethes6_match_pins[] = { + /* ETHES6_MATCH */ + RCAR_GP_PIN(9, 5), +}; +static const unsigned int ethes6_match_mux[] = { + ETHES6_MATCH_MARK, +}; + +static const unsigned int ethes7_pps_pins[] = { + /* ETHES7_PPS */ + RCAR_GP_PIN(9, 3), +}; +static const unsigned int ethes7_pps_mux[] = { + ETHES7_PPS_MARK, +}; +static const unsigned int ethes7_capture_pins[] = { + /* ETHES7_CAPTURE */ + RCAR_GP_PIN(9, 4), +}; +static const unsigned int ethes7_capture_mux[] = { + ETHES7_CAPTURE_MARK, +}; +static const unsigned int ethes7_match_pins[] = { + /* ETHES7_MATCH */ + RCAR_GP_PIN(9, 5), +}; +static const unsigned int ethes7_match_mux[] = { + ETHES7_MATCH_MARK, +}; + +static const struct sh_pfc_pin_group pinmux_groups[] = { + SH_PFC_PIN_GROUP(hscif0_data), + SH_PFC_PIN_GROUP(hscif0_clk), + SH_PFC_PIN_GROUP(hscif0_ctrl), + SH_PFC_PIN_GROUP(hscif1_data), + SH_PFC_PIN_GROUP(hscif1_clk), + SH_PFC_PIN_GROUP(hscif1_ctrl), + SH_PFC_PIN_GROUP(hscif2_data_a), + SH_PFC_PIN_GROUP(hscif2_clk_a), + SH_PFC_PIN_GROUP(hscif2_ctrl_a), + SH_PFC_PIN_GROUP(hscif2_data_b), + SH_PFC_PIN_GROUP(hscif2_clk_b), + SH_PFC_PIN_GROUP(hscif2_ctrl_b), + SH_PFC_PIN_GROUP(hscif3_data), + SH_PFC_PIN_GROUP(hscif3_clk), + SH_PFC_PIN_GROUP(hscif3_ctrl), + + SH_PFC_PIN_GROUP(scif0_data), + SH_PFC_PIN_GROUP(scif0_clk), + SH_PFC_PIN_GROUP(scif0_ctrl), + SH_PFC_PIN_GROUP(scif1_data), + SH_PFC_PIN_GROUP(scif1_clk), + SH_PFC_PIN_GROUP(scif1_ctrl), + SH_PFC_PIN_GROUP(scif3_data), + SH_PFC_PIN_GROUP(scif3_clk), + SH_PFC_PIN_GROUP(scif3_ctrl), + SH_PFC_PIN_GROUP(scif4_data_a), + SH_PFC_PIN_GROUP(scif4_clk_a), + SH_PFC_PIN_GROUP(scif4_ctrl_a), + SH_PFC_PIN_GROUP(scif4_data_b), + SH_PFC_PIN_GROUP(scif4_clk_b), + SH_PFC_PIN_GROUP(scif4_ctrl_b), + SH_PFC_PIN_GROUP(scif_clk), + + SH_PFC_PIN_GROUP(i2c0), + SH_PFC_PIN_GROUP(i2c1), + SH_PFC_PIN_GROUP(i2c2), + SH_PFC_PIN_GROUP(i2c3), + SH_PFC_PIN_GROUP(i2c4), + SH_PFC_PIN_GROUP(i2c5), + SH_PFC_PIN_GROUP(i2c6), + SH_PFC_PIN_GROUP(i2c7), + SH_PFC_PIN_GROUP(i2c8), + + SH_PFC_PIN_GROUP(intc_ex_irq0), + SH_PFC_PIN_GROUP(intc_ex_irq1), + SH_PFC_PIN_GROUP(intc_ex_irq2), + SH_PFC_PIN_GROUP(intc_ex_irq3), + + SH_PFC_PIN_GROUP(pcie40_clkreq_n), + SH_PFC_PIN_GROUP(pcie41_clkreq_n), + SH_PFC_PIN_GROUP(pcie60_clkreq_n), + SH_PFC_PIN_GROUP(pcie61_clkreq_n), + + SH_PFC_PIN_GROUP(qspi0_ctrl), + BUS_DATA_PIN_GROUP(qspi0_data, 2), + BUS_DATA_PIN_GROUP(qspi0_data, 4), + SH_PFC_PIN_GROUP(qspi1_ctrl), + BUS_DATA_PIN_GROUP(qspi1_data, 2), + BUS_DATA_PIN_GROUP(qspi1_data, 4), + + BUS_DATA_PIN_GROUP(mmc0_data, 1), + BUS_DATA_PIN_GROUP(mmc0_data, 4), + BUS_DATA_PIN_GROUP(mmc0_data, 8), + SH_PFC_PIN_GROUP(mmc0_ctrl), + SH_PFC_PIN_GROUP(mmc0_cd), + SH_PFC_PIN_GROUP(mmc0_wp), + SH_PFC_PIN_GROUP(mmc0_ds), + + SH_PFC_PIN_GROUP(rsw3_match), + SH_PFC_PIN_GROUP(rsw3_capture), + SH_PFC_PIN_GROUP(rsw3_pps), + + SH_PFC_PIN_GROUP(eth10g0_link), + SH_PFC_PIN_GROUP(eth10g0_phyint), + SH_PFC_PIN_GROUP(eth10g0_mdio), + SH_PFC_PIN_GROUP(eth25g0_link), + SH_PFC_PIN_GROUP(eth25g0_phyint), + SH_PFC_PIN_GROUP(eth25g0_mdio), + + SH_PFC_PIN_GROUP(eth10g1_link), + SH_PFC_PIN_GROUP(eth10g1_phyint), + SH_PFC_PIN_GROUP(eth10g1_mdio), + SH_PFC_PIN_GROUP(eth25g1_link), + SH_PFC_PIN_GROUP(eth25g1_phyint), + SH_PFC_PIN_GROUP(eth25g1_mdio), + + SH_PFC_PIN_GROUP(eth25g2_link), + SH_PFC_PIN_GROUP(eth25g2_phyint), + SH_PFC_PIN_GROUP(eth25g2_mdio), + + SH_PFC_PIN_GROUP(ethes0_pps), + SH_PFC_PIN_GROUP(ethes0_capture), + SH_PFC_PIN_GROUP(ethes0_match), + SH_PFC_PIN_GROUP(ethes1_pps), + SH_PFC_PIN_GROUP(ethes1_capture), + SH_PFC_PIN_GROUP(ethes1_match), + SH_PFC_PIN_GROUP(ethes2_pps), + SH_PFC_PIN_GROUP(ethes2_capture), + SH_PFC_PIN_GROUP(ethes2_match), + SH_PFC_PIN_GROUP(ethes3_pps), + SH_PFC_PIN_GROUP(ethes3_capture), + SH_PFC_PIN_GROUP(ethes3_match), + SH_PFC_PIN_GROUP(ethes4_pps), + SH_PFC_PIN_GROUP(ethes4_capture), + SH_PFC_PIN_GROUP(ethes4_match), + SH_PFC_PIN_GROUP(ethes5_pps), + SH_PFC_PIN_GROUP(ethes5_capture), + SH_PFC_PIN_GROUP(ethes5_match), + SH_PFC_PIN_GROUP(ethes6_pps), + SH_PFC_PIN_GROUP(ethes6_capture), + SH_PFC_PIN_GROUP(ethes6_match), + SH_PFC_PIN_GROUP(ethes7_pps), + SH_PFC_PIN_GROUP(ethes7_capture), + SH_PFC_PIN_GROUP(ethes7_match), +}; + +static const char * const hscif0_groups[] = { + "hscif0_data", + "hscif0_clk", + "hscif0_ctrl", +}; + +static const char * const hscif1_groups[] = { + "hscif1_data", + "hscif1_clk", + "hscif1_ctrl", +}; + +static const char * const hscif2_groups[] = { + "hscif2_data_a", + "hscif2_clk_a", + "hscif2_ctrl_a", + "hscif2_data_b", + "hscif2_clk_b", + "hscif2_ctrl_b", +}; + +static const char * const hscif3_groups[] = { + "hscif3_data", + "hscif3_clk", + "hscif3_ctrl", +}; + +static const char * const scif0_groups[] = { + "scif0_data", + "scif0_clk", + "scif0_ctrl", +}; + +static const char * const scif1_groups[] = { + "scif1_data", + "scif1_clk", + "scif1_ctrl", +}; + +static const char * const scif3_groups[] = { + "scif3_data", + "scif3_clk", + "scif3_ctrl", +}; + +static const char * const scif4_groups[] = { + "scif4_data_a", + "scif4_clk_a", + "scif4_ctrl_a", + "scif4_data_b", + "scif4_clk_b", + "scif4_ctrl_b", +}; + +static const char * const scif_clk_groups[] = { + "scif_clk", +}; + +static const char * const i2c0_groups[] = { + "i2c0", +}; + +static const char * const i2c1_groups[] = { + "i2c1", +}; + +static const char * const i2c2_groups[] = { + "i2c2", +}; + +static const char * const i2c3_groups[] = { + "i2c3", +}; + +static const char * const i2c4_groups[] = { + "i2c4", +}; + +static const char * const i2c5_groups[] = { + "i2c5", +}; + +static const char * const i2c6_groups[] = { + "i2c6", +}; + +static const char * const i2c7_groups[] = { + "i2c7", +}; + +static const char * const i2c8_groups[] = { + "i2c8", +}; + +static const char * const intc_ex_groups[] = { + "intc_ex_irq0", + "intc_ex_irq1", + "intc_ex_irq2", + "intc_ex_irq3", +}; + +static const char * const pcie4_groups[] = { + "pcie40_clkreq_n", + "pcie41_clkreq_n", +}; + +static const char * const pcie6_groups[] = { + "pcie60_clkreq_n", + "pcie61_clkreq_n", +}; + +static const char * const qspi0_groups[] = { + "qspi0_ctrl", + "qspi0_data2", + "qspi0_data4", +}; + +static const char * const qspi1_groups[] = { + "qspi1_ctrl", + "qspi1_data2", + "qspi1_data4", +}; + +static const char * const mmc0_groups[] = { + "mmc0_data1", + "mmc0_data4", + "mmc0_data8", + "mmc0_ctrl", + "mmc0_cd", + "mmc0_wp", + "mmc0_ds", +}; + +static const char * const rsw3_groups[] = { + "rsw3_match", + "rsw3_capture", + "rsw3_pps", +}; + +static const char * const eth10g0_groups[] = { + "eth10g0_link", + "eth10g0_phyint", + "eth10g0_mdio", +}; + +static const char * const eth25g0_groups[] = { + "eth25g0_link", + "eth25g0_phyint", + "eth25g0_mdio", +}; + +static const char * const eth10g1_groups[] = { + "eth10g1_link", + "eth10g1_phyint", + "eth10g1_mdio", +}; + +static const char * const eth25g1_groups[] = { + "eth25g1_link", + "eth25g1_phyint", + "eth25g1_mdio", +}; + +static const char * const eth25g2_groups[] = { + "eth25g2_link", + "eth25g2_phyint", + "eth25g2_mdio", +}; + +static const char * const ethes0_groups[] = { + "ethes0_pps", + "ethes0_capture", + "ethes0_match", +}; + +static const char * const ethes1_groups[] = { + "ethes1_pps", + "ethes1_capture", + "ethes1_match", +}; + +static const char * const ethes2_groups[] = { + "ethes2_pps", + "ethes2_capture", + "ethes2_match", +}; + +static const char * const ethes3_groups[] = { + "ethes3_pps", + "ethes3_capture", + "ethes3_match", +}; + +static const char * const ethes4_groups[] = { + "ethes4_pps", + "ethes4_capture", + "ethes4_match", +}; + +static const char * const ethes5_groups[] = { + "ethes5_pps", + "ethes5_capture", + "ethes5_match", +}; + +static const char * const ethes6_groups[] = { + "ethes6_pps", + "ethes6_capture", + "ethes6_match", +}; + +static const char * const ethes7_groups[] = { + "ethes7_pps", + "ethes7_capture", + "ethes7_match", +}; + +static const struct sh_pfc_function pinmux_functions[] = { + SH_PFC_FUNCTION(hscif0), + SH_PFC_FUNCTION(hscif1), + SH_PFC_FUNCTION(hscif2), + SH_PFC_FUNCTION(hscif3), + + SH_PFC_FUNCTION(scif0), + SH_PFC_FUNCTION(scif1), + SH_PFC_FUNCTION(scif3), + SH_PFC_FUNCTION(scif4), + SH_PFC_FUNCTION(scif_clk), + + SH_PFC_FUNCTION(i2c0), + SH_PFC_FUNCTION(i2c1), + SH_PFC_FUNCTION(i2c2), + SH_PFC_FUNCTION(i2c3), + SH_PFC_FUNCTION(i2c4), + SH_PFC_FUNCTION(i2c5), + SH_PFC_FUNCTION(i2c6), + SH_PFC_FUNCTION(i2c7), + SH_PFC_FUNCTION(i2c8), + + SH_PFC_FUNCTION(intc_ex), + + SH_PFC_FUNCTION(pcie4), + SH_PFC_FUNCTION(pcie6), + + SH_PFC_FUNCTION(qspi0), + SH_PFC_FUNCTION(qspi1), + + SH_PFC_FUNCTION(mmc0), + + SH_PFC_FUNCTION(rsw3), + + SH_PFC_FUNCTION(eth10g0), + SH_PFC_FUNCTION(eth25g0), + SH_PFC_FUNCTION(eth10g1), + SH_PFC_FUNCTION(eth25g1), + SH_PFC_FUNCTION(eth25g2), + + SH_PFC_FUNCTION(ethes0), + SH_PFC_FUNCTION(ethes1), + SH_PFC_FUNCTION(ethes2), + SH_PFC_FUNCTION(ethes3), + SH_PFC_FUNCTION(ethes4), + SH_PFC_FUNCTION(ethes5), + SH_PFC_FUNCTION(ethes6), + SH_PFC_FUNCTION(ethes7), +}; + +static const struct pinmux_cfg_reg pinmux_config_regs[] = { +#define F_(x, y) FN_##y +#define FM(x) FN_##x + { PINMUX_CFG_REG_VAR("GPSR0", 0xC1080040, 32, + GROUP(-4, + 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1), + GROUP( + /* GP0_31_28 RESERVED */ + GP_0_27_FN, GPSR0_27, + GP_0_26_FN, GPSR0_26, + GP_0_25_FN, GPSR0_25, + GP_0_24_FN, GPSR0_24, + GP_0_23_FN, GPSR0_23, + GP_0_22_FN, GPSR0_22, + GP_0_21_FN, GPSR0_21, + GP_0_20_FN, GPSR0_20, + GP_0_19_FN, GPSR0_19, + GP_0_18_FN, GPSR0_18, + GP_0_17_FN, GPSR0_17, + GP_0_16_FN, GPSR0_16, + GP_0_15_FN, GPSR0_15, + GP_0_14_FN, GPSR0_14, + GP_0_13_FN, GPSR0_13, + GP_0_12_FN, GPSR0_12, + GP_0_11_FN, GPSR0_11, + GP_0_10_FN, GPSR0_10, + GP_0_9_FN, GPSR0_9, + GP_0_8_FN, GPSR0_8, + GP_0_7_FN, GPSR0_7, + GP_0_6_FN, GPSR0_6, + GP_0_5_FN, GPSR0_5, + GP_0_4_FN, GPSR0_4, + GP_0_3_FN, GPSR0_3, + GP_0_2_FN, GPSR0_2, + GP_0_1_FN, GPSR0_1, + GP_0_0_FN, GPSR0_0, )) + }, + { PINMUX_CFG_REG_VAR("GPSR1", 0xC1080840, 32, + GROUP(-10, + 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1), + GROUP( + /* GP1_31_22 RESERVED */ + GP_1_21_FN, GPSR1_21, + GP_1_20_FN, GPSR1_20, + GP_1_19_FN, GPSR1_19, + GP_1_18_FN, GPSR1_18, + GP_1_17_FN, GPSR1_17, + GP_1_16_FN, GPSR1_16, + GP_1_15_FN, GPSR1_15, + GP_1_14_FN, GPSR1_14, + GP_1_13_FN, GPSR1_13, + GP_1_12_FN, GPSR1_12, + GP_1_11_FN, GPSR1_11, + GP_1_10_FN, GPSR1_10, + GP_1_9_FN, GPSR1_9, + GP_1_8_FN, GPSR1_8, + GP_1_7_FN, GPSR1_7, + GP_1_6_FN, GPSR1_6, + GP_1_5_FN, GPSR1_5, + GP_1_4_FN, GPSR1_4, + GP_1_3_FN, GPSR1_3, + GP_1_2_FN, GPSR1_2, + GP_1_1_FN, GPSR1_1, + GP_1_0_FN, GPSR1_0, )) + }, + { PINMUX_CFG_REG_VAR("GPSR2", 0xC1081040, 32, + GROUP(-3, + 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1), + GROUP( + /* GP2_31_29 RESERVED */ + GP_2_28_FN, GPSR2_28, + GP_2_27_FN, GPSR2_27, + GP_2_26_FN, GPSR2_26, + GP_2_25_FN, GPSR2_25, + GP_2_24_FN, GPSR2_24, + GP_2_23_FN, GPSR2_23, + GP_2_22_FN, GPSR2_22, + GP_2_21_FN, GPSR2_21, + GP_2_20_FN, GPSR2_20, + GP_2_19_FN, GPSR2_19, + GP_2_18_FN, GPSR2_18, + GP_2_17_FN, GPSR2_17, + GP_2_16_FN, GPSR2_16, + GP_2_15_FN, GPSR2_15, + GP_2_14_FN, GPSR2_14, + GP_2_13_FN, GPSR2_13, + GP_2_12_FN, GPSR2_12, + GP_2_11_FN, GPSR2_11, + GP_2_10_FN, GPSR2_10, + GP_2_9_FN, GPSR2_9, + GP_2_8_FN, GPSR2_8, + GP_2_7_FN, GPSR2_7, + GP_2_6_FN, GPSR2_6, + GP_2_5_FN, GPSR2_5, + GP_2_4_FN, GPSR2_4, + GP_2_3_FN, GPSR2_3, + GP_2_2_FN, GPSR2_2, + GP_2_1_FN, GPSR2_1, + GP_2_0_FN, GPSR2_0, )) + }, + { PINMUX_CFG_REG_VAR("GPSR3", 0xC0800040, 32, + GROUP(-15, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1), + GROUP( + /* GP3_31_17 RESERVED */ + GP_3_16_FN, GPSR3_16, + GP_3_15_FN, GPSR3_15, + GP_3_14_FN, GPSR3_14, + GP_3_13_FN, GPSR3_13, + GP_3_12_FN, GPSR3_12, + GP_3_11_FN, GPSR3_11, + GP_3_10_FN, GPSR3_10, + GP_3_9_FN, GPSR3_9, + GP_3_8_FN, GPSR3_8, + GP_3_7_FN, GPSR3_7, + GP_3_6_FN, GPSR3_6, + GP_3_5_FN, GPSR3_5, + GP_3_4_FN, GPSR3_4, + GP_3_3_FN, GPSR3_3, + GP_3_2_FN, GPSR3_2, + GP_3_1_FN, GPSR3_1, + GP_3_0_FN, GPSR3_0, )) + }, + { PINMUX_CFG_REG_VAR("GPSR4", 0xC0800840, 32, + GROUP(-16, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1), + GROUP( + /* GP4_31_16 RESERVED */ + GP_4_15_FN, GPSR4_15, + GP_4_14_FN, GPSR4_14, + GP_4_13_FN, GPSR4_13, + GP_4_12_FN, GPSR4_12, + GP_4_11_FN, GPSR4_11, + GP_4_10_FN, GPSR4_10, + GP_4_9_FN, GPSR4_9, + GP_4_8_FN, GPSR4_8, + GP_4_7_FN, GPSR4_7, + GP_4_6_FN, GPSR4_6, + GP_4_5_FN, GPSR4_5, + GP_4_4_FN, GPSR4_4, + GP_4_3_FN, GPSR4_3, + GP_4_2_FN, GPSR4_2, + GP_4_1_FN, GPSR4_1, + GP_4_0_FN, GPSR4_0, )) + }, + { PINMUX_CFG_REG_VAR("GPSR5", 0xC0400040, 32, + GROUP(-9, + 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1), + GROUP( + /* GP5_31_23 RESERVED */ + GP_5_22_FN, GPSR5_22, + GP_5_21_FN, GPSR5_21, + GP_5_20_FN, GPSR5_20, + GP_5_19_FN, GPSR5_19, + GP_5_18_FN, GPSR5_18, + GP_5_17_FN, GPSR5_17, + GP_5_16_FN, GPSR5_16, + GP_5_15_FN, GPSR5_15, + GP_5_14_FN, GPSR5_14, + GP_5_13_FN, GPSR5_13, + GP_5_12_FN, GPSR5_12, + GP_5_11_FN, GPSR5_11, + GP_5_10_FN, GPSR5_10, + GP_5_9_FN, GPSR5_9, + GP_5_8_FN, GPSR5_8, + GP_5_7_FN, GPSR5_7, + GP_5_6_FN, GPSR5_6, + GP_5_5_FN, GPSR5_5, + GP_5_4_FN, GPSR5_4, + GP_5_3_FN, GPSR5_3, + GP_5_2_FN, GPSR5_2, + GP_5_1_FN, GPSR5_1, + GP_5_0_FN, GPSR5_0, )) + }, + { PINMUX_CFG_REG("GPSR6", 0xC0400840, 32, 1, GROUP( + 0, 0, + GP_6_30_FN, GPSR6_30, + GP_6_29_FN, GPSR6_29, + GP_6_28_FN, GPSR6_28, + GP_6_27_FN, GPSR6_27, + GP_6_26_FN, GPSR6_26, + GP_6_25_FN, GPSR6_25, + GP_6_24_FN, GPSR6_24, + GP_6_23_FN, GPSR6_23, + GP_6_22_FN, GPSR6_22, + GP_6_21_FN, GPSR6_21, + GP_6_20_FN, GPSR6_20, + GP_6_19_FN, GPSR6_19, + GP_6_18_FN, GPSR6_18, + GP_6_17_FN, GPSR6_17, + GP_6_16_FN, GPSR6_16, + GP_6_15_FN, GPSR6_15, + GP_6_14_FN, GPSR6_14, + GP_6_13_FN, GPSR6_13, + GP_6_12_FN, GPSR6_12, + GP_6_11_FN, GPSR6_11, + GP_6_10_FN, GPSR6_10, + GP_6_9_FN, GPSR6_9, + GP_6_8_FN, GPSR6_8, + GP_6_7_FN, GPSR6_7, + GP_6_6_FN, GPSR6_6, + GP_6_5_FN, GPSR6_5, + GP_6_4_FN, GPSR6_4, + GP_6_3_FN, GPSR6_3, + GP_6_2_FN, GPSR6_2, + GP_6_1_FN, GPSR6_1, + GP_6_0_FN, GPSR6_0, )) + }, + { PINMUX_CFG_REG("GPSR7", 0xC0401040, 32, 1, GROUP( + 0, 0, + GP_7_30_FN, GPSR7_30, + GP_7_29_FN, GPSR7_29, + GP_7_28_FN, GPSR7_28, + GP_7_27_FN, GPSR7_27, + GP_7_26_FN, GPSR7_26, + GP_7_25_FN, GPSR7_25, + GP_7_24_FN, GPSR7_24, + GP_7_23_FN, GPSR7_23, + GP_7_22_FN, GPSR7_22, + GP_7_21_FN, GPSR7_21, + GP_7_20_FN, GPSR7_20, + GP_7_19_FN, GPSR7_19, + GP_7_18_FN, GPSR7_18, + GP_7_17_FN, GPSR7_17, + GP_7_16_FN, GPSR7_16, + GP_7_15_FN, GPSR7_15, + GP_7_14_FN, GPSR7_14, + GP_7_13_FN, GPSR7_13, + GP_7_12_FN, GPSR7_12, + GP_7_11_FN, GPSR7_11, + GP_7_10_FN, GPSR7_10, + GP_7_9_FN, GPSR7_9, + GP_7_8_FN, GPSR7_8, + GP_7_7_FN, GPSR7_7, + GP_7_6_FN, GPSR7_6, + GP_7_5_FN, GPSR7_5, + GP_7_4_FN, GPSR7_4, + GP_7_3_FN, GPSR7_3, + GP_7_2_FN, GPSR7_2, + GP_7_1_FN, GPSR7_1, + GP_7_0_FN, GPSR7_0, )) + }, + { PINMUX_CFG_REG_VAR("GPSR8", 0xC0401840, 32, + GROUP(1, 1, 1, 1, 1, 1, + -10, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1), + GROUP( + GP_8_31_FN, GPSR8_31, + GP_8_30_FN, GPSR8_30, + GP_8_29_FN, GPSR8_29, + GP_8_28_FN, GPSR8_28, + GP_8_27_FN, GPSR8_27, + GP_8_26_FN, GPSR8_26, + /* GP8_25_16 RESERVED */ + GP_8_15_FN, GPSR8_15, + GP_8_14_FN, GPSR8_14, + GP_8_13_FN, GPSR8_13, + GP_8_12_FN, GPSR8_12, + GP_8_11_FN, GPSR8_11, + GP_8_10_FN, GPSR8_10, + GP_8_9_FN, GPSR8_9, + GP_8_8_FN, GPSR8_8, + GP_8_7_FN, GPSR8_7, + GP_8_6_FN, GPSR8_6, + GP_8_5_FN, GPSR8_5, + GP_8_4_FN, GPSR8_4, + GP_8_3_FN, GPSR8_3, + GP_8_2_FN, GPSR8_2, + GP_8_1_FN, GPSR8_1, + GP_8_0_FN, GPSR8_0, )) + }, + { PINMUX_CFG_REG_VAR("GPSR9", 0xC9B00040, 32, + GROUP(-15, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1), + GROUP( + /* GP9_31_17 RESERVED */ + GP_9_16_FN, GPSR9_16, + GP_9_15_FN, GPSR9_15, + GP_9_14_FN, GPSR9_14, + GP_9_13_FN, GPSR9_13, + GP_9_12_FN, GPSR9_12, + GP_9_11_FN, GPSR9_11, + GP_9_10_FN, GPSR9_10, + GP_9_9_FN, GPSR9_9, + GP_9_8_FN, GPSR9_8, + GP_9_7_FN, GPSR9_7, + GP_9_6_FN, GPSR9_6, + GP_9_5_FN, GPSR9_5, + GP_9_4_FN, GPSR9_4, + GP_9_3_FN, GPSR9_3, + GP_9_2_FN, GPSR9_2, + GP_9_1_FN, GPSR9_1, + GP_9_0_FN, GPSR9_0, )) + }, + { PINMUX_CFG_REG_VAR("GPSR10", 0xC9B00840, 32, + GROUP(-18, + 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1), + GROUP( + /* GP10_31_14 RESERVED */ + GP_10_13_FN, GPSR10_13, + GP_10_12_FN, GPSR10_12, + GP_10_11_FN, GPSR10_11, + GP_10_10_FN, GPSR10_10, + GP_10_9_FN, GPSR10_9, + GP_10_8_FN, GPSR10_8, + GP_10_7_FN, GPSR10_7, + GP_10_6_FN, GPSR10_6, + GP_10_5_FN, GPSR10_5, + GP_10_4_FN, GPSR10_4, + GP_10_3_FN, GPSR10_3, + GP_10_2_FN, GPSR10_2, + GP_10_1_FN, GPSR10_1, + GP_10_0_FN, GPSR10_0, )) + }, +#undef F_ +#undef FM + +#define F_(x, y) x, +#define FM(x) FN_##x, + { PINMUX_CFG_REG("GP0_ALTSEL0", 0xC1080060, 32, 1, GROUP( + GP_ALTSEL0(0) + )) + }, + { PINMUX_CFG_REG("GP0_ALTSEL1", 0xC1080064, 32, 1, GROUP( + GP_ALTSEL1(0) + )) + }, + { PINMUX_CFG_REG("GP0_ALTSEL2", 0xC1080068, 32, 1, GROUP( + GP_ALTSEL2(0) + )) + }, + { PINMUX_CFG_REG("GP0_ALTSEL3", 0xC108006C, 32, 1, GROUP( + GP_ALTSEL3(0) + )) + }, + { PINMUX_CFG_REG("GP1_ALTSEL0", 0xC1080860, 32, 1, GROUP( + GP_ALTSEL0(1) + )) + }, + { PINMUX_CFG_REG("GP1_ALTSEL1", 0xC1080864, 32, 1, GROUP( + GP_ALTSEL1(1) + )) + }, + { PINMUX_CFG_REG("GP1_ALTSEL2", 0xC1080868, 32, 1, GROUP( + GP_ALTSEL2(1) + )) + }, + { PINMUX_CFG_REG("GP1_ALTSEL3", 0xC108086C, 32, 1, GROUP( + GP_ALTSEL3(1) + )) + }, + { PINMUX_CFG_REG("GP2_ALTSEL0", 0xC1081060, 32, 1, GROUP( + GP_ALTSEL0(2) + )) + }, + { PINMUX_CFG_REG("GP2_ALTSEL1", 0xC1081064, 32, 1, GROUP( + GP_ALTSEL1(2) + )) + }, + { PINMUX_CFG_REG("GP2_ALTSEL2", 0xC1081068, 32, 1, GROUP( + GP_ALTSEL2(2) + )) + }, + { PINMUX_CFG_REG("GP2_ALTSEL3", 0xC108106C, 32, 1, GROUP( + GP_ALTSEL3(2) + )) + }, + { PINMUX_CFG_REG("GP3_ALTSEL0", 0xC0800060, 32, 1, GROUP( + GP_ALTSEL0(3) + )) + }, + { PINMUX_CFG_REG("GP3_ALTSEL1", 0xC0800064, 32, 1, GROUP( + GP_ALTSEL1(3) + )) + }, + { PINMUX_CFG_REG("GP3_ALTSEL2", 0xC0800068, 32, 1, GROUP( + GP_ALTSEL2(3) + )) + }, + { PINMUX_CFG_REG("GP3_ALTSEL3", 0xC080006C, 32, 1, GROUP( + GP_ALTSEL3(3) + )) + }, + { PINMUX_CFG_REG("GP4_ALTSEL0", 0xC0800860, 32, 1, GROUP( + GP_ALTSEL0(4) + )) + }, + { PINMUX_CFG_REG("GP4_ALTSEL1", 0xC0800864, 32, 1, GROUP( + GP_ALTSEL1(4) + )) + }, + { PINMUX_CFG_REG("GP4_ALTSEL2", 0xC0800868, 32, 1, GROUP( + GP_ALTSEL2(4) + )) + }, + { PINMUX_CFG_REG("GP4_ALTSEL3", 0xC080086C, 32, 1, GROUP( + GP_ALTSEL3(4) + )) + }, + { PINMUX_CFG_REG("GP5_ALTSEL0", 0xC0400060, 32, 1, GROUP( + GP_ALTSEL0(5) + )) + }, + { PINMUX_CFG_REG("GP5_ALTSEL1", 0xC0400064, 32, 1, GROUP( + GP_ALTSEL1(5) + )) + }, + { PINMUX_CFG_REG("GP5_ALTSEL2", 0xC0400068, 32, 1, GROUP( + GP_ALTSEL2(5) + )) + }, + { PINMUX_CFG_REG("GP5_ALTSEL3", 0xC040006C, 32, 1, GROUP( + GP_ALTSEL3(5) + )) + }, + { PINMUX_CFG_REG("GP6_ALTSEL0", 0xC0400860, 32, 1, GROUP( + GP_ALTSEL0(6) + )) + }, + { PINMUX_CFG_REG("GP6_ALTSEL1", 0xC0400864, 32, 1, GROUP( + GP_ALTSEL1(6) + )) + }, + { PINMUX_CFG_REG("GP6_ALTSEL2", 0xC0400868, 32, 1, GROUP( + GP_ALTSEL2(6) + )) + }, + { PINMUX_CFG_REG("GP6_ALTSEL3", 0xC040086C, 32, 1, GROUP( + GP_ALTSEL3(6) + )) + }, + { PINMUX_CFG_REG("GP7_ALTSEL0", 0xC0401060, 32, 1, GROUP( + GP_ALTSEL0(7) + )) + }, + { PINMUX_CFG_REG("GP7_ALTSEL1", 0xC0401064, 32, 1, GROUP( + GP_ALTSEL1(7) + )) + }, + { PINMUX_CFG_REG("GP7_ALTSEL2", 0xC0401068, 32, 1, GROUP( + GP_ALTSEL2(7) + )) + }, + { PINMUX_CFG_REG("GP7_ALTSEL3", 0xC040106C, 32, 1, GROUP( + GP_ALTSEL3(7) + )) + }, + { PINMUX_CFG_REG("GP8_ALTSEL0", 0xC0401860, 32, 1, GROUP( + GP_ALTSEL0(8) + )) + }, + { PINMUX_CFG_REG("GP8_ALTSEL1", 0xC0401864, 32, 1, GROUP( + GP_ALTSEL1(8) + )) + }, + { PINMUX_CFG_REG("GP8_ALTSEL2", 0xC0401868, 32, 1, GROUP( + GP_ALTSEL2(8) + )) + }, + { PINMUX_CFG_REG("GP8_ALTSEL3", 0xC040186C, 32, 1, GROUP( + GP_ALTSEL3(8) + )) + }, + { PINMUX_CFG_REG("GP9_ALTSEL0", 0xC9B00060, 32, 1, GROUP( + GP_ALTSEL0(9) + )) + }, + { PINMUX_CFG_REG("GP5_ALTSEL1", 0xC9B00064, 32, 1, GROUP( + GP_ALTSEL1(9) + )) + }, + { PINMUX_CFG_REG("GP9_ALTSEL2", 0xC9B00068, 32, 1, GROUP( + GP_ALTSEL2(9) + )) + }, + { PINMUX_CFG_REG("GP9_ALTSEL3", 0xC9B0006C, 32, 1, GROUP( + GP_ALTSEL3(9) + )) + }, + { PINMUX_CFG_REG("GP10_ALTSEL0", 0xC9B00860, 32, 1, GROUP( + GP_ALTSEL0(10) + )) + }, + { PINMUX_CFG_REG("GP10_ALTSEL1", 0xC9B00864, 32, 1, GROUP( + GP_ALTSEL1(10) + )) + }, + { PINMUX_CFG_REG("GP10_ALTSEL2", 0xC9B00868, 32, 1, GROUP( + GP_ALTSEL2(10) + )) + }, + { PINMUX_CFG_REG("GP10_ALTSEL3", 0xC9B0086C, 32, 1, GROUP( + GP_ALTSEL3(10) + )) + }, +#undef F_ +#undef FM + +#define F_(x, y) x, +#define FM(x) FN_##x, + { PINMUX_CFG_REG_VAR("GP1_MODSEL", 0xC1080900, 32, + GROUP(-10, + 1, 1, 1, 1, 1, 1, 1, 1, + -14), + GROUP( + /* GP1_MODSEL_31_22 RESERVED */ + GP1_MODSEL_21 + GP1_MODSEL_20 + GP1_MODSEL_19 + GP1_MODSEL_18 + GP1_MODSEL_17 + GP1_MODSEL_16 + GP1_MODSEL_15 + GP1_MODSEL_14 + /* GP1_MODSEL_13_0 RESERVED */ + )) + }, + { PINMUX_CFG_REG_VAR("GP2_MODSEL", 0xC1081100, 32, + GROUP(-11, + 1, 1, + -19), + GROUP( + /* GP2_MODSEL_31_21 RESERVED */ + GP2_MODSEL_20 + GP2_MODSEL_19 + /* GP2_MODSEL_18_0 RESERVED */ + )) + }, + { PINMUX_CFG_REG_VAR("GP8_MODSEL", 0xC0401900, 32, + GROUP(-16, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1), + GROUP( + /* GP8_MODSEL_31_16 RESERVED */ + GP8_MODSEL_15 + GP8_MODSEL_14 + GP8_MODSEL_13 + GP8_MODSEL_12 + GP8_MODSEL_11 + GP8_MODSEL_10 + GP8_MODSEL_9 + GP8_MODSEL_8 + GP8_MODSEL_7 + GP8_MODSEL_6 + GP8_MODSEL_5 + GP8_MODSEL_4 + GP8_MODSEL_3 + GP8_MODSEL_2 + GP8_MODSEL_1 + GP8_MODSEL_0 + )) + }, + { }, +}; + +#define RCAR5_PINMUX_DRIVE_REG(name1, r1, name2, r2, name3, r3) \ + .drvctrl0 = r1, \ + .drvctrl1 = r2, \ + .drvctrl2 = r3, \ + .pins = + +struct rcar5_pinmux_drive_reg { + u32 drvctrl0; + u32 drvctrl1; + u32 drvctrl2; + const u16 pins[32]; +}; + +static const struct rcar5_pinmux_drive_reg pinmux_drive_regs[] = { + { RCAR5_PINMUX_DRIVE_REG("GP0_DRVCTRL0", 0xC1080080, "GP0_DRVCTRL1", 0xC1080084, "GP0_DRVCTRL2", 0xC1080088) { + [ 0] = RCAR_GP_PIN(0, 0), /* GP0_00 */ + [ 1] = RCAR_GP_PIN(0, 1), /* GP0_01 */ + [ 2] = RCAR_GP_PIN(0, 2), /* GP0_02 */ + [ 3] = RCAR_GP_PIN(0, 3), /* STPWT_EXTFXR_A */ + [ 4] = RCAR_GP_PIN(0, 4), /* FXR_CLKOUT1_A */ + [ 5] = RCAR_GP_PIN(0, 5), /* FXR_CLKOUT2_A */ + [ 6] = RCAR_GP_PIN(0, 6), /* CLK_EXTFXR_A */ + [ 7] = RCAR_GP_PIN(0, 7), /* FXR_TXDA_A */ + [ 8] = RCAR_GP_PIN(0, 8), /* FXR_TXENA_N_A */ + [ 9] = RCAR_GP_PIN(0, 9), /* RXDA_EXTFXR_A */ + [10] = RCAR_GP_PIN(0, 10), /* FXR_TXDB_A */ + [11] = RCAR_GP_PIN(0, 11), /* FXR_TXENB_N_A */ + [12] = RCAR_GP_PIN(0, 12), /* RXDB_EXTFXR_A */ + [13] = RCAR_GP_PIN(0, 13), /* MSIOF0_SCK */ + [14] = RCAR_GP_PIN(0, 14), /* MSIOF0_TXD */ + [15] = RCAR_GP_PIN(0, 15), /* MSIOF0_RXD */ + [16] = RCAR_GP_PIN(0, 16), /* MSIOF0_SYNC */ + [17] = RCAR_GP_PIN(0, 17), /* MSIOF0_SS1 */ + [18] = RCAR_GP_PIN(0, 18), /* MSIOF0_SS2 */ + [19] = RCAR_GP_PIN(0, 19), /* MSIOF1_SCK_A */ + [20] = RCAR_GP_PIN(0, 20), /* MSIOF1_TXD_A */ + [21] = RCAR_GP_PIN(0, 21), /* MSIOF1_RXD_A */ + [22] = RCAR_GP_PIN(0, 22), /* MSIOF1_SYNC_A */ + [23] = RCAR_GP_PIN(0, 23), /* MSIOF1_SS1_A */ + [24] = RCAR_GP_PIN(0, 24), /* MSIOF1_SS2_A */ + [25] = RCAR_GP_PIN(0, 25), /* DP0_HOTPLUG */ + [26] = RCAR_GP_PIN(0, 26), /* DP1_HOTPLUG */ + [27] = RCAR_GP_PIN(0, 27), /* DP2_HOTPLUG */ + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { RCAR5_PINMUX_DRIVE_REG("GP1_DRVCTRL0", 0xC1080880, "GP1_DRVCTRL1", 0xC1080884, "GP1_DRVCTRL2", 0xC1080888) { + [ 0] = RCAR_GP_PIN(1, 0), /* CAN0RX_INTP0 */ + [ 1] = RCAR_GP_PIN(1, 1), /* CAN0TX */ + [ 2] = RCAR_GP_PIN(1, 2), /* CAN1RX_INTP1 */ + [ 3] = RCAR_GP_PIN(1, 3), /* CAN1TX */ + [ 4] = RCAR_GP_PIN(1, 4), /* CAN2RX_INTP2 */ + [ 5] = RCAR_GP_PIN(1, 5), /* CAN2TX */ + [ 6] = RCAR_GP_PIN(1, 6), /* CAN3RX_INTP3 */ + [ 7] = RCAR_GP_PIN(1, 7), /* CAN3TX */ + [ 8] = RCAR_GP_PIN(1, 8), /* CAN4RX_INTP4 */ + [ 9] = RCAR_GP_PIN(1, 9), /* CAN4TX */ + [10] = RCAR_GP_PIN(1, 10), /* CAN5RX_INTP5 */ + [11] = RCAR_GP_PIN(1, 11), /* CAN5TX */ + [12] = RCAR_GP_PIN(1, 12), /* CAN6RX_INTP6 */ + [13] = RCAR_GP_PIN(1, 13), /* CAN6TX */ + [14] = RCAR_GP_PIN(1, 14), /* RLIN30RX_INTP16 */ + [15] = RCAR_GP_PIN(1, 15), /* RLIN30TX */ + [16] = RCAR_GP_PIN(1, 16), /* RLIN31RX_INTP17 */ + [17] = RCAR_GP_PIN(1, 17), /* RLIN31TX */ + [18] = RCAR_GP_PIN(1, 18), /* RLIN32RX_INTP18 */ + [19] = RCAR_GP_PIN(1, 19), /* RLIN32TX */ + [20] = RCAR_GP_PIN(1, 20), /* RLIN33RX_INTP19 */ + [21] = RCAR_GP_PIN(1, 21), /* RLIN33TX */ + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { RCAR5_PINMUX_DRIVE_REG("GP2_DRVCTRL0", 0xC1081080, "GP2_DRVCTRL1", 0xC1081084, "GP2_DRVCTRL2", 0xC1081088) { + [ 0] = RCAR_GP_PIN(2, 0), /* RLIN34RX_INTP20_B */ + [ 1] = RCAR_GP_PIN(2, 1), /* RLIN34TX_B */ + [ 2] = RCAR_GP_PIN(2, 2), /* RLIN35RX_INTP21_B */ + [ 3] = RCAR_GP_PIN(2, 3), /* RLIN35TX_B */ + [ 4] = RCAR_GP_PIN(2, 4), /* RLIN36RX_INTP22_B */ + [ 5] = RCAR_GP_PIN(2, 5), /* RLIN36TX_B */ + [ 6] = RCAR_GP_PIN(2, 6), /* RLIN37RX_INTP23_B */ + [ 7] = RCAR_GP_PIN(2, 7), /* RLIN37TX_B */ + [ 8] = RCAR_GP_PIN(2, 8), /* CAN12RX_INTP12_B */ + [ 9] = RCAR_GP_PIN(2, 9), /* CAN12TX_B */ + [10] = RCAR_GP_PIN(2, 10), /* CAN13RX_INTP13_B */ + [11] = RCAR_GP_PIN(2, 11), /* CAN13TX_B */ + [12] = RCAR_GP_PIN(2, 12), /* CAN14RX_INTP14_B */ + [13] = RCAR_GP_PIN(2, 13), /* CAN14TX_B */ + [14] = RCAR_GP_PIN(2, 14), /* CAN15RX_INTP15_B */ + [15] = RCAR_GP_PIN(2, 15), /* CAN15TX_B */ + [16] = RCAR_GP_PIN(2, 16), /* CAN_CLK */ + [17] = RCAR_GP_PIN(2, 17), /* INTP32_B */ + [18] = RCAR_GP_PIN(2, 18), /* INTP33_B */ + [19] = RCAR_GP_PIN(2, 19), /* SCL0 */ + [20] = RCAR_GP_PIN(2, 20), /* SDA0 */ + [21] = RCAR_GP_PIN(2, 21), /* AVS0 */ + [22] = RCAR_GP_PIN(2, 22), /* AVS1 */ + [23] = RCAR_GP_PIN(2, 23), /* EXTCLK0O_B */ + [24] = RCAR_GP_PIN(2, 24), /* TAUD1O0 */ + [25] = RCAR_GP_PIN(2, 25), /* TAUD1O1 */ + [26] = RCAR_GP_PIN(2, 26), /* TAUD1O2 */ + [27] = RCAR_GP_PIN(2, 27), /* TAUD1O3 */ + [28] = RCAR_GP_PIN(2, 28), /* INTP34_B */ + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { RCAR5_PINMUX_DRIVE_REG("GP3_DRVCTRL0", 0xC0800080, "GP3_DRVCTRL1", 0xC0800084, "GP3_DRVCTRL2", 0xC0800088) { + [ 0] = RCAR_GP_PIN(3, 0), /* QSPI0_SPCLK */ + [ 1] = RCAR_GP_PIN(3, 1), /* QSPI0_MOSI_IO0 */ + [ 2] = RCAR_GP_PIN(3, 2), /* QSPI0_MISO_IO1 */ + [ 3] = RCAR_GP_PIN(3, 3), /* QSPI0_IO2 */ + [ 4] = RCAR_GP_PIN(3, 4), /* QSPI0_IO3 */ + [ 5] = RCAR_GP_PIN(3, 5), /* QSPI0_SSL */ + [ 6] = RCAR_GP_PIN(3, 6), /* RPC_RESET_N */ + [ 7] = RCAR_GP_PIN(3, 7), /* RPC_WP_N */ + [ 8] = RCAR_GP_PIN(3, 8), /* RPC_INT_N */ + [ 9] = RCAR_GP_PIN(3, 9), /* QSPI1_SPCLK */ + [10] = RCAR_GP_PIN(3, 10), /* QSPI1_MOSI_IO0 */ + [11] = RCAR_GP_PIN(3, 11), /* QSPI1_MISO_IO1 */ + [12] = RCAR_GP_PIN(3, 12), /* QSPI1_IO2 */ + [13] = RCAR_GP_PIN(3, 13), /* QSPI1_IO3 */ + [14] = RCAR_GP_PIN(3, 14), /* QSPI1_SSL */ + [15] = RCAR_GP_PIN(3, 15), /* ERROROUT_N */ + [16] = RCAR_GP_PIN(3, 16), /* ERRORIN_N */ + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { RCAR5_PINMUX_DRIVE_REG("GP4_DRVCTRL0", 0xC0800880, "GP4_DRVCTRL1", 0xC0800884, "GP4_DRVCTRL2", 0xC0800888) { + [ 0] = RCAR_GP_PIN(4, 0), /* MMC0_SD_CLK */ + [ 1] = RCAR_GP_PIN(4, 1), /* MMC0_SD_CMD */ + [ 2] = RCAR_GP_PIN(4, 2), /* MMC0_SD_D0 */ + [ 3] = RCAR_GP_PIN(4, 3), /* MMC0_SD_D1 */ + [ 4] = RCAR_GP_PIN(4, 4), /* MMC0_SD_D2 */ + [ 5] = RCAR_GP_PIN(4, 5), /* MMC0_SD_D3 */ + [ 6] = RCAR_GP_PIN(4, 6), /* MMC0_D4 */ + [ 7] = RCAR_GP_PIN(4, 7), /* MMC0_D5 */ + [ 8] = RCAR_GP_PIN(4, 8), /* MMC0_D6 */ + [ 9] = RCAR_GP_PIN(4, 9), /* MMC0_D7 */ + [10] = RCAR_GP_PIN(4, 10), /* MMC0_DS */ + [11] = RCAR_GP_PIN(4, 11), /* SD0_WP */ + [12] = RCAR_GP_PIN(4, 12), /* SD0_CD */ + [13] = RCAR_GP_PIN(4, 13), /* ERRORIN_N */ + [14] = RCAR_GP_PIN(4, 14), /* PCIE60_CLKREQ_N */ + [15] = RCAR_GP_PIN(4, 15), /* PCIE61_CLKREQ_N */ + [16] = SH_PFC_PIN_NONE, + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { RCAR5_PINMUX_DRIVE_REG("GP5_DRVCTRL0", 0xC0400080, "GP5_DRVCTRL1", 0xC0400084, "GP5_DRVCTRL2", 0xC0400088) { + [ 0] = RCAR_GP_PIN(5, 0), /* HTX0 */ + [ 1] = RCAR_GP_PIN(5, 1), /* HRX0 */ + [ 2] = RCAR_GP_PIN(5, 2), /* HRTS0_N */ + [ 3] = RCAR_GP_PIN(5, 3), /* HCTS0_N */ + [ 4] = RCAR_GP_PIN(5, 4), /* HSCK0 */ + [ 5] = RCAR_GP_PIN(5, 5), /* SCIF_CLK */ + [ 6] = RCAR_GP_PIN(5, 6), /* HTX1 */ + [ 7] = RCAR_GP_PIN(5, 7), /* HRX1 */ + [ 8] = RCAR_GP_PIN(5, 8), /* HRTS1_N */ + [ 9] = RCAR_GP_PIN(5, 9), /* HCTS1_N */ + [10] = RCAR_GP_PIN(5, 10), /* HSCK1 */ + [11] = RCAR_GP_PIN(5, 11), /* IRQ0_A */ + [12] = RCAR_GP_PIN(5, 12), /* IRQ1_A */ + [13] = RCAR_GP_PIN(5, 13), /* IRQ2_A */ + [14] = RCAR_GP_PIN(5, 14), /* IRQ3_A */ + [15] = RCAR_GP_PIN(5, 15), /* TCLK1 */ + [16] = RCAR_GP_PIN(5, 16), /* TCLK2 */ + [17] = RCAR_GP_PIN(5, 17), /* TCLK3 */ + [18] = RCAR_GP_PIN(5, 18), /* TCLK4 */ + [19] = RCAR_GP_PIN(5, 19), /* TPU0TO0 */ + [20] = RCAR_GP_PIN(5, 20), /* TPU0TO1 */ + [21] = RCAR_GP_PIN(5, 21), /* TPU0TO2 */ + [22] = RCAR_GP_PIN(5, 22), /* TPU0TO3 */ + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { RCAR5_PINMUX_DRIVE_REG("GP6_DRVCTRL0", 0xC0400880, "GP6_DRVCTRL1", 0xC0400884, "GP6_DRVCTRL2", 0xC0400888) { + [ 0] = RCAR_GP_PIN(6, 0), /* RIF6_D0 */ + [ 1] = RCAR_GP_PIN(6, 1), /* RIF6_D1 */ + [ 2] = RCAR_GP_PIN(6, 2), /* RIF6_SYNC */ + [ 3] = RCAR_GP_PIN(6, 3), /* RIF6_CLK */ + [ 4] = RCAR_GP_PIN(6, 4), /* MSIOF7_SCK_A */ + [ 5] = RCAR_GP_PIN(6, 5), /* MSIOF7_TXD_A */ + [ 6] = RCAR_GP_PIN(6, 6), /* MSIOF7_RXD_A */ + [ 7] = RCAR_GP_PIN(6, 7), /* MSIOF7_SYNC_A */ + [ 8] = RCAR_GP_PIN(6, 8), /* MSIOF7_SS1_A */ + [ 9] = RCAR_GP_PIN(6, 9), /* MSIOF7_SS2_A */ + [10] = RCAR_GP_PIN(6, 10), /* MSIOF4_SCK_B */ + [11] = RCAR_GP_PIN(6, 11), /* MSIOF4_TXD_B */ + [12] = RCAR_GP_PIN(6, 12), /* MSIOF4_RXD_B */ + [13] = RCAR_GP_PIN(6, 13), /* MSIOF4_SYNC_B */ + [14] = RCAR_GP_PIN(6, 14), /* MSIOF4_SS1_B */ + [15] = RCAR_GP_PIN(6, 15), /* MSIOF4_SS2_B */ + [16] = RCAR_GP_PIN(6, 16), /* SSI0_SCK */ + [17] = RCAR_GP_PIN(6, 17), /* SSI0_WS */ + [18] = RCAR_GP_PIN(6, 18), /* SSI0_SD */ + [19] = RCAR_GP_PIN(6, 19), /* AUDIO0_CLKOUT0 */ + [20] = RCAR_GP_PIN(6, 20), /* AUDIO0_CLKOUT1 */ + [21] = RCAR_GP_PIN(6, 21), /* SSI1_SCK */ + [22] = RCAR_GP_PIN(6, 22), /* SSI1_WS */ + [23] = RCAR_GP_PIN(6, 23), /* SSI1_SD */ + [24] = RCAR_GP_PIN(6, 24), /* AUDIO0_CLKOUT2 */ + [25] = RCAR_GP_PIN(6, 25), /* AUDIO0_CLKOUT3 */ + [26] = RCAR_GP_PIN(6, 26), /* SSI2_SCK */ + [27] = RCAR_GP_PIN(6, 27), /* SSI2_WS */ + [28] = RCAR_GP_PIN(6, 28), /* SSI2_SD */ + [29] = RCAR_GP_PIN(6, 29), /* AUDIO1_CLKOUT0 */ + [30] = RCAR_GP_PIN(6, 30), /* AUDIO1_CLKOUT1 */ + [31] = SH_PFC_PIN_NONE, + } }, + { RCAR5_PINMUX_DRIVE_REG("GP7_DRVCTRL0", 0xC0401080, "GP7_DRVCTRL1", 0xC0401084, "GP7_DRVCTRL2", 0xC0401088) { + [ 0] = RCAR_GP_PIN(7, 0), /* SSI3_SCK */ + [ 1] = RCAR_GP_PIN(7, 1), /* SSI3_WS */ + [ 2] = RCAR_GP_PIN(7, 2), /* SSI3_SD */ + [ 3] = RCAR_GP_PIN(7, 3), /* AUDIO1_CLKOUT2 */ + [ 4] = RCAR_GP_PIN(7, 4), /* AUDIO1_CLKOUT3 */ + [ 5] = RCAR_GP_PIN(7, 5), /* SSI4_SCK */ + [ 6] = RCAR_GP_PIN(7, 6), /* SSI4_WS */ + [ 7] = RCAR_GP_PIN(7, 7), /* SSI4_SD */ + [ 8] = RCAR_GP_PIN(7, 8), /* AUDIO_CLKA_A */ + [ 9] = RCAR_GP_PIN(7, 9), /* SSI5_SCK */ + [10] = RCAR_GP_PIN(7, 10), /* SSI5_WS */ + [11] = RCAR_GP_PIN(7, 11), /* SSI5_SD */ + [12] = RCAR_GP_PIN(7, 12), /* AUDIO_CLKB_A */ + [13] = RCAR_GP_PIN(7, 13), /* SSI6_SCK */ + [14] = RCAR_GP_PIN(7, 14), /* SSI6_WS */ + [15] = RCAR_GP_PIN(7, 15), /* SSI6_SD */ + [16] = RCAR_GP_PIN(7, 16), /* AUDIO_CLKC_A */ + [17] = RCAR_GP_PIN(7, 17), /* MSIOF5_SCK */ + [18] = RCAR_GP_PIN(7, 18), /* GP07_18 */ + [19] = RCAR_GP_PIN(7, 19), /* GP07_19 */ + [20] = RCAR_GP_PIN(7, 20), /* MSIOF5_TXD */ + [21] = RCAR_GP_PIN(7, 21), /* MSIOF5_RXD */ + [22] = RCAR_GP_PIN(7, 22), /* MSIOF5_SYNC */ + [23] = RCAR_GP_PIN(7, 23), /* MSIOF5_SS1 */ + [24] = RCAR_GP_PIN(7, 24), /* MSIOF5_SS2 */ + [25] = RCAR_GP_PIN(7, 25), /* MSIOF6_SCK_B */ + [26] = RCAR_GP_PIN(7, 26), /* MSIOF6_TXD_B */ + [27] = RCAR_GP_PIN(7, 27), /* MSIOF6_RXD_B */ + [28] = RCAR_GP_PIN(7, 28), /* MSIOF6_SYNC_B */ + [29] = RCAR_GP_PIN(7, 29), /* MSIOF6_SS1_B */ + [30] = RCAR_GP_PIN(7, 30), /* MSIOF6_SS2_B */ + [31] = SH_PFC_PIN_NONE, + } }, + { RCAR5_PINMUX_DRIVE_REG("GP8_DRVCTRL0", 0xC0401880, "GP8_DRVCTRL1", 0xC0401884, "GP8_DRVCTRL2", 0xC0401888) { + [ 0] = RCAR_GP_PIN(8, 0), /* SCL1 */ + [ 1] = RCAR_GP_PIN(8, 1), /* SDA1 */ + [ 2] = RCAR_GP_PIN(8, 2), /* SCL2 */ + [ 3] = RCAR_GP_PIN(8, 3), /* SDA2 */ + [ 4] = RCAR_GP_PIN(8, 4), /* SCL3 */ + [ 5] = RCAR_GP_PIN(8, 5), /* SDA3 */ + [ 6] = RCAR_GP_PIN(8, 6), /* SCL4 */ + [ 7] = RCAR_GP_PIN(8, 7), /* SDA4 */ + [ 8] = RCAR_GP_PIN(8, 8), /* SCL5 */ + [ 9] = RCAR_GP_PIN(8, 9), /* SDA5 */ + [10] = RCAR_GP_PIN(8, 10), /* SCL6 */ + [11] = RCAR_GP_PIN(8, 11), /* SDA6 */ + [12] = RCAR_GP_PIN(8, 12), /* SCL7 */ + [13] = RCAR_GP_PIN(8, 13), /* SDA7 */ + [14] = RCAR_GP_PIN(8, 14), /* SCL8 */ + [15] = RCAR_GP_PIN(8, 15), /* SDA8 */ + [16] = SH_PFC_PIN_NONE, + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = RCAR_GP_PIN(8, 26), /* S3CL0 */ + [27] = RCAR_GP_PIN(8, 27), /* S3DA0 */ + [28] = RCAR_GP_PIN(8, 28), /* S3CL1 */ + [29] = RCAR_GP_PIN(8, 29), /* S3DA1 */ + [30] = RCAR_GP_PIN(8, 30), /* S3CL2 */ + [31] = RCAR_GP_PIN(8, 31), /* S3DA2 */ + } }, + { RCAR5_PINMUX_DRIVE_REG("GP9_DRVCTRL0", 0xC9B00080, "GP9_DRVCTRL1", 0xC9B00084, "GP9_DRVCTRL2", 0xC9B00088) { + [ 0] = RCAR_GP_PIN(9, 0), /* ETHES0_PPS */ + [ 1] = RCAR_GP_PIN(9, 1), /* ETHES0_CAPTURE */ + [ 2] = RCAR_GP_PIN(9, 2), /* ETHES0_MATCH */ + [ 3] = RCAR_GP_PIN(9, 3), /* ETHES4_PPS */ + [ 4] = RCAR_GP_PIN(9, 4), /* ETHES4_CAPTURE */ + [ 5] = RCAR_GP_PIN(9, 5), /* ETHES4_MATCH */ + [ 6] = RCAR_GP_PIN(9, 6), /* ETH25G0_MDIO */ + [ 7] = RCAR_GP_PIN(9, 7), /* ETH25G0_MDC */ + [ 8] = RCAR_GP_PIN(9, 8), /* ETH25G0_LINK */ + [ 9] = RCAR_GP_PIN(9, 9), /* ETH25G0_PHYINT */ + [10] = RCAR_GP_PIN(9, 10), /* ETH10G0_MDIO */ + [11] = RCAR_GP_PIN(9, 11), /* ETH10G0_MDC */ + [12] = RCAR_GP_PIN(9, 12), /* ETH10G0_LINK */ + [13] = RCAR_GP_PIN(9, 13), /* ETH10G0_PHYINT */ + [14] = RCAR_GP_PIN(9, 14), /* RSW3_PPS */ + [15] = RCAR_GP_PIN(9, 15), /* RSW3_CAPTURE */ + [16] = RCAR_GP_PIN(9, 16), /* RSW3_MATCH */ + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { RCAR5_PINMUX_DRIVE_REG("GP10_DRVCTRL0", 0xC9B00880, "GP10_DRVCTRL1", 0xC9B00884, "GP10_DRVCTRL2", 0xC9B00888) { + [ 0] = RCAR_GP_PIN(10, 0), /* USB0_PWEN */ + [ 1] = RCAR_GP_PIN(10, 1), /* USB0_OVC */ + [ 2] = RCAR_GP_PIN(10, 2), /* USB0_VBUS_VALID */ + [ 3] = RCAR_GP_PIN(10, 3), /* USB1_PWEN */ + [ 4] = RCAR_GP_PIN(10, 4), /* USB1_OVC */ + [ 5] = RCAR_GP_PIN(10, 5), /* USB1_VBUS_VALID */ + [ 6] = RCAR_GP_PIN(10, 6), /* USB2_PWEN */ + [ 7] = RCAR_GP_PIN(10, 7), /* USB2_OVC */ + [ 8] = RCAR_GP_PIN(10, 8), /* USB2_VBUS_VALID */ + [ 9] = RCAR_GP_PIN(10, 9), /* USB3_PWEN */ + [10] = RCAR_GP_PIN(10, 10), /* USB3_OVC */ + [11] = RCAR_GP_PIN(10, 11), /* USB3_VBUS_VALID */ + [12] = RCAR_GP_PIN(10, 12), /* PCIE40_CLKREQ_N */ + [13] = RCAR_GP_PIN(10, 13), /* PCIE41_CLKREQ_N */ + [14] = SH_PFC_PIN_NONE, + [15] = SH_PFC_PIN_NONE, + [16] = SH_PFC_PIN_NONE, + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { /* sentinel */ }, +}; + +enum ioctrl_regs { + GP0_TDSEL0, + GP0_TDSEL1, + GP1_TDSEL0, + GP1_TDSEL1, + GP2_TDSEL0, + GP2_TDSEL1, + GP3_TDSEL0, + GP3_TDSEL1, + GP4_TDSEL0, + GP4_TDSEL1, + GP5_TDSEL0, + GP5_TDSEL1, + GP6_TDSEL0, + GP6_TDSEL1, + GP7_TDSEL0, + GP7_TDSEL1, + GP8_TDSEL0, + GP8_TDSEL1, + GP9_TDSEL0, + GP9_TDSEL1, + GP10_TDSEL0, + GP10_TDSEL1, +}; + +static const struct pinmux_ioctrl_reg pinmux_ioctrl_regs[] = { + [GP0_TDSEL0] = { 0xC1080094, }, + [GP0_TDSEL1] = { 0xC1080098, }, + [GP1_TDSEL0] = { 0xC1080894, }, + [GP1_TDSEL1] = { 0xC1080898, }, + [GP2_TDSEL0] = { 0xC1081094, }, + [GP2_TDSEL1] = { 0xC1081098, }, + [GP3_TDSEL0] = { 0xC0800094, }, + [GP3_TDSEL1] = { 0xC0800098, }, + [GP4_TDSEL0] = { 0xC0800894, }, + [GP4_TDSEL1] = { 0xC0800898, }, + [GP5_TDSEL0] = { 0xC0400094, }, + [GP5_TDSEL1] = { 0xC0400098, }, + [GP6_TDSEL0] = { 0xC0400894, }, + [GP6_TDSEL1] = { 0xC0400898, }, + [GP7_TDSEL0] = { 0xC0401094, }, + [GP7_TDSEL1] = { 0xC0401098, }, + [GP8_TDSEL0] = { 0xC0401894, }, + [GP8_TDSEL1] = { 0xC0401898, }, + [GP9_TDSEL0] = { 0xC9B00094, }, + [GP9_TDSEL1] = { 0xC9B00098, }, + [GP10_TDSEL0] = { 0xC9B00894, }, + [GP10_TDSEL1] = { 0xC9B00898, }, + { /* sentinel */ } +}; + +static const struct pinmux_bias_reg pinmux_bias_regs[] = { + { PINMUX_BIAS_REG("GP0_PULLEN", 0xC10800C0, "GP0_PUDSEL", 0xC10800C4) { + [ 0] = RCAR_GP_PIN(0, 0), /* GP0_00 */ + [ 1] = RCAR_GP_PIN(0, 1), /* GP0_01 */ + [ 2] = RCAR_GP_PIN(0, 2), /* GP0_02 */ + [ 3] = RCAR_GP_PIN(0, 3), /* STPWT_EXTFXR_A */ + [ 4] = RCAR_GP_PIN(0, 4), /* FXR_CLKOUT1_A */ + [ 5] = RCAR_GP_PIN(0, 5), /* FXR_CLKOUT2_A */ + [ 6] = RCAR_GP_PIN(0, 6), /* CLK_EXTFXR_A */ + [ 7] = RCAR_GP_PIN(0, 7), /* FXR_TXDA_A */ + [ 8] = RCAR_GP_PIN(0, 8), /* FXR_TXENA_N_A */ + [ 9] = RCAR_GP_PIN(0, 9), /* RXDA_EXTFXR_A */ + [10] = RCAR_GP_PIN(0, 10), /* FXR_TXDB_A */ + [11] = RCAR_GP_PIN(0, 11), /* FXR_TXENB_N_A */ + [12] = RCAR_GP_PIN(0, 12), /* RXDB_EXTFXR_A */ + [13] = RCAR_GP_PIN(0, 13), /* MSIOF0_SCK */ + [14] = RCAR_GP_PIN(0, 14), /* MSIOF0_TXD */ + [15] = RCAR_GP_PIN(0, 15), /* MSIOF0_RXD */ + [16] = RCAR_GP_PIN(0, 16), /* MSIOF0_SYNC */ + [17] = RCAR_GP_PIN(0, 17), /* MSIOF0_SS1 */ + [18] = RCAR_GP_PIN(0, 18), /* MSIOF0_SS2 */ + [19] = RCAR_GP_PIN(0, 19), /* MSIOF1_SCK_A */ + [20] = RCAR_GP_PIN(0, 20), /* MSIOF1_TXD_A */ + [21] = RCAR_GP_PIN(0, 21), /* MSIOF1_RXD_A */ + [22] = RCAR_GP_PIN(0, 22), /* MSIOF1_SYNC_A */ + [23] = RCAR_GP_PIN(0, 23), /* MSIOF1_SS1_A */ + [24] = RCAR_GP_PIN(0, 24), /* MSIOF1_SS2_A */ + [25] = RCAR_GP_PIN(0, 25), /* DP0_HOTPLUG */ + [26] = RCAR_GP_PIN(0, 26), /* DP1_HOTPLUG */ + [27] = RCAR_GP_PIN(0, 27), /* DP2_HOTPLUG */ + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { PINMUX_BIAS_REG("GP1_PULLEN", 0xC10808C0, "GP1_PUDSEL", 0xC10808C4) { + [ 0] = RCAR_GP_PIN(1, 0), /* CAN0RX_INTP0 */ + [ 1] = RCAR_GP_PIN(1, 1), /* CAN0TX */ + [ 2] = RCAR_GP_PIN(1, 2), /* CAN1RX_INTP1 */ + [ 3] = RCAR_GP_PIN(1, 3), /* CAN1TX */ + [ 4] = RCAR_GP_PIN(1, 4), /* CAN2RX_INTP2 */ + [ 5] = RCAR_GP_PIN(1, 5), /* CAN2TX */ + [ 6] = RCAR_GP_PIN(1, 6), /* CAN3RX_INTP3 */ + [ 7] = RCAR_GP_PIN(1, 7), /* CAN3TX */ + [ 8] = RCAR_GP_PIN(1, 8), /* CAN4RX_INTP4 */ + [ 9] = RCAR_GP_PIN(1, 9), /* CAN4TX */ + [10] = RCAR_GP_PIN(1, 10), /* CAN5RX_INTP5 */ + [11] = RCAR_GP_PIN(1, 11), /* CAN5TX */ + [12] = RCAR_GP_PIN(1, 12), /* CAN6RX_INTP6 */ + [13] = RCAR_GP_PIN(1, 13), /* CAN6TX */ + [14] = RCAR_GP_PIN(1, 14), /* RLIN30RX_INTP16 */ + [15] = RCAR_GP_PIN(1, 15), /* RLIN30TX */ + [16] = RCAR_GP_PIN(1, 16), /* RLIN31RX_INTP17 */ + [17] = RCAR_GP_PIN(1, 17), /* RLIN31TX */ + [18] = RCAR_GP_PIN(1, 18), /* RLIN32RX_INTP18 */ + [19] = RCAR_GP_PIN(1, 19), /* RLIN32TX */ + [20] = RCAR_GP_PIN(1, 20), /* RLIN33RX_INTP19 */ + [21] = RCAR_GP_PIN(1, 21), /* RLIN33TX */ + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { PINMUX_BIAS_REG("GP2_PULLEN", 0xC10810C0, "GP2_PUDSEL", 0xC10810C4) { + [ 0] = RCAR_GP_PIN(2, 0), /* RLIN34RX_INTP20_B */ + [ 1] = RCAR_GP_PIN(2, 1), /* RLIN34TX_B */ + [ 2] = RCAR_GP_PIN(2, 2), /* RLIN35RX_INTP21_B */ + [ 3] = RCAR_GP_PIN(2, 3), /* RLIN35TX_B */ + [ 4] = RCAR_GP_PIN(2, 4), /* RLIN36RX_INTP22_B */ + [ 5] = RCAR_GP_PIN(2, 5), /* RLIN36TX_B */ + [ 6] = RCAR_GP_PIN(2, 6), /* RLIN37RX_INTP23_B */ + [ 7] = RCAR_GP_PIN(2, 7), /* RLIN37TX_B */ + [ 8] = RCAR_GP_PIN(2, 8), /* CAN12RX_INTP12_B */ + [ 9] = RCAR_GP_PIN(2, 9), /* CAN12TX_B */ + [10] = RCAR_GP_PIN(2, 10), /* CAN13RX_INTP13_B */ + [11] = RCAR_GP_PIN(2, 11), /* CAN13TX_B */ + [12] = RCAR_GP_PIN(2, 12), /* CAN14RX_INTP14_B */ + [13] = RCAR_GP_PIN(2, 13), /* CAN14TX_B */ + [14] = RCAR_GP_PIN(2, 14), /* CAN15RX_INTP15_B */ + [15] = RCAR_GP_PIN(2, 15), /* CAN15TX_B */ + [16] = RCAR_GP_PIN(2, 16), /* CAN_CLK */ + [17] = RCAR_GP_PIN(2, 17), /* INTP32_B */ + [18] = RCAR_GP_PIN(2, 18), /* INTP33_B */ + [19] = RCAR_GP_PIN(2, 19), /* SCL0 */ + [20] = RCAR_GP_PIN(2, 20), /* SDA0 */ + [21] = RCAR_GP_PIN(2, 21), /* AVS0 */ + [22] = RCAR_GP_PIN(2, 22), /* AVS1 */ + [23] = RCAR_GP_PIN(2, 23), /* EXTCLK0O_B */ + [24] = RCAR_GP_PIN(2, 24), /* TAUD1O0 */ + [25] = RCAR_GP_PIN(2, 25), /* TAUD1O1 */ + [26] = RCAR_GP_PIN(2, 26), /* TAUD1O2 */ + [27] = RCAR_GP_PIN(2, 27), /* TAUD1O3 */ + [28] = RCAR_GP_PIN(2, 28), /* INTP34_B */ + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { PINMUX_BIAS_REG("GP3_PULLEN", 0xC08000C0, "GP3_PUDSEL", 0xC08000C4) { + [ 0] = RCAR_GP_PIN(3, 0), /* QSPI0_SPCLK */ + [ 1] = RCAR_GP_PIN(3, 1), /* QSPI0_MOSI_IO0 */ + [ 2] = RCAR_GP_PIN(3, 2), /* QSPI0_MISO_IO1 */ + [ 3] = RCAR_GP_PIN(3, 3), /* QSPI0_IO2 */ + [ 4] = RCAR_GP_PIN(3, 4), /* QSPI0_IO3 */ + [ 5] = RCAR_GP_PIN(3, 5), /* QSPI0_SSL */ + [ 6] = RCAR_GP_PIN(3, 6), /* RPC_RESET_N */ + [ 7] = RCAR_GP_PIN(3, 7), /* RPC_WP_N */ + [ 8] = RCAR_GP_PIN(3, 8), /* RPC_INT_N */ + [ 9] = RCAR_GP_PIN(3, 9), /* QSPI1_SPCLK */ + [10] = RCAR_GP_PIN(3, 10), /* QSPI1_MOSI_IO0 */ + [11] = RCAR_GP_PIN(3, 11), /* QSPI1_MISO_IO1 */ + [12] = RCAR_GP_PIN(3, 12), /* QSPI1_IO2 */ + [13] = RCAR_GP_PIN(3, 13), /* QSPI1_IO3 */ + [14] = RCAR_GP_PIN(3, 14), /* QSPI1_SSL */ + [15] = RCAR_GP_PIN(3, 15), /* ERROROUT_N */ + [16] = RCAR_GP_PIN(3, 16), /* ERRORIN_N */ + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { PINMUX_BIAS_REG("GP4_PULLEN", 0xC08008C0, "GP4_PUDSEL", 0xC08008C4) { + [ 0] = RCAR_GP_PIN(4, 0), /* MMC0_SD_CLK */ + [ 1] = RCAR_GP_PIN(4, 1), /* MMC0_SD_CMD */ + [ 2] = RCAR_GP_PIN(4, 2), /* MMC0_SD_D0 */ + [ 3] = RCAR_GP_PIN(4, 3), /* MMC0_SD_D1 */ + [ 4] = RCAR_GP_PIN(4, 4), /* MMC0_SD_D2 */ + [ 5] = RCAR_GP_PIN(4, 5), /* MMC0_SD_D3 */ + [ 6] = RCAR_GP_PIN(4, 6), /* MMC0_D4 */ + [ 7] = RCAR_GP_PIN(4, 7), /* MMC0_D5 */ + [ 8] = RCAR_GP_PIN(4, 8), /* MMC0_D6 */ + [ 9] = RCAR_GP_PIN(4, 9), /* MMC0_D7 */ + [10] = RCAR_GP_PIN(4, 10), /* MMC0_DS */ + [11] = RCAR_GP_PIN(4, 11), /* SD0_WP */ + [12] = RCAR_GP_PIN(4, 12), /* SD0_CD */ + [13] = RCAR_GP_PIN(4, 13), /* ERRORIN_N */ + [14] = RCAR_GP_PIN(4, 14), /* PCIE60_CLKREQ_N */ + [15] = RCAR_GP_PIN(4, 15), /* PCIE61_CLKREQ_N */ + [16] = SH_PFC_PIN_NONE, + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { PINMUX_BIAS_REG("GP5_PULLEN", 0xC04000C0, "GP5_PUDSEL", 0xC04000C4) { + [ 0] = RCAR_GP_PIN(5, 0), /* HTX0 */ + [ 1] = RCAR_GP_PIN(5, 1), /* HRX0 */ + [ 2] = RCAR_GP_PIN(5, 2), /* HRTS0_N */ + [ 3] = RCAR_GP_PIN(5, 3), /* HCTS0_N */ + [ 4] = RCAR_GP_PIN(5, 4), /* HSCK0 */ + [ 5] = RCAR_GP_PIN(5, 5), /* SCIF_CLK */ + [ 6] = RCAR_GP_PIN(5, 6), /* HTX1 */ + [ 7] = RCAR_GP_PIN(5, 7), /* HRX1 */ + [ 8] = RCAR_GP_PIN(5, 8), /* HRTS1_N */ + [ 9] = RCAR_GP_PIN(5, 9), /* HCTS1_N */ + [10] = RCAR_GP_PIN(5, 10), /* HSCK1 */ + [11] = RCAR_GP_PIN(5, 11), /* IRQ0_A */ + [12] = RCAR_GP_PIN(5, 12), /* IRQ1_A */ + [13] = RCAR_GP_PIN(5, 13), /* IRQ2_A */ + [14] = RCAR_GP_PIN(5, 14), /* IRQ3_A */ + [15] = RCAR_GP_PIN(5, 15), /* TCLK1 */ + [16] = RCAR_GP_PIN(5, 16), /* TCLK2 */ + [17] = RCAR_GP_PIN(5, 17), /* TCLK3 */ + [18] = RCAR_GP_PIN(5, 18), /* TCLK4 */ + [19] = RCAR_GP_PIN(5, 19), /* TPU0TO0 */ + [20] = RCAR_GP_PIN(5, 20), /* TPU0TO1 */ + [21] = RCAR_GP_PIN(5, 21), /* TPU0TO2 */ + [22] = RCAR_GP_PIN(5, 22), /* TPU0TO3 */ + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { PINMUX_BIAS_REG("GP6_PULLEN", 0xC04008C0, "GP6_PUDSEL", 0xC04008C4) { + [ 0] = RCAR_GP_PIN(6, 0), /* RIF6_D0 */ + [ 1] = RCAR_GP_PIN(6, 1), /* RIF6_D1 */ + [ 2] = RCAR_GP_PIN(6, 2), /* RIF6_SYNC */ + [ 3] = RCAR_GP_PIN(6, 3), /* RIF6_CLK */ + [ 4] = RCAR_GP_PIN(6, 4), /* MSIOF7_SCK_A */ + [ 5] = RCAR_GP_PIN(6, 5), /* MSIOF7_TXD_A */ + [ 6] = RCAR_GP_PIN(6, 6), /* MSIOF7_RXD_A */ + [ 7] = RCAR_GP_PIN(6, 7), /* MSIOF7_SYNC_A */ + [ 8] = RCAR_GP_PIN(6, 8), /* MSIOF7_SS1_A */ + [ 9] = RCAR_GP_PIN(6, 9), /* MSIOF7_SS2_A */ + [10] = RCAR_GP_PIN(6, 10), /* MSIOF4_SCK_B */ + [11] = RCAR_GP_PIN(6, 11), /* MSIOF4_TXD_B */ + [12] = RCAR_GP_PIN(6, 12), /* MSIOF4_RXD_B */ + [13] = RCAR_GP_PIN(6, 13), /* MSIOF4_SYNC_B */ + [14] = RCAR_GP_PIN(6, 14), /* MSIOF4_SS1_B */ + [15] = RCAR_GP_PIN(6, 15), /* MSIOF4_SS2_B */ + [16] = RCAR_GP_PIN(6, 16), /* SSI0_SCK */ + [17] = RCAR_GP_PIN(6, 17), /* SSI0_WS */ + [18] = RCAR_GP_PIN(6, 18), /* SSI0_SD */ + [19] = RCAR_GP_PIN(6, 19), /* AUDIO0_CLKOUT0 */ + [20] = RCAR_GP_PIN(6, 20), /* AUDIO0_CLKOUT1 */ + [21] = RCAR_GP_PIN(6, 21), /* SSI1_SCK */ + [22] = RCAR_GP_PIN(6, 22), /* SSI1_WS */ + [23] = RCAR_GP_PIN(6, 23), /* SSI1_SD */ + [24] = RCAR_GP_PIN(6, 24), /* AUDIO0_CLKOUT2 */ + [25] = RCAR_GP_PIN(6, 25), /* AUDIO0_CLKOUT3 */ + [26] = RCAR_GP_PIN(6, 26), /* SSI2_SCK */ + [27] = RCAR_GP_PIN(6, 27), /* SSI2_WS */ + [28] = RCAR_GP_PIN(6, 28), /* SSI2_SD */ + [29] = RCAR_GP_PIN(6, 29), /* AUDIO1_CLKOUT0 */ + [30] = RCAR_GP_PIN(6, 30), /* AUDIO1_CLKOUT1 */ + [31] = SH_PFC_PIN_NONE, + } }, + { PINMUX_BIAS_REG("GP7_PULLEN", 0xC04010C0, "GP7_PUDSEL", 0xC04010C4) { + [ 0] = RCAR_GP_PIN(7, 0), /* SSI3_SCK */ + [ 1] = RCAR_GP_PIN(7, 1), /* SSI3_WS */ + [ 2] = RCAR_GP_PIN(7, 2), /* SSI3_SD */ + [ 3] = RCAR_GP_PIN(7, 3), /* AUDIO1_CLKOUT2 */ + [ 4] = RCAR_GP_PIN(7, 4), /* AUDIO1_CLKOUT3 */ + [ 5] = RCAR_GP_PIN(7, 5), /* SSI4_SCK */ + [ 6] = RCAR_GP_PIN(7, 6), /* SSI4_WS */ + [ 7] = RCAR_GP_PIN(7, 7), /* SSI4_SD */ + [ 8] = RCAR_GP_PIN(7, 8), /* AUDIO_CLKA_A */ + [ 9] = RCAR_GP_PIN(7, 9), /* SSI5_SCK */ + [10] = RCAR_GP_PIN(7, 10), /* SSI5_WS */ + [11] = RCAR_GP_PIN(7, 11), /* SSI5_SD */ + [12] = RCAR_GP_PIN(7, 12), /* AUDIO_CLKB_A */ + [13] = RCAR_GP_PIN(7, 13), /* SSI6_SCK */ + [14] = RCAR_GP_PIN(7, 14), /* SSI6_WS */ + [15] = RCAR_GP_PIN(7, 15), /* SSI6_SD */ + [16] = RCAR_GP_PIN(7, 16), /* AUDIO_CLKC_A */ + [17] = RCAR_GP_PIN(7, 17), /* MSIOF5_SCK */ + [18] = RCAR_GP_PIN(7, 18), /* GP07_18 */ + [19] = RCAR_GP_PIN(7, 19), /* GP07_19 */ + [20] = RCAR_GP_PIN(7, 20), /* MSIOF5_TXD */ + [21] = RCAR_GP_PIN(7, 21), /* MSIOF5_RXD */ + [22] = RCAR_GP_PIN(7, 22), /* MSIOF5_SYNC */ + [23] = RCAR_GP_PIN(7, 23), /* MSIOF5_SS1 */ + [24] = RCAR_GP_PIN(7, 24), /* MSIOF5_SS2 */ + [25] = RCAR_GP_PIN(7, 25), /* MSIOF6_SCK_B */ + [26] = RCAR_GP_PIN(7, 26), /* MSIOF6_TXD_B */ + [27] = RCAR_GP_PIN(7, 27), /* MSIOF6_RXD_B */ + [28] = RCAR_GP_PIN(7, 28), /* MSIOF6_SYNC_B */ + [29] = RCAR_GP_PIN(7, 29), /* MSIOF6_SS1_B */ + [30] = RCAR_GP_PIN(7, 30), /* MSIOF6_SS2_B */ + [31] = SH_PFC_PIN_NONE, + } }, + { PINMUX_BIAS_REG("GP8_PULLEN", 0xC04018C0, "GP8_PUDSEL", 0xC04018C4) { + [ 0] = RCAR_GP_PIN(8, 0), /* SCL1 */ + [ 1] = RCAR_GP_PIN(8, 1), /* SDA1 */ + [ 2] = RCAR_GP_PIN(8, 2), /* SCL2 */ + [ 3] = RCAR_GP_PIN(8, 3), /* SDA2 */ + [ 4] = RCAR_GP_PIN(8, 4), /* SCL3 */ + [ 5] = RCAR_GP_PIN(8, 5), /* SDA3 */ + [ 6] = RCAR_GP_PIN(8, 6), /* SCL4 */ + [ 7] = RCAR_GP_PIN(8, 7), /* SDA4 */ + [ 8] = RCAR_GP_PIN(8, 8), /* SCL5 */ + [ 9] = RCAR_GP_PIN(8, 9), /* SDA5 */ + [10] = RCAR_GP_PIN(8, 10), /* SCL6 */ + [11] = RCAR_GP_PIN(8, 11), /* SDA6 */ + [12] = RCAR_GP_PIN(8, 12), /* SCL7 */ + [13] = RCAR_GP_PIN(8, 13), /* SDA7 */ + [14] = RCAR_GP_PIN(8, 14), /* SCL8 */ + [15] = RCAR_GP_PIN(8, 15), /* SDA8 */ + [16] = SH_PFC_PIN_NONE, + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = RCAR_GP_PIN(8, 26), /* S3CL0 */ + [27] = RCAR_GP_PIN(8, 27), /* S3DA0 */ + [28] = RCAR_GP_PIN(8, 28), /* S3CL1 */ + [29] = RCAR_GP_PIN(8, 29), /* S3DA1 */ + [30] = RCAR_GP_PIN(8, 30), /* S3CL2 */ + [31] = RCAR_GP_PIN(8, 31), /* S3DA2 */ + } }, + { PINMUX_BIAS_REG("GP9_PULLEN", 0xC9B000C0, "GP9_PUDSEL", 0xC9B000C4) { + [ 0] = RCAR_GP_PIN(9, 0), /* ETHES0_PPS */ + [ 1] = RCAR_GP_PIN(9, 1), /* ETHES0_CAPTURE */ + [ 2] = RCAR_GP_PIN(9, 2), /* ETHES0_MATCH */ + [ 3] = RCAR_GP_PIN(9, 3), /* ETHES4_PPS */ + [ 4] = RCAR_GP_PIN(9, 4), /* ETHES4_CAPTURE */ + [ 5] = RCAR_GP_PIN(9, 5), /* ETHES4_MATCH */ + [ 6] = RCAR_GP_PIN(9, 6), /* ETH25G0_MDIO */ + [ 7] = RCAR_GP_PIN(9, 7), /* ETH25G0_MDC */ + [ 8] = RCAR_GP_PIN(9, 8), /* ETH25G0_LINK */ + [ 9] = RCAR_GP_PIN(9, 9), /* ETH25G0_PHYINT */ + [10] = RCAR_GP_PIN(9, 10), /* ETH10G0_MDIO */ + [11] = RCAR_GP_PIN(9, 11), /* ETH10G0_MDC */ + [12] = RCAR_GP_PIN(9, 12), /* ETH10G0_LINK */ + [13] = RCAR_GP_PIN(9, 13), /* ETH10G0_PHYINT */ + [14] = RCAR_GP_PIN(9, 14), /* RSW3_PPS */ + [15] = RCAR_GP_PIN(9, 15), /* RSW3_CAPTURE */ + [16] = RCAR_GP_PIN(9, 16), /* RSW3_MATCH */ + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { PINMUX_BIAS_REG("GP10_PULLEN", 0xC9B008C0, "GP10_PUDSEL", 0xC9B008C4) { + [ 0] = RCAR_GP_PIN(10, 0), /* USB0_PWEN */ + [ 1] = RCAR_GP_PIN(10, 1), /* USB0_OVC */ + [ 2] = RCAR_GP_PIN(10, 2), /* USB0_VBUS_VALID */ + [ 3] = RCAR_GP_PIN(10, 3), /* USB1_PWEN */ + [ 4] = RCAR_GP_PIN(10, 4), /* USB1_OVC */ + [ 5] = RCAR_GP_PIN(10, 5), /* USB1_VBUS_VALID */ + [ 6] = RCAR_GP_PIN(10, 6), /* USB2_PWEN */ + [ 7] = RCAR_GP_PIN(10, 7), /* USB2_OVC */ + [ 8] = RCAR_GP_PIN(10, 8), /* USB2_VBUS_VALID */ + [ 9] = RCAR_GP_PIN(10, 9), /* USB3_PWEN */ + [10] = RCAR_GP_PIN(10, 10), /* USB3_OVC */ + [11] = RCAR_GP_PIN(10, 11), /* USB3_VBUS_VALID */ + [12] = RCAR_GP_PIN(10, 12), /* PCIE40_CLKREQ_N */ + [13] = RCAR_GP_PIN(10, 13), /* PCIE41_CLKREQ_N */ + [14] = SH_PFC_PIN_NONE, + [15] = SH_PFC_PIN_NONE, + [16] = SH_PFC_PIN_NONE, + [17] = SH_PFC_PIN_NONE, + [18] = SH_PFC_PIN_NONE, + [19] = SH_PFC_PIN_NONE, + [20] = SH_PFC_PIN_NONE, + [21] = SH_PFC_PIN_NONE, + [22] = SH_PFC_PIN_NONE, + [23] = SH_PFC_PIN_NONE, + [24] = SH_PFC_PIN_NONE, + [25] = SH_PFC_PIN_NONE, + [26] = SH_PFC_PIN_NONE, + [27] = SH_PFC_PIN_NONE, + [28] = SH_PFC_PIN_NONE, + [29] = SH_PFC_PIN_NONE, + [30] = SH_PFC_PIN_NONE, + [31] = SH_PFC_PIN_NONE, + } }, + { /* sentinel */ }, +}; + +static int rcar5_pinconf_write_bit(struct sh_pfc *pfc, unsigned int bit, + u16 value, u32 reg) +{ + u32 val = sh_pfc_read(pfc, reg); + + val &= ~BIT(bit); + val |= value << bit; + + sh_pfc_write(pfc, reg, val); + + return 0; +} + +static int rcar5_pinconf_set_drive_strength(struct sh_pfc *pfc, + unsigned int pin, u16 strength) +{ + unsigned int bank = pin / 32; + unsigned int bit = pin % 32; + const struct rcar5_pinmux_drive_reg *reg = &pinmux_drive_regs[bank]; + + if (reg->pins[bit] != pin) + return -EINVAL; + + if (strength < 3 || strength > 24) + return -EINVAL; + + /* Convert the value from mA based on a full drive strength value of + * 24mA. We can make the full value configurable later if needed. + */ + strength = strength / 3 - 1; + + rcar5_pinconf_write_bit(pfc, bit, bitfield_extract(strength, 0, 1), reg->drvctrl0); + rcar5_pinconf_write_bit(pfc, bit, bitfield_extract(strength, 1, 1), reg->drvctrl1); + rcar5_pinconf_write_bit(pfc, bit, bitfield_extract(strength, 2, 1), reg->drvctrl2); + + return 0; +} + +static const struct sh_pfc_soc_operations r8a78000_pin_ops = { + .get_bias = rcar_pinmux_get_bias, + .set_bias = rcar_pinmux_set_bias, + .set_drive_strength = rcar5_pinconf_set_drive_strength, +}; + +const struct sh_pfc_soc_info r8a78000_pinmux_info = { + .name = "r8a78000_pfc", + .ops = &r8a78000_pin_ops, + .unlock_reg = 0x1ff, /* PMMRn mask */ + + .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END }, + + .pins = pinmux_pins, + .nr_pins = ARRAY_SIZE(pinmux_pins), + .groups = pinmux_groups, + .nr_groups = ARRAY_SIZE(pinmux_groups), + .functions = pinmux_functions, + .nr_functions = ARRAY_SIZE(pinmux_functions), + + .cfg_regs = pinmux_config_regs, + .bias_regs = pinmux_bias_regs, + .ioctrl_regs = pinmux_ioctrl_regs, + + .pinmux_data = pinmux_data, + .pinmux_data_size = ARRAY_SIZE(pinmux_data), +}; diff --git a/drivers/pinctrl/renesas/pfc.c b/drivers/pinctrl/renesas/pfc.c index db6be39a528..1e0fc3f563d 100644 --- a/drivers/pinctrl/renesas/pfc.c +++ b/drivers/pinctrl/renesas/pfc.c @@ -45,6 +45,7 @@ enum sh_pfc_model { SH_PFC_R8A779F0, SH_PFC_R8A779G0, SH_PFC_R8A779H0, + SH_PFC_R8A78000, }; struct sh_pfc_pin_config { @@ -188,9 +189,9 @@ static void sh_pfc_write_config_reg(struct sh_pfc *pfc, sh_pfc_config_reg_helper(pfc, crp, field, &mapped_reg, &mask, &pos); - dev_dbg(pfc->dev, "write_reg addr = %x, value = 0x%x, field = %u, " - "r_width = %u, f_width = %u\n", - crp->reg, value, field, crp->reg_width, crp->field_width); + dev_dbg(pfc->dev, + "write_reg addr = %x, value = 0x%x, field = %u, pos = %u, r_width = %u, f_width = %u\n", + crp->reg, value, field, pos, crp->reg_width, crp->field_width); mask = ~(mask << pos); value = value << pos; @@ -743,8 +744,8 @@ sh_pfc_pinconf_find_drive_strength_reg(struct sh_pfc *pfc, unsigned int pin, return NULL; } -static int sh_pfc_pinconf_set_drive_strength(struct sh_pfc *pfc, - unsigned int pin, u16 strength) +int rcar_pinconf_set_drive_strength(struct sh_pfc *pfc, + unsigned int pin, u16 strength) { unsigned int offset; unsigned int size; @@ -831,7 +832,10 @@ static int sh_pfc_pinconf_set(struct sh_pfc_pinctrl *pmx, unsigned _pin, break; case PIN_CONFIG_DRIVE_STRENGTH: - ret = sh_pfc_pinconf_set_drive_strength(pfc, _pin, arg); + if (!pfc->info->ops || !pfc->info->ops->set_drive_strength) + return -ENOTSUPP; + + ret = pfc->info->ops->set_drive_strength(pfc, _pin, arg); if (ret < 0) return ret; @@ -1003,6 +1007,8 @@ static int sh_pfc_pinctrl_probe(struct udevice *dev) priv->pfc.info = &r8a779g0_pinmux_info; else if (IS_ENABLED(CONFIG_PINCTRL_PFC_R8A779H0) && model == SH_PFC_R8A779H0) priv->pfc.info = &r8a779h0_pinmux_info; + else if (IS_ENABLED(CONFIG_PINCTRL_PFC_R8A78000) && model == SH_PFC_R8A78000) + priv->pfc.info = &r8a78000_pinmux_info; else return -ENODEV; @@ -1140,6 +1146,12 @@ static const struct udevice_id sh_pfc_pinctrl_ids[] = { .data = SH_PFC_R8A779H0, }, #endif +#if IS_ENABLED(CONFIG_PINCTRL_PFC_R8A78000) + { + .compatible = "renesas,pfc-r8a78000", + .data = SH_PFC_R8A78000, + }, +#endif { }, }; diff --git a/drivers/pinctrl/renesas/sh_pfc.h b/drivers/pinctrl/renesas/sh_pfc.h index 79c6125a0d7..30d2e6a8e81 100644 --- a/drivers/pinctrl/renesas/sh_pfc.h +++ b/drivers/pinctrl/renesas/sh_pfc.h @@ -245,6 +245,8 @@ struct sh_pfc_soc_operations { unsigned int bias); int (*pin_to_pocctrl)(unsigned int pin, u32 *pocctrl); int (*pin_to_portcr)(unsigned int pin); + int (*set_drive_strength)(struct sh_pfc *pfc, unsigned int pin, + u16 strength); }; struct sh_pfc_soc_info { @@ -308,6 +310,7 @@ extern const struct sh_pfc_soc_info r8a779a0_pinmux_info; extern const struct sh_pfc_soc_info r8a779f0_pinmux_info; extern const struct sh_pfc_soc_info r8a779g0_pinmux_info; extern const struct sh_pfc_soc_info r8a779h0_pinmux_info; +extern const struct sh_pfc_soc_info r8a78000_pinmux_info; /* ----------------------------------------------------------------------------- * Helper macros to create pin and port lists @@ -741,5 +744,7 @@ rcar_pin_to_bias_reg(const struct sh_pfc_soc_info *info, unsigned int pin, unsigned int rcar_pinmux_get_bias(struct sh_pfc *pfc, unsigned int pin); void rcar_pinmux_set_bias(struct sh_pfc *pfc, unsigned int pin, unsigned int bias); +int rcar_pinconf_set_drive_strength(struct sh_pfc *pfc, + unsigned int pin, u16 strength); #endif /* __SH_PFC_H */ diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig index ebf5d828cb0..0ad885c9e8b 100644 --- a/drivers/power/domain/Kconfig +++ b/drivers/power/domain/Kconfig @@ -20,7 +20,7 @@ config APPLE_PMGR_POWER_DOMAIN config AGILEX5_PMGR_POWER_DOMAIN bool "Enable the Agilex5 PMGR power domain driver" - depends on SPL_POWER_DOMAIN + depends on SPL_POWER_DOMAIN && TARGET_SOCFPGA_SOC64 help Enable support for power gating peripherals' SRAM specified in the handoff data values obtained from the bitstream to reduce diff --git a/drivers/power/domain/zynqmp-power-domain.c b/drivers/power/domain/zynqmp-power-domain.c index ac93934eb42..a54de5c1439 100644 --- a/drivers/power/domain/zynqmp-power-domain.c +++ b/drivers/power/domain/zynqmp-power-domain.c @@ -17,7 +17,7 @@ static int zynqmp_pm_request_node(const u32 node, const u32 capabilities, const u32 qos, const enum zynqmp_pm_request_ack ack) { return xilinx_pm_request(PM_REQUEST_NODE, node, capabilities, - qos, ack, NULL); + qos, ack, 0, 0, NULL); } static int zynqmp_power_domain_request(struct power_domain *power_domain) diff --git a/drivers/power/pmic/s2mps11.c b/drivers/power/pmic/s2mps11.c index 6e819579030..5cf9d34ffaf 100644 --- a/drivers/power/pmic/s2mps11.c +++ b/drivers/power/pmic/s2mps11.c @@ -13,15 +13,28 @@ #include <power/pmic.h> #include <power/s2mps11.h> -static const struct pmic_child_info pmic_children_info[] = { +static const struct pmic_child_info s2mps11_pmic_children_info[] = { { .prefix = S2MPS11_OF_LDO_PREFIX, .driver = S2MPS11_LDO_DRIVER }, { .prefix = S2MPS11_OF_BUCK_PREFIX, .driver = S2MPS11_BUCK_DRIVER }, { }, }; +static const struct pmic_child_info s2mpu05_pmic_children_info[] = { + { .prefix = S2MPU05_OF_LDO_PREFIX, .driver = S2MPS11_LDO_DRIVER }, + { .prefix = S2MPU05_OF_BUCK_PREFIX, .driver = S2MPS11_BUCK_DRIVER }, + { }, +}; + static int s2mps11_reg_count(struct udevice *dev) { - return S2MPS11_REG_COUNT; + switch (dev_get_driver_data(dev)) { + case VARIANT_S2MPS11: + return S2MPS11_REG_COUNT; + case VARIANT_S2MPU05: + return S2MPU05_REG_COUNT; + default: + return -EINVAL; + } } static int s2mps11_write(struct udevice *dev, uint reg, const uint8_t *buff, @@ -47,10 +60,11 @@ static int s2mps11_read(struct udevice *dev, uint reg, uint8_t *buff, int len) return ret; } -static int s2mps11_probe(struct udevice *dev) +static int s2mps11_bind(struct udevice *dev) { ofnode regulators_node; int children; + const struct pmic_child_info *pmic_children_info; regulators_node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(regulators_node)) { @@ -61,6 +75,18 @@ static int s2mps11_probe(struct udevice *dev) debug("%s: '%s' - found regulators subnode\n", __func__, dev->name); + switch (dev_get_driver_data(dev)) { + case VARIANT_S2MPS11: + pmic_children_info = s2mps11_pmic_children_info; + break; + case VARIANT_S2MPU05: + pmic_children_info = s2mpu05_pmic_children_info; + break; + default: + debug("%s: unknown device type\n", __func__); + return -EINVAL; + } + children = pmic_bind_children(dev, regulators_node, pmic_children_info); if (!children) debug("%s: %s - no child found\n", __func__, dev->name); @@ -75,7 +101,8 @@ static struct dm_pmic_ops s2mps11_ops = { }; static const struct udevice_id s2mps11_ids[] = { - { .compatible = "samsung,s2mps11-pmic" }, + { .compatible = "samsung,s2mps11-pmic", .data = VARIANT_S2MPS11 }, + { .compatible = "samsung,s2mpu05-pmic", .data = VARIANT_S2MPU05 }, { } }; @@ -84,5 +111,5 @@ U_BOOT_DRIVER(pmic_s2mps11) = { .id = UCLASS_PMIC, .of_match = s2mps11_ids, .ops = &s2mps11_ops, - .probe = s2mps11_probe, + .bind = s2mps11_bind, }; diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 65b99e89656..1875e61967c 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -143,7 +143,7 @@ config REGULATOR_PWM config SPL_REGULATOR_PWM bool "Enable Driver for PWM regulators in SPL" - depends on REGULATOR_PWM && SPL + depends on SPL_DM_REGULATOR && SPL && SPL_DM_PWM help This config enables implementation of driver-model regulator uclass features for PWM regulators in SPL. diff --git a/drivers/power/regulator/fixed.c b/drivers/power/regulator/fixed.c index 996da41546a..1dd137f493e 100644 --- a/drivers/power/regulator/fixed.c +++ b/drivers/power/regulator/fixed.c @@ -13,7 +13,6 @@ #include <asm/gpio.h> #include <power/pmic.h> #include <power/regulator.h> -#include "regulator_common.h" #include "regulator_common.h" diff --git a/drivers/power/regulator/gpio-regulator.c b/drivers/power/regulator/gpio-regulator.c index 38b22535c3d..787f8170234 100644 --- a/drivers/power/regulator/gpio-regulator.c +++ b/drivers/power/regulator/gpio-regulator.c @@ -12,7 +12,6 @@ #include <linux/printk.h> #include <power/pmic.h> #include <power/regulator.h> -#include "regulator_common.h" #include "regulator_common.h" diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c index 954deca5ed7..06466142560 100644 --- a/drivers/power/regulator/qcom-rpmh-regulator.c +++ b/drivers/power/regulator/qcom-rpmh-regulator.c @@ -456,6 +456,16 @@ static const struct rpmh_vreg_hw_data pmic5_pldo_lv = { .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo), }; +static const struct rpmh_vreg_hw_data pmic5_nldo = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 123, 8000), + .n_voltages = 124, + .hpm_min_load_uA = 30000, + .pmic_mode_map = pmic_mode_map_pmic5_ldo, + .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo), +}; + static const struct rpmh_vreg_hw_data pmic5_nldo515 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_drms_ops, @@ -493,6 +503,23 @@ static const struct rpmh_vreg_hw_data pmic5_pldo515_mv = { .supply_name = _supply_name, \ } +static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = { + /* smps1 - smps8 are not added to u-boot yet */ + RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l11"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l1-l8"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l9-l10"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"), + RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"), + {} +}; + static const struct rpmh_vreg_init_data pm8150_vreg_data[] = { RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"), {} @@ -706,6 +733,10 @@ static int rpmh_regulators_bind(struct udevice *dev) static const struct udevice_id rpmh_regulator_ids[] = { { + .compatible = "qcom,pm6150l-rpmh-regulators", + .data = (ulong)pm6150l_vreg_data, + }, + { .compatible = "qcom,pm8150-rpmh-regulators", .data = (ulong)pm8150_vreg_data, }, diff --git a/drivers/power/regulator/regulator_common.c b/drivers/power/regulator/regulator_common.c index c80f10c3aa3..685d8735fa5 100644 --- a/drivers/power/regulator/regulator_common.c +++ b/drivers/power/regulator/regulator_common.c @@ -9,7 +9,6 @@ #include <asm/gpio.h> #include <linux/delay.h> #include <power/regulator.h> -#include "regulator_common.h" #include "regulator_common.h" @@ -45,16 +44,6 @@ int regulator_common_of_to_plat(struct udevice *dev, dev_read_u32_default(dev, "u-boot,off-on-delay-us", 0); } - ret = device_get_supply_regulator(dev, "vin-supply", &plat->vin_supply); - if (ret) { - debug("Regulator vin regulator not defined: %d\n", ret); - if (ret != -ENOENT) - return ret; - } - - if (plat->vin_supply) - regulator_set_enable_if_allowed(plat->vin_supply, true); - return 0; } diff --git a/drivers/power/regulator/regulator_common.h b/drivers/power/regulator/regulator_common.h index 799c968d0b6..d4962899d83 100644 --- a/drivers/power/regulator/regulator_common.h +++ b/drivers/power/regulator/regulator_common.h @@ -14,7 +14,6 @@ struct regulator_common_plat { unsigned int startup_delay_us; unsigned int off_on_delay_us; unsigned int enable_count; - struct udevice *vin_supply; }; int regulator_common_of_to_plat(struct udevice *dev, diff --git a/drivers/power/regulator/s2mps11_regulator.c b/drivers/power/regulator/s2mps11_regulator.c index 96de55065fe..4b4353af639 100644 --- a/drivers/power/regulator/s2mps11_regulator.c +++ b/drivers/power/regulator/s2mps11_regulator.c @@ -13,6 +13,193 @@ #include <power/regulator.h> #include <power/s2mps11.h> +#define regulator_desc_s2mps11_buck(num, mask, min, step, max_hex) \ + [num] = { \ + .mode_reg = S2MPS11_REG_B##num##CTRL1, \ + .mode_mask = S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT, \ + .volt_reg = S2MPS11_REG_B##num##CTRL2, \ + .volt_mask = mask, \ + .volt_min = min, \ + .volt_step = step, \ + .volt_max_hex = max_hex, \ + } + +#define regulator_desc_s2mps11_buck1_2_3_4_6(num) \ + regulator_desc_s2mps11_buck(num, S2MPS11_BUCK_VOLT_MASK, \ + S2MPS11_BUCK_UV_MIN, \ + S2MPS11_BUCK_LSTEP, \ + S2MPS11_BUCK_VOLT_MAX_HEX) + +#define regulator_desc_s2mps11_buck5 \ + regulator_desc_s2mps11_buck(5, S2MPS11_BUCK_VOLT_MASK, \ + S2MPS11_BUCK_UV_MIN, \ + S2MPS11_BUCK_LSTEP, \ + S2MPS11_BUCK5_VOLT_MAX_HEX) + +#define regulator_desc_s2mps11_buck7_8_10(num) \ + regulator_desc_s2mps11_buck(num, S2MPS11_BUCK_VOLT_MASK, \ + S2MPS11_BUCK_UV_HMIN, \ + S2MPS11_BUCK_HSTEP, \ + S2MPS11_BUCK7_8_10_VOLT_MAX_HEX) + +#define regulator_desc_s2mps11_buck9 \ + regulator_desc_s2mps11_buck(9, S2MPS11_BUCK9_VOLT_MASK, \ + S2MPS11_BUCK_UV_MIN, \ + S2MPS11_BUCK9_STEP, \ + S2MPS11_BUCK9_VOLT_MAX_HEX) + +static const struct sec_regulator_desc s2mps11_buck_desc[] = { + regulator_desc_s2mps11_buck1_2_3_4_6(1), + regulator_desc_s2mps11_buck1_2_3_4_6(2), + regulator_desc_s2mps11_buck1_2_3_4_6(3), + regulator_desc_s2mps11_buck1_2_3_4_6(4), + regulator_desc_s2mps11_buck5, + regulator_desc_s2mps11_buck1_2_3_4_6(6), + regulator_desc_s2mps11_buck7_8_10(7), + regulator_desc_s2mps11_buck7_8_10(8), + regulator_desc_s2mps11_buck9, + regulator_desc_s2mps11_buck7_8_10(10), +}; + +#define regulator_desc_s2mps11_ldo(num, step) \ + [num] = { \ + .mode_reg = S2MPS11_REG_L##num##CTRL, \ + .mode_mask = S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT, \ + .volt_reg = S2MPS11_REG_L##num##CTRL, \ + .volt_mask = S2MPS11_LDO_VOLT_MASK, \ + .volt_min = S2MPS11_LDO_UV_MIN, \ + .volt_step = step, \ + .volt_max_hex = S2MPS11_LDO_VOLT_MAX_HEX \ + } + +#define regulator_desc_s2mps11_ldo_type1(num) \ + regulator_desc_s2mps11_ldo(num, S2MPS11_LDO_STEP) + +#define regulator_desc_s2mps11_ldo_type2(num) \ + regulator_desc_s2mps11_ldo(num, S2MPS11_LDO_STEP * 2) + +static const struct sec_regulator_desc s2mps11_ldo_desc[] = { + regulator_desc_s2mps11_ldo_type1(1), + regulator_desc_s2mps11_ldo_type2(2), + regulator_desc_s2mps11_ldo_type2(3), + regulator_desc_s2mps11_ldo_type2(4), + regulator_desc_s2mps11_ldo_type2(5), + regulator_desc_s2mps11_ldo_type1(6), + regulator_desc_s2mps11_ldo_type2(7), + regulator_desc_s2mps11_ldo_type2(8), + regulator_desc_s2mps11_ldo_type2(9), + regulator_desc_s2mps11_ldo_type2(10), + regulator_desc_s2mps11_ldo_type1(11), + regulator_desc_s2mps11_ldo_type2(12), + regulator_desc_s2mps11_ldo_type2(13), + regulator_desc_s2mps11_ldo_type2(14), + regulator_desc_s2mps11_ldo_type2(15), + regulator_desc_s2mps11_ldo_type2(16), + regulator_desc_s2mps11_ldo_type2(17), + regulator_desc_s2mps11_ldo_type2(18), + regulator_desc_s2mps11_ldo_type2(19), + regulator_desc_s2mps11_ldo_type2(20), + regulator_desc_s2mps11_ldo_type2(21), + regulator_desc_s2mps11_ldo_type1(22), + regulator_desc_s2mps11_ldo_type1(23), + regulator_desc_s2mps11_ldo_type2(24), + regulator_desc_s2mps11_ldo_type2(25), + regulator_desc_s2mps11_ldo_type2(26), + regulator_desc_s2mps11_ldo_type1(27), + regulator_desc_s2mps11_ldo_type2(28), + regulator_desc_s2mps11_ldo_type2(29), + regulator_desc_s2mps11_ldo_type2(30), + regulator_desc_s2mps11_ldo_type2(31), + regulator_desc_s2mps11_ldo_type2(32), + regulator_desc_s2mps11_ldo_type2(33), + regulator_desc_s2mps11_ldo_type2(34), + regulator_desc_s2mps11_ldo_type1(35), + regulator_desc_s2mps11_ldo_type2(36), + regulator_desc_s2mps11_ldo_type2(37), + regulator_desc_s2mps11_ldo_type2(38), +}; + +#define regulator_desc_s2mpu05_buck(num, which) \ + [num] = { \ + .mode_reg = S2MPU05_REG_B##num##CTRL1, \ + .mode_mask = S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT, \ + .volt_reg = S2MPU05_REG_B##num##CTRL2, \ + .volt_mask = S2MPS11_BUCK_VOLT_MASK, \ + .volt_min = S2MPU05_BUCK_MIN##which, \ + .volt_step = S2MPU05_BUCK_STEP##which, \ + .volt_max_hex = S2MPS11_BUCK_VOLT_MASK, \ + } + +#define regulator_desc_s2mpu05_buck1_2_3(num) \ + regulator_desc_s2mpu05_buck(num, 1) + +#define regulator_desc_s2mpu05_buck4_5(num) \ + regulator_desc_s2mpu05_buck(num, 2) + +static const struct sec_regulator_desc s2mpu05_buck_desc[] = { + regulator_desc_s2mpu05_buck1_2_3(1), + regulator_desc_s2mpu05_buck1_2_3(2), + regulator_desc_s2mpu05_buck1_2_3(3), + regulator_desc_s2mpu05_buck4_5(4), + regulator_desc_s2mpu05_buck4_5(5), +}; + +#define regulator_desc_s2mpu05_ldo(num, reg, min, step) \ + [num] = { \ + .mode_reg = S2MPU05_REG_L##num##reg, \ + .mode_mask = S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT, \ + .volt_reg = S2MPU05_REG_L##num##reg, \ + .volt_mask = S2MPS11_LDO_VOLT_MASK, \ + .volt_min = min, \ + .volt_step = step, \ + .volt_max_hex = S2MPS11_LDO_VOLT_MAX_HEX, \ + } + +#define regulator_desc_s2mpu05_ldo_type1(num) \ + regulator_desc_s2mpu05_ldo(num, CTRL, S2MPU05_LDO_MIN1, \ + S2MPU05_LDO_STEP1) + +#define regulator_desc_s2mpu05_ldo_type2(num) \ + regulator_desc_s2mpu05_ldo(num, CTRL, S2MPU05_LDO_MIN1, \ + S2MPU05_LDO_STEP2) + +#define regulator_desc_s2mpu05_ldo_type3(num) \ + regulator_desc_s2mpu05_ldo(num, CTRL, S2MPU05_LDO_MIN2, \ + S2MPU05_LDO_STEP2) + +#define regulator_desc_s2mpu05_ldo_type4(num) \ + regulator_desc_s2mpu05_ldo(num, CTRL, S2MPU05_LDO_MIN3, \ + S2MPU05_LDO_STEP2) + +#define regulator_desc_s2mpu05_ldo_type5(num) \ + regulator_desc_s2mpu05_ldo(num, CTRL1, S2MPU05_LDO_MIN3, \ + S2MPU05_LDO_STEP2) + +static const struct sec_regulator_desc s2mpu05_ldo_desc[] = { + regulator_desc_s2mpu05_ldo_type4(1), + regulator_desc_s2mpu05_ldo_type3(2), + regulator_desc_s2mpu05_ldo_type2(3), + regulator_desc_s2mpu05_ldo_type1(4), + regulator_desc_s2mpu05_ldo_type1(5), + regulator_desc_s2mpu05_ldo_type1(6), + regulator_desc_s2mpu05_ldo_type2(7), + regulator_desc_s2mpu05_ldo_type3(8), + regulator_desc_s2mpu05_ldo_type5(9), + regulator_desc_s2mpu05_ldo_type4(10), + /* LDOs 11-24 are used for CP. They aren't documented. */ + regulator_desc_s2mpu05_ldo_type2(25), + regulator_desc_s2mpu05_ldo_type3(26), + regulator_desc_s2mpu05_ldo_type2(27), + regulator_desc_s2mpu05_ldo_type3(28), + regulator_desc_s2mpu05_ldo_type3(29), + regulator_desc_s2mpu05_ldo_type2(30), + regulator_desc_s2mpu05_ldo_type3(31), + regulator_desc_s2mpu05_ldo_type3(32), + regulator_desc_s2mpu05_ldo_type3(33), + regulator_desc_s2mpu05_ldo_type3(34), + regulator_desc_s2mpu05_ldo_type3(35), +}; + #define MODE(_id, _val, _name) { \ .id = _id, \ .register_value = _val, \ @@ -33,94 +220,46 @@ static struct dm_regulator_mode s2mps11_ldo_modes[] = { MODE(OP_ON, S2MPS11_LDO_MODE_ON, "ON"), }; -static const char s2mps11_buck_ctrl[] = { - 0xff, 0x25, 0x27, 0x29, 0x2b, 0x2d, 0x33, 0x35, 0x37, 0x39, 0x3b -}; - -static const char s2mps11_buck_out[] = { - 0xff, 0x26, 0x28, 0x2a, 0x2c, 0x2f, 0x34, 0x36, 0x38, 0x3a, 0x3c +static struct dm_regulator_mode s2mpu05_regulator_modes[] = { + MODE(OP_OFF, S2MPS11_LDO_MODE_OFF, "OFF"), + MODE(OP_ON, S2MPS11_LDO_MODE_ON, "ON"), }; -static int s2mps11_buck_hex2volt(int buck, int hex) +static const ulong s2mps11_get_variant(struct udevice *dev) { - unsigned int uV = 0; - - if (hex < 0) - goto bad; - - switch (buck) { - case 7: - case 8: - case 10: - if (hex > S2MPS11_BUCK7_8_10_VOLT_MAX_HEX) - goto bad; + struct udevice *parent = dev_get_parent(dev); - uV = hex * S2MPS11_BUCK_HSTEP + S2MPS11_BUCK_UV_HMIN; - break; - case 9: - if (hex > S2MPS11_BUCK9_VOLT_MAX_HEX) - goto bad; - uV = hex * S2MPS11_BUCK9_STEP * 2 + S2MPS11_BUCK9_UV_MIN; - break; - default: - if (buck == 5 && hex > S2MPS11_BUCK5_VOLT_MAX_HEX) - goto bad; - else if (buck != 5 && hex > S2MPS11_BUCK_VOLT_MAX_HEX) - goto bad; - - uV = hex * S2MPS11_BUCK_LSTEP + S2MPS11_BUCK_UV_MIN; - break; + if (!parent) { + pr_err("Parent is non-existent, this shouldn't happen!\n"); + return VARIANT_NONE; } - return uV; -bad: - pr_err("Value: %#x is wrong for BUCK%d", hex, buck); - return -EINVAL; + return dev_get_driver_data(parent); } -static int s2mps11_buck_volt2hex(int buck, int uV) +static int s2mps11_buck_val(struct udevice *dev, int op, int *uV) { - int hex; - - switch (buck) { - case 7: - case 8: - case 10: - hex = (uV - S2MPS11_BUCK_UV_HMIN) / S2MPS11_BUCK_HSTEP; - if (hex > S2MPS11_BUCK7_8_10_VOLT_MAX_HEX) - goto bad; + const struct sec_regulator_desc *buck_desc; + int num_bucks, hex, buck, ret; + u32 addr; + u8 val; + switch (s2mps11_get_variant(dev)) { + case VARIANT_S2MPS11: + buck_desc = s2mps11_buck_desc; + num_bucks = ARRAY_SIZE(s2mps11_buck_desc); break; - case 9: - hex = (uV - S2MPS11_BUCK9_UV_MIN) / S2MPS11_BUCK9_STEP; - if (hex > S2MPS11_BUCK9_VOLT_MAX_HEX) - goto bad; + case VARIANT_S2MPU05: + buck_desc = s2mpu05_buck_desc; + num_bucks = ARRAY_SIZE(s2mpu05_buck_desc); break; default: - hex = (uV - S2MPS11_BUCK_UV_MIN) / S2MPS11_BUCK_LSTEP; - if (buck == 5 && hex > S2MPS11_BUCK5_VOLT_MAX_HEX) - goto bad; - else if (buck != 5 && hex > S2MPS11_BUCK_VOLT_MAX_HEX) - goto bad; - break; - }; - - if (hex >= 0) - return hex; - -bad: - pr_err("Value: %d uV is wrong for BUCK%d", uV, buck); - return -EINVAL; -} - -static int s2mps11_buck_val(struct udevice *dev, int op, int *uV) -{ - int hex, buck, ret; - u32 mask, addr; - u8 val; + pr_err("Unknown device type\n"); + return -EINVAL; + } buck = dev->driver_data; - if (buck < 1 || buck > S2MPS11_BUCK_NUM) { + if (buck < 1 || buck > num_bucks) { pr_err("Wrong buck number: %d\n", buck); return -EINVAL; } @@ -128,35 +267,25 @@ static int s2mps11_buck_val(struct udevice *dev, int op, int *uV) if (op == PMIC_OP_GET) *uV = 0; - addr = s2mps11_buck_out[buck]; - - switch (buck) { - case 9: - mask = S2MPS11_BUCK9_VOLT_MASK; - break; - default: - mask = S2MPS11_BUCK_VOLT_MASK; - break; - } + addr = buck_desc[buck].volt_reg; ret = pmic_read(dev->parent, addr, &val, 1); if (ret) return ret; if (op == PMIC_OP_GET) { - val &= mask; - ret = s2mps11_buck_hex2volt(buck, val); - if (ret < 0) - return ret; - *uV = ret; + val &= buck_desc[buck].volt_mask; + *uV = val * buck_desc[buck].volt_step + buck_desc[buck].volt_min; return 0; } - hex = s2mps11_buck_volt2hex(buck, *uV); - if (hex < 0) - return hex; + hex = (*uV - buck_desc[buck].volt_min) / buck_desc[buck].volt_step; + if (hex > buck_desc[buck].volt_max_hex) { + pr_err("Value: %d uV is wrong for LDO%d\n", *uV, buck); + return -EINVAL; + } - val &= ~mask; + val &= ~buck_desc[buck].volt_mask; val |= hex; ret = pmic_write(dev->parent, addr, &val, 1); @@ -165,60 +294,63 @@ static int s2mps11_buck_val(struct udevice *dev, int op, int *uV) static int s2mps11_buck_mode(struct udevice *dev, int op, int *opmode) { + struct dm_regulator_uclass_plat *uc_pdata = dev_get_uclass_plat(dev); + const struct sec_regulator_desc *buck_desc; unsigned int addr, mode; unsigned char val; - int buck, ret; + int num_bucks, buck, ret, i; + + switch (s2mps11_get_variant(dev)) { + case VARIANT_S2MPS11: + buck_desc = s2mps11_buck_desc; + num_bucks = ARRAY_SIZE(s2mps11_buck_desc); + break; + case VARIANT_S2MPU05: + buck_desc = s2mpu05_buck_desc; + num_bucks = ARRAY_SIZE(s2mpu05_buck_desc); + break; + default: + pr_err("Unknown device type\n"); + return -EINVAL; + } buck = dev->driver_data; - if (buck < 1 || buck > S2MPS11_BUCK_NUM) { + if (buck < 1 || buck > num_bucks) { pr_err("Wrong buck number: %d\n", buck); return -EINVAL; } - addr = s2mps11_buck_ctrl[buck]; + addr = buck_desc[buck].mode_reg; ret = pmic_read(dev->parent, addr, &val, 1); if (ret) return ret; if (op == PMIC_OP_GET) { - val &= (S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT); - switch (val) { - case S2MPS11_BUCK_MODE_OFF: - *opmode = OP_OFF; - break; - case S2MPS11_BUCK_MODE_STANDBY: - *opmode = OP_STANDBY; - break; - case S2MPS11_BUCK_MODE_ON: - *opmode = OP_ON; - break; - default: - return -EINVAL; + val &= buck_desc[buck].mode_mask; + for (i = 0; i < uc_pdata->mode_count; i++) { + if (uc_pdata->mode[i].register_value != val) + continue; + + *opmode = uc_pdata->mode[i].id; + return 0; } - return 0; - } - switch (*opmode) { - case OP_OFF: - mode = S2MPS11_BUCK_MODE_OFF; - break; - case OP_STANDBY: - mode = S2MPS11_BUCK_MODE_STANDBY; - break; - case OP_ON: - mode = S2MPS11_BUCK_MODE_ON; - break; - default: - pr_err("Wrong mode: %d for buck: %d\n", *opmode, buck); return -EINVAL; } - val &= ~(S2MPS11_BUCK_MODE_MASK << S2MPS11_BUCK_MODE_SHIFT); - val |= mode; - ret = pmic_write(dev->parent, addr, &val, 1); + for (i = 0; i < uc_pdata->mode_count; i++) { + if (uc_pdata->mode[i].id != *opmode) + continue; - return ret; + mode = uc_pdata->mode[i].register_value; + val &= ~buck_desc[buck].mode_mask; + val |= mode; + return pmic_write(dev->parent, addr, &val, 1); + } + + pr_err("Wrong mode: %d for buck: %d\n", *opmode, buck); + return -EINVAL; } static int s2mps11_buck_enable(struct udevice *dev, int op, bool *enable) @@ -307,10 +439,21 @@ static int s2mps11_buck_probe(struct udevice *dev) struct dm_regulator_uclass_plat *uc_pdata; uc_pdata = dev_get_uclass_plat(dev); - uc_pdata->type = REGULATOR_TYPE_BUCK; - uc_pdata->mode = s2mps11_buck_modes; - uc_pdata->mode_count = ARRAY_SIZE(s2mps11_buck_modes); + + switch (s2mps11_get_variant(dev)) { + case VARIANT_S2MPS11: + uc_pdata->mode = s2mps11_buck_modes; + uc_pdata->mode_count = ARRAY_SIZE(s2mps11_buck_modes); + break; + case VARIANT_S2MPU05: + uc_pdata->mode = s2mpu05_regulator_modes; + uc_pdata->mode_count = ARRAY_SIZE(s2mpu05_regulator_modes); + break; + default: + pr_err("Unknown device type\n"); + return -EINVAL; + } return 0; } @@ -331,95 +474,55 @@ U_BOOT_DRIVER(s2mps11_buck) = { .probe = s2mps11_buck_probe, }; -static int s2mps11_ldo_hex2volt(int ldo, int hex) +static int s2mps11_ldo_val(struct udevice *dev, int op, int *uV) { - unsigned int uV = 0; - - if (hex > S2MPS11_LDO_VOLT_MAX_HEX) { - pr_err("Value: %#x is wrong for LDO%d", hex, ldo); - return -EINVAL; - } + const struct sec_regulator_desc *ldo_desc; + unsigned int addr; + unsigned char val; + int num_ldos, hex, ldo, ret; - switch (ldo) { - case 1: - case 6: - case 11: - case 22: - case 23: - case 27: - case 35: - uV = hex * S2MPS11_LDO_STEP + S2MPS11_LDO_UV_MIN; - break; - default: - uV = hex * S2MPS11_LDO_STEP * 2 + S2MPS11_LDO_UV_MIN; + switch (s2mps11_get_variant(dev)) { + case VARIANT_S2MPS11: + ldo_desc = s2mps11_ldo_desc; + num_ldos = ARRAY_SIZE(s2mps11_ldo_desc); break; - } - - return uV; -} - -static int s2mps11_ldo_volt2hex(int ldo, int uV) -{ - int hex = 0; - - switch (ldo) { - case 1: - case 6: - case 11: - case 22: - case 23: - case 27: - case 35: - hex = (uV - S2MPS11_LDO_UV_MIN) / S2MPS11_LDO_STEP; + case VARIANT_S2MPU05: + ldo_desc = s2mpu05_ldo_desc; + num_ldos = ARRAY_SIZE(s2mpu05_ldo_desc); break; default: - hex = (uV - S2MPS11_LDO_UV_MIN) / (S2MPS11_LDO_STEP * 2); - break; + pr_err("Unknown device type\n"); + return -EINVAL; } - if (hex >= 0 && hex <= S2MPS11_LDO_VOLT_MAX_HEX) - return hex; - - pr_err("Value: %d uV is wrong for LDO%d", uV, ldo); - return -EINVAL; - - return 0; -} - -static int s2mps11_ldo_val(struct udevice *dev, int op, int *uV) -{ - unsigned int addr; - unsigned char val; - int hex, ldo, ret; - ldo = dev->driver_data; - if (ldo < 1 || ldo > S2MPS11_LDO_NUM) { + if (ldo < 1 || ldo > num_ldos) { pr_err("Wrong ldo number: %d\n", ldo); return -EINVAL; } - addr = S2MPS11_REG_L1CTRL + ldo - 1; + addr = ldo_desc[ldo].volt_reg; + + if (op == PMIC_OP_GET) + *uV = 0; ret = pmic_read(dev->parent, addr, &val, 1); if (ret) return ret; if (op == PMIC_OP_GET) { - *uV = 0; - val &= S2MPS11_LDO_VOLT_MASK; - ret = s2mps11_ldo_hex2volt(ldo, val); - if (ret < 0) - return ret; - - *uV = ret; + val &= ldo_desc[ldo].volt_mask; + *uV = val * ldo_desc[ldo].volt_step + ldo_desc[ldo].volt_min; return 0; } - hex = s2mps11_ldo_volt2hex(ldo, *uV); - if (hex < 0) - return hex; + hex = (*uV - ldo_desc[ldo].volt_min) / ldo_desc[ldo].volt_step; + if (hex > ldo_desc[ldo].volt_max_hex) { + pr_err("Value: %d uV is wrong for LDO%d\n", *uV, ldo); + return -EINVAL; + } - val &= ~S2MPS11_LDO_VOLT_MASK; + val &= ~ldo_desc[ldo].volt_mask; val |= hex; ret = pmic_write(dev->parent, addr, &val, 1); @@ -428,65 +531,64 @@ static int s2mps11_ldo_val(struct udevice *dev, int op, int *uV) static int s2mps11_ldo_mode(struct udevice *dev, int op, int *opmode) { + struct dm_regulator_uclass_plat *uc_pdata = dev_get_uclass_plat(dev); + const struct sec_regulator_desc *ldo_desc; unsigned int addr, mode; unsigned char val; - int ldo, ret; + int num_ldos, ldo, ret, i; + + switch (s2mps11_get_variant(dev)) { + case VARIANT_S2MPS11: + ldo_desc = s2mps11_ldo_desc; + num_ldos = ARRAY_SIZE(s2mps11_ldo_desc); + break; + case VARIANT_S2MPU05: + ldo_desc = s2mpu05_ldo_desc; + num_ldos = ARRAY_SIZE(s2mpu05_ldo_desc); + break; + default: + pr_err("Unknown device type\n"); + return -EINVAL; + } ldo = dev->driver_data; - if (ldo < 1 || ldo > S2MPS11_LDO_NUM) { + if (ldo < 1 || ldo > num_ldos) { pr_err("Wrong ldo number: %d\n", ldo); return -EINVAL; } - addr = S2MPS11_REG_L1CTRL + ldo - 1; + + addr = ldo_desc[ldo].mode_reg; ret = pmic_read(dev->parent, addr, &val, 1); if (ret) return ret; if (op == PMIC_OP_GET) { - val &= (S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT); - switch (val) { - case S2MPS11_LDO_MODE_OFF: - *opmode = OP_OFF; - break; - case S2MPS11_LDO_MODE_STANDBY: - *opmode = OP_STANDBY; - break; - case S2MPS11_LDO_MODE_STANDBY_LPM: - *opmode = OP_STANDBY_LPM; - break; - case S2MPS11_LDO_MODE_ON: - *opmode = OP_ON; - break; - default: - return -EINVAL; + val &= ldo_desc[ldo].mode_mask; + + for (i = 0; i < uc_pdata->mode_count; i++) { + if (uc_pdata->mode[i].register_value != val) + continue; + + *opmode = uc_pdata->mode[i].id; + return 0; } - return 0; - } - switch (*opmode) { - case OP_OFF: - mode = S2MPS11_LDO_MODE_OFF; - break; - case OP_STANDBY: - mode = S2MPS11_LDO_MODE_STANDBY; - break; - case OP_STANDBY_LPM: - mode = S2MPS11_LDO_MODE_STANDBY_LPM; - break; - case OP_ON: - mode = S2MPS11_LDO_MODE_ON; - break; - default: - pr_err("Wrong mode: %d for ldo: %d\n", *opmode, ldo); return -EINVAL; } - val &= ~(S2MPS11_LDO_MODE_MASK << S2MPS11_LDO_MODE_SHIFT); - val |= mode; - ret = pmic_write(dev->parent, addr, &val, 1); + for (i = 0; i < uc_pdata->mode_count; i++) { + if (uc_pdata->mode[i].id != *opmode) + continue; - return ret; + mode = uc_pdata->mode[i].register_value; + val &= ~ldo_desc[ldo].mode_mask; + val |= mode; + return pmic_write(dev->parent, addr, &val, 1); + } + + pr_err("Wrong mode: %d for ldo: %d\n", *opmode, ldo); + return -EINVAL; } static int s2mps11_ldo_enable(struct udevice *dev, int op, bool *enable) @@ -584,8 +686,20 @@ static int s2mps11_ldo_probe(struct udevice *dev) uc_pdata = dev_get_uclass_plat(dev); uc_pdata->type = REGULATOR_TYPE_LDO; - uc_pdata->mode = s2mps11_ldo_modes; - uc_pdata->mode_count = ARRAY_SIZE(s2mps11_ldo_modes); + + switch (s2mps11_get_variant(dev)) { + case VARIANT_S2MPS11: + uc_pdata->mode = s2mps11_ldo_modes; + uc_pdata->mode_count = ARRAY_SIZE(s2mps11_ldo_modes); + break; + case VARIANT_S2MPU05: + uc_pdata->mode = s2mpu05_regulator_modes; + uc_pdata->mode_count = ARRAY_SIZE(s2mpu05_regulator_modes); + break; + default: + pr_err("Unknown device type\n"); + return -EINVAL; + } return 0; } diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 06f42f699de..a69fe37caff 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -1,3 +1,5 @@ +menu "Pulse-width modulation (PWM)" + config DM_PWM bool "Enable support for pulse-width modulation devices (PWM)" depends on DM @@ -9,9 +11,21 @@ config DM_PWM frequency/period can be controlled along with the proportion of that time that the signal is high. +config PWM_IMX + bool "Enable support for i.MX27 and later PWM" + depends on MACH_IMX + help + This PWM is found i.MX27 and later i.MX SoCs. + +config PWM_S5P + bool "Enable non-DM support for S5P PWM" + depends on (S5P || ARCH_NEXELL) + default y + +if DM_PWM + config PWM_ASPEED bool "Enable support for the Aspeed PWM" - depends on DM_PWM select SYSCON help This PWM is found on Ast2600 SoCs. It supports a programmable period @@ -20,20 +34,19 @@ config PWM_ASPEED config PWM_AT91 bool "Enable support for PWM found on AT91 SoC's" - depends on DM_PWM && ARCH_AT91 + depends on ARCH_AT91 help Support for PWM hardware on AT91 based SoC. config PWM_CADENCE_TTC bool "Enable support for the Cadence TTC PWM" - depends on DM_PWM && !CADENCE_TTC_TIMER + depends on !CADENCE_TTC_TIMER help Cadence TTC can be configured as timer which is done via CONFIG_CADENCE_TTC_TIMER or as PWM. This is covering only PWM now. config PWM_CROS_EC bool "Enable support for the Chrome OS EC PWM" - depends on DM_PWM help This PWM is found on several Chrome OS devices and controlled by the Chrome OS embedded controller. It may be used to control the @@ -42,36 +55,28 @@ config PWM_CROS_EC config PWM_EXYNOS bool "Enable support for the Exynos PWM" - depends on DM_PWM && ARCH_EXYNOS + depends on ARCH_EXYNOS help This PWM is found on Samsung Exynos 5250 and other Samsung SoCs. It supports a programmable period and duty cycle. A 32-bit counter is used. It provides 5 channels which can be independently programmed. Channel 4 (the last) is normally used as a timer. -config PWM_IMX - bool "Enable support for i.MX27 and later PWM" - depends on MACH_IMX - help - This PWM is found i.MX27 and later i.MX SoCs. - config PWM_MESON bool "Enable support for Amlogic Meson SoCs PWM" - depends on DM_PWM help This PWM is found on Amlogic Meson SoCs. It supports a - programmable period and duty cycle for 2 independant channels. + programmable period and duty cycle for 2 independent channels. config PWM_MTK bool "Enable support for MediaTek PWM" - depends on DM_PWM help This PWM is found on MT7622, MT7623, and MT7629. It supports a programmable period and duty cycle. config PWM_ROCKCHIP bool "Enable support for the Rockchip PWM" - depends on DM_PWM && ARCH_ROCKCHIP + depends on ARCH_ROCKCHIP help This PWM is found on RK3288 and other Rockchip SoCs. It supports a programmable period and duty cycle. A 32-bit counter is used. @@ -86,20 +91,14 @@ config PWM_SANDBOX useful. The PWM can be enabled but is not connected to any outputs so this is not very useful. -config PWM_S5P - bool "Enable non-DM support for S5P PWM" - depends on (S5P || ARCH_NEXELL) - default y - config PWM_SIFIVE bool "Enable support for SiFive PWM" - depends on DM_PWM help This PWM is found SiFive's FU540 and other SoCs. config PWM_TEGRA bool "Enable support for the Tegra PWM" - depends on DM_PWM && ARCH_TEGRA + depends on ARCH_TEGRA help This PWM is found on Tegra 20 and other Nvidia SoCs. It supports four channels with a programmable period and duty cycle. Only a @@ -108,7 +107,7 @@ config PWM_TEGRA config PWM_STM32 bool "Enable support for STM32 PWM" - depends on DM_PWM && MFD_STM32_TIMERS + depends on MFD_STM32_TIMERS help This enables PWM driver for STMicroelectronics STM32 pulse width modulation. It uses STM32 timer devices that can have up to 4 output @@ -116,20 +115,23 @@ config PWM_STM32 config PWM_SUNXI bool "Enable support for the Allwinner Sunxi PWM" - depends on DM_PWM && ARCH_SUNXI + depends on ARCH_SUNXI help This PWM is found on H3, A64 and other Allwinner SoCs. It supports a programmable period and duty cycle. A 16-bit counter is used. config PWM_TI_EHRPWM bool "Enable support for EHRPWM PWM" - depends on DM_PWM && ARCH_OMAP2PLUS + depends on ARCH_OMAP2PLUS default y help PWM driver support for the EHRPWM controller found on TI SOCs. config PWM_TI_ECAP bool "Enable support for ECAP PWM" - depends on DM_PWM && ARCH_OMAP2PLUS + depends on ARCH_OMAP2PLUS help PWM driver support for the ECAP controller found on TI SOCs. + +endif +endmenu diff --git a/drivers/pwm/pwm-cadence-ttc.c b/drivers/pwm/pwm-cadence-ttc.c index 767628833bc..fae6d5a1739 100644 --- a/drivers/pwm/pwm-cadence-ttc.c +++ b/drivers/pwm/pwm-cadence-ttc.c @@ -47,6 +47,8 @@ #define TTC_MATCH_1_COUNTER(reg, channel) \ TTC_REG((reg) + MATCH_1_COUNTER, (channel)) +#define TTC_PWM_CHANNELS 3 + struct cadence_ttc_pwm_plat { u8 *regs; u32 timer_width; @@ -57,7 +59,7 @@ struct cadence_ttc_pwm_priv { u32 timer_width; u32 timer_mask; unsigned long frequency; - bool invert[2]; + bool invert[TTC_PWM_CHANNELS]; }; static int cadence_ttc_pwm_set_invert(struct udevice *dev, uint channel, @@ -65,7 +67,7 @@ static int cadence_ttc_pwm_set_invert(struct udevice *dev, uint channel, { struct cadence_ttc_pwm_priv *priv = dev_get_priv(dev); - if (channel > 2) { + if (channel >= TTC_PWM_CHANNELS) { dev_err(dev, "Unsupported channel number %d(max 2)\n", channel); return -EINVAL; } @@ -87,7 +89,7 @@ static int cadence_ttc_pwm_set_config(struct udevice *dev, uint channel, dev_dbg(dev, "channel %d, duty %d/period %d ns\n", channel, duty_ns, period_ns); - if (channel > 2) { + if (channel >= TTC_PWM_CHANNELS) { dev_err(dev, "Unsupported channel number %d(max 2)\n", channel); return -EINVAL; } @@ -153,7 +155,7 @@ static int cadence_ttc_pwm_set_enable(struct udevice *dev, uint channel, { struct cadence_ttc_pwm_priv *priv = dev_get_priv(dev); - if (channel > 2) { + if (channel >= TTC_PWM_CHANNELS) { dev_err(dev, "Unsupported channel number %d(max 2)\n", channel); return -EINVAL; } diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index c2597d8b669..caa7af085fa 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -359,8 +359,9 @@ static int meson_pwm_probe(struct udevice *dev) /* We have our source clock, do not alter HW clock mux */ continue; - } else + } else if (err) { return err; + } /* Get id in list */ for (p = 0 ; p < data->num_parents ; ++p) { diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index e9f19a69433..8056f210abc 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -33,6 +33,13 @@ config REMOTEPROC_ADI_SC5XX Say 'y' here to add support for loading code onto SHARC cores in an ADSP-SC5xx SoC from Analog Devices +config REMOTEPROC_IMX + bool "Support for NXP i.MX remoteproc" + select REMOTEPROC + depends on DM && MACH_IMX && OF_CONTROL + help + Say 'y' here to add support for i.MX remoteproc. + config REMOTEPROC_RENESAS_APMU bool "Support for Renesas R-Car Gen4 APMU start of CR52 processor" select REMOTEPROC diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 47bd57c7890..7ea8023c50b 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_$(PHASE_)REMOTEPROC) += rproc-uclass.o rproc-elf-loader.o # Remote proc drivers - Please keep this list alphabetically sorted. obj-$(CONFIG_K3_SYSTEM_CONTROLLER) += k3_system_controller.o obj-$(CONFIG_REMOTEPROC_ADI_SC5XX) += adi_sc5xx_rproc.o +obj-$(CONFIG_REMOTEPROC_IMX) += imx_rproc.o obj-$(CONFIG_REMOTEPROC_RENESAS_APMU) += renesas_apmu.o obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c new file mode 100644 index 00000000000..9bb55327998 --- /dev/null +++ b/drivers/remoteproc/imx_rproc.c @@ -0,0 +1,370 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2025 NXP + */ + +#include <asm/io.h> +#include <dm.h> +#include <errno.h> +#include <dm/device_compat.h> +#include <linux/arm-smccc.h> +#include <linux/types.h> +#include <regmap.h> +#include <remoteproc.h> +#include <syscon.h> + +#include "imx_rproc.h" + +#define IMX7D_SRC_SCR 0x0C +#define IMX7D_ENABLE_M4 BIT(3) +#define IMX7D_SW_M4P_RST BIT(2) +#define IMX7D_SW_M4C_RST BIT(1) +#define IMX7D_SW_M4C_NON_SCLR_RST BIT(0) + +#define IMX7D_M4_RST_MASK (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \ + | IMX7D_SW_M4C_RST \ + | IMX7D_SW_M4C_NON_SCLR_RST) + +#define IMX7D_M4_START (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \ + | IMX7D_SW_M4C_RST) +#define IMX7D_M4_STOP (IMX7D_ENABLE_M4 | IMX7D_SW_M4C_RST | \ + IMX7D_SW_M4C_NON_SCLR_RST) + +#define IMX_RPROC_MEM_MAX 32 + +#define IMX_SIP_RPROC 0xC2000005 +#define IMX_SIP_RPROC_START 0x00 +#define IMX_SIP_RPROC_STARTED 0x01 +#define IMX_SIP_RPROC_STOP 0x02 + +struct imx_rproc { + const struct imx_rproc_dcfg *dcfg; + struct regmap *regmap; +}; + +/* att flags: lower 16 bits specifying core, higher 16 bits for flags */ +/* M4 own area. Can be mapped at probe */ +#define ATT_OWN BIT(31) +#define ATT_IOMEM BIT(30) + +static int imx_rproc_arm_smc_start(struct udevice *dev) +{ + struct arm_smccc_res res; + + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_START, 0, 0, 0, 0, 0, 0, &res); + + return res.a0; +} + +static int imx_rproc_mmio_start(struct udevice *dev) +{ + struct imx_rproc *priv = dev_get_priv(dev); + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + + return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_start); +} + +static int imx_rproc_start(struct udevice *dev) +{ + struct imx_rproc *priv = dev_get_priv(dev); + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + int ret; + + if (!dcfg->ops || !dcfg->ops->start) + return -EOPNOTSUPP; + + ret = dcfg->ops->start(dev); + if (ret) + dev_err(dev, "Failed to enable remote core!\n"); + + return ret; +} + +static int imx_rproc_arm_smc_stop(struct udevice *dev) +{ + struct arm_smccc_res res; + + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STOP, 0, 0, 0, 0, 0, 0, &res); + if (res.a1) + dev_info(dev, "Not in wfi, force stopped\n"); + + return res.a0; +} + +static int imx_rproc_mmio_stop(struct udevice *dev) +{ + struct imx_rproc *priv = dev_get_priv(dev); + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + + return regmap_update_bits(priv->regmap, dcfg->src_reg, dcfg->src_mask, dcfg->src_stop); +} + +static int imx_rproc_stop(struct udevice *dev) +{ + struct imx_rproc *priv = dev_get_priv(dev); + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + int ret; + + if (!dcfg->ops || !dcfg->ops->stop) + return -EOPNOTSUPP; + + ret = dcfg->ops->stop(dev); + if (ret) + dev_err(dev, "Failed to stop remote core\n"); + + return ret; +} + +static int imx_rproc_arm_smc_is_running(struct udevice *dev) +{ + struct arm_smccc_res res; + + arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res); + if (res.a0) + return 0; + + return 1; +} + +static int imx_rproc_mmio_is_running(struct udevice *dev) +{ + struct imx_rproc *priv = dev_get_priv(dev); + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + int ret; + u32 val; + + ret = regmap_read(priv->regmap, dcfg->src_reg, &val); + if (ret) { + dev_err(dev, "Failed to read src\n"); + return ret; + } + + if ((val & dcfg->src_mask) != dcfg->src_stop) + return 0; + + return 1; +} + +static int imx_rproc_is_running(struct udevice *dev) +{ + struct imx_rproc *priv = dev_get_priv(dev); + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + + if (!dcfg->ops || !dcfg->ops->is_running) + return 0; + + return dcfg->ops->is_running(dev); +} + +static int imx_rproc_init(struct udevice *dev) +{ + return 0; +} + +static int imx_rproc_da_to_sys(struct udevice *dev, u64 da, size_t len, u64 *sys, bool *is_iomem) +{ + struct imx_rproc *priv = dev_get_priv(dev); + const struct imx_rproc_dcfg *dcfg = priv->dcfg; + int i; + + /* parse address translation table */ + for (i = 0; i < dcfg->att_size; i++) { + const struct imx_rproc_att *att = &dcfg->att[i]; + + if (da >= att->da && da + len < att->da + att->size) { + unsigned int offset = da - att->da; + + *sys = att->sa + offset; + + if (is_iomem) + *is_iomem = att->flags & ATT_IOMEM; + + return 0; + } + } + + dev_err(dev, "Translation failed: da = 0x%llx len = 0x%zx\n", da, len); + + return -ENOENT; +} + +static void *imx_rproc_device_to_virt(struct udevice *dev, ulong da, ulong size, bool *is_iomem) +{ + u64 sys; + + if (imx_rproc_da_to_sys(dev, da, size, &sys, is_iomem)) + return NULL; + + dev_dbg(dev, "da = 0x%lx len = 0x%lx sys = 0x%llx\n", da, size, sys); + + return phys_to_virt(sys); +} + +static int imx_rproc_load(struct udevice *dev, ulong addr, ulong size) +{ + return rproc_elf_load_image(dev, addr, size); +} + +static const struct dm_rproc_ops imx_rproc_ops = { + .init = imx_rproc_init, + .start = imx_rproc_start, + .stop = imx_rproc_stop, + .load = imx_rproc_load, + .device_to_virt = imx_rproc_device_to_virt, + .is_running = imx_rproc_is_running, +}; + +static int imx_rproc_probe(struct udevice *dev) +{ + struct imx_rproc *priv = dev_get_priv(dev); + struct imx_rproc_dcfg *dcfg = (struct imx_rproc_dcfg *)dev_get_driver_data(dev); + ofnode node; + + node = dev_ofnode(dev); + + priv->dcfg = dcfg; + + if (dcfg->method != IMX_RPROC_MMIO) + return 0; + + priv->regmap = syscon_regmap_lookup_by_phandle(dev, "syscon"); + if (IS_ERR(priv->regmap)) { + dev_err(dev, "No syscon: %ld\n", PTR_ERR(priv->regmap)); + return PTR_ERR(priv->regmap); + } + + return 0; +} + +static const struct imx_rproc_att imx_rproc_att_imx8mn[] = { + /* dev addr , sys addr , size , flags */ + /* ITCM */ + { 0x00000000, 0x007E0000, 0x00020000, ATT_OWN | ATT_IOMEM }, + /* OCRAM_S */ + { 0x00180000, 0x00180000, 0x00009000, 0 }, + /* OCRAM */ + { 0x00900000, 0x00900000, 0x00020000, 0 }, + /* OCRAM */ + { 0x00920000, 0x00920000, 0x00020000, 0 }, + /* OCRAM */ + { 0x00940000, 0x00940000, 0x00050000, 0 }, + /* QSPI Code - alias */ + { 0x08000000, 0x08000000, 0x08000000, 0 }, + /* DDR (Code) - alias */ + { 0x10000000, 0x40000000, 0x0FFE0000, 0 }, + /* DTCM */ + { 0x20000000, 0x00800000, 0x00020000, ATT_OWN | ATT_IOMEM }, + /* OCRAM_S - alias */ + { 0x20180000, 0x00180000, 0x00008000, ATT_OWN }, + /* OCRAM */ + { 0x20200000, 0x00900000, 0x00020000, ATT_OWN }, + /* OCRAM */ + { 0x20220000, 0x00920000, 0x00020000, ATT_OWN }, + /* OCRAM */ + { 0x20240000, 0x00940000, 0x00040000, ATT_OWN }, + /* DDR (Data) */ + { 0x40000000, 0x40000000, 0x80000000, 0 }, +}; + +static const struct imx_rproc_plat_ops imx_rproc_ops_arm_smc = { + .start = imx_rproc_arm_smc_start, + .stop = imx_rproc_arm_smc_stop, + .is_running = imx_rproc_arm_smc_is_running, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mn = { + .att = imx_rproc_att_imx8mn, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8mn), + .method = IMX_RPROC_SMC, + .ops = &imx_rproc_ops_arm_smc, +}; + +static const struct imx_rproc_att imx_rproc_att_imx8mq[] = { + /* dev addr , sys addr , size , flags */ + /* TCML - alias */ + { 0x00000000, 0x007e0000, 0x00020000, ATT_IOMEM}, + /* OCRAM_S */ + { 0x00180000, 0x00180000, 0x00008000, 0 }, + /* OCRAM */ + { 0x00900000, 0x00900000, 0x00020000, 0 }, + /* OCRAM */ + { 0x00920000, 0x00920000, 0x00020000, 0 }, + /* QSPI Code - alias */ + { 0x08000000, 0x08000000, 0x08000000, 0 }, + /* DDR (Code) - alias */ + { 0x10000000, 0x40000000, 0x0FFE0000, 0 }, + /* TCML/U */ + { 0x1FFE0000, 0x007E0000, 0x00040000, ATT_OWN | ATT_IOMEM}, + /* OCRAM_S */ + { 0x20180000, 0x00180000, 0x00008000, ATT_OWN }, + /* OCRAM */ + { 0x20200000, 0x00900000, 0x00020000, ATT_OWN }, + /* OCRAM */ + { 0x20220000, 0x00920000, 0x00020000, ATT_OWN }, + /* DDR (Data) */ + { 0x40000000, 0x40000000, 0x80000000, 0 }, +}; + +static const struct imx_rproc_plat_ops imx_rproc_ops_mmio = { + .start = imx_rproc_mmio_start, + .stop = imx_rproc_mmio_stop, + .is_running = imx_rproc_mmio_is_running, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx8mq = { + .src_reg = IMX7D_SRC_SCR, + .src_mask = IMX7D_M4_RST_MASK, + .src_start = IMX7D_M4_START, + .src_stop = IMX7D_M4_STOP, + .att = imx_rproc_att_imx8mq, + .att_size = ARRAY_SIZE(imx_rproc_att_imx8mq), + .method = IMX_RPROC_MMIO, + .ops = &imx_rproc_ops_mmio, +}; + +static const struct imx_rproc_att imx_rproc_att_imx93[] = { + /* dev addr , sys addr , size , flags */ + /* TCM CODE NON-SECURE */ + { 0x0FFC0000, 0x201C0000, 0x00040000, ATT_OWN | ATT_IOMEM }, + + /* TCM CODE SECURE */ + { 0x1FFC0000, 0x201C0000, 0x00040000, ATT_OWN | ATT_IOMEM }, + + /* TCM SYS NON-SECURE*/ + { 0x20000000, 0x20200000, 0x00040000, ATT_OWN | ATT_IOMEM }, + + /* TCM SYS SECURE*/ + { 0x30000000, 0x20200000, 0x00040000, ATT_OWN | ATT_IOMEM }, + + /* DDR */ + { 0x80000000, 0x80000000, 0x10000000, 0 }, + { 0x90000000, 0x80000000, 0x10000000, 0 }, + + { 0xC0000000, 0xC0000000, 0x10000000, 0 }, + { 0xD0000000, 0xC0000000, 0x10000000, 0 }, +}; + +static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = { + .att = imx_rproc_att_imx93, + .att_size = ARRAY_SIZE(imx_rproc_att_imx93), + .method = IMX_RPROC_SMC, + .ops = &imx_rproc_ops_arm_smc, +}; + +static const struct udevice_id imx_rproc_ids[] = { + { .compatible = "fsl,imx8mm-cm4", .data = (ulong)&imx_rproc_cfg_imx8mq }, + { .compatible = "fsl,imx8mn-cm7", .data = (ulong)&imx_rproc_cfg_imx8mn, }, + { .compatible = "fsl,imx8mp-cm7", .data = (ulong)&imx_rproc_cfg_imx8mn, }, + { .compatible = "fsl,imx8mq-cm4", .data = (ulong)&imx_rproc_cfg_imx8mq }, + { .compatible = "fsl,imx93-cm33", .data = (ulong)&imx_rproc_cfg_imx93 }, + {} +}; + +U_BOOT_DRIVER(imx_rproc) = { + .name = "imx_rproc", + .of_match = imx_rproc_ids, + .id = UCLASS_REMOTEPROC, + .ops = &imx_rproc_ops, + .probe = imx_rproc_probe, + .priv_auto = sizeof(struct imx_rproc), +}; diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h new file mode 100644 index 00000000000..7a82dc4a195 --- /dev/null +++ b/drivers/remoteproc/imx_rproc.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> + * Copyright 2021 NXP + */ + +#ifndef _IMX_RPROC_H +#define _IMX_RPROC_H + +/* address translation table */ +struct imx_rproc_att { + u32 da; /* device address (From Cortex M4 view)*/ + u32 sa; /* system bus address */ + u32 size; /* size of reg range */ + int flags; +}; + +/* Remote core start/stop method */ +enum imx_rproc_method { + IMX_RPROC_NONE, + /* Through syscon regmap */ + IMX_RPROC_MMIO, + /* Through ARM SMCCC */ + IMX_RPROC_SMC, + /* Through System Control Unit API */ + IMX_RPROC_SCU_API, + /* Through Reset Controller API */ + IMX_RPROC_RESET_CONTROLLER, + /* Through System Manager */ + IMX_RPROC_SM, +}; + +/* dcfg flags */ +#define IMX_RPROC_NEED_SYSTEM_OFF BIT(0) + +struct imx_rproc_plat_ops { + int (*start)(struct udevice *dev); + int (*stop)(struct udevice *dev); + int (*is_running)(struct udevice *dev); +}; + +struct imx_rproc_dcfg { + u32 src_reg; + u32 src_mask; + u32 src_start; + u32 src_stop; + u32 gpr_reg; + u32 gpr_wait; + const struct imx_rproc_att *att; + size_t att_size; + enum imx_rproc_method method; + u32 flags; + const struct imx_rproc_plat_ops *ops; +}; + +#endif /* _IMX_RPROC_H */ diff --git a/drivers/remoteproc/renesas_apmu.c b/drivers/remoteproc/renesas_apmu.c index 1a50cd3289b..91586a99e0d 100644 --- a/drivers/remoteproc/renesas_apmu.c +++ b/drivers/remoteproc/renesas_apmu.c @@ -170,11 +170,12 @@ static int renesas_apmu_rproc_init(struct udevice *dev) * @dev: corresponding remote processor device * @da: device address * @size: Size of the memory region @da is pointing to + * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory * * Return: converted virtual address */ static void *renesas_apmu_rproc_device_to_virt(struct udevice *dev, ulong da, - ulong size) + ulong size, bool *is_iomem) { /* * The Cortex R52 and A76 share the same address space, diff --git a/drivers/remoteproc/rproc-elf-loader.c b/drivers/remoteproc/rproc-elf-loader.c index 0b3941b7798..83d70c2fb54 100644 --- a/drivers/remoteproc/rproc-elf-loader.c +++ b/drivers/remoteproc/rproc-elf-loader.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* * Copyright (C) 2019, STMicroelectronics - All Rights Reserved + * Copyright 2025 NXP */ #include <cpu_func.h> #include <dm.h> @@ -9,6 +10,7 @@ #include <mapmem.h> #include <remoteproc.h> #include <asm/cache.h> +#include <asm/io.h> #include <dm/device_compat.h> #include <linux/compat.h> #include <linux/printk.h> @@ -181,27 +183,38 @@ int rproc_elf32_load_image(struct udevice *dev, unsigned long addr, ulong size) for (i = 0; i < ehdr->e_phnum; i++, phdr++) { void *dst = (void *)(uintptr_t)phdr->p_paddr; void *src = (void *)addr + phdr->p_offset; + bool is_iomem = false; ulong dst_addr; - if (phdr->p_type != PT_LOAD) + if (phdr->p_type != PT_LOAD || !phdr->p_memsz) continue; if (ops->device_to_virt) dst = ops->device_to_virt(dev, (ulong)dst, - phdr->p_memsz); + phdr->p_memsz, &is_iomem); dev_dbg(dev, "Loading phdr %i to 0x%p (%i bytes)\n", i, dst, phdr->p_filesz); - if (phdr->p_filesz) - memcpy(dst, src, phdr->p_filesz); - if (phdr->p_filesz != phdr->p_memsz) - memset(dst + phdr->p_filesz, 0x00, - phdr->p_memsz - phdr->p_filesz); + if (phdr->p_filesz) { + if (is_iomem) + memcpy_toio(dst, src, phdr->p_filesz); + else + memcpy(dst, src, phdr->p_filesz); + } + if (phdr->p_filesz != phdr->p_memsz) { + if (is_iomem) + memset_io(dst + phdr->p_filesz, 0x00, + phdr->p_memsz - phdr->p_filesz); + else + memset(dst + phdr->p_filesz, 0x00, + phdr->p_memsz - phdr->p_filesz); + } dst_addr = map_to_sysmem(dst); - flush_cache(rounddown(dst_addr, ARCH_DMA_MINALIGN), - roundup(dst_addr + phdr->p_filesz, - ARCH_DMA_MINALIGN) - - rounddown(dst_addr, ARCH_DMA_MINALIGN)); + if (!is_iomem) { + flush_cache(rounddown(dst_addr, ARCH_DMA_MINALIGN), + roundup(dst_addr + phdr->p_filesz, ARCH_DMA_MINALIGN) - + rounddown(dst_addr, ARCH_DMA_MINALIGN)); + } } return 0; @@ -230,6 +243,7 @@ int rproc_elf64_load_image(struct udevice *dev, ulong addr, ulong size) memsz = phdr->p_memsz; filesz = phdr->p_filesz; offset = phdr->p_offset; + bool is_iomem = false; if (phdr->p_type != PT_LOAD) continue; @@ -239,7 +253,7 @@ int rproc_elf64_load_image(struct udevice *dev, ulong addr, ulong size) ptr = (void *)(uintptr_t)da; if (ops->device_to_virt) { - ptr = ops->device_to_virt(dev, da, phdr->p_memsz); + ptr = ops->device_to_virt(dev, da, phdr->p_memsz, &is_iomem); if (!ptr) { dev_err(dev, "bad da 0x%llx mem 0x%llx\n", da, memsz); @@ -248,14 +262,24 @@ int rproc_elf64_load_image(struct udevice *dev, ulong addr, ulong size) } } - if (filesz) - memcpy(ptr, (void *)addr + offset, filesz); - if (filesz != memsz) - memset(ptr + filesz, 0x00, memsz - filesz); + if (filesz) { + if (is_iomem) + memcpy_toio(ptr, (void *)addr + offset, filesz); + else + memcpy(ptr, (void *)addr + offset, filesz); + } + if (filesz != memsz) { + if (is_iomem) + memset_io(ptr + filesz, 0x00, memsz - filesz); + else + memset(ptr + filesz, 0x00, memsz - filesz); + } - flush_cache(rounddown((ulong)ptr, ARCH_DMA_MINALIGN), - roundup((ulong)ptr + filesz, ARCH_DMA_MINALIGN) - - rounddown((ulong)ptr, ARCH_DMA_MINALIGN)); + if (!is_iomem) { + flush_cache(rounddown((ulong)ptr, ARCH_DMA_MINALIGN), + roundup((ulong)ptr + filesz, ARCH_DMA_MINALIGN) - + rounddown((ulong)ptr, ARCH_DMA_MINALIGN)); + } } return ret; @@ -381,6 +405,7 @@ int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr, Elf32_Shdr *shdr; void *src, *dst; ulong dst_addr; + bool is_iomem = false; shdr = rproc_elf32_find_rsc_table(dev, fw_addr, fw_size); if (!shdr) @@ -394,18 +419,22 @@ int rproc_elf32_load_rsc_table(struct udevice *dev, ulong fw_addr, src = (void *)fw_addr + shdr->sh_offset; if (ops->device_to_virt) - dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size); + dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size, &is_iomem); else dst = (void *)rsc_addr; dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n", (ulong)dst, *rsc_size); - memcpy(dst, src, *rsc_size); - dst_addr = map_to_sysmem(dst); - flush_cache(rounddown(dst_addr, ARCH_DMA_MINALIGN), - roundup(dst_addr + *rsc_size, ARCH_DMA_MINALIGN) - - rounddown(dst_addr, ARCH_DMA_MINALIGN)); + if (is_iomem) { + memcpy_toio(dst, src, *rsc_size); + } else { + memcpy(dst, src, *rsc_size); + dst_addr = map_to_sysmem(dst); + flush_cache(rounddown(dst_addr, ARCH_DMA_MINALIGN), + roundup(dst_addr + *rsc_size, ARCH_DMA_MINALIGN) - + rounddown(dst_addr, ARCH_DMA_MINALIGN)); + } return 0; } @@ -490,6 +519,7 @@ int rproc_elf64_load_rsc_table(struct udevice *dev, ulong fw_addr, const struct dm_rproc_ops *ops; Elf64_Shdr *shdr; void *src, *dst; + bool is_iomem = false; shdr = rproc_elf64_find_rsc_table(dev, fw_addr, fw_size); if (!shdr) @@ -503,18 +533,21 @@ int rproc_elf64_load_rsc_table(struct udevice *dev, ulong fw_addr, src = (void *)fw_addr + shdr->sh_offset; if (ops->device_to_virt) - dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size); + dst = (void *)ops->device_to_virt(dev, *rsc_addr, *rsc_size, &is_iomem); else dst = (void *)rsc_addr; dev_dbg(dev, "Loading resource table to 0x%8lx (%ld bytes)\n", (ulong)dst, *rsc_size); - memcpy(dst, src, *rsc_size); - flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), - roundup((unsigned long)dst + *rsc_size, - ARCH_DMA_MINALIGN) - - rounddown((unsigned long)dst, ARCH_DMA_MINALIGN)); + if (is_iomem) { + memcpy_toio(dst, src, *rsc_size); + } else { + memcpy(dst, src, *rsc_size); + flush_cache(rounddown((unsigned long)dst, ARCH_DMA_MINALIGN), + roundup((unsigned long)dst + *rsc_size, ARCH_DMA_MINALIGN) - + rounddown((unsigned long)dst, ARCH_DMA_MINALIGN)); + } return 0; } diff --git a/drivers/remoteproc/sandbox_testproc.c b/drivers/remoteproc/sandbox_testproc.c index ad575a7c10f..7ed38e8656c 100644 --- a/drivers/remoteproc/sandbox_testproc.c +++ b/drivers/remoteproc/sandbox_testproc.c @@ -308,10 +308,11 @@ static int sandbox_testproc_ping(struct udevice *dev) * @dev: device to operate upon * @da: device address * @size: Size of the memory region @da is pointing to + * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory * Return: converted virtual address */ static void *sandbox_testproc_device_to_virt(struct udevice *dev, ulong da, - ulong size) + ulong size, bool *is_iomem) { u64 paddr; diff --git a/drivers/remoteproc/stm32_copro.c b/drivers/remoteproc/stm32_copro.c index f45da9a68ac..bf721e78bb3 100644 --- a/drivers/remoteproc/stm32_copro.c +++ b/drivers/remoteproc/stm32_copro.c @@ -61,10 +61,11 @@ static int stm32_copro_probe(struct udevice *dev) * @dev: corresponding STM32 remote processor device * @da: device address * @size: Size of the memory region @da is pointing to + * @is_iomem: optional pointer filled in to indicate if @da is iomapped memory * Return: converted virtual address */ static void *stm32_copro_device_to_virt(struct udevice *dev, ulong da, - ulong size) + ulong size, bool *is_iomem) { fdt32_t in_addr = cpu_to_be32(da), end_addr; u64 paddr; diff --git a/drivers/remoteproc/ti_k3_dsp_rproc.c b/drivers/remoteproc/ti_k3_dsp_rproc.c index 5a7d6377283..9275e1b241d 100644 --- a/drivers/remoteproc/ti_k3_dsp_rproc.c +++ b/drivers/remoteproc/ti_k3_dsp_rproc.c @@ -261,7 +261,7 @@ static int k3_dsp_reset(struct udevice *dev) return 0; } -static void *k3_dsp_da_to_va(struct udevice *dev, ulong da, ulong len) +static void *k3_dsp_da_to_va(struct udevice *dev, ulong da, ulong len, bool *is_iomem) { struct k3_dsp_privdata *dsp = dev_get_priv(dev); phys_addr_t bus_addr, dev_addr; diff --git a/drivers/remoteproc/ti_k3_m4_rproc.c b/drivers/remoteproc/ti_k3_m4_rproc.c index 31b9de71579..f358788f07f 100644 --- a/drivers/remoteproc/ti_k3_m4_rproc.c +++ b/drivers/remoteproc/ti_k3_m4_rproc.c @@ -181,7 +181,7 @@ static int k3_m4_stop(struct udevice *dev) return 0; } -static void *k3_m4_da_to_va(struct udevice *dev, ulong da, ulong len) +static void *k3_m4_da_to_va(struct udevice *dev, ulong da, ulong len, bool *is_iomem) { struct k3_m4_privdata *m4 = dev_get_priv(dev); phys_addr_t bus_addr, dev_addr; diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c index 48401bc6eb6..c738607c109 100644 --- a/drivers/remoteproc/ti_k3_r5f_rproc.c +++ b/drivers/remoteproc/ti_k3_r5f_rproc.c @@ -534,7 +534,7 @@ proc_release: return ret; } -static void *k3_r5f_da_to_va(struct udevice *dev, ulong da, ulong size) +static void *k3_r5f_da_to_va(struct udevice *dev, ulong da, ulong size, bool *is_iomem) { struct k3_r5f_core *core = dev_get_priv(dev); void __iomem *va = NULL; diff --git a/drivers/reset/reset-airoha.c b/drivers/reset/reset-airoha.c index e878af6167c..ef8c47a067b 100644 --- a/drivers/reset/reset-airoha.c +++ b/drivers/reset/reset-airoha.c @@ -10,7 +10,10 @@ #include <dm.h> #include <linux/io.h> #include <reset-uclass.h> +#include <regmap.h> +#include <asm/arch/scu-regmap.h> +#include <dt-bindings/reset/airoha,en7523-reset.h> #include <dt-bindings/reset/airoha,en7581-reset.h> #define RST_NR_PER_BANK 32 @@ -21,7 +24,8 @@ struct airoha_reset_priv { const u16 *bank_ofs; const u16 *idx_map; - void __iomem *base; + int num_rsts; + struct regmap *map; }; static const u16 en7581_rst_ofs[] = { @@ -29,6 +33,53 @@ static const u16 en7581_rst_ofs[] = { REG_RESET_CONTROL1, }; +static const u16 en7523_rst_map[] = { + /* RST_CTRL2 */ + [EN7523_XPON_PHY_RST] = 0, + [EN7523_XSI_MAC_RST] = 7, + [EN7523_XSI_PHY_RST] = 8, + [EN7523_NPU_RST] = 9, + [EN7523_I2S_RST] = 10, + [EN7523_TRNG_RST] = 11, + [EN7523_TRNG_MSTART_RST] = 12, + [EN7523_DUAL_HSI0_RST] = 13, + [EN7523_DUAL_HSI1_RST] = 14, + [EN7523_HSI_RST] = 15, + [EN7523_DUAL_HSI0_MAC_RST] = 16, + [EN7523_DUAL_HSI1_MAC_RST] = 17, + [EN7523_HSI_MAC_RST] = 18, + [EN7523_WDMA_RST] = 19, + [EN7523_WOE0_RST] = 20, + [EN7523_WOE1_RST] = 21, + [EN7523_HSDMA_RST] = 22, + [EN7523_I2C2RBUS_RST] = 23, + [EN7523_TDMA_RST] = 24, + /* RST_CTRL1 */ + [EN7523_PCM1_ZSI_ISI_RST] = RST_NR_PER_BANK + 0, + [EN7523_FE_PDMA_RST] = RST_NR_PER_BANK + 1, + [EN7523_FE_QDMA_RST] = RST_NR_PER_BANK + 2, + [EN7523_PCM_SPIWP_RST] = RST_NR_PER_BANK + 4, + [EN7523_CRYPTO_RST] = RST_NR_PER_BANK + 6, + [EN7523_TIMER_RST] = RST_NR_PER_BANK + 8, + [EN7523_PCM1_RST] = RST_NR_PER_BANK + 11, + [EN7523_UART_RST] = RST_NR_PER_BANK + 12, + [EN7523_GPIO_RST] = RST_NR_PER_BANK + 13, + [EN7523_GDMA_RST] = RST_NR_PER_BANK + 14, + [EN7523_I2C_MASTER_RST] = RST_NR_PER_BANK + 16, + [EN7523_PCM2_ZSI_ISI_RST] = RST_NR_PER_BANK + 17, + [EN7523_SFC_RST] = RST_NR_PER_BANK + 18, + [EN7523_UART2_RST] = RST_NR_PER_BANK + 19, + [EN7523_GDMP_RST] = RST_NR_PER_BANK + 20, + [EN7523_FE_RST] = RST_NR_PER_BANK + 21, + [EN7523_USB_HOST_P0_RST] = RST_NR_PER_BANK + 22, + [EN7523_GSW_RST] = RST_NR_PER_BANK + 23, + [EN7523_SFC2_PCM_RST] = RST_NR_PER_BANK + 25, + [EN7523_PCIE0_RST] = RST_NR_PER_BANK + 26, + [EN7523_PCIE1_RST] = RST_NR_PER_BANK + 27, + [EN7523_PCIE_HB_RST] = RST_NR_PER_BANK + 29, + [EN7523_XPON_MAC_RST] = RST_NR_PER_BANK + 31, +}; + static const u16 en7581_rst_map[] = { /* RST_CTRL2 */ [EN7581_XPON_PHY_RST] = 0, @@ -90,17 +141,11 @@ static const u16 en7581_rst_map[] = { static int airoha_reset_update(struct airoha_reset_priv *priv, unsigned long id, bool assert) { - void __iomem *addr = priv->base + priv->bank_ofs[id / RST_NR_PER_BANK]; - u32 val; - - val = readl(addr); - if (assert) - val |= BIT(id % RST_NR_PER_BANK); - else - val &= ~BIT(id % RST_NR_PER_BANK); - writel(val, addr); + u16 offset = priv->bank_ofs[id / RST_NR_PER_BANK]; - return 0; + return regmap_update_bits(priv->map, offset, + BIT(id % RST_NR_PER_BANK), + assert ? BIT(id % RST_NR_PER_BANK) : 0); } static int airoha_reset_assert(struct reset_ctl *reset_ctl) @@ -123,11 +168,16 @@ static int airoha_reset_status(struct reset_ctl *reset_ctl) { struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev); int id = reset_ctl->id; - void __iomem *addr; + u16 offset; + u32 val; + int ret; - addr = priv->base + priv->bank_ofs[id / RST_NR_PER_BANK]; + offset = priv->bank_ofs[id / RST_NR_PER_BANK]; + ret = regmap_read(priv->map, offset, &val); + if (ret) + return ret; - return !!(readl(addr) & BIT(id % RST_NR_PER_BANK)); + return !!(val & BIT(id % RST_NR_PER_BANK)); } static int airoha_reset_xlate(struct reset_ctl *reset_ctl, @@ -135,7 +185,7 @@ static int airoha_reset_xlate(struct reset_ctl *reset_ctl, { struct airoha_reset_priv *priv = dev_get_priv(reset_ctl->dev); - if (args->args[0] >= ARRAY_SIZE(en7581_rst_map)) + if (args->args[0] >= priv->num_rsts) return -EINVAL; reset_ctl->id = priv->idx_map[args->args[0]]; @@ -150,20 +200,36 @@ static struct reset_ops airoha_reset_ops = { .rst_status = airoha_reset_status, }; -static int airoha_reset_probe(struct udevice *dev) +static int reset_init(struct udevice *dev, const u16 *rst_map, int num_rsts) { struct airoha_reset_priv *priv = dev_get_priv(dev); - priv->base = dev_remap_addr(dev); - if (!priv->base) - return -ENOMEM; + priv->map = airoha_get_scu_regmap(); + if (IS_ERR(priv->map)) + return PTR_ERR(priv->map); priv->bank_ofs = en7581_rst_ofs; - priv->idx_map = en7581_rst_map; + priv->idx_map = rst_map; + priv->num_rsts = num_rsts; return 0; } +static int airoha_reset_probe(struct udevice *dev) +{ + if (ofnode_device_is_compatible(dev_ofnode(dev), + "airoha,en7523-scu")) + return reset_init(dev, en7523_rst_map, + ARRAY_SIZE(en7523_rst_map)); + + if (ofnode_device_is_compatible(dev_ofnode(dev), + "airoha,en7581-scu")) + return reset_init(dev, en7581_rst_map, + ARRAY_SIZE(en7581_rst_map)); + + return -ENODEV; +} + U_BOOT_DRIVER(airoha_reset) = { .name = "airoha-reset", .id = UCLASS_RESET, diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c index b9c4f09fdfd..d04e8eef3bb 100644 --- a/drivers/reset/reset-zynqmp.c +++ b/drivers/reset/reset-zynqmp.c @@ -22,7 +22,7 @@ static int zynqmp_pm_reset_assert(const u32 reset, const enum zynqmp_pm_reset_action assert_flag) { return xilinx_pm_request(PM_RESET_ASSERT, reset, assert_flag, 0, 0, - NULL); + 0, 0, NULL); } static int zynqmp_reset_assert(struct reset_ctl *rst) diff --git a/drivers/rng/Kconfig b/drivers/rng/Kconfig index b35d8c66b9c..19b2b707677 100644 --- a/drivers/rng/Kconfig +++ b/drivers/rng/Kconfig @@ -40,7 +40,7 @@ config RNG_MSM config RNG_NPCM bool "Nuvoton NPCM SoCs Random Number Generator support" - depends on DM_RNG + depends on DM_RNG && !LIB_RAND help Enable random number generator on NPCM SoCs. This unit can provide 750 to 1000 random bits per second @@ -122,7 +122,7 @@ config RNG_TURRIS_RWTM config RNG_EXYNOS bool "Samsung Exynos True Random Number Generator support" - depends on DM_RNG + depends on DM_RNG && ARM help Enable support for True Random Number Generator (TRNG) available on Exynos SoCs. diff --git a/drivers/rtc/ds1672.c b/drivers/rtc/ds1672.c index 4705e5abc93..651b1dc950f 100644 --- a/drivers/rtc/ds1672.c +++ b/drivers/rtc/ds1672.c @@ -108,7 +108,7 @@ static const struct udevice_id ds1672_of_id[] = { { } }; -U_BOOT_DRIVER(rtc_max313xx) = { +U_BOOT_DRIVER(rtc_ds1672) = { .name = "rtc-ds1672", .id = UCLASS_RTC, .probe = ds1672_probe, diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 05608399be1..b414d022f3f 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -584,7 +584,7 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose) struct udevice *bdev; struct blk_desc bd; struct blk_desc *bdesc; - char str[10], *name; + char str[10]; /* * detect the scsi driver to get information about its geometry (block @@ -600,10 +600,7 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose) * block devices created */ snprintf(str, sizeof(str), "id%dlun%d", id, lun); - name = strdup(str); - if (!name) - return log_msg_ret("nam", -ENOMEM); - ret = blk_create_devicef(dev, "scsi_blk", name, UCLASS_SCSI, -1, + ret = blk_create_devicef(dev, "scsi_blk", str, UCLASS_SCSI, -1, bd.blksz, bd.lba, &bdev); if (ret) { debug("Can't create device\n"); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index bc05d2f1508..371d7aa5bba 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -194,7 +194,7 @@ config TPL_DM_SERIAL config VPL_DM_SERIAL bool "Enable Driver Model for serial drivers in VPL" - depends on DM_SERIAL + depends on DM_SERIAL && VPL_DM default y if VPL && DM_SERIAL help Enable driver model for serial in VPL. This replaces @@ -328,7 +328,7 @@ config DEBUG_UART_MSM be available until the real driver-model serial is running. config DEBUG_UART_MSM_GENI - bool "Qualcomm snapdragon" + bool "Qualcomm GENI UART debug" depends on ARCH_SNAPDRAGON help Select this to enable a debug UART using the serial_msm driver. You @@ -1001,6 +1001,7 @@ config MSM_SERIAL config MSM_GENI_SERIAL bool "Qualcomm on-chip GENI UART" + depends on QCOM_GENI help Support UART based on Generic Interface (GENI) Serial Engine (SE), used on Qualcomm Snapdragon SoCs. Should support all qualcomm SOCs diff --git a/drivers/serial/serial_msm.c b/drivers/serial/serial_msm.c index 757e5eaf974..18d15b7b15b 100644 --- a/drivers/serial/serial_msm.c +++ b/drivers/serial/serial_msm.c @@ -17,20 +17,17 @@ #include <asm/global_data.h> #include <asm/io.h> #include <linux/compiler.h> -#include <linux/delay.h> #include <dm/pinctrl.h> /* Serial registers - this driver works in uartdm mode*/ -#define UARTDM_DMRX 0x34 /* Max RX transfer length */ -#define UARTDM_DMEN 0x3C /* DMA/data-packing mode */ -#define UARTDM_NCF_TX 0x40 /* Number of chars to TX */ +#define UARTDM_DMEN 0x3C /* DMA/data-packing mode */ +#define UARTDM_DMEN_TXRX_SC_ENABLE (BIT(4) | BIT(5)) -#define UARTDM_RXFS 0x50 /* RX channel status register */ -#define UARTDM_RXFS_BUF_SHIFT 0x7 /* Number of bytes in the packing buffer */ -#define UARTDM_RXFS_BUF_MASK 0x7 #define UARTDM_MR1 0x00 +#define UARTDM_MR1_RX_RDY_CTL BIT(7) #define UARTDM_MR2 0x04 +#define UARTDM_MR2_8_N_1_MODE 0x34 /* * This is documented on page 1817 of the apq8016e technical reference manual. * section 6.2.5.3.26 @@ -44,119 +41,56 @@ #define UARTDM_CSR 0xA0 #define UARTDM_SR 0xA4 /* Status register */ -#define UARTDM_SR_RX_READY (1 << 0) /* Word is the receiver FIFO */ +#define UARTDM_SR_RX_READY (1 << 0) /* Receiver FIFO has data */ +#define UARTDM_SR_TX_READY (1 << 2) /* Transmitter FIFO has space */ #define UARTDM_SR_TX_EMPTY (1 << 3) /* Transmitter underrun */ -#define UARTDM_SR_UART_OVERRUN (1 << 4) /* Receive overrun */ #define UARTDM_CR 0xA8 /* Command register */ -#define UARTDM_CR_CMD_RESET_ERR (3 << 4) /* Clear overrun error */ -#define UARTDM_CR_CMD_RESET_STALE_INT (8 << 4) /* Clears stale irq */ -#define UARTDM_CR_CMD_RESET_TX_READY (3 << 8) /* Clears TX Ready irq*/ -#define UARTDM_CR_CMD_FORCE_STALE (4 << 8) /* Causes stale event */ -#define UARTDM_CR_CMD_STALE_EVENT_DISABLE (6 << 8) /* Disable stale event */ - -#define UARTDM_IMR 0xB0 /* Interrupt mask register */ -#define UARTDM_ISR 0xB4 /* Interrupt status register */ -#define UARTDM_ISR_TX_READY 0x80 /* TX FIFO empty */ +#define UARTDM_CR_RX_ENABLE (1 << 0) /* Enable receiver */ +#define UARTDM_CR_TX_ENABLE (1 << 2) /* Enable transmitter */ +#define UARTDM_CR_CMD_RESET_RX (1 << 4) /* Reset receiver */ +#define UARTDM_CR_CMD_RESET_TX (2 << 4) /* Reset transmitter */ #define UARTDM_TF 0x100 /* UART Transmit FIFO register */ #define UARTDM_RF 0x140 /* UART Receive FIFO register */ - -#define MSM_BOOT_UART_DM_8_N_1_MODE 0x34 -#define MSM_BOOT_UART_DM_CMD_RESET_RX 0x10 -#define MSM_BOOT_UART_DM_CMD_RESET_TX 0x20 -#define MSM_UART_MR1_RX_RDY_CTL BIT(7) +#define UARTDM_RF_CHAR 0xff /* higher bits contain error information */ DECLARE_GLOBAL_DATA_PTR; struct msm_serial_data { phys_addr_t base; - unsigned chars_cnt; /* number of buffered chars */ - uint32_t chars_buf; /* buffered chars */ uint32_t clk_rate; /* core clock rate */ }; -static int msm_serial_fetch(struct udevice *dev) -{ - struct msm_serial_data *priv = dev_get_priv(dev); - unsigned sr; - - if (priv->chars_cnt) - return priv->chars_cnt; - - /* Clear error in case of buffer overrun */ - if (readl(priv->base + UARTDM_SR) & UARTDM_SR_UART_OVERRUN) - writel(UARTDM_CR_CMD_RESET_ERR, priv->base + UARTDM_CR); - - /* We need to fetch new character */ - sr = readl(priv->base + UARTDM_SR); - - if (sr & UARTDM_SR_RX_READY) { - /* There are at least 4 bytes in fifo */ - priv->chars_buf = readl(priv->base + UARTDM_RF); - priv->chars_cnt = 4; - } else { - /* Check if there is anything in fifo */ - priv->chars_cnt = readl(priv->base + UARTDM_RXFS); - /* Extract number of characters in UART packing buffer*/ - priv->chars_cnt = (priv->chars_cnt >> - UARTDM_RXFS_BUF_SHIFT) & - UARTDM_RXFS_BUF_MASK; - if (!priv->chars_cnt) - return 0; - - /* There is at least one charcter, move it to fifo */ - writel(UARTDM_CR_CMD_FORCE_STALE, - priv->base + UARTDM_CR); - - priv->chars_buf = readl(priv->base + UARTDM_RF); - writel(UARTDM_CR_CMD_RESET_STALE_INT, - priv->base + UARTDM_CR); - writel(0x7, priv->base + UARTDM_DMRX); - } - - return priv->chars_cnt; -} - static int msm_serial_getc(struct udevice *dev) { struct msm_serial_data *priv = dev_get_priv(dev); - char c; - if (!msm_serial_fetch(dev)) + if (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_RX_READY)) return -EAGAIN; - c = priv->chars_buf & 0xFF; - priv->chars_buf >>= 8; - priv->chars_cnt--; - - return c; + return readl(priv->base + UARTDM_RF) & UARTDM_RF_CHAR; } static int msm_serial_putc(struct udevice *dev, const char ch) { struct msm_serial_data *priv = dev_get_priv(dev); - if (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY) && - !(readl(priv->base + UARTDM_ISR) & UARTDM_ISR_TX_READY)) + if (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_READY)) return -EAGAIN; - writel(UARTDM_CR_CMD_RESET_TX_READY, priv->base + UARTDM_CR); - - writel(1, priv->base + UARTDM_NCF_TX); writel(ch, priv->base + UARTDM_TF); - return 0; } static int msm_serial_pending(struct udevice *dev, bool input) { - if (input) { - if (msm_serial_fetch(dev)) - return 1; - } + struct msm_serial_data *priv = dev_get_priv(dev); - return 0; + if (input) + return !!(readl(priv->base + UARTDM_SR) & UARTDM_SR_RX_READY); + else + return !(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY); } static const struct dm_serial_ops msm_serial_ops = { @@ -207,8 +141,6 @@ static int calc_csr_bitrate(struct msm_serial_data *priv) static void uart_dm_init(struct msm_serial_data *priv) { - /* Delay initialization for a bit to let pins stabilize if necessary */ - mdelay(5); int bitrate = calc_csr_bitrate(priv); if (bitrate < 0) { log_warning("Couldn't calculate bit clock divider! Using default\n"); @@ -221,13 +153,16 @@ static void uart_dm_init(struct msm_serial_data *priv) writel(bitrate, priv->base + UARTDM_CSR); /* Enable RS232 flow control to support RS232 db9 connector */ - writel(MSM_UART_MR1_RX_RDY_CTL, priv->base + UARTDM_MR1); - writel(MSM_BOOT_UART_DM_8_N_1_MODE, priv->base + UARTDM_MR2); - writel(MSM_BOOT_UART_DM_CMD_RESET_RX, priv->base + UARTDM_CR); - writel(MSM_BOOT_UART_DM_CMD_RESET_TX, priv->base + UARTDM_CR); + writel(UARTDM_MR1_RX_RDY_CTL, priv->base + UARTDM_MR1); + writel(UARTDM_MR2_8_N_1_MODE, priv->base + UARTDM_MR2); - /* Make sure BAM/single character mode is disabled */ - writel(0x0, priv->base + UARTDM_DMEN); + /* Enable single character mode */ + writel(UARTDM_DMEN_TXRX_SC_ENABLE, priv->base + UARTDM_DMEN); + + writel(UARTDM_CR_CMD_RESET_RX, priv->base + UARTDM_CR); + writel(UARTDM_CR_CMD_RESET_TX, priv->base + UARTDM_CR); + writel(UARTDM_CR_RX_ENABLE, priv->base + UARTDM_CR); + writel(UARTDM_CR_TX_ENABLE, priv->base + UARTDM_CR); } static int msm_serial_probe(struct udevice *dev) { @@ -319,13 +254,9 @@ static inline void _debug_uart_putc(int ch) { struct msm_serial_data *priv = &init_serial_data; - while (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_EMPTY) && - !(readl(priv->base + UARTDM_ISR) & UARTDM_ISR_TX_READY)) + while (!(readl(priv->base + UARTDM_SR) & UARTDM_SR_TX_READY)) ; - writel(UARTDM_CR_CMD_RESET_TX_READY, priv->base + UARTDM_CR); - - writel(1, priv->base + UARTDM_NCF_TX); writel(ch, priv->base + UARTDM_TF); } diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c index 0eb90f82a34..bb5a2cb4d2c 100644 --- a/drivers/serial/serial_msm_geni.c +++ b/drivers/serial/serial_msm_geni.c @@ -10,11 +10,14 @@ #include <asm/io.h> #include <clk.h> #include <dm.h> +#include <dm/device_compat.h> #include <errno.h> #include <linux/delay.h> #include <linux/time.h> #include <misc.h> #include <serial.h> +#include <soc/qcom/qup-fw-load.h> +#include <soc/qcom/geni-se.h> #define UART_OVERSAMPLING 32 #define STALE_TIMEOUT 160 @@ -22,8 +25,6 @@ /* Registers*/ #define GENI_FORCE_DEFAULT_REG 0x20 #define GENI_SER_M_CLK_CFG 0x48 -#define GENI_SER_S_CLK_CFG 0x4C -#define SE_HW_PARAM_0 0xE24 #define SE_GENI_STATUS 0x40 #define SE_GENI_S_CMD0 0x630 #define SE_GENI_S_CMD_CTRL_REG 0x634 @@ -39,7 +40,6 @@ #define SE_GENI_RX_FIFOn 0x780 #define SE_GENI_TX_FIFO_STATUS 0x800 #define SE_GENI_RX_FIFO_STATUS 0x804 -#define SE_GENI_TX_WATERMARK_REG 0x80C #define SE_GENI_TX_PACKING_CFG0 0x260 #define SE_GENI_TX_PACKING_CFG1 0x264 #define SE_GENI_RX_PACKING_CFG0 0x284 @@ -54,59 +54,24 @@ #define SE_UART_RX_TRANS_CFG 0x280 #define SE_UART_RX_PARITY_CFG 0x2a8 -#define M_TX_FIFO_WATERMARK_EN (BIT(30)) #define DEF_TX_WM 2 /* GENI_FORCE_DEFAULT_REG fields */ -#define FORCE_DEFAULT (BIT(0)) - -#define S_CMD_ABORT_EN (BIT(5)) #define UART_START_READ 0x1 -/* GENI_M_CMD_CTRL_REG */ -#define M_GENI_CMD_CANCEL (BIT(2)) -#define M_GENI_CMD_ABORT (BIT(1)) -#define M_GENI_DISABLE (BIT(0)) - -#define M_CMD_ABORT_EN (BIT(5)) -#define M_CMD_DONE_EN (BIT(0)) #define M_CMD_DONE_DISABLE_MASK (~M_CMD_DONE_EN) -#define S_GENI_CMD_ABORT (BIT(1)) - -/* GENI_S_CMD0 fields */ -#define S_OPCODE_MSK (GENMASK(31, 27)) -#define S_PARAMS_MSK (GENMASK(26, 0)) - -/* GENI_STATUS fields */ -#define M_GENI_CMD_ACTIVE (BIT(0)) -#define S_GENI_CMD_ACTIVE (BIT(12)) -#define M_CMD_DONE_EN (BIT(0)) -#define S_CMD_DONE_EN (BIT(0)) - #define M_OPCODE_SHIFT 27 #define S_OPCODE_SHIFT 27 -#define M_TX_FIFO_WATERMARK_EN (BIT(30)) #define UART_START_TX 0x1 #define UART_CTS_MASK (BIT(1)) -#define M_SEC_IRQ_EN (BIT(31)) #define TX_FIFO_WC_MSK (GENMASK(27, 0)) -#define RX_FIFO_WC_MSK (GENMASK(24, 0)) - -#define S_RX_FIFO_WATERMARK_EN (BIT(26)) -#define S_RX_FIFO_LAST_EN (BIT(27)) -#define M_RX_FIFO_WATERMARK_EN (BIT(26)) -#define M_RX_FIFO_LAST_EN (BIT(27)) /* GENI_SER_M_CLK_CFG/GENI_SER_S_CLK_CFG */ -#define SER_CLK_EN (BIT(0)) -#define CLK_DIV_MSK (GENMASK(15, 4)) #define CLK_DIV_SHFT 4 /* SE_HW_PARAM_0 fields */ -#define TX_FIFO_WIDTH_MSK (GENMASK(29, 24)) #define TX_FIFO_WIDTH_SHFT 24 -#define TX_FIFO_DEPTH_MSK (GENMASK(21, 16)) #define TX_FIFO_DEPTH_SHFT 16 /* GENI SE QUP Registers */ @@ -131,6 +96,7 @@ struct msm_serial_data { phys_addr_t base; u32 baud; u32 oversampling; + struct clk *se; }; unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200, @@ -181,19 +147,6 @@ static int get_clk_div_rate(u32 baud, u64 sampling_rate, u32 *clk_div) return ser_clk; } -static int geni_serial_set_clock_rate(struct udevice *dev, u64 rate) -{ - struct clk *clk; - int ret; - - clk = devm_clk_get(dev, NULL); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - ret = clk_set_rate(clk, rate); - return ret; -} - /** * geni_se_get_tx_fifo_depth() - Get the TX fifo depth of the serial engine * @base: Pointer to the concerned serial engine. @@ -256,7 +209,7 @@ static int msm_serial_setbrg(struct udevice *dev, int baud) pr_err("%s: Couldn't get clock division rate\n", __func__); return -EINVAL; } - ret = geni_serial_set_clock_rate(dev, clk_rate); + ret = clk_set_rate(priv->se, clk_rate); if (ret < 0) { pr_err("%s: Couldn't set clock rate: %d\n", __func__, ret); return ret; @@ -561,6 +514,42 @@ static int msm_serial_probe(struct udevice *dev) { struct msm_serial_data *priv = dev_get_priv(dev); int ret; + u32 proto; + struct clk *clk; + + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + priv->se = clk; + + /* Try enable clock */ + ret = clk_enable(clk); + + /* Check if firmware loading is needed (BT UART) */ + proto = readl(priv->base + GENI_FW_REVISION_RO); + proto &= FW_REV_PROTOCOL_MSK; + proto >>= FW_REV_PROTOCOL_SHFT; + + if (proto == GENI_SE_INVALID_PROTO) { + qcom_geni_load_firmware(priv->base, dev); + proto = readl(priv->base + GENI_FW_REVISION_RO); + proto &= FW_REV_PROTOCOL_MSK; + proto >>= FW_REV_PROTOCOL_SHFT; + } + + if (proto != GENI_SE_UART) { + dev_err(dev, "Invalid proto %d\n", proto); + clk_disable(clk); + return -ENXIO; + } + + /* Don't actually probe non-debug UARTs */ + if (ofnode_device_is_compatible(dev_ofnode(dev), "qcom,geni-uart")) + return -ENOENT; + + /* Now handle clock enable return value */ + if (ret) + return ret; ret = geni_set_oversampling(dev); if (ret < 0) @@ -591,6 +580,7 @@ static int msm_serial_ofdata_to_platdata(struct udevice *dev) static const struct udevice_id msm_serial_ids[] = { { .compatible = "qcom,geni-debug-uart" }, + { .compatible = "qcom,geni-uart" }, { } }; @@ -605,19 +595,6 @@ U_BOOT_DRIVER(serial_msm_geni) = { .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, }; -static const struct udevice_id geniqup_ids[] = { - { .compatible = "qcom,geni-se-qup" }, - { } -}; - -U_BOOT_DRIVER(geni_se_qup) = { - .name = "geni-se-qup", - .id = UCLASS_NOP, - .of_match = geniqup_ids, - .bind = dm_scan_fdt_dev, - .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, -}; - #ifdef CONFIG_DEBUG_UART_MSM_GENI static struct msm_serial_data init_serial_data = { diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c index e4cc4ee4260..7ab62e0e90b 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -112,7 +112,16 @@ static int serial_raw_putc(struct uart_port *port, const char c) static int serial_rx_fifo_level(struct uart_port *port) { - return scif_rxfill(port); + int ret; + + ret = scif_rxfill(port); + if (ret) + return ret; + + if (sci_in(port, SCxSR) & SCxSR_RDxF(port)) + return 1; + + return 0; } static int sh_serial_tstc_generic(struct uart_port *port) diff --git a/drivers/soc/soc_amd_versal2.c b/drivers/soc/soc_amd_versal2.c index 8507da0bd22..7f06c1e70bc 100644 --- a/drivers/soc/soc_amd_versal2.c +++ b/drivers/soc/soc_amd_versal2.c @@ -55,7 +55,7 @@ static int soc_amd_versal2_probe(struct udevice *dev) if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) { ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, - ret_payload); + 0, 0, ret_payload); if (ret) return ret; } else { diff --git a/drivers/soc/soc_xilinx_versal.c b/drivers/soc/soc_xilinx_versal.c index 7427f8432c8..c43a80df1fc 100644 --- a/drivers/soc/soc_xilinx_versal.c +++ b/drivers/soc/soc_xilinx_versal.c @@ -51,7 +51,7 @@ static int soc_xilinx_versal_probe(struct udevice *dev) if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) { ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, - ret_payload); + 0, 0, ret_payload); if (ret) return ret; } else { diff --git a/drivers/soc/soc_xilinx_versal_net.c b/drivers/soc/soc_xilinx_versal_net.c index d64fc366a6d..210f9f8f8fd 100644 --- a/drivers/soc/soc_xilinx_versal_net.c +++ b/drivers/soc/soc_xilinx_versal_net.c @@ -53,7 +53,7 @@ static int soc_xilinx_versal_net_probe(struct udevice *dev) if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) { ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, - ret_payload); + 0, 0, ret_payload); if (ret) return ret; } else { diff --git a/drivers/soc/soc_xilinx_zynqmp.c b/drivers/soc/soc_xilinx_zynqmp.c index 4b69ff3de13..b97cd443c60 100644 --- a/drivers/soc/soc_xilinx_zynqmp.c +++ b/drivers/soc/soc_xilinx_zynqmp.c @@ -362,7 +362,7 @@ static int soc_xilinx_zynqmp_probe(struct udevice *dev) ret = zynqmp_mmio_read(ZYNQMP_PS_VERSION, &ret_payload[2]); else ret = xilinx_pm_request(PM_GET_CHIPID, 0, 0, 0, 0, - ret_payload); + 0, 0, ret_payload); if (ret < 0) return ret; diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig index 81de9b30f39..afcc08c27bc 100644 --- a/drivers/sound/Kconfig +++ b/drivers/sound/Kconfig @@ -12,9 +12,10 @@ config SOUND audio codecs are called from the sound-i2s code. This could be converted to driver model. +if SOUND + config I2S bool "Enable I2S support" - depends on SOUND help I2S is a serial bus often used to transmit audio data from the SoC to the audio codec. This option enables sound support using @@ -42,7 +43,6 @@ config I2S_SAMSUNG config SOUND_DA7219 bool "Dialog Semiconductor audio codec" - depends on SOUND help The DA7219 is an ultra-low-power audio codec with Advanced Accessory Detection (AAD). This driver only supports generation of ACPI tables. @@ -51,7 +51,7 @@ config SOUND_DA7219 config SOUND_I8254 bool "Intel i8254 timer / beeper" - depends on SOUND && X86 + depends on X86 help This enables support for a beeper that uses the i8254 timer chip. This can emit beeps at a fixed frequency. It is possible to control @@ -63,7 +63,6 @@ config SOUND_I8254 config SOUND_INTEL_HDA bool "Intel HDA audio codec" - depends on SOUND help Most Intel chips have an HDA (High-definition audio) codec which can be used by U-Boot to play simple beeps. This is also sometimes called @@ -72,7 +71,6 @@ config SOUND_INTEL_HDA config SOUND_IVYBRIDGE bool "Intel Ivybridge sound support" - depends on SOUND select SOUND_INTEL_HDA help Enable sound output on supported Intel Ivybridge-based boards. This @@ -148,4 +146,6 @@ config SOUND_WM8994 audio data and I2C for codec control. At present it only works with the Samsung I2S driver. +endif + endmenu diff --git a/drivers/sound/maxim_codec.c b/drivers/sound/maxim_codec.c index 505a739ad7d..a3750e18f7d 100644 --- a/drivers/sound/maxim_codec.c +++ b/drivers/sound/maxim_codec.c @@ -18,8 +18,8 @@ * Writes value to a device register through i2c * * @param priv Private data for driver - * @param reg reg number to be write - * @param data data to be writen to the above registor + * @param reg reg number to be written + * @param data data to be written to the above registor * * Return: int value 1 for change, 0 for no change or negative error code. */ diff --git a/drivers/sound/maxim_codec.h b/drivers/sound/maxim_codec.h index deaefd93eb1..23f8341e59c 100644 --- a/drivers/sound/maxim_codec.h +++ b/drivers/sound/maxim_codec.h @@ -31,8 +31,8 @@ struct maxim_priv { * Writes value to a device register through i2c * * @param priv Private data for driver - * @param reg reg number to be write - * @param data data to be writen to the above registor + * @param reg reg number to be written + * @param data data to be written to the above registor * * Return: int value 1 for change, 0 for no change or negative error code. */ diff --git a/drivers/sound/wm8994.c b/drivers/sound/wm8994.c index 42947357836..ae27947d43f 100644 --- a/drivers/sound/wm8994.c +++ b/drivers/sound/wm8994.c @@ -67,8 +67,8 @@ static int bclk_divs[] = { * Writes value to a device register through i2c * * @param priv Private data for driver - * @param reg reg number to be write - * @param data data to be writen to the above registor + * @param reg reg number to be written + * @param data data to be written to the above registor * * Return: int value 1 for change, 0 for no change or negative error code. */ diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 2960822211a..c88918606d2 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -452,6 +452,7 @@ config ROCKCHIP_SFC config ROCKCHIP_SPI bool "Rockchip SPI driver" + depends on ARCH_ROCKCHIP help Enable the Rockchip SPI driver, used to access SPI NOR flash and other SPI peripherals (such as the Chrome OS EC) on Rockchip SoCs. @@ -495,7 +496,7 @@ config SANDBOX_SPI_MAX_CS config SPI_ASPEED_SMC bool "ASPEED SPI flash controller driver" - depends on DM_SPI && SPI_MEM + depends on DM_SPI && SPI_MEM && ARCH_ASPEED help Enable ASPEED SPI flash controller driver for AST2500 and AST2600 SoCs. @@ -622,6 +623,7 @@ config ZYNQ_SPI config ZYNQ_QSPI bool "Zynq QSPI driver" + depends on ARCH_VERSAL || ARCH_VERSAL_NET || ARCH_VERSAL2 || ARCH_ZYNQ || ARCH_ZYNQMP imply SPI_FLASH_BAR help Enable the Zynq Quad-SPI (QSPI) driver. This driver can be @@ -631,6 +633,7 @@ config ZYNQ_QSPI config ZYNQMP_GQSPI bool "Configure ZynqMP Generic QSPI" + depends on ARCH_VERSAL || ARCH_VERSAL_NET || ARCH_VERSAL2 || ARCH_ZYNQ || ARCH_ZYNQMP help This option is used to enable ZynqMP QSPI controller driver which is used to communicate with qspi flash devices. diff --git a/drivers/spi/airoha_snfi_spi.c b/drivers/spi/airoha_snfi_spi.c index 3ea25b293d1..769ec956793 100644 --- a/drivers/spi/airoha_snfi_spi.c +++ b/drivers/spi/airoha_snfi_spi.c @@ -141,12 +141,15 @@ #define SPI_NFI_CUS_SEC_SIZE_EN BIT(16) #define REG_SPI_NFI_RD_CTL2 0x0510 +#define SPI_NFI_DATA_READ_CMD GENMASK(7, 0) + #define REG_SPI_NFI_RD_CTL3 0x0514 #define REG_SPI_NFI_PG_CTL1 0x0524 #define SPI_NFI_PG_LOAD_CMD GENMASK(15, 8) #define REG_SPI_NFI_PG_CTL2 0x0528 + #define REG_SPI_NFI_NOR_PROG_ADDR 0x052c #define REG_SPI_NFI_NOR_RD_ADDR 0x0534 @@ -173,7 +176,9 @@ #define SPI_NAND_OP_READ_FROM_CACHE_SINGLE 0x03 #define SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST 0x0b #define SPI_NAND_OP_READ_FROM_CACHE_DUAL 0x3b +#define SPI_NAND_OP_READ_FROM_CACHE_DUALIO 0xbb #define SPI_NAND_OP_READ_FROM_CACHE_QUAD 0x6b +#define SPI_NAND_OP_READ_FROM_CACHE_QUADIO 0xeb #define SPI_NAND_OP_WRITE_ENABLE 0x06 #define SPI_NAND_OP_WRITE_DISABLE 0x04 #define SPI_NAND_OP_PROGRAM_LOAD_SINGLE 0x02 @@ -186,6 +191,14 @@ #define SPI_NAND_OP_RESET 0xff #define SPI_NAND_OP_DIE_SELECT 0xc2 +/* SNAND FIFO commands */ +#define SNAND_FIFO_TX_BUSWIDTH_SINGLE 0x08 +#define SNAND_FIFO_TX_BUSWIDTH_DUAL 0x09 +#define SNAND_FIFO_TX_BUSWIDTH_QUAD 0x0a +#define SNAND_FIFO_RX_BUSWIDTH_SINGLE 0x0c +#define SNAND_FIFO_RX_BUSWIDTH_DUAL 0x0e +#define SNAND_FIFO_RX_BUSWIDTH_QUAD 0x0f + #define SPI_NAND_CACHE_SIZE (SZ_4K + SZ_256) #define SPI_MAX_TRANSFER_SIZE 511 @@ -205,12 +218,8 @@ struct airoha_snand_priv { struct regmap *regmap_nfi; struct clk *spi_clk; - struct { - size_t page_size; - size_t sec_size; - u8 sec_num; - u8 spare_size; - } nfi_cfg; + u8 *txrx_buf; + int dma; }; static int airoha_snand_set_fifo_op(struct airoha_snand_priv *priv, @@ -380,10 +389,26 @@ static int airoha_snand_set_mode(struct airoha_snand_priv *priv, return regmap_write(priv->regmap_ctrl, REG_SPI_CTRL_DUMMY, 0); } -static int airoha_snand_write_data(struct airoha_snand_priv *priv, u8 cmd, - const u8 *data, int len) +static int airoha_snand_write_data(struct airoha_snand_priv *priv, + const u8 *data, int len, int buswidth) { int i, data_len; + u8 cmd; + + switch (buswidth) { + case 0: + case 1: + cmd = SNAND_FIFO_TX_BUSWIDTH_SINGLE; + break; + case 2: + cmd = SNAND_FIFO_TX_BUSWIDTH_DUAL; + break; + case 4: + cmd = SNAND_FIFO_TX_BUSWIDTH_QUAD; + break; + default: + return -EINVAL; + } for (i = 0; i < len; i += data_len) { int err; @@ -402,16 +427,32 @@ static int airoha_snand_write_data(struct airoha_snand_priv *priv, u8 cmd, return 0; } -static int airoha_snand_read_data(struct airoha_snand_priv *priv, u8 *data, - int len) +static int airoha_snand_read_data(struct airoha_snand_priv *priv, + u8 *data, int len, int buswidth) { int i, data_len; + u8 cmd; + + switch (buswidth) { + case 0: + case 1: + cmd = SNAND_FIFO_RX_BUSWIDTH_SINGLE; + break; + case 2: + cmd = SNAND_FIFO_RX_BUSWIDTH_DUAL; + break; + case 4: + cmd = SNAND_FIFO_RX_BUSWIDTH_QUAD; + break; + default: + return -EINVAL; + } for (i = 0; i < len; i += data_len) { int err; data_len = min(len - i, SPI_MAX_TRANSFER_SIZE); - err = airoha_snand_set_fifo_op(priv, 0xc, data_len); + err = airoha_snand_set_fifo_op(priv, cmd, data_len); if (err) return err; @@ -439,131 +480,498 @@ static int airoha_snand_nfi_init(struct airoha_snand_priv *priv) SPI_NFI_ALL_IRQ_EN, SPI_NFI_AHB_DONE_EN); } -static int airoha_snand_nfi_config(struct airoha_snand_priv *priv) +static bool airoha_snand_is_page_ops(const struct spi_mem_op *op) +{ + if (op->addr.nbytes != 2) + return false; + + if (op->addr.buswidth != 1 && op->addr.buswidth != 2 && + op->addr.buswidth != 4) + return false; + + switch (op->data.dir) { + case SPI_MEM_DATA_IN: + if (op->dummy.nbytes * BITS_PER_BYTE / op->dummy.buswidth > 0xf) + return false; + + /* quad in / quad out */ + if (op->addr.buswidth == 4) + return op->data.buswidth == 4; + + if (op->addr.buswidth == 2) + return op->data.buswidth == 2; + + /* standard spi */ + return op->data.buswidth == 4 || op->data.buswidth == 2 || + op->data.buswidth == 1; + case SPI_MEM_DATA_OUT: + return !op->dummy.nbytes && op->addr.buswidth == 1 && + (op->data.buswidth == 4 || op->data.buswidth == 1); + default: + return false; + } +} + +static bool airoha_snand_supports_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + if (!spi_mem_default_supports_op(slave, op)) + return false; + + if (op->cmd.buswidth != 1) + return false; + + if (airoha_snand_is_page_ops(op)) + return true; + + return (!op->addr.nbytes || op->addr.buswidth == 1) && + (!op->dummy.nbytes || op->dummy.buswidth == 1) && + (!op->data.nbytes || op->data.buswidth == 1); +} + +static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc) +{ + struct spi_slave *slave = desc->slave; + struct udevice *bus = slave->dev->parent; + struct airoha_snand_priv *priv = dev_get_priv(bus); + + if (!priv->txrx_buf) + return -EINVAL; + + if (desc->info.offset + desc->info.length > U32_MAX) + return -EINVAL; + + /* continuous reading is not supported */ + if (desc->info.length > SPI_NAND_CACHE_SIZE) + return -E2BIG; + + if (!airoha_snand_supports_op(desc->slave, &desc->info.op_tmpl)) + return -EOPNOTSUPP; + + return 0; +} + +static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, void *buf) { + struct spi_slave *slave = desc->slave; + struct udevice *bus = slave->dev->parent; + struct airoha_snand_priv *priv = dev_get_priv(bus); + u8 *txrx_buf = priv->txrx_buf; + dma_addr_t dma_addr; + u32 val, rd_mode, opcode; + size_t bytes; int err; - u32 val; + if (!priv->dma) { + /* simplified version of spi_mem_no_dirmap_read() */ + struct spi_mem_op op = desc->info.op_tmpl; + + op.addr.val = desc->info.offset + offs; + op.data.buf.in = buf; + op.data.nbytes = len; + err = spi_mem_exec_op(desc->slave, &op); + if (err) + return err; + + return op.data.nbytes; + } + + /* minimum oob size is 64 */ + bytes = round_up(offs + len, 64); + + /* + * DUALIO and QUADIO opcodes are not supported by the spi controller, + * replace them with supported opcodes. + */ + opcode = desc->info.op_tmpl.cmd.opcode; + switch (opcode) { + case SPI_NAND_OP_READ_FROM_CACHE_SINGLE: + case SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST: + rd_mode = 0; + break; + case SPI_NAND_OP_READ_FROM_CACHE_DUAL: + case SPI_NAND_OP_READ_FROM_CACHE_DUALIO: + opcode = SPI_NAND_OP_READ_FROM_CACHE_DUAL; + rd_mode = 1; + break; + case SPI_NAND_OP_READ_FROM_CACHE_QUAD: + case SPI_NAND_OP_READ_FROM_CACHE_QUADIO: + opcode = SPI_NAND_OP_READ_FROM_CACHE_QUAD; + rd_mode = 2; + break; + default: + /* unknown opcode */ + return -EOPNOTSUPP; + } + + err = airoha_snand_set_mode(priv, SPI_MODE_DMA); + if (err < 0) + return err; + + /* NFI reset */ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_CON, SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); if (err) - return err; + goto error_dma_mode_off; + + /* NFI configure: + * - No AutoFDM (custom sector size (SECCUS) register will be used) + * - No SoC's hardware ECC (flash internal ECC will be used) + * - Use burst mode (faster, but requires 16 byte alignment for addresses) + * - Setup for reading (SPI_NFI_READ_MODE) + * - Setup reading command: FIELD_PREP(SPI_NFI_OPMODE, 6) + * - Use DMA instead of PIO for data reading + */ + err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_DMA_MODE | + SPI_NFI_READ_MODE | + SPI_NFI_DMA_BURST_EN | + SPI_NFI_HW_ECC_EN | + SPI_NFI_AUTO_FDM_EN | + SPI_NFI_OPMODE, + SPI_NFI_DMA_MODE | + SPI_NFI_READ_MODE | + SPI_NFI_DMA_BURST_EN | + FIELD_PREP(SPI_NFI_OPMODE, 6)); + if (err) + goto error_dma_mode_off; - /* auto FDM */ - err = regmap_clear_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG, - SPI_NFI_AUTO_FDM_EN); + /* Set number of sector will be read */ + err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_SEC_NUM, + FIELD_PREP(SPI_NFI_SEC_NUM, 1)); if (err) - return err; + goto error_dma_mode_off; + + /* Set custom sector size */ + err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE | + SPI_NFI_CUS_SEC_SIZE_EN, + FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) | + SPI_NFI_CUS_SEC_SIZE_EN); + if (err) + goto error_dma_mode_off; + + dma_addr = dma_map_single(txrx_buf, SPI_NAND_CACHE_SIZE, + DMA_FROM_DEVICE); - /* HW ECC */ - err = regmap_clear_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG, - SPI_NFI_HW_ECC_EN); + /* set dma addr */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_STRADDR, + dma_addr); if (err) - return err; + goto error_dma_unmap; + + /* + * Setup transfer length + * --------------------- + * The following rule MUST be met: + * transfer_length = + * = NFI_SNF_MISC_CTL2.read_data_byte_number = + * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size + */ + err = regmap_update_bits(priv->regmap_nfi, + REG_SPI_NFI_SNF_MISC_CTL2, + SPI_NFI_READ_DATA_BYTE_NUM, + FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, bytes)); + if (err) + goto error_dma_unmap; - /* DMA Burst */ - err = regmap_set_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG, - SPI_NFI_DMA_BURST_EN); + /* set read command */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_RD_CTL2, + FIELD_PREP(SPI_NFI_DATA_READ_CMD, opcode)); if (err) - return err; + goto error_dma_unmap; - /* page format */ - switch (priv->nfi_cfg.spare_size) { - case 26: - val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x1); - break; - case 27: - val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x2); - break; - case 28: - val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x3); - break; - default: - val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x0); - break; - } + /* set read mode */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL, + FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, rd_mode)); + if (err) + goto error_dma_unmap; + + /* set read addr: zero page offset + descriptor read offset */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_RD_CTL3, + desc->info.offset); + if (err) + goto error_dma_unmap; - err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_PAGEFMT, - SPI_NFI_SPARE_SIZE, val); + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_CMD, 0x0); if (err) + goto error_dma_unmap; + + /* trigger dma reading */ + err = regmap_clear_bits(priv->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_RD_TRIG); + if (err) + goto error_dma_unmap; + + err = regmap_set_bits(priv->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_RD_TRIG); + if (err) + goto error_dma_unmap; + + err = regmap_read_poll_timeout(priv->regmap_nfi, + REG_SPI_NFI_SNF_STA_CTL1, val, + (val & SPI_NFI_READ_FROM_CACHE_DONE), + 0, 1 * MSEC_PER_SEC); + if (err) + goto error_dma_unmap; + + /* + * SPI_NFI_READ_FROM_CACHE_DONE bit must be written at the end + * of dirmap_read operation even if it is already set. + */ + err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1, + SPI_NFI_READ_FROM_CACHE_DONE, + SPI_NFI_READ_FROM_CACHE_DONE); + if (err) + goto error_dma_unmap; + + err = regmap_read_poll_timeout(priv->regmap_nfi, REG_SPI_NFI_INTR, + val, (val & SPI_NFI_AHB_DONE), 0, + 1 * MSEC_PER_SEC); + if (err) + goto error_dma_unmap; + + /* DMA read need delay for data ready from controller to DRAM */ + udelay(1); + + dma_unmap_single(dma_addr, SPI_NAND_CACHE_SIZE, DMA_FROM_DEVICE); + + err = airoha_snand_set_mode(priv, SPI_MODE_MANUAL); + if (err < 0) return err; - switch (priv->nfi_cfg.page_size) { - case 2048: - val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x1); + memcpy(buf, txrx_buf + offs, len); + + return len; + +error_dma_unmap: + dma_unmap_single(dma_addr, SPI_NAND_CACHE_SIZE, DMA_FROM_DEVICE); +error_dma_mode_off: + airoha_snand_set_mode(priv, SPI_MODE_MANUAL); + return err; +} + +static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, const void *buf) +{ + struct spi_slave *slave = desc->slave; + struct udevice *bus = slave->dev->parent; + struct airoha_snand_priv *priv = dev_get_priv(bus); + u8 *txrx_buf = priv->txrx_buf; + dma_addr_t dma_addr; + u32 wr_mode, val, opcode; + size_t bytes; + int err; + + if (!priv->dma) { + /* simplified version of spi_mem_no_dirmap_write() */ + struct spi_mem_op op = desc->info.op_tmpl; + + op.addr.val = desc->info.offset + offs; + op.data.buf.out = buf; + op.data.nbytes = len; + err = spi_mem_exec_op(desc->slave, &op); + if (err) + return err; + + return op.data.nbytes; + } + + /* minimum oob size is 64 */ + bytes = round_up(offs + len, 64); + + opcode = desc->info.op_tmpl.cmd.opcode; + switch (opcode) { + case SPI_NAND_OP_PROGRAM_LOAD_SINGLE: + case SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE: + wr_mode = 0; break; - case 4096: - val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x2); + case SPI_NAND_OP_PROGRAM_LOAD_QUAD: + case SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD: + wr_mode = 2; break; default: - val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x0); - break; + /* unknown opcode */ + return -EOPNOTSUPP; } - err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_PAGEFMT, - SPI_NFI_PAGE_SIZE, val); - if (err) + if (offs > 0) + memset(txrx_buf, 0xff, offs); + memcpy(txrx_buf + offs, buf, len); + if (bytes > offs + len) + memset(txrx_buf + offs + len, 0xff, bytes - offs - len); + + err = airoha_snand_set_mode(priv, SPI_MODE_DMA); + if (err < 0) return err; - /* sec num */ - val = FIELD_PREP(SPI_NFI_SEC_NUM, priv->nfi_cfg.sec_num); + /* NFI reset */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); + if (err) + goto error_dma_mode_off; + + /* + * NFI configure: + * - No AutoFDM (custom sector size (SECCUS) register will be used) + * - No SoC's hardware ECC (flash internal ECC will be used) + * - Use burst mode (faster, but requires 16 byte alignment for addresses) + * - Setup for writing (SPI_NFI_READ_MODE bit is cleared) + * - Setup writing command: FIELD_PREP(SPI_NFI_OPMODE, 3) + * - Use DMA instead of PIO for data writing + */ + err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_DMA_MODE | + SPI_NFI_READ_MODE | + SPI_NFI_DMA_BURST_EN | + SPI_NFI_HW_ECC_EN | + SPI_NFI_AUTO_FDM_EN | + SPI_NFI_OPMODE, + SPI_NFI_DMA_MODE | + SPI_NFI_DMA_BURST_EN | + FIELD_PREP(SPI_NFI_OPMODE, 3)); + if (err) + goto error_dma_mode_off; + + /* Set number of sector will be written */ err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_CON, - SPI_NFI_SEC_NUM, val); + SPI_NFI_SEC_NUM, + FIELD_PREP(SPI_NFI_SEC_NUM, 1)); if (err) - return err; + goto error_dma_mode_off; + + /* Set custom sector size */ + err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE | + SPI_NFI_CUS_SEC_SIZE_EN, + FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) | + SPI_NFI_CUS_SEC_SIZE_EN); + if (err) + goto error_dma_mode_off; - /* enable cust sec size */ - err = regmap_set_bits(priv->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, - SPI_NFI_CUS_SEC_SIZE_EN); + dma_addr = dma_map_single(txrx_buf, SPI_NAND_CACHE_SIZE, + DMA_TO_DEVICE); + + /* set dma addr */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_STRADDR, + dma_addr); if (err) - return err; + goto error_dma_unmap; + + /* + * Setup transfer length + * --------------------- + * The following rule MUST be met: + * transfer_length = + * = NFI_SNF_MISC_CTL2.write_data_byte_number = + * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size + */ + err = regmap_update_bits(priv->regmap_nfi, + REG_SPI_NFI_SNF_MISC_CTL2, + SPI_NFI_PROG_LOAD_BYTE_NUM, + FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, bytes)); + if (err) + goto error_dma_unmap; - /* set cust sec size */ - val = FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, priv->nfi_cfg.sec_size); - return regmap_update_bits(priv->regmap_nfi, - REG_SPI_NFI_SECCUS_SIZE, - SPI_NFI_CUS_SEC_SIZE, val); -} + /* set write command */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_PG_CTL1, + FIELD_PREP(SPI_NFI_PG_LOAD_CMD, opcode)); + if (err) + goto error_dma_unmap; -static int airoha_snand_adjust_op_size(struct spi_slave *slave, - struct spi_mem_op *op) -{ - size_t max_len; + /* set write mode */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL, + FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, wr_mode)); + if (err) + goto error_dma_unmap; - max_len = 1 + op->addr.nbytes + op->dummy.nbytes; - if (max_len >= 160) - return -EOPNOTSUPP; + /* set write addr: zero page offset + descriptor write offset */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_PG_CTL2, + desc->info.offset); + if (err) + goto error_dma_unmap; - if (op->data.nbytes > 160 - max_len) - op->data.nbytes = 160 - max_len; + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_CMD, 0x80); + if (err) + goto error_dma_unmap; - return 0; -} + /* trigger dma writing */ + err = regmap_clear_bits(priv->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_WR_TRIG); + if (err) + goto error_dma_unmap; -static bool airoha_snand_supports_op(struct spi_slave *slave, - const struct spi_mem_op *op) -{ - if (!spi_mem_default_supports_op(slave, op)) - return false; + err = regmap_set_bits(priv->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_WR_TRIG); + if (err) + goto error_dma_unmap; - if (op->cmd.buswidth != 1) - return false; + err = regmap_read_poll_timeout(priv->regmap_nfi, REG_SPI_NFI_INTR, + val, (val & SPI_NFI_AHB_DONE), 0, + 1 * MSEC_PER_SEC); + if (err) + goto error_dma_unmap; - return (!op->addr.nbytes || op->addr.buswidth == 1) && - (!op->dummy.nbytes || op->dummy.buswidth == 1) && - (!op->data.nbytes || op->data.buswidth == 1); + err = regmap_read_poll_timeout(priv->regmap_nfi, + REG_SPI_NFI_SNF_STA_CTL1, val, + (val & SPI_NFI_LOAD_TO_CACHE_DONE), + 0, 1 * MSEC_PER_SEC); + if (err) + goto error_dma_unmap; + + /* + * SPI_NFI_LOAD_TO_CACHE_DONE bit must be written at the end + * of dirmap_write operation even if it is already set. + */ + err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1, + SPI_NFI_LOAD_TO_CACHE_DONE, + SPI_NFI_LOAD_TO_CACHE_DONE); + if (err) + goto error_dma_unmap; + + dma_unmap_single(dma_addr, SPI_NAND_CACHE_SIZE, DMA_TO_DEVICE); + + err = airoha_snand_set_mode(priv, SPI_MODE_MANUAL); + if (err < 0) + return err; + + return len; + +error_dma_unmap: + dma_unmap_single(dma_addr, SPI_NAND_CACHE_SIZE, DMA_TO_DEVICE); +error_dma_mode_off: + airoha_snand_set_mode(priv, SPI_MODE_MANUAL); + return err; } static int airoha_snand_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) { - u8 data[8], cmd, opcode = op->cmd.opcode; struct udevice *bus = slave->dev->parent; struct airoha_snand_priv *priv; + int op_len, addr_len, dummy_len; + u8 buf[20], *data; int i, err; priv = dev_get_priv(bus); + op_len = op->cmd.nbytes; + addr_len = op->addr.nbytes; + dummy_len = op->dummy.nbytes; + + if (op_len + dummy_len + addr_len > sizeof(buf)) + return -EIO; + + data = buf; + for (i = 0; i < op_len; i++) + *data++ = op->cmd.opcode >> (8 * (op_len - i - 1)); + for (i = 0; i < addr_len; i++) + *data++ = op->addr.val >> (8 * (addr_len - i - 1)); + for (i = 0; i < dummy_len; i++) + *data++ = 0xff; + /* switch to manual mode */ err = airoha_snand_set_mode(priv, SPI_MODE_MANUAL); if (err < 0) @@ -574,40 +982,40 @@ static int airoha_snand_exec_op(struct spi_slave *slave, return err; /* opcode */ - err = airoha_snand_write_data(priv, 0x8, &opcode, sizeof(opcode)); + data = buf; + err = airoha_snand_write_data(priv, data, op_len, + op->cmd.buswidth); if (err) return err; /* addr part */ - cmd = opcode == SPI_NAND_OP_GET_FEATURE ? 0x11 : 0x8; - put_unaligned_be64(op->addr.val, data); - - for (i = ARRAY_SIZE(data) - op->addr.nbytes; - i < ARRAY_SIZE(data); i++) { - err = airoha_snand_write_data(priv, cmd, &data[i], - sizeof(data[0])); + data += op_len; + if (addr_len) { + err = airoha_snand_write_data(priv, data, addr_len, + op->addr.buswidth); if (err) return err; } /* dummy */ - data[0] = 0xff; - for (i = 0; i < op->dummy.nbytes; i++) { - err = airoha_snand_write_data(priv, 0x8, &data[0], - sizeof(data[0])); + data += addr_len; + if (dummy_len) { + err = airoha_snand_write_data(priv, data, dummy_len, + op->dummy.buswidth); if (err) return err; } /* data */ - if (op->data.dir == SPI_MEM_DATA_IN) { - err = airoha_snand_read_data(priv, op->data.buf.in, - op->data.nbytes); - if (err) - return err; - } else { - err = airoha_snand_write_data(priv, 0x8, op->data.buf.out, - op->data.nbytes); + if (op->data.nbytes) { + if (op->data.dir == SPI_MEM_DATA_IN) + err = airoha_snand_read_data(priv, op->data.buf.in, + op->data.nbytes, + op->data.buswidth); + else + err = airoha_snand_write_data(priv, op->data.buf.out, + op->data.nbytes, + op->data.buswidth); if (err) return err; } @@ -619,6 +1027,13 @@ static int airoha_snand_probe(struct udevice *dev) { struct airoha_snand_priv *priv = dev_get_priv(dev); int ret; + u32 sfc_strap; + + priv->txrx_buf = memalign(ARCH_DMA_MINALIGN, SPI_NAND_CACHE_SIZE); + if (!priv->txrx_buf) { + dev_err(dev, "failed to alloacate memory for dirmap\n"); + return -ENOMEM; + } ret = regmap_init_mem_index(dev_ofnode(dev), &priv->regmap_ctrl, 0); if (ret) { @@ -639,6 +1054,25 @@ static int airoha_snand_probe(struct udevice *dev) } clk_enable(priv->spi_clk); + priv->dma = 1; + if (device_is_compatible(dev, "airoha,en7523-snand")){ + ret = regmap_read(priv->regmap_ctrl, REG_SPI_CTRL_SFC_STRAP, &sfc_strap); + if (ret) + return ret; + + if (!(sfc_strap & 0x04)) { + priv->dma = 0; + printf("\n" + "=== WARNING ======================================================\n" + "Detected booting in RESERVED mode (UART_TXD was short to GND).\n" + "This mode is known for incorrect DMA reading of some flashes.\n" + "Usage of DMA for flash operations will be disabled to prevent data\n" + "damage. Unplug your serial console and power cycle the board\n" + "to boot with full performance.\n" + "==================================================================\n\n"); + } + } + return airoha_snand_nfi_init(priv); } @@ -659,48 +1093,18 @@ static int airoha_snand_nfi_set_mode(struct udevice *bus, uint mode) return 0; } -static int airoha_snand_nfi_setup(struct spi_slave *slave, - const struct spinand_info *spinand_info) -{ - struct udevice *bus = slave->dev->parent; - struct airoha_snand_priv *priv; - u32 sec_size, sec_num; - int pagesize, oobsize; - - priv = dev_get_priv(bus); - - pagesize = spinand_info->memorg.pagesize; - oobsize = spinand_info->memorg.oobsize; - - if (pagesize == 2 * 1024) - sec_num = 4; - else if (pagesize == 4 * 1024) - sec_num = 8; - else - sec_num = 1; - - sec_size = (pagesize + oobsize) / sec_num; - - /* init default value */ - priv->nfi_cfg.sec_size = sec_size; - priv->nfi_cfg.sec_num = sec_num; - priv->nfi_cfg.page_size = round_down(sec_size * sec_num, 1024); - priv->nfi_cfg.spare_size = 16; - - return airoha_snand_nfi_config(priv); -} - static const struct spi_controller_mem_ops airoha_snand_mem_ops = { - .adjust_op_size = airoha_snand_adjust_op_size, .supports_op = airoha_snand_supports_op, .exec_op = airoha_snand_exec_op, + .dirmap_create = airoha_snand_dirmap_create, + .dirmap_read = airoha_snand_dirmap_read, + .dirmap_write = airoha_snand_dirmap_write, }; static const struct dm_spi_ops airoha_snfi_spi_ops = { .mem_ops = &airoha_snand_mem_ops, .set_speed = airoha_snand_nfi_set_speed, .set_mode = airoha_snand_nfi_set_mode, - .setup_for_spinand = airoha_snand_nfi_setup, }; static const struct udevice_id airoha_snand_ids[] = { diff --git a/drivers/spi/altera_spi.c b/drivers/spi/altera_spi.c index dafaf1130bb..a75d861bda4 100644 --- a/drivers/spi/altera_spi.c +++ b/drivers/spi/altera_spi.c @@ -12,6 +12,7 @@ #include <malloc.h> #include <fdtdec.h> #include <spi.h> +#include <time.h> #include <asm/io.h> #include <linux/bitops.h> diff --git a/drivers/spi/cadence_ospi_versal.c b/drivers/spi/cadence_ospi_versal.c index 6dc6fbe5a5b..0efbbf56a5e 100644 --- a/drivers/spi/cadence_ospi_versal.c +++ b/drivers/spi/cadence_ospi_versal.c @@ -199,12 +199,12 @@ void cadence_qspi_apb_enable_linear_mode(bool enable) /* ahb read mode */ xilinx_pm_request(PM_IOCTL, PM_DEV_OSPI, IOCTL_OSPI_MUX_SELECT, - PM_OSPI_MUX_SEL_LINEAR, 0, NULL); + PM_OSPI_MUX_SEL_LINEAR, 0, 0, 0, NULL); else /* DMA mode */ xilinx_pm_request(PM_IOCTL, PM_DEV_OSPI, IOCTL_OSPI_MUX_SELECT, - PM_OSPI_MUX_SEL_DMA, 0, NULL); + PM_OSPI_MUX_SEL_DMA, 0, 0, 0, NULL); } else { if (enable) writel(readl(VERSAL_AXI_MUX_SEL) | diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index 9edbfaa821b..9b45cab9c04 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -142,7 +142,7 @@ static int spi_calibration(struct udevice *bus, uint hz) if (range_lo == -1) { puts("SF: Calibration failed (low range)\n"); - return err; + return -EIO; } /* Disable QSPI for subsequent initialization */ @@ -230,7 +230,7 @@ static int cadence_spi_probe(struct udevice *bus) if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) xilinx_pm_request(PM_REQUEST_NODE, PM_DEV_OSPI, ZYNQMP_PM_CAPABILITY_ACCESS, ZYNQMP_PM_MAX_QOS, - ZYNQMP_PM_REQUEST_ACK_NO, NULL); + ZYNQMP_PM_REQUEST_ACK_NO, 0, 0, NULL); if (priv->ref_clk_hz == 0) { ret = clk_get_by_index(bus, 0, &clk); diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c index 4696c09f754..0d4bc685f5d 100644 --- a/drivers/spi/cadence_qspi_apb.c +++ b/drivers/spi/cadence_qspi_apb.c @@ -354,7 +354,7 @@ void cadence_qspi_apb_controller_init(struct cadence_spi_priv *priv) int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg) { - unsigned int retry = CQSPI_REG_RETRY; + int retry = CQSPI_REG_RETRY; /* Write the CMDCTRL without start execution. */ writel(reg, reg_base + CQSPI_REG_CMDCTRL); @@ -369,7 +369,7 @@ int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg) udelay(1); } - if (!retry) { + if (retry == -1) { printf("QSPI: flash command execution timeout\n"); return -EIO; } diff --git a/drivers/spi/ich.c b/drivers/spi/ich.c index 2264ca83d66..733ff8ac777 100644 --- a/drivers/spi/ich.c +++ b/drivers/spi/ich.c @@ -256,7 +256,7 @@ static int ich_spi_exec_op_swseq(struct spi_slave *slave, struct ich_spi_priv *ctlr = dev_get_priv(bus); uint16_t control; int16_t opcode_index; - int with_address; + int with_address = 0; int status; struct spi_trans *trans = &ctlr->trans; bool lock = spi_lock_status(plat, ctlr->base); diff --git a/drivers/spi/npcm_fiu_spi.c b/drivers/spi/npcm_fiu_spi.c index 7b8271c8bbc..761ef8c058b 100644 --- a/drivers/spi/npcm_fiu_spi.c +++ b/drivers/spi/npcm_fiu_spi.c @@ -273,8 +273,7 @@ static int npcm_fiu_uma_operation(struct npcm_fiu_priv *priv, const struct spi_m if (op->data.dir == SPI_MEM_DATA_OUT && nbytes) { memcpy(data_reg, tx, nbytes); - if (nbytes) - writel(data_reg[0], ®s->uma_dw0); + writel(data_reg[0], ®s->uma_dw0); if (nbytes > DW_SIZE) writel(data_reg[1], ®s->uma_dw1); if (nbytes > DW_SIZE * 2) diff --git a/drivers/spi/nxp_fspi.c b/drivers/spi/nxp_fspi.c index 6d97b8eefc9..46de915c238 100644 --- a/drivers/spi/nxp_fspi.c +++ b/drivers/spi/nxp_fspi.c @@ -337,6 +337,33 @@ static struct nxp_fspi_devtype_data imxrt1170_data = { .little_endian = true, }; +static const struct nxp_fspi_devtype_data imx8qxp_data = { + .rxfifo = SZ_512, /* (64 * 64 bits) */ + .txfifo = SZ_1K, /* (128 * 64 bits) */ + .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ + .quirks = 0, + .lut_num = 32, + .little_endian = true, /* little-endian */ +}; + +static const struct nxp_fspi_devtype_data imx8dxl_data = { + .rxfifo = SZ_512, /* (64 * 64 bits) */ + .txfifo = SZ_1K, /* (128 * 64 bits) */ + .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ + .quirks = FSPI_QUIRK_USE_IP_ONLY, + .lut_num = 32, + .little_endian = true, /* little-endian */ +}; + +static const struct nxp_fspi_devtype_data imx8ulp_data = { + .rxfifo = SZ_1K, /* (128 * 64 bits) */ + .txfifo = SZ_1K, /* (128 * 64 bits) */ + .ahb_buf_size = SZ_2K, /* (256 * 64 bits) */ + .quirks = 0, + .lut_num = 16, + .little_endian = true, /* little-endian */ +}; + struct nxp_fspi { struct udevice *dev; void __iomem *iobase; @@ -539,6 +566,15 @@ static void nxp_fspi_prepare_lut(struct nxp_fspi *f, fspi_writel(f, lutval[i], base + target_lut_reg); } + if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN && + op->addr.nbytes) { + lut_offset = (f->devtype_data->lut_num - 2) * 4 * 4; + for (i = 0; i < ARRAY_SIZE(lutval); i++) { + target_lut_reg = FSPI_LUT_BASE + lut_offset + i * 4; + fspi_writel(f, lutval[i], base + target_lut_reg); + } + } + dev_dbg(f->dev, "CMD[%x] lutval[0:%x \t 1:%x \t 2:%x \t 3:%x], size: 0x%08x\n", op->cmd.opcode, lutval[0], lutval[1], lutval[2], lutval[3], op->data.nbytes); @@ -846,9 +882,9 @@ static void erratum_err050568(struct nxp_fspi *f) /* Check for LS1028A variants */ svr = SVR_SOC_VER(get_svr()); - if (svr != SVR_LS1017A || - svr != SVR_LS1018A || - svr != SVR_LS1027A || + if (svr != SVR_LS1017A && + svr != SVR_LS1018A && + svr != SVR_LS1027A && svr != SVR_LS1028A) { dev_dbg(f->dev, "Errata applicable only for LS1028A variants\n"); return; @@ -943,9 +979,10 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f) /* * The driver only uses one single LUT entry, that is updated on * each call of exec_op(). Index 0 is preset at boot with a basic - * read operation, so let's use the last entry. + * read operation, last entry is used for dynamic lut, the second + * last entry is used for AHB read. */ - seqid_lut = f->devtype_data->lut_num - 1; + seqid_lut = f->devtype_data->lut_num - 2; /* AHB Read - Set lut sequence ID for all CS. */ fspi_writel(f, seqid_lut, base + FSPI_FLSHA1CR2); fspi_writel(f, seqid_lut, base + FSPI_FLSHA2CR2); @@ -1071,6 +1108,9 @@ static const struct udevice_id nxp_fspi_ids[] = { { .compatible = "nxp,lx2160a-fspi", .data = (ulong)&lx2160a_data, }, { .compatible = "nxp,imx8mm-fspi", .data = (ulong)&imx8mm_data, }, { .compatible = "nxp,imx8mp-fspi", .data = (ulong)&imx8mm_data, }, + { .compatible = "nxp,imx8qxp-fspi", .data = (ulong)&imx8qxp_data, }, + { .compatible = "nxp,imx8dxl-fspi", .data = (ulong)&imx8dxl_data, }, + { .compatible = "nxp,imx8ulp-fspi", .data = (ulong)&imx8ulp_data, }, { .compatible = "nxp,imxrt1170-fspi", .data = (ulong)&imxrt1170_data, }, { } }; diff --git a/drivers/spi/rockchip_sfc.c b/drivers/spi/rockchip_sfc.c index 73738ab26d3..60e74117057 100644 --- a/drivers/spi/rockchip_sfc.c +++ b/drivers/spi/rockchip_sfc.c @@ -108,6 +108,7 @@ #define SFC_VER_3 0x3 #define SFC_VER_4 0x4 #define SFC_VER_5 0x5 +#define SFC_VER_8 0x8 /* Delay line controller resiter */ #define SFC_DLL_CTRL0 0x3C @@ -589,6 +590,16 @@ static int rockchip_sfc_adjust_op_size(struct spi_slave *mem, struct spi_mem_op return 0; } +#if CONFIG_IS_ENABLED(CLK) +static int rockchip_sfc_clk_set_rate(struct rockchip_sfc *sfc, uint speed) +{ + if (sfc->version >= SFC_VER_8) + return clk_set_rate(&sfc->clk, speed * 2); + else + return clk_set_rate(&sfc->clk, speed); +} +#endif + static int rockchip_sfc_set_speed(struct udevice *bus, uint speed) { struct rockchip_sfc *sfc = dev_get_plat(bus); @@ -600,7 +611,7 @@ static int rockchip_sfc_set_speed(struct udevice *bus, uint speed) return 0; #if CONFIG_IS_ENABLED(CLK) - int ret = clk_set_rate(&sfc->clk, speed); + int ret = rockchip_sfc_clk_set_rate(sfc, speed); if (ret < 0) { dev_err(sfc->dev, "set_freq=%dHz fail, check if it's the cru support level\n", diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 3579b7d7db5..3fd2353af94 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -120,18 +120,21 @@ static int spi_check_buswidth_req(struct spi_slave *slave, u8 buswidth, bool tx) return 0; case 2: - if ((tx && (mode & (SPI_TX_DUAL | SPI_TX_QUAD))) || - (!tx && (mode & (SPI_RX_DUAL | SPI_RX_QUAD)))) + if ((tx && + (mode & (SPI_TX_DUAL | SPI_TX_QUAD | SPI_TX_OCTAL))) || + (!tx && + (mode & (SPI_RX_DUAL | SPI_RX_QUAD | SPI_RX_OCTAL)))) return 0; break; case 4: - if ((tx && (mode & SPI_TX_QUAD)) || - (!tx && (mode & SPI_RX_QUAD))) + if ((tx && (mode & (SPI_TX_QUAD | SPI_TX_OCTAL))) || + (!tx && (mode & (SPI_RX_QUAD | SPI_RX_OCTAL)))) return 0; break; + case 8: if ((tx && (mode & SPI_TX_OCTAL)) || (!tx && (mode & SPI_RX_OCTAL))) @@ -300,7 +303,7 @@ int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) * read path) and expect the core to use the regular SPI * interface in other cases. */ - if (!ret || ret != -ENOTSUPP) { + if (!ret || (ret != -ENOTSUPP && ret != -EOPNOTSUPP)) { spi_release_bus(slave); return ret; } @@ -496,6 +499,71 @@ int spi_mem_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op) } EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size); +static inline u64 spi_mem_bytes_to_ncycles(u32 nbytes, u8 buswidth, u8 dtr) +{ + u64 ncycles; + u32 divider = buswidth * (dtr ? 2 : 1); + + /* + * Theoretically + * + * ncycles = (nbytes * 8) / (buswidth * (dtr ? 2 : 1)); + * + * may lead to an integer overflow, if nbytes will be larger than + * 0x1fffffff. Lets split this operation on: + * + * 1) Operation with bits 0..28 (overflow will not happen), + * + * 2) Operation with bits 29..31. Here we'll take into account + * that buswidth is a small power of 2 (so whole divider is + * small power of 2). Hense we may divide first, then multiply. + */ + ncycles = ((nbytes & 0x1fffffff) * 8) / divider; + ncycles += ((u64) ((nbytes & ~0x1fffffff) / divider)) * 8; + + return ncycles; +} + +/** + * spi_mem_calc_op_duration() - Derives the theoretical length (in cpu cycles) + * of an operation. This helps finding the best + * variant among a list of possible choices. + * @op: the operation to benchmark + * + * Some chips have per-op frequency limitations, PCBs usually have their own + * limitations as well, and controllers can support dual, quad or even octal + * modes, sometimes in DTR. All these combinations make it impossible to + * statically list the best combination for all situations. If we want something + * accurate, all these combinations should be rated (eg. with a time estimate) + * and the best pick should be taken based on these calculations. + * + * Returns a estimate for the time this op would take. + */ +u64 spi_mem_calc_op_duration(struct spi_mem_op *op) +{ + u64 ncycles = 0; + + ncycles += spi_mem_bytes_to_ncycles(op->cmd.nbytes, + op->cmd.buswidth, + op->cmd.dtr); + ncycles += spi_mem_bytes_to_ncycles(op->addr.nbytes, + op->addr.buswidth, + op->addr.dtr); + + /* Dummy bytes are optional for some SPI flash memory operations */ + if (op->dummy.nbytes) + ncycles += spi_mem_bytes_to_ncycles(op->dummy.nbytes, + op->dummy.buswidth, + op->dummy.dtr); + + ncycles += spi_mem_bytes_to_ncycles(op->data.nbytes, + op->data.buswidth, + op->data.dtr); + + return ncycles; +} +EXPORT_SYMBOL_GPL(spi_mem_calc_op_duration); + static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, void *buf) { diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index d6049753740..49b584c648d 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -449,7 +449,8 @@ int _spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, #if CONFIG_IS_ENABLED(SPI_STACKED_PARALLEL) if ((dev_read_bool(dev, "parallel-memories")) && !slave->multi_cs_cap) { dev_err(dev, "controller doesn't support multi CS\n"); - return -EINVAL; + ret = -EINVAL; + goto err; } #endif /* diff --git a/drivers/spmi/spmi-sandbox.c b/drivers/spmi/spmi-sandbox.c index 992b08dd612..1a8561b3aea 100644 --- a/drivers/spmi/spmi-sandbox.c +++ b/drivers/spmi/spmi-sandbox.c @@ -144,7 +144,7 @@ static const struct udevice_id sandbox_spmi_ids[] = { { } }; -U_BOOT_DRIVER(msm_spmi) = { +U_BOOT_DRIVER(sandbox_spmi) = { .name = "sandbox_spmi", .id = UCLASS_SPMI, .of_match = sandbox_spmi_ids, diff --git a/drivers/tee/Makefile b/drivers/tee/Makefile index ff844195ae1..5bc5df0d380 100644 --- a/drivers/tee/Makefile +++ b/drivers/tee/Makefile @@ -1,8 +1,6 @@ # SPDX-License-Identifier: GPL-2.0+ obj-y += tee-uclass.o -obj-$(CONFIG_SANDBOX) += sandbox.o -obj-$(CONFIG_OPTEE_TA_RPC_TEST) += optee/supplicant.o -obj-$(CONFIG_OPTEE_TA_RPC_TEST) += optee/i2c.o +obj-$(CONFIG_SANDBOX_TEE) += sandbox.o optee/ obj-$(CONFIG_OPTEE) += optee/ obj-y += broadcom/ diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile index 068c6e7aa1b..36ac085ef42 100644 --- a/drivers/tee/optee/Makefile +++ b/drivers/tee/optee/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0+ -obj-y += core.o +obj-$(CONFIG_OPTEE) += core.o obj-y += supplicant.o obj-$(CONFIG_DM_I2C) += i2c.o obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 440eb64a566..91c39aa4dee 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -35,6 +35,14 @@ config IMX_TMU The boot is hold to the cool device to throttle CPUs when the passive trip is crossed +config RCAR_GEN3_THERMAL + bool "Renesas R-Car Gen3/Gen4 and RZ/G2 thermal driver" + depends on ARCH_RENESAS + depends on RCAR_64 + help + Enable this to plug the R-Car Gen3/Gen4 or RZ/G2 thermal sensor + driver into the U-Boot thermal framework. + config TI_DRA7_THERMAL bool "Temperature sensor driver for TI dra7xx SOCs" help diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 18ad453f9b1..b6f06c00ed9 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_DM_THERMAL) += thermal-uclass.o obj-$(CONFIG_IMX_SCU_THERMAL) += imx_scu_thermal.o obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o obj-$(CONFIG_IMX_TMU) += imx_tmu.o +obj-$(CONFIG_RCAR_GEN3_THERMAL) += rcar_gen3_thermal.o obj-$(CONFIG_SANDBOX) += thermal_sandbox.o obj-$(CONFIG_TI_DRA7_THERMAL) += ti-bandgap.o obj-$(CONFIG_TI_LM74_THERMAL) += ti-lm74.o diff --git a/drivers/thermal/imx_scu_thermal.c b/drivers/thermal/imx_scu_thermal.c index fc2b0e227b2..6b0b1d10d9d 100644 --- a/drivers/thermal/imx_scu_thermal.c +++ b/drivers/thermal/imx_scu_thermal.c @@ -72,7 +72,7 @@ int imx_sc_thermal_get_temp(struct udevice *dev, int *temp) break; } - *temp = cpu_temp / 1000; + *temp = cpu_temp; return 0; } diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index ea1fcc3dcb2..d04035950ee 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -223,7 +223,7 @@ int imx_thermal_get_temp(struct udevice *dev, int *temp) cpu_tmp = read_cpu_temperature(dev); } - *temp = cpu_tmp; + *temp = cpu_tmp * 1000; return 0; } diff --git a/drivers/thermal/imx_tmu.c b/drivers/thermal/imx_tmu.c index 70d002aee25..c8389d507ee 100644 --- a/drivers/thermal/imx_tmu.c +++ b/drivers/thermal/imx_tmu.c @@ -245,7 +245,7 @@ int imx_tmu_get_temp(struct udevice *dev, int *temp) return ret; } - *temp = cpu_tmp / 1000; + *temp = cpu_tmp; return 0; } @@ -532,6 +532,16 @@ static int imx_tmu_enable_msite(struct udevice *dev) return 0; } +static void imx_tmu_set_trips(struct imx_tmu_plat *pdata) +{ + int minc, maxc; + + /* default alert/crit temps based on temp grade */ + get_cpu_temp_grade(&minc, &maxc); + pdata->critical = maxc * 1000; + pdata->alert = (maxc - 10) * 1000; +} + static int imx_tmu_bind(struct udevice *dev) { struct imx_tmu_plat *pdata = dev_get_plat(dev); @@ -539,7 +549,6 @@ static int imx_tmu_bind(struct udevice *dev) ofnode node, offset; const char *name; const void *prop; - int minc, maxc; dev_dbg(dev, "%s\n", __func__); @@ -548,10 +557,7 @@ static int imx_tmu_bind(struct udevice *dev) return 0; pdata->zone_node = 1; - /* default alert/crit temps based on temp grade */ - get_cpu_temp_grade(&minc, &maxc); - pdata->critical = maxc * 1000; - pdata->alert = (maxc - 10) * 1000; + imx_tmu_set_trips(pdata); node = ofnode_path("/thermal-zones"); ofnode_for_each_subnode(offset, node) { @@ -572,7 +578,7 @@ static int imx_tmu_parse_fdt(struct udevice *dev) { struct imx_tmu_plat *pdata = dev_get_plat(dev), *p_parent_data; struct ofnode_phandle_args args; - ofnode trips_np, cpu_thermal_np; + ofnode cpu_thermal_np; int ret; dev_dbg(dev, "%s\n", __func__); @@ -612,20 +618,7 @@ static int imx_tmu_parse_fdt(struct udevice *dev) pdata->polling_delay = dev_read_u32_default(dev, "polling-delay", IMX_TMU_POLLING_DELAY_MS); - trips_np = ofnode_path("/thermal-zones/cpu-thermal/trips"); - ofnode_for_each_subnode(trips_np, trips_np) { - const char *type; - - type = ofnode_get_property(trips_np, "type", NULL); - if (!type) - continue; - if (!strcmp(type, "critical")) - pdata->critical = ofnode_read_u32_default(trips_np, "temperature", 85); - else if (strcmp(type, "passive") == 0) - pdata->alert = ofnode_read_u32_default(trips_np, "temperature", 80); - else - continue; - } + imx_tmu_set_trips(pdata); dev_dbg(dev, "id %d polling_delay %d, critical %d, alert %d\n", pdata->id, pdata->polling_delay, pdata->critical, pdata->alert); diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c new file mode 100644 index 00000000000..45e590535a0 --- /dev/null +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -0,0 +1,467 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * R-Car Gen3/Gen4 and RZ/G2 THS thermal sensor driver + * Based on rcar_thermal.c and work from Hien Dang and Khiem Nguyen. + * + * Copyright (C) 2016 Renesas Electronics Corporation. + * Copyright (C) 2016 Sang Engineering + */ + +#include <asm/io.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <linux/delay.h> +#include <thermal.h> + +/* Register offsets */ +#define REG_GEN3_IRQSTR 0x04 +#define REG_GEN3_IRQMSK 0x08 +#define REG_GEN3_IRQCTL 0x0c +#define REG_GEN3_IRQEN 0x10 +#define REG_GEN3_IRQTEMP1 0x14 +#define REG_GEN3_IRQTEMP2 0x18 +#define REG_GEN3_IRQTEMP3 0x1c +#define REG_GEN3_THCTR 0x20 +#define REG_GEN3_TEMP 0x28 +#define REG_GEN3_THCODE1 0x50 +#define REG_GEN3_THCODE2 0x54 +#define REG_GEN3_THCODE3 0x58 +#define REG_GEN3_PTAT1 0x5c +#define REG_GEN3_PTAT2 0x60 +#define REG_GEN3_PTAT3 0x64 +#define REG_GEN3_THSCP 0x68 +#define REG_GEN4_THSFMON00 0x180 +#define REG_GEN4_THSFMON01 0x184 +#define REG_GEN4_THSFMON02 0x188 +#define REG_GEN4_THSFMON15 0x1bc +#define REG_GEN4_THSFMON16 0x1c0 +#define REG_GEN4_THSFMON17 0x1c4 + +/* IRQ{STR,MSK,EN} bits */ +#define IRQ_TEMP1 BIT(0) +#define IRQ_TEMP2 BIT(1) +#define IRQ_TEMP3 BIT(2) +#define IRQ_TEMPD1 BIT(3) +#define IRQ_TEMPD2 BIT(4) +#define IRQ_TEMPD3 BIT(5) + +/* THCTR bits */ +#define THCTR_PONM BIT(6) +#define THCTR_THSST BIT(0) + +/* THSCP bits */ +#define THSCP_COR_PARA_VLD (BIT(15) | BIT(14)) + +#define CTEMP_MASK 0xfff + +#define MCELSIUS(temp) ((temp) * 1000) +#define GEN3_FUSE_MASK 0xfff +#define GEN4_FUSE_MASK 0xfff + +#define TSC_MAX_NUM 5 + +struct rcar_gen3_thermal_priv; + +struct rcar_gen3_thermal_fuse_info { + u32 ptat[3]; + u32 thcode[3]; + u32 mask; +}; + +struct rcar_gen3_thermal_fuse_default { + u32 ptat[3]; + u32 thcodes[TSC_MAX_NUM][3]; +}; + +struct rcar_thermal_info { + int scale; + int adj_below; + int adj_above; + const struct rcar_gen3_thermal_fuse_info *fuses; + const struct rcar_gen3_thermal_fuse_default *fuse_defaults; +}; + +struct equation_set_coef { + int a; + int b; +}; + +struct rcar_gen3_thermal_tsc { + void __iomem *base; + /* Different coefficients are used depending on a threshold. */ + struct { + struct equation_set_coef below; + struct equation_set_coef above; + } coef; + int thcode[3]; +}; + +struct rcar_gen3_thermal_priv { + struct rcar_gen3_thermal_tsc tscs[TSC_MAX_NUM]; + unsigned int num_tscs; + int ptat[3]; +}; + +static inline u32 rcar_gen3_thermal_read(struct rcar_gen3_thermal_tsc *tsc, + u32 reg) +{ + return readl(tsc->base + reg); +} + +static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc, + u32 reg, u32 data) +{ + writel(data, tsc->base + reg); +} + +/* + * Linear approximation for temperature + * + * [temp] = ((thadj - [reg]) * a) / b + adj + * [reg] = thadj - ([temp] - adj) * b / a + * + * The constants a and b are calculated using two triplets of int values PTAT + * and THCODE. PTAT and THCODE can either be read from hardware or use hard + * coded values from the driver. The formula to calculate a and b are taken from + * the datasheet. Different calculations are needed for a and b depending on + * if the input variables ([temp] or [reg]) are above or below a threshold. The + * threshold is also calculated from PTAT and THCODE using formulas from the + * datasheet. + * + * The constant thadj is one of the THCODE values, which one to use depends on + * the threshold and input value. + * + * The constants adj is taken verbatim from the datasheet. Two values exists, + * which one to use depends on the input value and the calculated threshold. + * Furthermore different SoC models supported by the driver have different sets + * of values. The values for each model are stored in the device match data. + */ +static void rcar_gen3_thermal_tsc_coefs(struct udevice *dev, + struct rcar_gen3_thermal_tsc *tsc) +{ + struct rcar_thermal_info *info = (struct rcar_thermal_info *)dev_get_driver_data(dev); + struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev); + + tsc->coef.below.a = info->scale * (priv->ptat[2] - priv->ptat[1]); + tsc->coef.above.a = info->scale * (priv->ptat[0] - priv->ptat[1]); + + tsc->coef.below.b = (priv->ptat[2] - priv->ptat[0]) * (tsc->thcode[2] - tsc->thcode[1]); + tsc->coef.above.b = (priv->ptat[0] - priv->ptat[2]) * (tsc->thcode[1] - tsc->thcode[0]); +} + +static int rcar_gen3_thermal_get_temp(struct udevice *dev, int *temp) +{ + struct rcar_thermal_info *info = (struct rcar_thermal_info *)dev_get_driver_data(dev->parent); + struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev->parent); + unsigned int tsc_id = dev_get_driver_data(dev); + struct rcar_gen3_thermal_tsc *tsc = &(priv->tscs[tsc_id]); + const struct equation_set_coef *coef; + int adj, decicelsius, reg, thcode; + + /* Read register and convert to millidegree Celsius */ + reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK; + + if (reg < tsc->thcode[1]) { + adj = info->adj_below; + coef = &tsc->coef.below; + thcode = tsc->thcode[2]; + } else { + adj = info->adj_above; + coef = &tsc->coef.above; + thcode = tsc->thcode[0]; + } + + /* + * The dividend can't be grown as it might overflow, instead shorten the + * divisor to convert to decidegree Celsius. If we convert after the + * division precision is lost as we will scale up from whole degrees + * Celsius. + */ + decicelsius = DIV_ROUND_CLOSEST(coef->a * (thcode - reg), coef->b / 10); + + /* Guaranteed operating range is -40C to 125C. */ + + /* Reporting is done in millidegree Celsius */ + *temp = decicelsius * 100 + adj * 1000; + + return 0; +} + +static const struct dm_thermal_ops rcar_gen3_thermal_ops = { + .get_temp = rcar_gen3_thermal_get_temp, +}; + +static void rcar_gen3_thermal_fetch_fuses(struct udevice *dev) +{ + struct rcar_thermal_info *info = (struct rcar_thermal_info *)dev_get_driver_data(dev); + struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev); + const struct rcar_gen3_thermal_fuse_info *fuses = info->fuses; + + /* + * Set the pseudo calibration points with fused values. + * PTAT is shared between all TSCs but only fused for the first + * TSC while THCODEs are fused for each TSC. + */ + priv->ptat[0] = rcar_gen3_thermal_read(&(priv->tscs[0]), fuses->ptat[0]) + & fuses->mask; + priv->ptat[1] = rcar_gen3_thermal_read(&(priv->tscs[0]), fuses->ptat[1]) + & fuses->mask; + priv->ptat[2] = rcar_gen3_thermal_read(&(priv->tscs[0]), fuses->ptat[2]) + & fuses->mask; + + for (unsigned int i = 0; i < priv->num_tscs; i++) { + struct rcar_gen3_thermal_tsc *tsc = &(priv->tscs[i]); + + tsc->thcode[0] = rcar_gen3_thermal_read(tsc, fuses->thcode[0]) + & fuses->mask; + tsc->thcode[1] = rcar_gen3_thermal_read(tsc, fuses->thcode[1]) + & fuses->mask; + tsc->thcode[2] = rcar_gen3_thermal_read(tsc, fuses->thcode[2]) + & fuses->mask; + } +} + +static bool rcar_gen3_thermal_read_fuses(struct udevice *dev) +{ + struct rcar_thermal_info *info = (struct rcar_thermal_info *)dev_get_driver_data(dev); + struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev); + const struct rcar_gen3_thermal_fuse_default *fuse_defaults = info->fuse_defaults; + unsigned int i; + u32 thscp; + + /* If fuses are not set, fallback to pseudo values. */ + thscp = rcar_gen3_thermal_read(&(priv->tscs[0]), REG_GEN3_THSCP); + if (!info->fuses || + (thscp & THSCP_COR_PARA_VLD) != THSCP_COR_PARA_VLD) { + /* Default THCODE values in case FUSEs are not set. */ + priv->ptat[0] = fuse_defaults->ptat[0]; + priv->ptat[1] = fuse_defaults->ptat[1]; + priv->ptat[2] = fuse_defaults->ptat[2]; + + for (i = 0; i < priv->num_tscs; i++) { + struct rcar_gen3_thermal_tsc *tsc = &(priv->tscs[i]); + + tsc->thcode[0] = fuse_defaults->thcodes[i][0]; + tsc->thcode[1] = fuse_defaults->thcodes[i][1]; + tsc->thcode[2] = fuse_defaults->thcodes[i][2]; + } + + return false; + } + + rcar_gen3_thermal_fetch_fuses(dev); + + return true; +} + +static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_priv *priv, + struct rcar_gen3_thermal_tsc *tsc) +{ + u32 reg_val; + + reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR); + reg_val &= ~THCTR_PONM; + rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val); + + udelay(1000); + + rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0); + rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0); + + reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR); + reg_val |= THCTR_THSST; + rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val); + + udelay(1000); +} + +static int rcar_gen3_thermal_probe(struct udevice *dev) +{ + struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev); + unsigned int i; + + if (!rcar_gen3_thermal_read_fuses(dev)) + dev_dbg(dev, "No calibration values fused, fallback to driver values\n"); + + for (i = 0; i < priv->num_tscs; i++) { + struct rcar_gen3_thermal_tsc *tsc = &(priv->tscs[i]); + + rcar_gen3_thermal_init(priv, tsc); + rcar_gen3_thermal_tsc_coefs(dev, tsc); + } + + return 0; +} + +static const struct rcar_gen3_thermal_fuse_info rcar_gen3_thermal_fuse_info_gen3 = { + .ptat = { REG_GEN3_PTAT1, REG_GEN3_PTAT2, REG_GEN3_PTAT3 }, + .thcode = { REG_GEN3_THCODE1, REG_GEN3_THCODE2, REG_GEN3_THCODE3 }, + .mask = GEN3_FUSE_MASK, +}; + +static const struct rcar_gen3_thermal_fuse_info rcar_gen3_thermal_fuse_info_gen4 = { + .ptat = { REG_GEN4_THSFMON16, REG_GEN4_THSFMON17, REG_GEN4_THSFMON15 }, + .thcode = { REG_GEN4_THSFMON01, REG_GEN4_THSFMON02, REG_GEN4_THSFMON00 }, + .mask = GEN4_FUSE_MASK, +}; + +static const struct rcar_gen3_thermal_fuse_default rcar_gen3_thermal_fuse_default_info_gen3 = { + .ptat = { 2631, 1509, 435 }, + .thcodes = { + { 3397, 2800, 2221 }, + { 3393, 2795, 2216 }, + { 3389, 2805, 2237 }, + { 3415, 2694, 2195 }, + { 3356, 2724, 2244 }, + }, +}; + +static const struct rcar_gen3_thermal_fuse_default rcar_gen3_thermal_fuse_default_info_v4h = { + .ptat = { 3274, 2164, 985 }, + .thcodes = { /* All four THS units share the same trimming */ + { 3218, 2617, 1980 }, + { 3218, 2617, 1980 }, + { 3218, 2617, 1980 }, + { 3218, 2617, 1980 }, + } +}; + +static const struct rcar_thermal_info rcar_m3w_thermal_info = { + .scale = 157, + .adj_below = -41, + .adj_above = 116, + .fuses = &rcar_gen3_thermal_fuse_info_gen3, + .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3, +}; + +static const struct rcar_thermal_info rcar_gen3_thermal_info = { + .scale = 167, + .adj_below = -41, + .adj_above = 126, + .fuses = &rcar_gen3_thermal_fuse_info_gen3, + .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3, +}; + +static const struct rcar_thermal_info rcar_gen4_thermal_info = { + .scale = 167, + .adj_below = -41, + .adj_above = 126, + .fuses = &rcar_gen3_thermal_fuse_info_gen4, + .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_gen3, +}; + +static const struct rcar_thermal_info rcar_v4h_thermal_info = { + .scale = 167, + .adj_below = -41, + .adj_above = 126, + .fuses = &rcar_gen3_thermal_fuse_info_gen4, + .fuse_defaults = &rcar_gen3_thermal_fuse_default_info_v4h, +}; + +static const struct udevice_id rcar_gen3_thermal_ids[] = { + { + .compatible = "renesas,r8a774a1-thermal", + .data = (ulong)&rcar_m3w_thermal_info, + }, + { + .compatible = "renesas,r8a774b1-thermal", + .data = (ulong)&rcar_gen3_thermal_info, + }, + { + .compatible = "renesas,r8a774e1-thermal", + .data = (ulong)&rcar_gen3_thermal_info, + }, + { + .compatible = "renesas,r8a7795-thermal", + .data = (ulong)&rcar_gen3_thermal_info, + }, + { + .compatible = "renesas,r8a7796-thermal", + .data = (ulong)&rcar_m3w_thermal_info, + }, + { + .compatible = "renesas,r8a77961-thermal", + .data = (ulong)&rcar_m3w_thermal_info, + }, + { + .compatible = "renesas,r8a77965-thermal", + .data = (ulong)&rcar_gen3_thermal_info, + }, + { + .compatible = "renesas,r8a77980-thermal", + .data = (ulong)&rcar_gen3_thermal_info, + }, + { + .compatible = "renesas,r8a779a0-thermal", + .data = (ulong)&rcar_gen3_thermal_info, + }, + { + .compatible = "renesas,r8a779f0-thermal", + .data = (ulong)&rcar_gen4_thermal_info, + }, + { + .compatible = "renesas,r8a779g0-thermal", + .data = (ulong)&rcar_v4h_thermal_info, + }, + { + .compatible = "renesas,r8a779h0-thermal", + .data = (ulong)&rcar_gen4_thermal_info, + }, + { } +}; + +U_BOOT_DRIVER(thermal_rcar_gen3_tsc) = { + .name = "thermal-rcar-gen3-tsc", + .id = UCLASS_THERMAL, + .ops = &rcar_gen3_thermal_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +static int rcar_gen3_thermal_bind(struct udevice *dev) +{ + /* + * We use dev_get_plat() here, because plat data are available + * in bind, while private data are not allocated yet. + */ + struct rcar_gen3_thermal_priv *priv = dev_get_plat(dev); + struct udevice *tdev; + struct driver *tdrv; + char name[32]; + void *addr; + int i, ret; + + tdrv = lists_driver_lookup_name("thermal-rcar-gen3-tsc"); + if (!tdrv) + return -ENOENT; + + for (i = 0; i < TSC_MAX_NUM; i++) { + addr = dev_read_addr_index_ptr(dev, i); + if (!addr) + break; + + priv->tscs[i].base = addr; + + tdev = NULL; + snprintf(name, sizeof(name), "thermal-rcar-gen3-tsc.%d", i); + ret = device_bind_with_driver_data(dev, tdrv, strdup(name), i, + dev_ofnode(dev), &tdev); + if (ret) + return ret; + } + + priv->num_tscs = i; + + return 0; +} + +U_BOOT_DRIVER(thermal_rcar_gen3) = { + .name = "thermal-rcar-gen3", + .id = UCLASS_NOP, + .of_match = rcar_gen3_thermal_ids, + .bind = rcar_gen3_thermal_bind, + .probe = rcar_gen3_thermal_probe, + .plat_auto = sizeof(struct rcar_gen3_thermal_priv), + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/thermal/thermal_sandbox.c b/drivers/thermal/thermal_sandbox.c index b7c567d76cd..2e1f1559e53 100644 --- a/drivers/thermal/thermal_sandbox.c +++ b/drivers/thermal/thermal_sandbox.c @@ -12,7 +12,7 @@ static int sandbox_thermal_get_temp(struct udevice *dev, int *temp) { /* Simply return 100 deg C */ - *temp = 100; + *temp = 100 * 1000; return 0; } diff --git a/drivers/thermal/ti-bandgap.c b/drivers/thermal/ti-bandgap.c index 0ea17a909dd..dc869f108e4 100644 --- a/drivers/thermal/ti-bandgap.c +++ b/drivers/thermal/ti-bandgap.c @@ -163,7 +163,7 @@ static int ti_bandgap_get_temp(struct udevice *dev, int *temp) struct ti_bandgap *bgp = dev_get_priv(dev); bgp->adc_val = 0x3ff & readl(bgp->base + CTRL_CORE_TEMP_SENSOR_MPU); - *temp = dra752_adc_to_temp[bgp->adc_val - DRA752_ADC_START_VALUE]; + *temp = dra752_adc_to_temp[bgp->adc_val - DRA752_ADC_START_VALUE] * 1000; return 0; } diff --git a/drivers/thermal/ti-lm74.c b/drivers/thermal/ti-lm74.c index 7d56f75df06..104c27429f4 100644 --- a/drivers/thermal/ti-lm74.c +++ b/drivers/thermal/ti-lm74.c @@ -28,7 +28,7 @@ static int ti_lm74_get_temp(struct udevice *dev, int *temp) raw = ((buf[0] << 8) + buf[1]) >> 3; - *temp = (((int)raw * 125) + 1000) / 2000; + *temp = (((int)raw * 125) + 1000) / 2; return 0; } @@ -44,7 +44,7 @@ static const struct udevice_id of_ti_lm74_match[] = { {}, }; -U_BOOT_DRIVER(ti_bandgap_thermal) = { +U_BOOT_DRIVER(ti_lm74_thermal) = { .name = "ti_lm74_thermal", .id = UCLASS_THERMAL, .ops = &ti_lm74_ops, diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 81c154b378a..f9511503b02 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -147,7 +147,7 @@ config SPL_ATMEL_TCB_TIMER config CADENCE_TTC_TIMER bool "Cadence TTC (Triple Timer Counter)" - depends on TIMER + depends on TIMER && ARCH_ZYNQMP_R5 help Enables support for the cadence ttc driver. This driver is present on Xilinx Zynq and ZynqMP SoCs. @@ -312,7 +312,7 @@ config MTK_TIMER config MCHP_PIT64B_TIMER bool "Microchip 64-bit periodic interval timer support" - depends on TIMER + depends on TIMER && ARCH_AT91 help Select this to enable support for Microchip 64-bit periodic interval timer. diff --git a/drivers/timer/riscv_aclint_timer.c b/drivers/timer/riscv_aclint_timer.c index 35da1ea2fd2..175956bcfd3 100644 --- a/drivers/timer/riscv_aclint_timer.c +++ b/drivers/timer/riscv_aclint_timer.c @@ -83,6 +83,7 @@ static int riscv_aclint_timer_probe(struct udevice *dev) static const struct udevice_id riscv_aclint_timer_ids[] = { { .compatible = "riscv,clint0", .data = CLINT_MTIME_OFFSET }, { .compatible = "sifive,clint0", .data = CLINT_MTIME_OFFSET }, + { .compatible = "sifive,clint2", .data = CLINT_MTIME_OFFSET }, { .compatible = "riscv,aclint-mtimer", .data = ACLINT_MTIME_OFFSET }, { } }; diff --git a/drivers/timer/tegra-timer.c b/drivers/timer/tegra-timer.c index 3545424889d..778b65b6062 100644 --- a/drivers/timer/tegra-timer.c +++ b/drivers/timer/tegra-timer.c @@ -4,6 +4,7 @@ */ #include <dm.h> +#include <dm/lists.h> #include <errno.h> #include <timer.h> @@ -106,6 +107,14 @@ static int tegra_timer_probe(struct udevice *dev) return 0; } +static int tegra_timer_bind(struct udevice *dev) +{ + if (CONFIG_IS_ENABLED(WDT_TEGRA)) + return device_bind_driver_to_node(dev, "tegra_wdt", "tegra-wdt", + dev_ofnode(dev), NULL); + return 0; +} + static const struct timer_ops tegra_timer_ops = { .get_count = tegra_timer_get_count, }; @@ -123,6 +132,7 @@ U_BOOT_DRIVER(tegra_timer) = { .name = "tegra_timer", .id = UCLASS_TIMER, .of_match = tegra_timer_ids, + .bind = tegra_timer_bind, .probe = tegra_timer_probe, .ops = &tegra_timer_ops, .flags = DM_FLAG_PRE_RELOC, diff --git a/drivers/tpm/tpm_tis_infineon.c b/drivers/tpm/tpm_tis_infineon.c index 30f23f8610a..c1e7b98295c 100644 --- a/drivers/tpm/tpm_tis_infineon.c +++ b/drivers/tpm/tpm_tis_infineon.c @@ -626,7 +626,7 @@ static const struct udevice_id tpm_tis_i2c_ids[] = { { } }; -U_BOOT_DRIVER(tpm_tis_i2c) = { +U_BOOT_DRIVER(tpm_tis_infineon) = { .name = "tpm_tis_infineon", .id = UCLASS_TPM, .of_match = tpm_tis_i2c_ids, diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig index b08ca08b07c..445270e8da1 100644 --- a/drivers/ufs/Kconfig +++ b/drivers/ufs/Kconfig @@ -15,17 +15,6 @@ config CADENCE_UFS This selects the platform driver for the Cadence UFS host controller present on present TI's J721e devices. -config UFS_PCI - bool "PCI bus based UFS Controller support" - depends on PCI && UFS - help - This selects the PCI UFS Host Controller Interface. Select this if - you have UFS Host Controller with PCI Interface. - - If you have a controller with this interface, say Y here. - - If unsure, say N. - config QCOM_UFS bool "Qualcomm Host Controller driver for UFS" depends on UFS && ARCH_SNAPDRAGON @@ -33,21 +22,21 @@ config QCOM_UFS This selects the platform driver for the UFS host controller present on Qualcomm Snapdragon SoCs. +config ROCKCHIP_UFS + bool "Rockchip specific hooks to UFS controller platform driver" + depends on UFS + help + This selects the Rockchip specific additions to UFSHCD platform driver. + + Select this if you have UFS controller on Rockchip chipset. + If unsure, say N. + config TI_J721E_UFS bool "Glue Layer driver for UFS on TI J721E devices" help This selects the glue layer driver for Cadence controller present on TI's J721E devices. -config UFS_RENESAS - bool "Renesas specific hooks to UFS controller platform driver" - depends on UFS - select BOUNCE_BUFFER - help - This selects the Renesas specific additions to UFSHCD platform driver. - UFS host on Renesas needs some vendor specific configuration before - accessing the hardware. - config UFS_AMD_VERSAL2 bool "AMD Versal Gen 2 UFS controller platform driver" depends on UFS && ZYNQMP_FIRMWARE @@ -56,4 +45,47 @@ config UFS_AMD_VERSAL2 UFS host on AMD needs some vendor specific configuration before accessing the hardware. +config UFS_MEDIATEK + tristate "MediaTek UFS Host Controller Driver" + depends on UFS && ARCH_MEDIATEK + select PHY_MTK_UFS + help + This selects the MediaTek specific additions to UFSHCD platform driver. + UFS host on Mediatek needs some vendor specific configuration before + accessing the hardware which includes PHY configuration and vendor + specific registers. + + Select this if you have UFS controller on MediaTek chipset. + + If unsure, say N. + +config UFS_PCI + bool "PCI bus based UFS Controller support" + depends on PCI && UFS + help + This selects the PCI UFS Host Controller Interface. Select this if + you have UFS Host Controller with PCI Interface. + + If you have a controller with this interface, say Y here. + + If unsure, say N. + +config UFS_RENESAS + bool "Renesas R-Car S4 UFS Controller support" + depends on UFS + select BOUNCE_BUFFER + help + This selects the Renesas S4 specific additions to UFSHCD + platform driver. UFS host on Renesas needs some vendor + specific configuration before accessing the hardware. + +config UFS_RENESAS_GEN5 + bool "Renesas R-Car X5H UFS Controller support" + depends on UFS + select BOUNCE_BUFFER + help + This selects the Renesas X5H specific additions to UFSHCD + platform driver. UFS host on Renesas needs some vendor + specific configuration before accessing the hardware. + endmenu diff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile index 2a378e45111..6b2f2ccc9fc 100644 --- a/drivers/ufs/Makefile +++ b/drivers/ufs/Makefile @@ -3,10 +3,13 @@ # Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com # -obj-$(CONFIG_UFS) += ufs.o ufs-uclass.o +obj-$(CONFIG_UFS) += ufs-uclass.o obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o obj-$(CONFIG_QCOM_UFS) += ufs-qcom.o +obj-$(CONFIG_ROCKCHIP_UFS) += ufs-rockchip.o obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o +obj-$(CONFIG_UFS_AMD_VERSAL2) += ufs-amd-versal2.o ufshcd-dwc.o +obj-$(CONFIG_UFS_MEDIATEK) += ufs-mediatek.o obj-$(CONFIG_UFS_PCI) += ufs-pci.o obj-$(CONFIG_UFS_RENESAS) += ufs-renesas.o -obj-$(CONFIG_UFS_AMD_VERSAL2) += ufs-amd-versal2.o ufshcd-dwc.o +obj-$(CONFIG_UFS_RENESAS_GEN5) += ufs-renesas-rcar-gen5.o diff --git a/drivers/ufs/cdns-platform.c b/drivers/ufs/cdns-platform.c index 510a6a6aa5d..87d9c5bad79 100644 --- a/drivers/ufs/cdns-platform.c +++ b/drivers/ufs/cdns-platform.c @@ -101,13 +101,6 @@ static int cdns_ufs_pltfm_probe(struct udevice *dev) return err; } -static int cdns_ufs_pltfm_bind(struct udevice *dev) -{ - struct udevice *scsi_dev; - - return ufs_scsi_bind(dev, &scsi_dev); -} - static const struct udevice_id cdns_ufs_pltfm_ids[] = { { .compatible = "cdns,ufshc-m31-16nm", @@ -120,5 +113,4 @@ U_BOOT_DRIVER(cdns_ufs_pltfm) = { .id = UCLASS_UFS, .of_match = cdns_ufs_pltfm_ids, .probe = cdns_ufs_pltfm_probe, - .bind = cdns_ufs_pltfm_bind, }; diff --git a/drivers/ufs/ti-j721e-ufs.c b/drivers/ufs/ti-j721e-ufs.c index c5c08610ffd..176d9b0e5c3 100644 --- a/drivers/ufs/ti-j721e-ufs.c +++ b/drivers/ufs/ti-j721e-ufs.c @@ -17,7 +17,7 @@ static int ti_j721e_ufs_probe(struct udevice *dev) { void __iomem *base; - unsigned int clock; + unsigned long clock; struct clk clk; u32 reg = 0; int ret; @@ -29,9 +29,9 @@ static int ti_j721e_ufs_probe(struct udevice *dev) } clock = clk_get_rate(&clk); - if (IS_ERR_VALUE(clock)) { + if ((long)clock <= 0) { dev_err(dev, "failed to get rate\n"); - return ret; + return clock ? clock : -EIO; } base = dev_remap_addr_index(dev, 0); diff --git a/drivers/ufs/ufs-amd-versal2.c b/drivers/ufs/ufs-amd-versal2.c index 896dda2de4e..bf23439e59d 100644 --- a/drivers/ufs/ufs-amd-versal2.c +++ b/drivers/ufs/ufs-amd-versal2.c @@ -330,7 +330,7 @@ static int ufs_versal2_init(struct ufs_hba *hba) return PTR_ERR(priv->rstphy); } - ret = zynqmp_pm_ufs_cal_reg(&cal); + ret = zynqmp_pm_ufs_cal_reg(&cal); if (ret) return ret; @@ -552,13 +552,6 @@ static int ufs_versal2_probe(struct udevice *dev) return ret; } -static int ufs_versal2_bind(struct udevice *dev) -{ - struct udevice *scsi_dev; - - return ufs_scsi_bind(dev, &scsi_dev); -} - static const struct udevice_id ufs_versal2_ids[] = { { .compatible = "amd,versal2-ufs", @@ -567,9 +560,8 @@ static const struct udevice_id ufs_versal2_ids[] = { }; U_BOOT_DRIVER(ufs_versal2_pltfm) = { - .name = "ufs-versal2-pltfm", - .id = UCLASS_UFS, - .of_match = ufs_versal2_ids, - .probe = ufs_versal2_probe, - .bind = ufs_versal2_bind, + .name = "ufs-versal2-pltfm", + .id = UCLASS_UFS, + .of_match = ufs_versal2_ids, + .probe = ufs_versal2_probe, }; diff --git a/drivers/ufs/ufs-mediatek-sip.h b/drivers/ufs/ufs-mediatek-sip.h new file mode 100644 index 00000000000..6a61f7bac69 --- /dev/null +++ b/drivers/ufs/ufs-mediatek-sip.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2022 MediaTek Inc. + * Copyright (c) 2025, Igor Belwon <igor.belwon@mentallysanemainliners.org> + * + * Slimmed down header from Linux: drivers/ufs/host/ufs-mediatek-sip.h + */ + +#ifndef _UFS_MEDIATEK_SIP_H +#define _UFS_MEDIATEK_SIP_H + +#include <linux/arm-smccc.h> + +/* + * SiP (Slicon Partner) commands + */ +#define MTK_SIP_UFS_CONTROL ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_64, \ + ARM_SMCCC_OWNER_SIP, 0x276) +#define UFS_MTK_SIP_DEVICE_RESET BIT(1) +#define UFS_MTK_SIP_REF_CLK_NOTIFICATION BIT(3) + +/* + * SMC call wrapper function + */ +struct ufs_mtk_smc_arg { + unsigned long cmd; + struct arm_smccc_res *res; + unsigned long v1; + unsigned long v2; + unsigned long v3; + unsigned long v4; + unsigned long v5; + unsigned long v6; + unsigned long v7; +}; + +static inline void _ufs_mtk_smc(struct ufs_mtk_smc_arg s) +{ + arm_smccc_smc(MTK_SIP_UFS_CONTROL, + s.cmd, + s.v1, s.v2, s.v3, s.v4, s.v5, s.v6, s.res); +} + +#define ufs_mtk_smc(...) \ + _ufs_mtk_smc((struct ufs_mtk_smc_arg) {__VA_ARGS__}) + +/* SIP interface */ + +#define ufs_mtk_ref_clk_notify(on, stage, res) \ + ufs_mtk_smc(UFS_MTK_SIP_REF_CLK_NOTIFICATION, &(res), on, stage) + +#define ufs_mtk_device_reset_ctrl(high, res) \ + ufs_mtk_smc(UFS_MTK_SIP_DEVICE_RESET, &(res), high) + +#endif /* !_UFS_MEDIATEK_SIP_H */ diff --git a/drivers/ufs/ufs-mediatek.c b/drivers/ufs/ufs-mediatek.c new file mode 100644 index 00000000000..e860d765eea --- /dev/null +++ b/drivers/ufs/ufs-mediatek.c @@ -0,0 +1,395 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025, Igor Belwon <igor.belwon@mentallysanemainliners.org> + * + * Loosely based on Linux driver: drivers/ufs/host/ufs-mediatek.c + */ + +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <generic-phy.h> +#include <ufs.h> +#include <asm/gpio.h> +#include <reset.h> + +#include <linux/arm-smccc.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/err.h> + +#include "ufs.h" +#include "ufs-mediatek.h" +#include "ufs-mediatek-sip.h" + +static void ufs_mtk_advertise_quirks(struct ufs_hba *hba) +{ + hba->quirks |= UFSHCI_QUIRK_SKIP_MANUAL_WB_FLUSH_CTRL | + UFSHCD_QUIRK_MCQ_BROKEN_INTR | + UFSHCD_QUIRK_BROKEN_LSDBS_CAP; +} + +static int ufs_mtk_hce_enable_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + struct ufs_mtk_host *host = dev_get_priv(hba->dev); + + if (status == PRE_CHANGE) { + if (host->caps & UFS_MTK_CAP_DISABLE_AH8) { + ufshcd_writel(hba, 0, + REG_AUTO_HIBERNATE_IDLE_TIMER); + hba->capabilities &= ~MASK_AUTO_HIBERN8_SUPPORT; + } + + /* + * Turn on CLK_CG early to bypass abnormal ERR_CHK signal + * to prevent host hang issue + */ + ufshcd_writel(hba, + ufshcd_readl(hba, REG_UFS_XOUFS_CTRL) | 0x80, + REG_UFS_XOUFS_CTRL); + + /* DDR_EN setting */ + if (host->ip_ver >= IP_VER_MT6989) { + ufshcd_rmwl(hba, UFS_MASK(0x7FFF, 8), + 0x453000, REG_UFS_MMIO_OPT_CTRL_0); + } + } + + return 0; +} + +static int ufs_mtk_unipro_set_lpm(struct ufs_hba *hba, bool lpm) +{ + int ret; + struct ufs_mtk_host *host = dev_get_priv(hba->dev); + + ret = ufshcd_dme_set(hba, + UIC_ARG_MIB_SEL(VS_UNIPROPOWERDOWNCONTROL, 0), + lpm ? 1 : 0); + if (!ret || !lpm) { + /* + * Forcibly set as non-LPM mode if UIC commands is failed + * to use default hba_enable_delay_us value for re-enabling + * the host. + */ + host->unipro_lpm = lpm; + } + + return ret; +} + +static int ufs_mtk_pre_link(struct ufs_hba *hba) +{ + int ret; + u32 tmp; + + ret = ufs_mtk_unipro_set_lpm(hba, false); + if (ret) + return ret; + + /* + * Setting PA_Local_TX_LCC_Enable to 0 before link startup + * to make sure that both host and device TX LCC are disabled + * once link startup is completed. + */ + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0); + if (ret) + return ret; + + /* disable deep stall */ + ret = ufshcd_dme_get(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp); + if (ret) + return ret; + + tmp &= ~(1 << 6); + + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp); + if (ret) + return ret; + + ret = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_SCRAMBLING), tmp); + + return ret; +} + +static void ufs_mtk_cfg_unipro_cg(struct ufs_hba *hba, bool enable) +{ + u32 tmp; + + if (enable) { + ufshcd_dme_get(hba, + UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp); + tmp = tmp | + (1 << RX_SYMBOL_CLK_GATE_EN) | + (1 << SYS_CLK_GATE_EN) | + (1 << TX_CLK_GATE_EN); + ufshcd_dme_set(hba, + UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp); + + ufshcd_dme_get(hba, + UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp); + tmp = tmp & ~(1 << TX_SYMBOL_CLK_REQ_FORCE); + ufshcd_dme_set(hba, + UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp); + } else { + ufshcd_dme_get(hba, + UIC_ARG_MIB(VS_SAVEPOWERCONTROL), &tmp); + tmp = tmp & ~((1 << RX_SYMBOL_CLK_GATE_EN) | + (1 << SYS_CLK_GATE_EN) | + (1 << TX_CLK_GATE_EN)); + ufshcd_dme_set(hba, + UIC_ARG_MIB(VS_SAVEPOWERCONTROL), tmp); + + ufshcd_dme_get(hba, + UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), &tmp); + tmp = tmp | (1 << TX_SYMBOL_CLK_REQ_FORCE); + ufshcd_dme_set(hba, + UIC_ARG_MIB(VS_DEBUGCLOCKENABLE), tmp); + } +} + +static void ufs_mtk_post_link(struct ufs_hba *hba) +{ + /* enable unipro clock gating feature */ + ufs_mtk_cfg_unipro_cg(hba, true); +} + +static int ufs_mtk_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + int ret = 0; + + switch (status) { + case PRE_CHANGE: + ret = ufs_mtk_pre_link(hba); + break; + case POST_CHANGE: + ufs_mtk_post_link(hba); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int ufs_mtk_bind_mphy(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = dev_get_priv(hba->dev); + int err = 0; + + err = generic_phy_get_by_index(hba->dev, 0, host->mphy); + + if (IS_ERR(host->mphy)) { + err = PTR_ERR(host->mphy); + if (err != -ENODEV) { + dev_info(hba->dev, "%s: Could NOT get a valid PHY %d\n", __func__, + err); + } + } + + if (err) + host->mphy = NULL; + + return err; +} + +static void ufs_mtk_init_reset_control(struct ufs_hba *hba, + struct reset_ctl **rc, + char *str) +{ + *rc = devm_reset_control_get(hba->dev, str); + if (IS_ERR(*rc)) { + dev_info(hba->dev, "Failed to get reset control %s: %ld\n", + str, PTR_ERR(*rc)); + *rc = NULL; + } +} + +static void ufs_mtk_init_reset(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = dev_get_priv(hba->dev); + + ufs_mtk_init_reset_control(hba, &host->hci_reset, + "hci_rst"); + ufs_mtk_init_reset_control(hba, &host->unipro_reset, + "unipro_rst"); + ufs_mtk_init_reset_control(hba, &host->crypto_reset, + "crypto_rst"); +} + +static void ufs_mtk_get_hw_ip_version(struct ufs_hba *hba) +{ + struct ufs_mtk_host *host = dev_get_priv(hba->dev); + u32 hw_ip_ver; + + hw_ip_ver = ufshcd_readl(hba, REG_UFS_MTK_IP_VER); + + if (((hw_ip_ver & (0xFF << 24)) == (0x1 << 24)) || + ((hw_ip_ver & (0xFF << 24)) == 0)) { + hw_ip_ver &= ~(0xFF << 24); + hw_ip_ver |= (0x1 << 28); + } + + host->ip_ver = hw_ip_ver; + + dev_info(hba->dev, "MediaTek UFS IP Version: 0x%x\n", hw_ip_ver); +} + +static int ufs_mtk_setup_ref_clk(struct ufs_hba *hba, bool on) +{ + struct ufs_mtk_host *host = dev_get_priv(hba->dev); + struct arm_smccc_res res; + int timeout, time_checked = 0; + u32 value; + + if (host->ref_clk_enabled == on) + return 0; + + ufs_mtk_ref_clk_notify(on, PRE_CHANGE, res); + + if (on) { + ufshcd_writel(hba, REFCLK_REQUEST, REG_UFS_REFCLK_CTRL); + } else { + udelay(10); + ufshcd_writel(hba, REFCLK_RELEASE, REG_UFS_REFCLK_CTRL); + } + + /* Wait for ack */ + timeout = REFCLK_REQ_TIMEOUT_US; + do { + value = ufshcd_readl(hba, REG_UFS_REFCLK_CTRL); + + /* Wait until ack bit equals to req bit */ + if (((value & REFCLK_ACK) >> 1) == (value & REFCLK_REQUEST)) + goto out; + + udelay(200); + time_checked += 200; + } while (time_checked != timeout); + + dev_err(hba->dev, "missing ack of refclk req, reg: 0x%x\n", value); + + /* + * If clock on timeout, assume clock is off, notify tfa do clock + * off setting.(keep DIFN disable, release resource) + * If clock off timeout, assume clock will off finally, + * set ref_clk_enabled directly.(keep DIFN disable, keep resource) + */ + if (on) + ufs_mtk_ref_clk_notify(false, POST_CHANGE, res); + else + host->ref_clk_enabled = false; + + return -ETIMEDOUT; + +out: + host->ref_clk_enabled = on; + if (on) + udelay(10); + + ufs_mtk_ref_clk_notify(on, POST_CHANGE, res); + + return 0; +} + +/** + * ufs_mtk_init - bind phy with controller + * @hba: host controller instance + * + * Powers up PHY enabling clocks and regulators. + * + * Returns -ENODEV if binding fails, returns negative error + * on phy power up failure and returns zero on success. + */ +static int ufs_mtk_init(struct ufs_hba *hba) +{ + struct ufs_mtk_host *priv = dev_get_priv(hba->dev); + int err; + + priv->hba = hba; + + err = ufs_mtk_bind_mphy(hba); + if (err) + return -ENODEV; + + ufs_mtk_advertise_quirks(hba); + + ufs_mtk_init_reset(hba); + + // TODO: Clocking + + err = generic_phy_power_on(priv->mphy); + if (err) { + dev_err(hba->dev, "%s: phy init failed, err = %d\n", + __func__, err); + return err; + } + + ufs_mtk_setup_ref_clk(hba, true); + ufs_mtk_get_hw_ip_version(hba); + + return 0; +} + +static int ufs_mtk_device_reset(struct ufs_hba *hba) +{ + struct arm_smccc_res res; + + ufs_mtk_device_reset_ctrl(0, res); + + /* + * The reset signal is active low. UFS devices shall detect + * more than or equal to 1us of positive or negative RST_n + * pulse width. + * + * To be on safe side, keep the reset low for at least 10us. + */ + udelay(13); + + ufs_mtk_device_reset_ctrl(1, res); + + /* Some devices may need time to respond to rst_n */ + mdelay(13); + + dev_dbg(hba->dev, "device reset done\n"); + + return 0; +} + +static struct ufs_hba_ops ufs_mtk_hba_ops = { + .init = ufs_mtk_init, + .hce_enable_notify = ufs_mtk_hce_enable_notify, + .link_startup_notify = ufs_mtk_link_startup_notify, + .device_reset = ufs_mtk_device_reset, +}; + +static int ufs_mtk_probe(struct udevice *dev) +{ + int ret; + + ret = ufshcd_probe(dev, &ufs_mtk_hba_ops); + if (ret) { + dev_err(dev, "ufshcd_probe() failed, ret:%d\n", ret); + return ret; + } + + return 0; +} + +static const struct udevice_id ufs_mtk_ids[] = { + { .compatible = "mediatek,mt6878-ufshci" }, + {}, +}; + +U_BOOT_DRIVER(mediatek_ufshci) = { + .name = "mediatek-ufshci", + .id = UCLASS_UFS, + .of_match = ufs_mtk_ids, + .probe = ufs_mtk_probe, + .priv_auto = sizeof(struct ufs_mtk_host), +}; diff --git a/drivers/ufs/ufs-mediatek.h b/drivers/ufs/ufs-mediatek.h new file mode 100644 index 00000000000..11a83d34c5b --- /dev/null +++ b/drivers/ufs/ufs-mediatek.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 MediaTek Inc. + * Copyright (c) 2025, Igor Belwon <igor.belwon@mentallysanemainliners.org> + * + * Slimmed down header from Linux: drivers/ufs/host/ufs-mediatek.h + */ + +#ifndef _UFS_MEDIATEK_H +#define _UFS_MEDIATEK_H + +#include <clk.h> +#include <linux/bitops.h> + +/* + * MCQ define and struct + */ +#define UFSHCD_MAX_Q_NR 8 +#define MTK_MCQ_INVALID_IRQ 0xFFFF + +/* REG_UFS_MMIO_OPT_CTRL_0 160h */ +#define EHS_EN BIT(0) +#define PFM_IMPV BIT(1) +#define MCQ_MULTI_INTR_EN BIT(2) +#define MCQ_CMB_INTR_EN BIT(3) +#define MCQ_AH8 BIT(4) + +#define MCQ_INTR_EN_MSK (MCQ_MULTI_INTR_EN | MCQ_CMB_INTR_EN) + +/* + * Vendor specific UFSHCI Registers + */ +#define REG_UFS_XOUFS_CTRL 0x140 +#define REG_UFS_REFCLK_CTRL 0x144 +#define REG_UFS_MMIO_OPT_CTRL_0 0x160 +#define REG_UFS_EXTREG 0x2100 +#define REG_UFS_MPHYCTRL 0x2200 +#define REG_UFS_MTK_IP_VER 0x2240 +#define REG_UFS_REJECT_MON 0x22AC +#define REG_UFS_DEBUG_SEL 0x22C0 +#define REG_UFS_PROBE 0x22C8 +#define REG_UFS_DEBUG_SEL_B0 0x22D0 +#define REG_UFS_DEBUG_SEL_B1 0x22D4 +#define REG_UFS_DEBUG_SEL_B2 0x22D8 +#define REG_UFS_DEBUG_SEL_B3 0x22DC + +#define REG_UFS_MTK_SQD 0x2800 +#define REG_UFS_MTK_SQIS 0x2814 +#define REG_UFS_MTK_CQD 0x281C +#define REG_UFS_MTK_CQIS 0x2824 + +#define REG_UFS_MCQ_STRIDE 0x30 + +/* + * Ref-clk control + * + * Values for register REG_UFS_REFCLK_CTRL + */ +#define REFCLK_RELEASE 0x0 +#define REFCLK_REQUEST BIT(0) +#define REFCLK_ACK BIT(1) + +#define REFCLK_REQ_TIMEOUT_US 3000 +#define REFCLK_DEFAULT_WAIT_US 32 + +/* + * Other attributes + */ +#define VS_DEBUGCLOCKENABLE 0xD0A1 +#define VS_SAVEPOWERCONTROL 0xD0A6 +#define VS_UNIPROPOWERDOWNCONTROL 0xD0A8 + +/* + * Vendor specific link state + */ +enum { + VS_LINK_DISABLED = 0, + VS_LINK_DOWN = 1, + VS_LINK_UP = 2, + VS_LINK_HIBERN8 = 3, + VS_LINK_LOST = 4, + VS_LINK_CFG = 5, +}; + +/* + * Vendor specific host controller state + */ +enum { + VS_HCE_RESET = 0, + VS_HCE_BASE = 1, + VS_HCE_OOCPR_WAIT = 2, + VS_HCE_DME_RESET = 3, + VS_HCE_MIDDLE = 4, + VS_HCE_DME_ENABLE = 5, + VS_HCE_DEFAULTS = 6, + VS_HIB_IDLEEN = 7, + VS_HIB_ENTER = 8, + VS_HIB_ENTER_CONF = 9, + VS_HIB_MIDDLE = 10, + VS_HIB_WAITTIMER = 11, + VS_HIB_EXIT_CONF = 12, + VS_HIB_EXIT = 13, +}; + +/* + * VS_DEBUGCLOCKENABLE + */ +enum { + TX_SYMBOL_CLK_REQ_FORCE = 5, +}; + +/* + * VS_SAVEPOWERCONTROL + */ +enum { + RX_SYMBOL_CLK_GATE_EN = 0, + SYS_CLK_GATE_EN = 2, + TX_CLK_GATE_EN = 3, +}; + +/* + * Host capability + */ +enum ufs_mtk_host_caps { + UFS_MTK_CAP_BOOST_CRYPT_ENGINE = 1 << 0, + UFS_MTK_CAP_VA09_PWR_CTRL = 1 << 1, + UFS_MTK_CAP_DISABLE_AH8 = 1 << 2, + UFS_MTK_CAP_BROKEN_VCC = 1 << 3, + + /* + * Override UFS_MTK_CAP_BROKEN_VCC's behavior to + * allow vccqx upstream to enter LPM + */ + UFS_MTK_CAP_ALLOW_VCCQX_LPM = 1 << 5, + UFS_MTK_CAP_PMC_VIA_FASTAUTO = 1 << 6, + UFS_MTK_CAP_TX_SKEW_FIX = 1 << 7, + UFS_MTK_CAP_DISABLE_MCQ = 1 << 8, + /* Control MTCMOS with RTFF */ + UFS_MTK_CAP_RTFF_MTCMOS = 1 << 9, + + UFS_MTK_CAP_MCQ_BROKEN_RTC = 1 << 10, +}; + +struct ufs_mtk_hw_ver { + u8 step; + u8 minor; + u8 major; +}; + +struct ufs_mtk_mcq_intr_info { + struct ufs_hba *hba; + u32 irq; + u8 qid; +}; + +struct ufs_mtk_host { + struct phy *mphy; + struct reset_ctl *unipro_reset; + struct reset_ctl *crypto_reset; + struct reset_ctl *hci_reset; + struct ufs_hba *hba; + struct ufs_mtk_crypt_cfg *crypt; + struct clk_bulk clks; + struct ufs_mtk_hw_ver hw_ver; + enum ufs_mtk_host_caps caps; + bool mphy_powered_on; + bool unipro_lpm; + bool ref_clk_enabled; + bool is_clks_enabled; + u16 ref_clk_ungating_wait_us; + u16 ref_clk_gating_wait_us; + u32 ip_ver; + bool legacy_ip_ver; + + bool mcq_set_intr; + bool is_mcq_intr_enabled; + int mcq_nr_intr; + struct ufs_mtk_mcq_intr_info mcq_intr_info[UFSHCD_MAX_Q_NR]; +}; + +/* MTK delay of autosuspend: 500 ms */ +#define MTK_RPM_AUTOSUSPEND_DELAY_MS 500 + +/* MTK RTT support number */ +#define MTK_MAX_NUM_RTT 2 + +/* UFSHCI MTK ip version value */ +enum { + /* UFSHCI 3.1 */ + IP_VER_MT6983 = 0x10360000, + IP_VER_MT6878 = 0x10420200, + + /* UFSHCI 4.0 */ + IP_VER_MT6897 = 0x10440000, + IP_VER_MT6989 = 0x10450000, + IP_VER_MT6899 = 0x10450100, + IP_VER_MT6991_A0 = 0x10460000, + IP_VER_MT6991_B0 = 0x10470000, + IP_VER_MT6993 = 0x10480000, + + IP_VER_NONE = 0xFFFFFFFF +}; + +enum ip_ver_legacy { + IP_LEGACY_VER_MT6781 = 0x10380000, + IP_LEGACY_VER_MT6879 = 0x10360000, + IP_LEGACY_VER_MT6893 = 0x20160706 +}; + +#endif /* !_UFS_MEDIATEK_H */ diff --git a/drivers/ufs/ufs-pci.c b/drivers/ufs/ufs-pci.c index 871f3f50f5c..5b9c72a695d 100644 --- a/drivers/ufs/ufs-pci.c +++ b/drivers/ufs/ufs-pci.c @@ -11,13 +11,6 @@ #include <dm/device_compat.h> #include "ufs.h" -static int ufs_pci_bind(struct udevice *dev) -{ - struct udevice *scsi_dev; - - return ufs_scsi_bind(dev, &scsi_dev); -} - static int ufs_pci_probe(struct udevice *dev) { int err; @@ -32,7 +25,6 @@ static int ufs_pci_probe(struct udevice *dev) U_BOOT_DRIVER(ufs_pci) = { .name = "ufs_pci", .id = UCLASS_UFS, - .bind = ufs_pci_bind, .probe = ufs_pci_probe, }; diff --git a/drivers/ufs/ufs-qcom.c b/drivers/ufs/ufs-qcom.c index 843585726c7..9f0a6940d98 100644 --- a/drivers/ufs/ufs-qcom.c +++ b/drivers/ufs/ufs-qcom.c @@ -648,13 +648,6 @@ static int ufs_qcom_probe(struct udevice *dev) return 0; } -static int ufs_qcom_bind(struct udevice *dev) -{ - struct udevice *scsi_dev; - - return ufs_scsi_bind(dev, &scsi_dev); -} - static const struct udevice_id ufs_qcom_ids[] = { { .compatible = "qcom,ufshc" }, {}, @@ -665,6 +658,5 @@ U_BOOT_DRIVER(qcom_ufshcd) = { .id = UCLASS_UFS, .of_match = ufs_qcom_ids, .probe = ufs_qcom_probe, - .bind = ufs_qcom_bind, .priv_auto = sizeof(struct ufs_qcom_priv), }; diff --git a/drivers/ufs/ufs-renesas-rcar-gen5.c b/drivers/ufs/ufs-renesas-rcar-gen5.c new file mode 100644 index 00000000000..cc53e91449c --- /dev/null +++ b/drivers/ufs/ufs-renesas-rcar-gen5.c @@ -0,0 +1,268 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Renesas UFS host controller driver + * + * Copyright (C) 2025 Renesas Electronics Corporation + */ + +#include <clk.h> +#include <dm.h> +#include <ufs.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <linux/iopoll.h> +#include <reset.h> + +#include "ufs.h" + +#define UFS_RENESAS_TIMEOUT_US 100000 + +struct ufs_renesas_priv { + struct clk_bulk clks; + struct reset_ctl_bulk resets; + fdt_addr_t phy_base; + /* The hardware needs initialization once */ + bool initialized; +}; + +static void ufs_dme_command(struct ufs_hba *hba, u32 cmd, + u32 arg1, u32 arg2, u32 arg3) +{ + ufshcd_writel(hba, arg1, REG_UIC_COMMAND_ARG_1); + ufshcd_writel(hba, arg2, REG_UIC_COMMAND_ARG_2); + ufshcd_writel(hba, arg3, REG_UIC_COMMAND_ARG_3); + ufshcd_writel(hba, cmd, REG_UIC_COMMAND); +} + +static int ufs_renesas_pre_init(struct ufs_hba *hba) +{ + struct ufs_renesas_priv *priv = dev_get_priv(hba->dev); + u32 val32; + u16 val16; + int ret; + + writew(0x0001, priv->phy_base + 0x20000); + writew(0x005c, priv->phy_base + 0x20212); + writew(0x005c, priv->phy_base + 0x20214); + writew(0x005c, priv->phy_base + 0x20216); + writew(0x005c, priv->phy_base + 0x20218); + writew(0x036a, priv->phy_base + 0x201d0); + writew(0x0102, priv->phy_base + 0x201d2); + writew(0x001f, priv->phy_base + 0x20082); + writew(0x000b, priv->phy_base + 0x20084); + writew(0x0126, priv->phy_base + 0x201d2); + writew(0x01dc, priv->phy_base + 0x20214); + writew(0x01dc, priv->phy_base + 0x20218); + writew(0x0000, priv->phy_base + 0x201cc); + writew(0x0200, priv->phy_base + 0x201ce); + writew(0x0000, priv->phy_base + 0x20212); + writew(0x0000, priv->phy_base + 0x20216); + + ret = readw_poll_timeout(priv->phy_base + 0x201ec, val16, + !(val16 & BIT(12)), UFS_RENESAS_TIMEOUT_US); + if (ret) + return ret; + + ret = readw_poll_timeout(priv->phy_base + 0x201e4, val16, + !(val16 & BIT(12)), UFS_RENESAS_TIMEOUT_US); + if (ret) + return ret; + + ret = readw_poll_timeout(priv->phy_base + 0x201f0, val16, + !(val16 & BIT(12)), UFS_RENESAS_TIMEOUT_US); + if (ret) + return ret; + + writew(0x0000, priv->phy_base + 0x20000); + + ufshcd_writel(hba, BIT(0), REG_CONTROLLER_ENABLE); + + ret = read_poll_timeout(ufshcd_readl, val32, (val32 & BIT(0)), + 1, UFS_RENESAS_TIMEOUT_US, + hba, REG_CONTROLLER_ENABLE); + if (ret) + return ret; + + ret = read_poll_timeout(ufshcd_readl, val32, (val32 & BIT(3)), + 1, UFS_RENESAS_TIMEOUT_US, + hba, REG_CONTROLLER_STATUS); + if (ret) + return ret; + + /* Skip IE because we cannot handle interrupts here */ + ufs_dme_command(hba, 0x00000002, 0x81010000, 0x00000000, 0x00000005); + ufs_dme_command(hba, 0x00000002, 0x81150000, 0x00000000, 0x00000001); + ufs_dme_command(hba, 0x00000002, 0x81180000, 0x00000000, 0x00000001); + ufs_dme_command(hba, 0x00000002, 0x80090000, 0x00000000, 0x00000000); + ufs_dme_command(hba, 0x00000002, 0x800a0000, 0x00000000, 0x000000c8); + ufs_dme_command(hba, 0x00000002, 0x80090001, 0x00000000, 0x00000000); + ufs_dme_command(hba, 0x00000002, 0x800a0001, 0x00000000, 0x000000c8); + ufs_dme_command(hba, 0x00000002, 0x800a0004, 0x00000000, 0x00000000); + ufs_dme_command(hba, 0x00000002, 0x800b0004, 0x00000000, 0x00000064); + ufs_dme_command(hba, 0x00000002, 0x800a0005, 0x00000000, 0x00000000); + ufs_dme_command(hba, 0x00000002, 0x800b0005, 0x00000000, 0x00000064); + ufs_dme_command(hba, 0x00000002, 0xd0850000, 0x00000000, 0x00000001); + + writew(0x0001, priv->phy_base + 0x20000); + + clrbits_le16(priv->phy_base + 0x20022, BIT(0)); + + ret = readw_poll_timeout(priv->phy_base + (0x00198 << 1), val16, + (val16 & BIT(0)), UFS_RENESAS_TIMEOUT_US); + if (ret) + return ret; + + writew(0x0368, priv->phy_base + 0x201d0); + + ret = readw_poll_timeout(priv->phy_base + 0x201e4, val16, + !(val16 & BIT(11)), UFS_RENESAS_TIMEOUT_US); + if (ret) + return ret; + + ret = readw_poll_timeout(priv->phy_base + 0x201e8, val16, + !(val16 & BIT(11)), UFS_RENESAS_TIMEOUT_US); + if (ret) + return ret; + + ret = readw_poll_timeout(priv->phy_base + 0x201ec, val16, + !(val16 & BIT(11)), UFS_RENESAS_TIMEOUT_US); + if (ret) + return ret; + + ret = readw_poll_timeout(priv->phy_base + 0x201f0, val16, + !(val16 & BIT(11)), UFS_RENESAS_TIMEOUT_US); + if (ret) + return ret; + + priv->initialized = true; + + return 0; +} + +static int ufs_renesas_init(struct ufs_hba *hba) +{ + hba->quirks |= UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS | UFSHCD_QUIRK_HIBERN_FASTAUTO | + UFSHCD_QUIRK_BROKEN_LCC; + + return 0; +} + +static int ufs_renesas_hce_enable_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + struct ufs_renesas_priv *priv = dev_get_priv(hba->dev); + int ret; + + if (priv->initialized) + return 0; + + if (status == PRE_CHANGE) { + ret = ufs_renesas_pre_init(hba); + if (ret) + return ret; + } + + priv->initialized = true; + + return 0; +} + +static int ufs_renesas_link_startup_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + if (status == PRE_CHANGE) + return ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0); + + return 0; +} + +static int ufs_renesas_get_max_pwr_mode(struct ufs_hba *hba, + struct ufs_pwr_mode_info *max_pwr_info) +{ + max_pwr_info->info.gear_rx = UFS_HS_G5; + max_pwr_info->info.gear_tx = UFS_HS_G5; + max_pwr_info->info.pwr_tx = FASTAUTO_MODE; + max_pwr_info->info.pwr_rx = FASTAUTO_MODE; + max_pwr_info->info.hs_rate = PA_HS_MODE_A; + + max_pwr_info->info.lane_rx = 1; + max_pwr_info->info.lane_tx = 1; + + dev_info(hba->dev, "Max HS Gear: %d\n", max_pwr_info->info.gear_rx); + + return 0; +} + +static struct ufs_hba_ops ufs_renesas_vops = { + .init = ufs_renesas_init, + .hce_enable_notify = ufs_renesas_hce_enable_notify, + .link_startup_notify = ufs_renesas_link_startup_notify, + .get_max_pwr_mode = ufs_renesas_get_max_pwr_mode, +}; + +static int ufs_renesas_pltfm_probe(struct udevice *dev) +{ + struct ufs_renesas_priv *priv = dev_get_priv(dev); + int ret; + + priv->phy_base = dev_read_addr_name(dev, "phy"); + if (priv->phy_base == FDT_ADDR_T_NONE) + return -EINVAL; + + ret = reset_get_bulk(dev, &priv->resets); + if (ret < 0) + return ret; + + ret = clk_get_bulk(dev, &priv->clks); + if (ret < 0) + goto err_clk_get; + + ret = clk_enable_bulk(&priv->clks); + if (ret) + goto err_clk_enable; + + reset_assert_bulk(&priv->resets); + reset_deassert_bulk(&priv->resets); + + ret = ufshcd_probe(dev, &ufs_renesas_vops); + if (ret) { + dev_err(dev, "ufshcd_probe() failed %d\n", ret); + goto err_ufshcd_probe; + } + + return 0; + +err_ufshcd_probe: + reset_assert_bulk(&priv->resets); + clk_disable_bulk(&priv->clks); +err_clk_enable: + clk_release_bulk(&priv->clks); +err_clk_get: + reset_release_bulk(&priv->resets); + return ret; +} + +static int ufs_renesas_pltfm_remove(struct udevice *dev) +{ + struct ufs_renesas_priv *priv = dev_get_priv(dev); + + reset_release_bulk(&priv->resets); + clk_disable_bulk(&priv->clks); + clk_release_bulk(&priv->clks); + + return 0; +} + +static const struct udevice_id ufs_renesas_pltfm_ids[] = { + { .compatible = "renesas,r8a78000-ufs" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(ufs_renesas_gen5) = { + .name = "ufs-renesas-gen5", + .id = UCLASS_UFS, + .of_match = ufs_renesas_pltfm_ids, + .probe = ufs_renesas_pltfm_probe, + .remove = ufs_renesas_pltfm_remove, + .priv_auto = sizeof(struct ufs_renesas_priv), +}; diff --git a/drivers/ufs/ufs-renesas.c b/drivers/ufs/ufs-renesas.c index ae05bdc8102..0b74b39dc2a 100644 --- a/drivers/ufs/ufs-renesas.c +++ b/drivers/ufs/ufs-renesas.c @@ -351,13 +351,6 @@ static struct ufs_hba_ops ufs_renesas_vops = { .hce_enable_notify = ufs_renesas_hce_enable_notify, }; -static int ufs_renesas_pltfm_bind(struct udevice *dev) -{ - struct udevice *scsi_dev; - - return ufs_scsi_bind(dev, &scsi_dev); -} - static int ufs_renesas_pltfm_probe(struct udevice *dev) { struct ufs_renesas_priv *priv = dev_get_priv(dev); @@ -405,7 +398,6 @@ U_BOOT_DRIVER(ufs_renesas) = { .name = "ufs-renesas", .id = UCLASS_UFS, .of_match = ufs_renesas_pltfm_ids, - .bind = ufs_renesas_pltfm_bind, .probe = ufs_renesas_pltfm_probe, .remove = ufs_renesas_pltfm_remove, .priv_auto = sizeof(struct ufs_renesas_priv), diff --git a/drivers/ufs/ufs-rockchip.c b/drivers/ufs/ufs-rockchip.c new file mode 100644 index 00000000000..0384244387d --- /dev/null +++ b/drivers/ufs/ufs-rockchip.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Rockchip UFS Host Controller driver + * + * Copyright (C) 2025 Rockchip Electronics Co.Ltd. + */ + +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/ioport.h> +#include <reset.h> +#include <ufs.h> + +#include "ufs.h" +#include "unipro.h" +#include "ufs-rockchip.h" + +static int ufs_rockchip_hce_enable_notify(struct ufs_hba *hba, + enum ufs_notify_change_status status) +{ + int err = 0; + + if (status != POST_CHANGE) + return 0; + + ufshcd_dme_reset(hba); + ufshcd_dme_enable(hba); + + if (hba->ops->phy_initialization) { + err = hba->ops->phy_initialization(hba); + if (err) + dev_err(hba->dev, + "Phy init failed (%d)\n", err); + } + + return err; +} + +static void ufs_rockchip_rk3576_phy_parameter_init(struct ufs_hba *hba) +{ + struct ufs_rockchip_host *host = dev_get_priv(hba->dev); + + ufs_sys_writel(host->mphy_base, 0x80, CMN_REG23); + ufs_sys_writel(host->mphy_base, 0xB5, TRSV0_REG14); + ufs_sys_writel(host->mphy_base, 0xB5, TRSV1_REG14); + ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG15); + ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG15); + ufs_sys_writel(host->mphy_base, 0x38, TRSV0_REG08); + ufs_sys_writel(host->mphy_base, 0x38, TRSV1_REG08); + ufs_sys_writel(host->mphy_base, 0x50, TRSV0_REG29); + ufs_sys_writel(host->mphy_base, 0x50, TRSV1_REG29); + ufs_sys_writel(host->mphy_base, 0x80, TRSV0_REG2E); + ufs_sys_writel(host->mphy_base, 0x80, TRSV1_REG2E); + ufs_sys_writel(host->mphy_base, 0x18, TRSV0_REG3C); + ufs_sys_writel(host->mphy_base, 0x18, TRSV1_REG3C); + ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG16); + ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG16); + ufs_sys_writel(host->mphy_base, 0x20, TRSV0_REG17); + ufs_sys_writel(host->mphy_base, 0x20, TRSV1_REG17); + ufs_sys_writel(host->mphy_base, 0xC0, TRSV0_REG18); + ufs_sys_writel(host->mphy_base, 0xC0, TRSV1_REG18); + ufs_sys_writel(host->mphy_base, 0x03, CMN_REG25); + ufs_sys_writel(host->mphy_base, 0x03, TRSV0_REG3D); + ufs_sys_writel(host->mphy_base, 0x03, TRSV1_REG3D); + ufs_sys_writel(host->mphy_base, 0xC0, CMN_REG23); + udelay(1); + ufs_sys_writel(host->mphy_base, 0x00, CMN_REG23); + udelay(200); +} + +static int ufs_rockchip_rk3576_phy_init(struct ufs_hba *hba) +{ + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(PA_LOCAL_TX_LCC_ENABLE, 0x0), 0x0); + /* enable the mphy DME_SET cfg */ + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MPHY_CFG, 0x0), MPHY_CFG_ENABLE); + for (int i = 0; i < 2; i++) { + /* Configuration M-TX */ + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD, SEL_TX_LANE0 + i), 0x06); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD_EN, SEL_TX_LANE0 + i), 0x02); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_VALUE, SEL_TX_LANE0 + i), 0x44); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE1, SEL_TX_LANE0 + i), 0xe6); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE2, SEL_TX_LANE0 + i), 0x07); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_TASE_VALUE, SEL_TX_LANE0 + i), 0x93); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_BASE_NVALUE, SEL_TX_LANE0 + i), 0xc9); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_POWER_SAVING_CTRL, SEL_TX_LANE0 + i), 0x00); + /* Configuration M-RX */ + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD, SEL_RX_LANE0 + i), 0x06); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD_EN, SEL_RX_LANE0 + i), 0x00); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE, SEL_RX_LANE0 + i), 0x58); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_PVALUE1, SEL_RX_LANE0 + i), 0x8c); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_PVALUE2, SEL_RX_LANE0 + i), 0x02); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_OPTION, SEL_RX_LANE0 + i), 0xf6); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_POWER_SAVING_CTRL, SEL_RX_LANE0 + i), 0x69); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_SAVE_DET_CTRL, SEL_RX_LANE0 + i), 0x18); + } + + /* disable the mphy DME_SET cfg */ + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MPHY_CFG, 0x0), MPHY_CFG_DISABLE); + + ufs_rockchip_rk3576_phy_parameter_init(hba); + + /* start link up */ + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MIB_T_DBG_CPORT_TX_ENDIAN, 0), 0x0); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(MIB_T_DBG_CPORT_RX_ENDIAN, 0), 0x0); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(N_DEVICEID, 0), 0x0); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(N_DEVICEID_VALID, 0), 0x1); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(T_PEERDEVICEID, 0), 0x1); + ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(T_CONNECTIONSTATE, 0), 0x1); + + return 0; +} + +static int ufs_rockchip_common_init(struct ufs_hba *hba) +{ + struct udevice *dev = hba->dev; + struct ufs_rockchip_host *host = dev_get_priv(dev); + struct resource res; + int err; + + /* system control register for hci */ + err = dev_read_resource_byname(dev, "hci_grf", &res); + if (err) { + dev_err(dev, "cannot ioremap for hci system control register\n"); + return err; + } + host->ufs_sys_ctrl = (void *)(res.start); + + /* system control register for mphy */ + err = dev_read_resource_byname(dev, "mphy_grf", &res); + if (err) { + dev_err(dev, "cannot ioremap for mphy system control register\n"); + return err; + } + host->ufs_phy_ctrl = (void *)(res.start); + + /* mphy base register */ + err = dev_read_resource_byname(dev, "mphy", &res); + if (err) { + dev_err(dev, "cannot ioremap for mphy base register\n"); + return err; + } + host->mphy_base = (void *)(res.start); + + host->phy_config_mode = dev_read_u32_default(dev, "ufs-phy-config-mode", 0); + + err = reset_get_bulk(dev, &host->rsts); + if (err) { + dev_err(dev, "Can't get reset: %d\n", err); + return err; + } + + host->hba = hba; + + return 0; +} + +static int ufs_rockchip_rk3576_init(struct ufs_hba *hba) +{ + int ret = 0; + + ret = ufs_rockchip_common_init(hba); + if (ret) { + dev_err(hba->dev, "%s: ufs common init fail\n", __func__); + return ret; + } + + return 0; +} + +static struct ufs_hba_ops ufs_hba_rk3576_vops = { + .init = ufs_rockchip_rk3576_init, + .phy_initialization = ufs_rockchip_rk3576_phy_init, + .hce_enable_notify = ufs_rockchip_hce_enable_notify, +}; + +static const struct udevice_id ufs_rockchip_of_match[] = { + { .compatible = "rockchip,rk3576-ufshc", .data = (ulong)&ufs_hba_rk3576_vops}, + {}, +}; + +static int ufs_rockchip_probe(struct udevice *dev) +{ + struct ufs_hba_ops *ops = (struct ufs_hba_ops *)dev_get_driver_data(dev); + int err; + + err = ufshcd_probe(dev, ops); + if (err) + dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err); + + return err; +} + +U_BOOT_DRIVER(rockchip_ufs) = { + .name = "ufshcd-rockchip", + .id = UCLASS_UFS, + .of_match = ufs_rockchip_of_match, + .probe = ufs_rockchip_probe, + .priv_auto = sizeof(struct ufs_rockchip_host), +}; diff --git a/drivers/ufs/ufs-rockchip.h b/drivers/ufs/ufs-rockchip.h new file mode 100644 index 00000000000..3dcb80f5702 --- /dev/null +++ b/drivers/ufs/ufs-rockchip.h @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Rockchip UFS Host Controller driver + * + * Copyright (C) 2025 Rockchip Electronics Co.Ltd. + */ + +#ifndef _UFS_ROCKCHIP_H_ +#define _UFS_ROCKCHIP_H_ + +#define UFS_MAX_CLKS 3 + +#define SEL_TX_LANE0 0x0 +#define SEL_TX_LANE1 0x1 +#define SEL_TX_LANE2 0x2 +#define SEL_TX_LANE3 0x3 +#define SEL_RX_LANE0 0x4 +#define SEL_RX_LANE1 0x5 +#define SEL_RX_LANE2 0x6 +#define SEL_RX_LANE3 0x7 + +#define VND_TX_CLK_PRD 0xAA +#define VND_TX_CLK_PRD_EN 0xA9 +#define VND_TX_LINERESET_PVALUE2 0xAB +#define VND_TX_LINERESET_PVALUE1 0xAC +#define VND_TX_LINERESET_VALUE 0xAD +#define VND_TX_BASE_NVALUE 0x93 +#define VND_TX_TASE_VALUE 0x94 +#define VND_TX_POWER_SAVING_CTRL 0x7F +#define VND_RX_CLK_PRD 0x12 +#define VND_RX_CLK_PRD_EN 0x11 +#define VND_RX_LINERESET_PVALUE2 0x1B +#define VND_RX_LINERESET_PVALUE1 0x1C +#define VND_RX_LINERESET_VALUE 0x1D +#define VND_RX_LINERESET_OPTION 0x25 +#define VND_RX_POWER_SAVING_CTRL 0x2F +#define VND_RX_SAVE_DET_CTRL 0x1E + +#define CMN_REG23 0x8C +#define CMN_REG25 0x94 +#define TRSV0_REG08 0xE0 +#define TRSV1_REG08 0x220 +#define TRSV0_REG14 0x110 +#define TRSV1_REG14 0x250 +#define TRSV0_REG15 0x134 +#define TRSV1_REG15 0x274 +#define TRSV0_REG16 0x128 +#define TRSV1_REG16 0x268 +#define TRSV0_REG17 0x12C +#define TRSV1_REG17 0x26c +#define TRSV0_REG18 0x120 +#define TRSV1_REG18 0x260 +#define TRSV0_REG29 0x164 +#define TRSV1_REG29 0x2A4 +#define TRSV0_REG2E 0x178 +#define TRSV1_REG2E 0x2B8 +#define TRSV0_REG3C 0x1B0 +#define TRSV1_REG3C 0x2F0 +#define TRSV0_REG3D 0x1B4 +#define TRSV1_REG3D 0x2F4 + +#define MPHY_CFG 0x200 +#define MPHY_CFG_ENABLE 0x40 +#define MPHY_CFG_DISABLE 0x0 + +#define MIB_T_DBG_CPORT_TX_ENDIAN 0xc022 +#define MIB_T_DBG_CPORT_RX_ENDIAN 0xc023 + +struct ufs_rockchip_host { + struct ufs_hba *hba; + void __iomem *ufs_phy_ctrl; + void __iomem *ufs_sys_ctrl; + void __iomem *mphy_base; + struct reset_ctl_bulk rsts; + struct clk ref_out_clk; + uint64_t caps; + uint32_t phy_config_mode; +}; + +#define ufs_sys_writel(base, val, reg) \ + writel((val), (base) + (reg)) +#define ufs_sys_readl(base, reg) readl((base) + (reg)) +#define ufs_sys_set_bits(base, mask, reg) \ + ufs_sys_writel((base), ((mask) | (ufs_sys_readl((base), (reg)))), (reg)) +#define ufs_sys_ctrl_clr_bits(base, mask, reg) \ + ufs_sys_writel((base), ((~(mask)) & (ufs_sys_readl((base), (reg)))), (reg)) + +#endif /* _UFS_ROCKCHIP_H_ */ diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c index 334bfcfa06a..3c8e4299259 100644 --- a/drivers/ufs/ufs-uclass.c +++ b/drivers/ufs/ufs-uclass.c @@ -1,17 +1,2308 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0+ /** - * ufs-uclass.c - Universal Flash Storage (UFS) Uclass driver + * ufs.c - Universal Flash Storage (UFS) driver + * + * Taken from Linux Kernel v5.2 (drivers/scsi/ufs/ufshcd.c) and ported + * to u-boot. * * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com */ -#define LOG_CATEGORY UCLASS_UFS +#include <bouncebuf.h> +#include <charset.h> +#include <clk.h> +#include <dm.h> +#include <log.h> +#include <dm/device_compat.h> +#include <dm/devres.h> +#include <dm/lists.h> +#include <dm/device-internal.h> +#include <malloc.h> +#include <hexdump.h> +#include <scsi.h> +#include <ufs.h> +#include <asm/io.h> +#include <asm/dma-mapping.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> #include "ufs.h" -#include <dm.h> + +#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\ + UTP_TASK_REQ_COMPL |\ + UFSHCD_ERROR_MASK) +/* maximum number of link-startup retries */ +#define DME_LINKSTARTUP_RETRIES 3 + +/* maximum number of retries for a general UIC command */ +#define UFS_UIC_COMMAND_RETRIES 3 + +/* Query request retries */ +#define QUERY_REQ_RETRIES 3 +/* Query request timeout */ +#define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */ + +/* maximum timeout in ms for a general UIC command */ +#define UFS_UIC_CMD_TIMEOUT 1000 +/* NOP OUT retries waiting for NOP IN response */ +#define NOP_OUT_RETRIES 10 +/* Timeout after 30 msecs if NOP OUT hangs without response */ +#define NOP_OUT_TIMEOUT 30 /* msecs */ + +/* Only use one Task Tag for all requests */ +#define TASK_TAG 0 + +/* Expose the flag value from utp_upiu_query.value */ +#define MASK_QUERY_UPIU_FLAG_LOC 0xFF + +#define MAX_PRDT_ENTRY 262144 + +/* maximum bytes per request */ +#define UFS_MAX_BYTES (128 * 256 * 1024) + +static inline bool ufshcd_is_hba_active(struct ufs_hba *hba); +static inline void ufshcd_hba_stop(struct ufs_hba *hba); +static int ufshcd_hba_enable(struct ufs_hba *hba); + +/* + * ufshcd_wait_for_register - wait for register value to change + */ +static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, + u32 val, unsigned long timeout_ms) +{ + int err = 0; + unsigned long start = get_timer(0); + + /* ignore bits that we don't intend to wait on */ + val = val & mask; + + while ((ufshcd_readl(hba, reg) & mask) != val) { + if (get_timer(start) > timeout_ms) { + if ((ufshcd_readl(hba, reg) & mask) != val) + err = -ETIMEDOUT; + break; + } + } + + return err; +} + +/** + * ufshcd_init_pwr_info - setting the POR (power on reset) + * values in hba power info + */ +static void ufshcd_init_pwr_info(struct ufs_hba *hba) +{ + hba->pwr_info.gear_rx = UFS_PWM_G1; + hba->pwr_info.gear_tx = UFS_PWM_G1; + hba->pwr_info.lane_rx = 1; + hba->pwr_info.lane_tx = 1; + hba->pwr_info.pwr_rx = SLOWAUTO_MODE; + hba->pwr_info.pwr_tx = SLOWAUTO_MODE; + hba->pwr_info.hs_rate = 0; +} + +/** + * ufshcd_print_pwr_info - print power params as saved in hba + * power info + */ +static void ufshcd_print_pwr_info(struct ufs_hba *hba) +{ + static const char * const names[] = { + "INVALID MODE", + "FAST MODE", + "SLOW_MODE", + "INVALID MODE", + "FASTAUTO_MODE", + "SLOWAUTO_MODE", + "INVALID MODE", + }; + + dev_err(hba->dev, "[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n", + hba->pwr_info.gear_rx, hba->pwr_info.gear_tx, + hba->pwr_info.lane_rx, hba->pwr_info.lane_tx, + names[hba->pwr_info.pwr_rx], + names[hba->pwr_info.pwr_tx], + hba->pwr_info.hs_rate); +} + +static void ufshcd_device_reset(struct ufs_hba *hba) +{ + ufshcd_vops_device_reset(hba); +} + +/** + * ufshcd_ready_for_uic_cmd - Check if controller is ready + * to accept UIC commands + */ +static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba) +{ + if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY) + return true; + else + return false; +} + +/** + * ufshcd_get_uic_cmd_result - Get the UIC command result + */ +static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba) +{ + return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) & + MASK_UIC_COMMAND_RESULT; +} + +/** + * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command + */ +static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba) +{ + return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3); +} + +/** + * ufshcd_is_device_present - Check if any device connected to + * the host controller + */ +static inline bool ufshcd_is_device_present(struct ufs_hba *hba) +{ + return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & + DEVICE_PRESENT) ? true : false; +} + +/** + * ufshcd_send_uic_cmd - UFS Interconnect layer command API + * + */ +static int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) +{ + unsigned long start = 0; + u32 intr_status; + u32 enabled_intr_status; + + if (!ufshcd_ready_for_uic_cmd(hba)) { + dev_err(hba->dev, + "Controller not ready to accept UIC commands\n"); + return -EIO; + } + + debug("sending uic command:%d\n", uic_cmd->command); + + /* Write Args */ + ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1); + ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2); + ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3); + + /* Write UIC Cmd */ + ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK, + REG_UIC_COMMAND); + + start = get_timer(0); + do { + intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); + enabled_intr_status = intr_status & hba->intr_mask; + ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS); + + if (get_timer(start) > UFS_UIC_CMD_TIMEOUT) { + dev_err(hba->dev, + "Timedout waiting for UIC response\n"); + + return -ETIMEDOUT; + } + + if (enabled_intr_status & UFSHCD_ERROR_MASK) { + dev_err(hba->dev, "Error in status:%08x\n", + enabled_intr_status); + + return -1; + } + } while (!(enabled_intr_status & UFSHCD_UIC_MASK)); + + uic_cmd->argument2 = ufshcd_get_uic_cmd_result(hba); + uic_cmd->argument3 = ufshcd_get_dme_attr_val(hba); + + debug("Sent successfully\n"); + + return 0; +} + +int ufshcd_dme_configure_adapt(struct ufs_hba *hba, + int agreed_gear, + int adapt_val) +{ + int ret; + + if (agreed_gear < UFS_HS_G4) + adapt_val = PA_NO_ADAPT; + + ret = ufshcd_dme_set(hba, + UIC_ARG_MIB(PA_TXHSADAPTTYPE), + adapt_val); + return ret; +} + +/** + * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET + * + */ +int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, u8 attr_set, + u32 mib_val, u8 peer) +{ + struct uic_command uic_cmd = {0}; + static const char *const action[] = { + "dme-set", + "dme-peer-set" + }; + const char *set = action[!!peer]; + int ret; + int retries = UFS_UIC_COMMAND_RETRIES; + + uic_cmd.command = peer ? + UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET; + uic_cmd.argument1 = attr_sel; + uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set); + uic_cmd.argument3 = mib_val; + + do { + /* for peer attributes we retry upon failure */ + ret = ufshcd_send_uic_cmd(hba, &uic_cmd); + if (ret) + dev_dbg(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n", + set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret); + } while (ret && peer && --retries); + + if (ret) + dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x failed %d retries\n", + set, UIC_GET_ATTR_ID(attr_sel), mib_val, + UFS_UIC_COMMAND_RETRIES - retries); + + return ret; +} + +/** + * ufshcd_dme_get_attr - UIC command for DME_GET, DME_PEER_GET + * + */ +int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, + u32 *mib_val, u8 peer) +{ + struct uic_command uic_cmd = {0}; + static const char *const action[] = { + "dme-get", + "dme-peer-get" + }; + const char *get = action[!!peer]; + int ret; + int retries = UFS_UIC_COMMAND_RETRIES; + + uic_cmd.command = peer ? + UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET; + uic_cmd.argument1 = attr_sel; + + do { + /* for peer attributes we retry upon failure */ + ret = ufshcd_send_uic_cmd(hba, &uic_cmd); + if (ret) + dev_dbg(hba->dev, "%s: attr-id 0x%x error code %d\n", + get, UIC_GET_ATTR_ID(attr_sel), ret); + } while (ret && peer && --retries); + + if (ret) + dev_err(hba->dev, "%s: attr-id 0x%x failed %d retries\n", + get, UIC_GET_ATTR_ID(attr_sel), + UFS_UIC_COMMAND_RETRIES - retries); + + if (mib_val && !ret) + *mib_val = uic_cmd.argument3; + + return ret; +} + +static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, bool peer) +{ + u32 tx_lanes, i, err = 0; + + if (!peer) + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), + &tx_lanes); + else + ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), + &tx_lanes); + for (i = 0; i < tx_lanes; i++) { + unsigned int val = UIC_ARG_MIB_SEL(TX_LCC_ENABLE, + UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)); + if (!peer) + err = ufshcd_dme_set(hba, val, 0); + else + err = ufshcd_dme_peer_set(hba, val, 0); + if (err) { + dev_err(hba->dev, "%s: TX LCC Disable failed, peer = %d, lane = %d, err = %d\n", + __func__, peer, i, err); + break; + } + } + + return err; +} + +static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba) +{ + return ufshcd_disable_tx_lcc(hba, true); +} + +/** + * ufshcd_dme_link_startup - Notify Unipro to perform link startup + * + */ +static int ufshcd_dme_link_startup(struct ufs_hba *hba) +{ + struct uic_command uic_cmd = {0}; + int ret; + + uic_cmd.command = UIC_CMD_DME_LINK_STARTUP; + + ret = ufshcd_send_uic_cmd(hba, &uic_cmd); + if (ret) + dev_dbg(hba->dev, + "dme-link-startup: error code %d\n", ret); + return ret; +} + +int ufshcd_dme_enable(struct ufs_hba *hba) +{ + struct uic_command uic_cmd = {0}; + int ret; + + uic_cmd.command = UIC_CMD_DME_ENABLE; + + ret = ufshcd_send_uic_cmd(hba, &uic_cmd); + if (ret) + dev_dbg(hba->dev, + "dme-enable: error code %d\n", ret); + + return ret; +} + +int ufshcd_dme_reset(struct ufs_hba *hba) +{ + struct uic_command uic_cmd = {0}; + int ret; + + uic_cmd.command = UIC_CMD_DME_RESET; + + ret = ufshcd_send_uic_cmd(hba, &uic_cmd); + if (ret) + dev_dbg(hba->dev, + "dme-reset: error code %d\n", ret); + + return ret; +} + +/** + * ufshcd_disable_intr_aggr - Disables interrupt aggregation. + * + */ +static inline void ufshcd_disable_intr_aggr(struct ufs_hba *hba) +{ + ufshcd_writel(hba, 0, REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL); +} + +/** + * ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY + */ +static inline int ufshcd_get_lists_status(u32 reg) +{ + return !((reg & UFSHCD_STATUS_READY) == UFSHCD_STATUS_READY); +} + +/** + * ufshcd_enable_run_stop_reg - Enable run-stop registers, + * When run-stop registers are set to 1, it indicates the + * host controller that it can process the requests + */ +static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba) +{ + ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT, + REG_UTP_TASK_REQ_LIST_RUN_STOP); + ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT, + REG_UTP_TRANSFER_REQ_LIST_RUN_STOP); +} + +/** + * ufshcd_enable_intr - enable interrupts + */ +static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs) +{ + u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); + u32 rw; + + if (hba->version == UFSHCI_VERSION_10) { + rw = set & INTERRUPT_MASK_RW_VER_10; + set = rw | ((set ^ intrs) & intrs); + } else { + set |= intrs; + } + + ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE); + + hba->intr_mask = set; +} + +/** + * ufshcd_make_hba_operational - Make UFS controller operational + * + * To bring UFS host controller to operational state, + * 1. Enable required interrupts + * 2. Configure interrupt aggregation + * 3. Program UTRL and UTMRL base address + * 4. Configure run-stop-registers + * + */ +static int ufshcd_make_hba_operational(struct ufs_hba *hba) +{ + int err = 0; + u32 reg; + + /* Enable required interrupts */ + ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS); + + /* Disable interrupt aggregation */ + ufshcd_disable_intr_aggr(hba); + + /* Configure UTRL and UTMRL base address registers */ + ufshcd_writel(hba, lower_32_bits((dma_addr_t)hba->utrdl), + REG_UTP_TRANSFER_REQ_LIST_BASE_L); + ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utrdl), + REG_UTP_TRANSFER_REQ_LIST_BASE_H); + ufshcd_writel(hba, lower_32_bits((dma_addr_t)hba->utmrdl), + REG_UTP_TASK_REQ_LIST_BASE_L); + ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utmrdl), + REG_UTP_TASK_REQ_LIST_BASE_H); + + /* + * Make sure base address and interrupt setup are updated before + * enabling the run/stop registers below. + */ + wmb(); + + /* + * UCRDY, UTMRLDY and UTRLRDY bits must be 1 + */ + reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS); + if (!(ufshcd_get_lists_status(reg))) { + ufshcd_enable_run_stop_reg(hba); + } else { + dev_err(hba->dev, + "Host controller not ready to process requests\n"); + err = -EIO; + goto out; + } + +out: + return err; +} + +/** + * ufshcd_link_startup - Initialize unipro link startup + */ +static int ufshcd_link_startup(struct ufs_hba *hba) +{ + int ret; + int retries = DME_LINKSTARTUP_RETRIES; + + do { + ufshcd_ops_link_startup_notify(hba, PRE_CHANGE); + + ret = ufshcd_dme_link_startup(hba); + + /* check if device is detected by inter-connect layer */ + if (!ret && !ufshcd_is_device_present(hba)) { + dev_err(hba->dev, "%s: Device not present\n", __func__); + ret = -ENXIO; + goto out; + } + + /* + * DME link lost indication is only received when link is up, + * but we can't be sure if the link is up until link startup + * succeeds. So reset the local Uni-Pro and try again. + */ + if (ret && ufshcd_hba_enable(hba)) + goto out; + } while (ret && retries--); + + if (ret) + /* failed to get the link up... retire */ + goto out; + + /* Mark that link is up in PWM-G1, 1-lane, SLOW-AUTO mode */ + ufshcd_init_pwr_info(hba); + + if (hba->quirks & UFSHCD_QUIRK_BROKEN_LCC) { + ret = ufshcd_disable_device_tx_lcc(hba); + if (ret) + goto out; + } + + /* Include any host controller configuration via UIC commands */ + ret = ufshcd_ops_link_startup_notify(hba, POST_CHANGE); + if (ret) + goto out; + + /* Clear UECPA once due to LINERESET has happened during LINK_STARTUP */ + ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); + ret = ufshcd_make_hba_operational(hba); +out: + if (ret) + dev_err(hba->dev, "link startup failed %d\n", ret); + + return ret; +} + +/** + * ufshcd_hba_stop - Send controller to reset state + */ +static inline void ufshcd_hba_stop(struct ufs_hba *hba) +{ + int err; + + ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE); + err = ufshcd_wait_for_register(hba, REG_CONTROLLER_ENABLE, + CONTROLLER_ENABLE, CONTROLLER_DISABLE, + 10); + if (err) + dev_err(hba->dev, "%s: Controller disable failed\n", __func__); +} + +/** + * ufshcd_is_hba_active - Get controller state + */ +static inline bool ufshcd_is_hba_active(struct ufs_hba *hba) +{ + return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & CONTROLLER_ENABLE) + ? false : true; +} + +/** + * ufshcd_hba_start - Start controller initialization sequence + */ +static inline void ufshcd_hba_start(struct ufs_hba *hba) +{ + ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE); +} + +/** + * ufshcd_hba_enable - initialize the controller + */ +static int ufshcd_hba_enable(struct ufs_hba *hba) +{ + int retry; + + if (!ufshcd_is_hba_active(hba)) + /* change controller state to "reset state" */ + ufshcd_hba_stop(hba); + + ufshcd_ops_hce_enable_notify(hba, PRE_CHANGE); + + /* start controller initialization sequence */ + ufshcd_hba_start(hba); + + /* + * To initialize a UFS host controller HCE bit must be set to 1. + * During initialization the HCE bit value changes from 1->0->1. + * When the host controller completes initialization sequence + * it sets the value of HCE bit to 1. The same HCE bit is read back + * to check if the controller has completed initialization sequence. + * So without this delay the value HCE = 1, set in the previous + * instruction might be read back. + * This delay can be changed based on the controller. + */ + mdelay(1); + + /* wait for the host controller to complete initialization */ + retry = 10; + while (ufshcd_is_hba_active(hba)) { + if (retry) { + retry--; + } else { + dev_err(hba->dev, "Controller enable failed\n"); + return -EIO; + } + mdelay(5); + } + + /* enable UIC related interrupts */ + ufshcd_enable_intr(hba, UFSHCD_UIC_MASK); + + ufshcd_ops_hce_enable_notify(hba, POST_CHANGE); + + return 0; +} + +/** + * ufshcd_host_memory_configure - configure local reference block with + * memory offsets + */ +static void ufshcd_host_memory_configure(struct ufs_hba *hba) +{ + struct utp_transfer_req_desc *utrdlp; + dma_addr_t cmd_desc_dma_addr; + u16 response_offset; + u16 prdt_offset; + + utrdlp = hba->utrdl; + cmd_desc_dma_addr = (dma_addr_t)hba->ucdl; + + utrdlp->command_desc_base_addr_lo = + cpu_to_le32(lower_32_bits(cmd_desc_dma_addr)); + utrdlp->command_desc_base_addr_hi = + cpu_to_le32(upper_32_bits(cmd_desc_dma_addr)); + + response_offset = offsetof(struct utp_transfer_cmd_desc, response_upiu); + prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table); + + utrdlp->response_upiu_offset = cpu_to_le16(response_offset >> 2); + utrdlp->prd_table_offset = cpu_to_le16(prdt_offset >> 2); + utrdlp->response_upiu_length = cpu_to_le16(ALIGNED_UPIU_SIZE >> 2); + + hba->ucd_req_ptr = (struct utp_upiu_req *)hba->ucdl; + hba->ucd_rsp_ptr = + (struct utp_upiu_rsp *)&hba->ucdl->response_upiu; + hba->ucd_prdt_ptr = + (struct ufshcd_sg_entry *)&hba->ucdl->prd_table; +} + +/** + * ufshcd_memory_alloc - allocate memory for host memory space data structures + */ +static int ufshcd_memory_alloc(struct ufs_hba *hba) +{ + /* Allocate one Transfer Request Descriptor + * Should be aligned to 1k boundary. + */ + hba->utrdl = memalign(1024, + ALIGN(sizeof(struct utp_transfer_req_desc), + ARCH_DMA_MINALIGN)); + if (!hba->utrdl) { + dev_err(hba->dev, "Transfer Descriptor memory allocation failed\n"); + return -ENOMEM; + } + + /* Allocate one Command Descriptor + * Should be aligned to 1k boundary. + */ + hba->ucdl = memalign(1024, + ALIGN(sizeof(struct utp_transfer_cmd_desc), + ARCH_DMA_MINALIGN)); + if (!hba->ucdl) { + dev_err(hba->dev, "Command descriptor memory allocation failed\n"); + return -ENOMEM; + } + + return 0; +} + +/** + * ufshcd_get_intr_mask - Get the interrupt bit mask + */ +static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba) +{ + u32 intr_mask = 0; + + switch (hba->version) { + case UFSHCI_VERSION_10: + intr_mask = INTERRUPT_MASK_ALL_VER_10; + break; + case UFSHCI_VERSION_11: + case UFSHCI_VERSION_20: + intr_mask = INTERRUPT_MASK_ALL_VER_11; + break; + case UFSHCI_VERSION_21: + default: + intr_mask = INTERRUPT_MASK_ALL_VER_21; + break; + } + + return intr_mask; +} + +/** + * ufshcd_get_ufs_version - Get the UFS version supported by the HBA + */ +static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba) +{ + return ufshcd_readl(hba, REG_UFS_VERSION); +} + +/** + * ufshcd_get_upmcrs - Get the power mode change request status + */ +static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba) +{ + return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7; +} + +/** + * ufshcd_cache_flush - Flush cache + * + * Flush cache in aligned address..address+size range. + */ +static void ufshcd_cache_flush(void *addr, unsigned long size) +{ + uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN); + + flush_dcache_range(start_addr, end_addr); +} + +/** + * ufshcd_cache_invalidate - Invalidate cache + * + * Invalidate cache in aligned address..address+size range. + */ +static void ufshcd_cache_invalidate(void *addr, unsigned long size) +{ + uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start_addr, end_addr); +} + +/** + * ufshcd_prepare_req_desc_hdr() - Fills the requests header + * descriptor according to request + */ +static void ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba, + u32 *upiu_flags, + enum dma_data_direction cmd_dir) +{ + struct utp_transfer_req_desc *req_desc = hba->utrdl; + u32 data_direction; + u32 dword_0; + + if (cmd_dir == DMA_FROM_DEVICE) { + data_direction = UTP_DEVICE_TO_HOST; + *upiu_flags = UPIU_CMD_FLAGS_READ; + } else if (cmd_dir == DMA_TO_DEVICE) { + data_direction = UTP_HOST_TO_DEVICE; + *upiu_flags = UPIU_CMD_FLAGS_WRITE; + } else { + data_direction = UTP_NO_DATA_TRANSFER; + *upiu_flags = UPIU_CMD_FLAGS_NONE; + } + + dword_0 = (data_direction << UPIU_DATA_DIRECTION_OFFSET) + | (0x1 << UPIU_COMMAND_TYPE_OFFSET); + + /* Enable Interrupt for command */ + dword_0 |= UTP_REQ_DESC_INT_CMD; + + /* Transfer request descriptor header fields */ + req_desc->header.dword_0 = cpu_to_le32(dword_0); + /* dword_1 is reserved, hence it is set to 0 */ + req_desc->header.dword_1 = 0; + /* + * assigning invalid value for command status. Controller + * updates OCS on command completion, with the command + * status + */ + req_desc->header.dword_2 = + cpu_to_le32(OCS_INVALID_COMMAND_STATUS); + /* dword_3 is reserved, hence it is set to 0 */ + req_desc->header.dword_3 = 0; + + req_desc->prd_table_length = 0; + + ufshcd_cache_flush(req_desc, sizeof(*req_desc)); +} + +static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, + u32 upiu_flags) +{ + struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr; + struct ufs_query *query = &hba->dev_cmd.query; + u16 len = be16_to_cpu(query->request.upiu_req.length); + + /* Query request header */ + ucd_req_ptr->header.dword_0 = + UPIU_HEADER_DWORD(UPIU_TRANSACTION_QUERY_REQ, + upiu_flags, 0, TASK_TAG); + ucd_req_ptr->header.dword_1 = + UPIU_HEADER_DWORD(0, query->request.query_func, + 0, 0); + + /* Data segment length only need for WRITE_DESC */ + if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) + ucd_req_ptr->header.dword_2 = + UPIU_HEADER_DWORD(0, 0, (len >> 8), (u8)len); + else + ucd_req_ptr->header.dword_2 = 0; + + /* Copy the Query Request buffer as is */ + memcpy(&ucd_req_ptr->qr, &query->request.upiu_req, QUERY_OSF_SIZE); + + /* Copy the Descriptor */ + if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) { + memcpy(ucd_req_ptr + 1, query->descriptor, len); + ufshcd_cache_flush(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr)); + } else { + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); + } + + memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); +} + +static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba) +{ + struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr; + + memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req)); + + /* command descriptor fields */ + ucd_req_ptr->header.dword_0 = + UPIU_HEADER_DWORD(UPIU_TRANSACTION_NOP_OUT, 0, 0, TASK_TAG); + /* clear rest of the fields of basic header */ + ucd_req_ptr->header.dword_1 = 0; + ucd_req_ptr->header.dword_2 = 0; + + memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); + + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); +} + +/** + * ufshcd_comp_devman_upiu - UFS Protocol Information Unit(UPIU) + * for Device Management Purposes + */ +static int ufshcd_comp_devman_upiu(struct ufs_hba *hba, + enum dev_cmd_type cmd_type) +{ + u32 upiu_flags; + int ret = 0; + + hba->dev_cmd.type = cmd_type; + + ufshcd_prepare_req_desc_hdr(hba, &upiu_flags, DMA_NONE); + switch (cmd_type) { + case DEV_CMD_TYPE_QUERY: + ufshcd_prepare_utp_query_req_upiu(hba, upiu_flags); + break; + case DEV_CMD_TYPE_NOP: + ufshcd_prepare_utp_nop_upiu(hba); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) +{ + unsigned long start; + u32 intr_status; + u32 enabled_intr_status; + + ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL); + + /* Make sure doorbell reg is updated before reading interrupt status */ + wmb(); + + start = get_timer(0); + do { + intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); + enabled_intr_status = intr_status & hba->intr_mask; + ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS); + + if (get_timer(start) > QUERY_REQ_TIMEOUT) { + dev_err(hba->dev, + "Timedout waiting for UTP response\n"); + + return -ETIMEDOUT; + } + + if (enabled_intr_status & UFSHCD_ERROR_MASK) { + dev_err(hba->dev, "Error in status:%08x\n", + enabled_intr_status); + + return -1; + } + } while (!(enabled_intr_status & UTP_TRANSFER_REQ_COMPL)); + + return 0; +} + +/** + * ufshcd_get_req_rsp - returns the TR response transaction type + */ +static inline int ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr) +{ + ufshcd_cache_invalidate(ucd_rsp_ptr, sizeof(*ucd_rsp_ptr)); + + return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24; +} + +/** + * ufshcd_get_tr_ocs - Get the UTRD Overall Command Status + * + */ +static inline int ufshcd_get_tr_ocs(struct ufs_hba *hba) +{ + struct utp_transfer_req_desc *req_desc = hba->utrdl; + + ufshcd_cache_invalidate(req_desc, sizeof(*req_desc)); + + return le32_to_cpu(req_desc->header.dword_2) & MASK_OCS; +} + +static inline int ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr) +{ + return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT; +} + +static int ufshcd_check_query_response(struct ufs_hba *hba) +{ + struct ufs_query_res *query_res = &hba->dev_cmd.query.response; + + /* Get the UPIU response */ + query_res->response = ufshcd_get_rsp_upiu_result(hba->ucd_rsp_ptr) >> + UPIU_RSP_CODE_OFFSET; + return query_res->response; +} + +/** + * ufshcd_copy_query_response() - Copy the Query Response and the data + * descriptor + */ +static int ufshcd_copy_query_response(struct ufs_hba *hba) +{ + struct ufs_query_res *query_res = &hba->dev_cmd.query.response; + + memcpy(&query_res->upiu_res, &hba->ucd_rsp_ptr->qr, QUERY_OSF_SIZE); + + /* Get the descriptor */ + if (hba->dev_cmd.query.descriptor && + hba->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) { + u8 *descp = (u8 *)hba->ucd_rsp_ptr + + GENERAL_UPIU_REQUEST_SIZE; + u16 resp_len; + u16 buf_len; + + /* data segment length */ + resp_len = be32_to_cpu(hba->ucd_rsp_ptr->header.dword_2) & + MASK_QUERY_DATA_SEG_LEN; + buf_len = + be16_to_cpu(hba->dev_cmd.query.request.upiu_req.length); + if (likely(buf_len >= resp_len)) { + memcpy(hba->dev_cmd.query.descriptor, descp, resp_len); + } else { + dev_warn(hba->dev, + "%s: Response size is bigger than buffer\n", + __func__); + return -EINVAL; + } + } + + return 0; +} + +/** + * ufshcd_exec_dev_cmd - API for sending device management requests + */ +static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, enum dev_cmd_type cmd_type, + int timeout) +{ + int err; + int resp; + + err = ufshcd_comp_devman_upiu(hba, cmd_type); + if (err) + return err; + + err = ufshcd_send_command(hba, TASK_TAG); + if (err) + return err; + + err = ufshcd_get_tr_ocs(hba); + if (err) { + dev_err(hba->dev, "Error in OCS:%d\n", err); + return -EINVAL; + } + + resp = ufshcd_get_req_rsp(hba->ucd_rsp_ptr); + switch (resp) { + case UPIU_TRANSACTION_NOP_IN: + break; + case UPIU_TRANSACTION_QUERY_RSP: + err = ufshcd_check_query_response(hba); + if (!err) + err = ufshcd_copy_query_response(hba); + break; + case UPIU_TRANSACTION_REJECT_UPIU: + /* TODO: handle Reject UPIU Response */ + err = -EPERM; + dev_err(hba->dev, "%s: Reject UPIU not fully implemented\n", + __func__); + break; + default: + err = -EINVAL; + dev_err(hba->dev, "%s: Invalid device management cmd response: %x\n", + __func__, resp); + } + + return err; +} + +/** + * ufshcd_init_query() - init the query response and request parameters + */ +static inline void ufshcd_init_query(struct ufs_hba *hba, + struct ufs_query_req **request, + struct ufs_query_res **response, + enum query_opcode opcode, + u8 idn, u8 index, u8 selector) +{ + *request = &hba->dev_cmd.query.request; + *response = &hba->dev_cmd.query.response; + memset(*request, 0, sizeof(struct ufs_query_req)); + memset(*response, 0, sizeof(struct ufs_query_res)); + (*request)->upiu_req.opcode = opcode; + (*request)->upiu_req.idn = idn; + (*request)->upiu_req.index = index; + (*request)->upiu_req.selector = selector; +} + +/** + * ufshcd_query_flag() - API function for sending flag query requests + */ +static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, + enum flag_idn idn, bool *flag_res) +{ + struct ufs_query_req *request = NULL; + struct ufs_query_res *response = NULL; + int err, index = 0, selector = 0; + int timeout = QUERY_REQ_TIMEOUT; + + ufshcd_init_query(hba, &request, &response, opcode, idn, index, + selector); + + switch (opcode) { + case UPIU_QUERY_OPCODE_SET_FLAG: + case UPIU_QUERY_OPCODE_CLEAR_FLAG: + case UPIU_QUERY_OPCODE_TOGGLE_FLAG: + request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST; + break; + case UPIU_QUERY_OPCODE_READ_FLAG: + request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; + if (!flag_res) { + /* No dummy reads */ + dev_err(hba->dev, "%s: Invalid argument for read request\n", + __func__); + err = -EINVAL; + goto out; + } + break; + default: + dev_err(hba->dev, + "%s: Expected query flag opcode but got = %d\n", + __func__, opcode); + err = -EINVAL; + goto out; + } + + err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, timeout); + + if (err) { + dev_err(hba->dev, + "%s: Sending flag query for idn %d failed, err = %d\n", + __func__, idn, err); + goto out; + } + + if (flag_res) + *flag_res = (be32_to_cpu(response->upiu_res.value) & + MASK_QUERY_UPIU_FLAG_LOC) & 0x1; + +out: + return err; +} + +static int ufshcd_query_flag_retry(struct ufs_hba *hba, + enum query_opcode opcode, + enum flag_idn idn, bool *flag_res) +{ + int ret; + int retries; + + for (retries = 0; retries < QUERY_REQ_RETRIES; retries++) { + ret = ufshcd_query_flag(hba, opcode, idn, flag_res); + if (ret) + dev_dbg(hba->dev, + "%s: failed with error %d, retries %d\n", + __func__, ret, retries); + else + break; + } + + if (ret) + dev_err(hba->dev, + "%s: query attribute, opcode %d, idn %d, failed with error %d after %d retires\n", + __func__, opcode, idn, ret, retries); + return ret; +} + +/** + * ufshcd_query_attr - API function for sending attribute requests + * @hba: per-adapter instance + * @opcode: attribute opcode + * @idn: attribute idn to access + * @index: index field + * @selector: selector field + * @attr_val: the attribute value after the query request completes + * + * Return: 0 for success, non-zero in case of failure. + */ +int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, + enum attr_idn idn, u8 index, u8 selector, u32 *attr_val) +{ + struct ufs_query_req *request = NULL; + struct ufs_query_res *response = NULL; + int err; + + if (!attr_val) { + dev_err(hba->dev, + "%s: attribute value required for opcode 0x%x\n", + __func__, opcode); + return -EINVAL; + } + + ufshcd_init_query(hba, &request, &response, opcode, idn, index, selector); + + switch (opcode) { + case UPIU_QUERY_OPCODE_WRITE_ATTR: + request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST; + request->upiu_req.value = cpu_to_be32(*attr_val); + break; + case UPIU_QUERY_OPCODE_READ_ATTR: + request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; + break; + default: + dev_err(hba->dev, + "%s: Expected query attr opcode but got = 0x%.2x\n", + __func__, opcode); + err = -EINVAL; + goto out; + } + + err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT); + + if (err) { + dev_err(hba->dev, + "%s: opcode 0x%.2x for idn %d failed, index %d, err = %d\n", + __func__, opcode, idn, index, err); + goto out; + } + + *attr_val = be32_to_cpu(response->upiu_res.value); + +out: + return err; +} + +/** + * ufshcd_query_attr_retry() - API function for sending query + * attribute with retries + * @hba: per-adapter instance + * @opcode: attribute opcode + * @idn: attribute idn to access + * @index: index field + * @selector: selector field + * @attr_val: the attribute value after the query request + * completes + * + * Return: 0 for success, non-zero in case of failure. + */ +int ufshcd_query_attr_retry(struct ufs_hba *hba, enum query_opcode opcode, + enum attr_idn idn, u8 index, u8 selector, + u32 *attr_val) +{ + int ret = 0; + u32 retries; + + for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) { + ret = ufshcd_query_attr(hba, opcode, idn, index, selector, attr_val); + if (ret) + dev_dbg(hba->dev, + "%s: failed with error %d, retries %d\n", + __func__, ret, retries); + else + break; + } + + if (ret) + dev_err(hba->dev, + "%s: query attribute, idn %d, failed with error %d after %d retries\n", + __func__, idn, ret, QUERY_REQ_RETRIES); + return ret; +} + +static int __ufshcd_query_descriptor(struct ufs_hba *hba, + enum query_opcode opcode, + enum desc_idn idn, u8 index, u8 selector, + u8 *desc_buf, int *buf_len) +{ + struct ufs_query_req *request = NULL; + struct ufs_query_res *response = NULL; + int err; + + if (!desc_buf) { + dev_err(hba->dev, "%s: descriptor buffer required for opcode 0x%x\n", + __func__, opcode); + err = -EINVAL; + goto out; + } + + if (*buf_len < QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) { + dev_err(hba->dev, "%s: descriptor buffer size (%d) is out of range\n", + __func__, *buf_len); + err = -EINVAL; + goto out; + } + + ufshcd_init_query(hba, &request, &response, opcode, idn, index, + selector); + hba->dev_cmd.query.descriptor = desc_buf; + request->upiu_req.length = cpu_to_be16(*buf_len); + + switch (opcode) { + case UPIU_QUERY_OPCODE_WRITE_DESC: + request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST; + break; + case UPIU_QUERY_OPCODE_READ_DESC: + request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; + break; + default: + dev_err(hba->dev, "%s: Expected query descriptor opcode but got = 0x%.2x\n", + __func__, opcode); + err = -EINVAL; + goto out; + } + + err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT); + + if (err) { + dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index %d, err = %d\n", + __func__, opcode, idn, index, err); + goto out; + } + + hba->dev_cmd.query.descriptor = NULL; + *buf_len = be16_to_cpu(response->upiu_res.length); + +out: + return err; +} + +/** + * ufshcd_query_descriptor_retry - API function for sending descriptor requests + */ +static int ufshcd_query_descriptor_retry(struct ufs_hba *hba, enum query_opcode opcode, + enum desc_idn idn, u8 index, u8 selector, + u8 *desc_buf, int *buf_len) +{ + int err; + int retries; + + for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) { + err = __ufshcd_query_descriptor(hba, opcode, idn, index, + selector, desc_buf, buf_len); + if (!err || err == -EINVAL) + break; + } + + return err; +} + +/** + * ufshcd_read_desc_length - read the specified descriptor length from header + */ +static int ufshcd_read_desc_length(struct ufs_hba *hba, enum desc_idn desc_id, + int desc_index, int *desc_length) +{ + int ret; + u8 header[QUERY_DESC_HDR_SIZE]; + int header_len = QUERY_DESC_HDR_SIZE; + + if (desc_id >= QUERY_DESC_IDN_MAX) + return -EINVAL; + + ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, + desc_id, desc_index, 0, header, + &header_len); + + if (ret) { + dev_err(hba->dev, "%s: Failed to get descriptor header id %d\n", + __func__, desc_id); + return ret; + } else if (desc_id != header[QUERY_DESC_DESC_TYPE_OFFSET]) { + dev_warn(hba->dev, "%s: descriptor header id %d and desc_id %d mismatch\n", + __func__, header[QUERY_DESC_DESC_TYPE_OFFSET], + desc_id); + ret = -EINVAL; + } + + *desc_length = header[QUERY_DESC_LENGTH_OFFSET]; + + return ret; +} + +static void ufshcd_init_desc_sizes(struct ufs_hba *hba) +{ + int err; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_DEVICE, 0, + &hba->desc_size.dev_desc); + if (err) + hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_POWER, 0, + &hba->desc_size.pwr_desc); + if (err) + hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_INTERCONNECT, 0, + &hba->desc_size.interc_desc); + if (err) + hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_CONFIGURATION, 0, + &hba->desc_size.conf_desc); + if (err) + hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_UNIT, 0, + &hba->desc_size.unit_desc); + if (err) + hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_GEOMETRY, 0, + &hba->desc_size.geom_desc); + if (err) + hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; + + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_HEALTH, 0, + &hba->desc_size.hlth_desc); + if (err) + hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE; +} + +/** + * ufshcd_map_desc_id_to_length - map descriptor IDN to its length + * + */ +static int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, + int *desc_len) +{ + switch (desc_id) { + case QUERY_DESC_IDN_DEVICE: + *desc_len = hba->desc_size.dev_desc; + break; + case QUERY_DESC_IDN_POWER: + *desc_len = hba->desc_size.pwr_desc; + break; + case QUERY_DESC_IDN_GEOMETRY: + *desc_len = hba->desc_size.geom_desc; + break; + case QUERY_DESC_IDN_CONFIGURATION: + *desc_len = hba->desc_size.conf_desc; + break; + case QUERY_DESC_IDN_UNIT: + *desc_len = hba->desc_size.unit_desc; + break; + case QUERY_DESC_IDN_INTERCONNECT: + *desc_len = hba->desc_size.interc_desc; + break; + case QUERY_DESC_IDN_STRING: + *desc_len = QUERY_DESC_MAX_SIZE; + break; + case QUERY_DESC_IDN_HEALTH: + *desc_len = hba->desc_size.hlth_desc; + break; + case QUERY_DESC_IDN_RFU_0: + case QUERY_DESC_IDN_RFU_1: + *desc_len = 0; + break; + default: + *desc_len = 0; + return -EINVAL; + } + return 0; +} + +/** + * ufshcd_read_desc_param - read the specified descriptor parameter + * + */ +static int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id, + int desc_index, u8 param_offset, + u8 *param_read_buf, u8 param_size) +{ + int ret; + u8 *desc_buf; + int buff_len; + bool is_kmalloc = true; + + /* Safety check */ + if (desc_id >= QUERY_DESC_IDN_MAX || !param_size) + return -EINVAL; + + /* Get the max length of descriptor from structure filled up at probe + * time. + */ + ret = ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len); + + /* Sanity checks */ + if (ret || !buff_len) { + dev_err(hba->dev, "%s: Failed to get full descriptor length\n", + __func__); + return ret; + } + + /* Check whether we need temp memory */ + if (param_offset != 0 || param_size < buff_len) { + desc_buf = kmalloc(buff_len, GFP_KERNEL); + if (!desc_buf) + return -ENOMEM; + } else { + desc_buf = param_read_buf; + is_kmalloc = false; + } + + /* Request for full descriptor */ + ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, + desc_id, desc_index, 0, desc_buf, + &buff_len); + + if (ret) { + dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d\n", + __func__, desc_id, desc_index, param_offset, ret); + goto out; + } + + /* Sanity check */ + if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) { + dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header\n", + __func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]); + ret = -EINVAL; + goto out; + } + + /* Check wherher we will not copy more data, than available */ + if (is_kmalloc && param_size > buff_len) + param_size = buff_len; + + if (is_kmalloc) + memcpy(param_read_buf, &desc_buf[param_offset], param_size); +out: + if (is_kmalloc) + kfree(desc_buf); + return ret; +} + +/* replace non-printable or non-ASCII characters with spaces */ +static inline void ufshcd_remove_non_printable(uint8_t *val) +{ + if (!val) + return; + + if (*val < 0x20 || *val > 0x7e) + *val = ' '; +} + +/** + * ufshcd_uic_pwr_ctrl - executes UIC commands (which affects the link power + * state) and waits for it to take effect. + * + */ +static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) +{ + unsigned long start = 0; + u8 status; + int ret; + + ret = ufshcd_send_uic_cmd(hba, cmd); + if (ret) { + dev_err(hba->dev, + "pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n", + cmd->command, cmd->argument3, ret); + + return ret; + } + + start = get_timer(0); + do { + status = ufshcd_get_upmcrs(hba); + if (get_timer(start) > UFS_UIC_CMD_TIMEOUT) { + dev_err(hba->dev, + "pwr ctrl cmd 0x%x failed, host upmcrs:0x%x\n", + cmd->command, status); + ret = (status != PWR_OK) ? status : -1; + break; + } + } while (status != PWR_LOCAL); + + return ret; +} + +/** + * ufshcd_uic_change_pwr_mode - Perform the UIC power mode change + * using DME_SET primitives. + */ +static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode) +{ + struct uic_command uic_cmd = {0}; + int ret; + + uic_cmd.command = UIC_CMD_DME_SET; + uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE); + uic_cmd.argument3 = mode; + ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); + + return ret; +} + +static +void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufs_hba *hba, + struct scsi_cmd *pccb, u32 upiu_flags) +{ + struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr; + unsigned int cdb_len; + + /* command descriptor fields */ + ucd_req_ptr->header.dword_0 = + UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND, upiu_flags, + pccb->lun, TASK_TAG); + ucd_req_ptr->header.dword_1 = + UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0); + + /* Total EHS length and Data segment length will be zero */ + ucd_req_ptr->header.dword_2 = 0; + + ucd_req_ptr->sc.exp_data_transfer_len = cpu_to_be32(pccb->datalen); + + cdb_len = min_t(unsigned short, pccb->cmdlen, UFS_CDB_SIZE); + memset(ucd_req_ptr->sc.cdb, 0, UFS_CDB_SIZE); + memcpy(ucd_req_ptr->sc.cdb, pccb->cmd, cdb_len); + + memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); + ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); + ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); +} + +static inline void prepare_prdt_desc(struct ufshcd_sg_entry *entry, + unsigned char *buf, ulong len) +{ + entry->size = cpu_to_le32(len) | GENMASK(1, 0); + entry->base_addr = cpu_to_le32(lower_32_bits((unsigned long)buf)); + entry->upper_addr = cpu_to_le32(upper_32_bits((unsigned long)buf)); +} + +static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) +{ + struct utp_transfer_req_desc *req_desc = hba->utrdl; + struct ufshcd_sg_entry *prd_table = hba->ucd_prdt_ptr; + ulong datalen = pccb->datalen; + int table_length; + u8 *buf; + int i; + + if (!datalen) { + req_desc->prd_table_length = 0; + ufshcd_cache_flush(req_desc, sizeof(*req_desc)); + return; + } + + table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY); + buf = pccb->pdata; + i = table_length; + while (--i) { + prepare_prdt_desc(&prd_table[table_length - i - 1], buf, + MAX_PRDT_ENTRY - 1); + buf += MAX_PRDT_ENTRY; + datalen -= MAX_PRDT_ENTRY; + } + + prepare_prdt_desc(&prd_table[table_length - i - 1], buf, datalen - 1); + + req_desc->prd_table_length = table_length; + ufshcd_cache_flush(prd_table, sizeof(*prd_table) * table_length); + ufshcd_cache_flush(req_desc, sizeof(*req_desc)); +} + +static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb) +{ + struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent); + u32 upiu_flags; + int ocs, result = 0; + u8 scsi_status; + + ufshcd_prepare_req_desc_hdr(hba, &upiu_flags, pccb->dma_dir); + ufshcd_prepare_utp_scsi_cmd_upiu(hba, pccb, upiu_flags); + prepare_prdt_table(hba, pccb); + + ufshcd_cache_flush(pccb->pdata, pccb->datalen); + + ufshcd_send_command(hba, TASK_TAG); + + ufshcd_cache_invalidate(pccb->pdata, pccb->datalen); + + ocs = ufshcd_get_tr_ocs(hba); + switch (ocs) { + case OCS_SUCCESS: + result = ufshcd_get_req_rsp(hba->ucd_rsp_ptr); + switch (result) { + case UPIU_TRANSACTION_RESPONSE: + result = ufshcd_get_rsp_upiu_result(hba->ucd_rsp_ptr); + + scsi_status = result & MASK_SCSI_STATUS; + if (scsi_status) + return -EINVAL; + + break; + case UPIU_TRANSACTION_REJECT_UPIU: + /* TODO: handle Reject UPIU Response */ + dev_err(hba->dev, + "Reject UPIU not fully implemented\n"); + return -EINVAL; + default: + dev_err(hba->dev, + "Unexpected request response code = %x\n", + result); + return -EINVAL; + } + break; + default: + dev_err(hba->dev, "OCS error from controller = %x\n", ocs); + return -EINVAL; + } + + return 0; +} + +static inline int ufshcd_read_desc(struct ufs_hba *hba, enum desc_idn desc_id, + int desc_index, u8 *buf, u32 size) +{ + return ufshcd_read_desc_param(hba, desc_id, desc_index, 0, buf, size); +} + +static int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size) +{ + return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, buf, size); +} + +/** + * ufshcd_read_string_desc - read string descriptor + * + */ +static int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, + u8 *buf, u32 size, bool ascii) +{ + int err = 0; + + err = ufshcd_read_desc(hba, QUERY_DESC_IDN_STRING, desc_index, buf, + size); + + if (err) { + dev_err(hba->dev, "%s: reading String Desc failed after %d retries. err = %d\n", + __func__, QUERY_REQ_RETRIES, err); + goto out; + } + + if (ascii) { + int desc_len; + int ascii_len; + int i; + u8 *buff_ascii; + + desc_len = buf[0]; + /* remove header and divide by 2 to move from UTF16 to UTF8 */ + ascii_len = (desc_len - QUERY_DESC_HDR_SIZE) / 2 + 1; + if (size < ascii_len + QUERY_DESC_HDR_SIZE) { + dev_err(hba->dev, "%s: buffer allocated size is too small\n", + __func__); + err = -ENOMEM; + goto out; + } + + buff_ascii = kmalloc(ascii_len, GFP_KERNEL); + if (!buff_ascii) { + err = -ENOMEM; + goto out; + } + + /* + * the descriptor contains string in UTF16 format + * we need to convert to utf-8 so it can be displayed + */ + utf16_to_utf8(buff_ascii, + (uint16_t *)&buf[QUERY_DESC_HDR_SIZE], ascii_len); + + /* replace non-printable or non-ASCII characters with spaces */ + for (i = 0; i < ascii_len; i++) + ufshcd_remove_non_printable(&buff_ascii[i]); + + memset(buf + QUERY_DESC_HDR_SIZE, 0, + size - QUERY_DESC_HDR_SIZE); + memcpy(buf + QUERY_DESC_HDR_SIZE, buff_ascii, ascii_len); + buf[QUERY_DESC_LENGTH_OFFSET] = ascii_len + QUERY_DESC_HDR_SIZE; + kfree(buff_ascii); + } +out: + return err; +} + +static int ufs_get_device_desc(struct ufs_hba *hba, + struct ufs_dev_desc *dev_desc) +{ + int err; + size_t buff_len; + u8 model_index; + u8 *desc_buf; + + buff_len = max_t(size_t, hba->desc_size.dev_desc, + QUERY_DESC_MAX_SIZE + 1); + desc_buf = kmalloc(buff_len, GFP_KERNEL); + if (!desc_buf) { + err = -ENOMEM; + goto out; + } + + err = ufshcd_read_device_desc(hba, desc_buf, hba->desc_size.dev_desc); + if (err) { + dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n", + __func__, err); + goto out; + } + + /* + * getting vendor (manufacturerID) and Bank Index in big endian + * format + */ + dev_desc->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | + desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; + + model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; + + /* Zero-pad entire buffer for string termination. */ + memset(desc_buf, 0, buff_len); + + err = ufshcd_read_string_desc(hba, model_index, desc_buf, + QUERY_DESC_MAX_SIZE, true/*ASCII*/); + if (err) { + dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n", + __func__, err); + goto out; + } + + desc_buf[QUERY_DESC_MAX_SIZE] = '\0'; + strlcpy(dev_desc->model, (char *)(desc_buf + QUERY_DESC_HDR_SIZE), + min_t(u8, desc_buf[QUERY_DESC_LENGTH_OFFSET], + MAX_MODEL_LEN)); + + /* Null terminate the model string */ + dev_desc->model[MAX_MODEL_LEN] = '\0'; + +out: + kfree(desc_buf); + return err; +} + +struct ufs_ref_clk { + unsigned long freq_hz; + enum ufs_ref_clk_freq val; +}; + +static const struct ufs_ref_clk ufs_ref_clk_freqs[] = { + {19200000, REF_CLK_FREQ_19_2_MHZ}, + {26000000, REF_CLK_FREQ_26_MHZ}, + {38400000, REF_CLK_FREQ_38_4_MHZ}, + {52000000, REF_CLK_FREQ_52_MHZ}, + {0, REF_CLK_FREQ_INVAL}, +}; + +static enum ufs_ref_clk_freq +ufs_get_bref_clk_from_hz(unsigned long freq) +{ + int i; + + for (i = 0; ufs_ref_clk_freqs[i].freq_hz; i++) + if (ufs_ref_clk_freqs[i].freq_hz == freq) + return ufs_ref_clk_freqs[i].val; + + return REF_CLK_FREQ_INVAL; +} + +enum ufs_ref_clk_freq ufshcd_parse_dev_ref_clk_freq(struct ufs_hba *hba, struct clk *refclk) +{ + unsigned long freq; + + freq = clk_get_rate(refclk); + return ufs_get_bref_clk_from_hz(freq); +} + +static int ufshcd_set_dev_ref_clk(struct ufs_hba *hba) +{ + int err; + struct clk *ref_clk; + u32 host_ref_clk_freq; + u32 dev_ref_clk_freq; + + /* get ref_clk */ + ref_clk = devm_clk_get(hba->dev, "ref_clk"); + if (IS_ERR((const void *)ref_clk)) { + err = PTR_ERR(ref_clk); + goto out; + } + + host_ref_clk_freq = ufshcd_parse_dev_ref_clk_freq(hba, ref_clk); + if (host_ref_clk_freq == REF_CLK_FREQ_INVAL) + dev_err(hba->dev, + "invalid ref_clk setting = %ld\n", clk_get_rate(ref_clk)); + + if (host_ref_clk_freq == REF_CLK_FREQ_INVAL) + goto out; + + err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_REF_CLK_FREQ, 0, 0, &dev_ref_clk_freq); + + if (err) { + dev_err(hba->dev, "failed reading bRefClkFreq. err = %d\n", err); + goto out; + } + + if (dev_ref_clk_freq == host_ref_clk_freq) + goto out; /* nothing to update */ + + err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, + QUERY_ATTR_IDN_REF_CLK_FREQ, 0, 0, &host_ref_clk_freq); + + if (err) { + dev_err(hba->dev, "bRefClkFreq setting to %lu Hz failed\n", + ufs_ref_clk_freqs[host_ref_clk_freq].freq_hz); + goto out; + } + + dev_dbg(hba->dev, "bRefClkFreq setting to %lu Hz succeeded\n", + ufs_ref_clk_freqs[host_ref_clk_freq].freq_hz); + +out: + return err; +} + +/** + * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device + */ +static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba) +{ + struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info; + + if (hba->max_pwr_info.is_valid) + return 0; + + if (hba->quirks & UFSHCD_QUIRK_HIBERN_FASTAUTO) { + pwr_info->pwr_tx = FASTAUTO_MODE; + pwr_info->pwr_rx = FASTAUTO_MODE; + } else { + pwr_info->pwr_tx = FAST_MODE; + pwr_info->pwr_rx = FAST_MODE; + } + pwr_info->hs_rate = PA_HS_MODE_B; + + /* Get the connected lane count */ + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), + &pwr_info->lane_rx); + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), + &pwr_info->lane_tx); + + if (!pwr_info->lane_rx || !pwr_info->lane_tx) { + dev_err(hba->dev, "%s: invalid connected lanes value. rx=%d, tx=%d\n", + __func__, pwr_info->lane_rx, pwr_info->lane_tx); + return -EINVAL; + } + + /* + * First, get the maximum gears of HS speed. + * If a zero value, it means there is no HSGEAR capability. + * Then, get the maximum gears of PWM speed. + */ + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &pwr_info->gear_rx); + if (!pwr_info->gear_rx) { + ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), + &pwr_info->gear_rx); + if (!pwr_info->gear_rx) { + dev_err(hba->dev, "%s: invalid max pwm rx gear read = %d\n", + __func__, pwr_info->gear_rx); + return -EINVAL; + } + pwr_info->pwr_rx = SLOW_MODE; + } + + ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), + &pwr_info->gear_tx); + if (!pwr_info->gear_tx) { + ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), + &pwr_info->gear_tx); + if (!pwr_info->gear_tx) { + dev_err(hba->dev, "%s: invalid max pwm tx gear read = %d\n", + __func__, pwr_info->gear_tx); + return -EINVAL; + } + pwr_info->pwr_tx = SLOW_MODE; + } + + hba->max_pwr_info.is_valid = true; + return ufshcd_ops_get_max_pwr_mode(hba, &hba->max_pwr_info); +} + +static int ufshcd_change_power_mode(struct ufs_hba *hba, + struct ufs_pa_layer_attr *pwr_mode) +{ + int ret; + + /* if already configured to the requested pwr_mode */ + if (pwr_mode->gear_rx == hba->pwr_info.gear_rx && + pwr_mode->gear_tx == hba->pwr_info.gear_tx && + pwr_mode->lane_rx == hba->pwr_info.lane_rx && + pwr_mode->lane_tx == hba->pwr_info.lane_tx && + pwr_mode->pwr_rx == hba->pwr_info.pwr_rx && + pwr_mode->pwr_tx == hba->pwr_info.pwr_tx && + pwr_mode->hs_rate == hba->pwr_info.hs_rate) { + dev_dbg(hba->dev, "%s: power already configured\n", __func__); + return 0; + } + + /* + * Configure attributes for power mode change with below. + * - PA_RXGEAR, PA_ACTIVERXDATALANES, PA_RXTERMINATION, + * - PA_TXGEAR, PA_ACTIVETXDATALANES, PA_TXTERMINATION, + * - PA_HSSERIES + */ + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), pwr_mode->gear_rx); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES), + pwr_mode->lane_rx); + if (pwr_mode->pwr_rx == FASTAUTO_MODE || pwr_mode->pwr_rx == FAST_MODE) + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), TRUE); + else + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), FALSE); + + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), pwr_mode->gear_tx); + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES), + pwr_mode->lane_tx); + if (pwr_mode->pwr_tx == FASTAUTO_MODE || pwr_mode->pwr_tx == FAST_MODE) + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), TRUE); + else + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), FALSE); + + if (pwr_mode->pwr_rx == FASTAUTO_MODE || + pwr_mode->pwr_tx == FASTAUTO_MODE || + pwr_mode->pwr_rx == FAST_MODE || + pwr_mode->pwr_tx == FAST_MODE) + ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES), + pwr_mode->hs_rate); + + ret = ufshcd_uic_change_pwr_mode(hba, pwr_mode->pwr_rx << 4 | + pwr_mode->pwr_tx); + + if (ret) { + dev_err(hba->dev, + "%s: power mode change failed %d\n", __func__, ret); + + return ret; + } + + /* Copy new Power Mode to power info */ + memcpy(&hba->pwr_info, pwr_mode, sizeof(struct ufs_pa_layer_attr)); + + return ret; +} + +/** + * ufshcd_verify_dev_init() - Verify device initialization + * + */ +static int ufshcd_verify_dev_init(struct ufs_hba *hba) +{ + int retries; + int err; + + for (retries = NOP_OUT_RETRIES; retries > 0; retries--) { + err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_NOP, + NOP_OUT_TIMEOUT); + if (!err || err == -ETIMEDOUT) + break; + + dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err); + } + + if (err) + dev_err(hba->dev, "%s: NOP OUT failed %d\n", __func__, err); + + return err; +} + +/** + * ufshcd_complete_dev_init() - checks device readiness + */ +static int ufshcd_complete_dev_init(struct ufs_hba *hba) +{ + int i; + int err; + bool flag_res = 1; + + err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG, + QUERY_FLAG_IDN_FDEVICEINIT, NULL); + if (err) { + dev_err(hba->dev, + "%s setting fDeviceInit flag failed with error %d\n", + __func__, err); + goto out; + } + + /* poll for max. 1000 iterations for fDeviceInit flag to clear */ + for (i = 0; i < 1000 && !err && flag_res; i++) + err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG, + QUERY_FLAG_IDN_FDEVICEINIT, + &flag_res); + + if (err) + dev_err(hba->dev, + "%s reading fDeviceInit flag failed with error %d\n", + __func__, err); + else if (flag_res) + dev_err(hba->dev, + "%s fDeviceInit was not cleared by the device\n", + __func__); + +out: + return err; +} + +static void ufshcd_def_desc_sizes(struct ufs_hba *hba) +{ + hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; + hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; + hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; + hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; + hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; + hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; + hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE; +} + +static int ufs_start(struct ufs_hba *hba) +{ + struct ufs_dev_desc card = {0}; + int ret; + + ret = ufshcd_link_startup(hba); + if (ret) + return ret; + + ret = ufshcd_verify_dev_init(hba); + if (ret) + return ret; + + ret = ufshcd_complete_dev_init(hba); + if (ret) + return ret; + + /* Init check for device descriptor sizes */ + ufshcd_init_desc_sizes(hba); + + ret = ufs_get_device_desc(hba, &card); + if (ret) { + dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", + __func__, ret); + + return ret; + } + + ufshcd_set_dev_ref_clk(hba); + + if (ufshcd_get_max_pwr_mode(hba)) { + dev_err(hba->dev, + "%s: Failed getting max supported power mode\n", + __func__); + } else { + ret = ufshcd_change_power_mode(hba, &hba->max_pwr_info.info); + if (ret) { + dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n", + __func__, ret); + + return ret; + } + + debug("UFS Device %s is up!\n", hba->dev->name); + ufshcd_print_pwr_info(hba); + } + + return 0; +} + +int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops) +{ + struct ufs_hba *hba = dev_get_uclass_priv(ufs_dev); + struct scsi_plat *scsi_plat; + struct udevice *scsi_dev; + void __iomem *mmio_base; + int err; + + device_find_first_child(ufs_dev, &scsi_dev); + if (!scsi_dev) + return -ENODEV; + + scsi_plat = dev_get_uclass_plat(scsi_dev); + scsi_plat->max_id = UFSHCD_MAX_ID; + scsi_plat->max_lun = UFS_MAX_LUNS; + scsi_plat->max_bytes_per_req = UFS_MAX_BYTES; + + hba->dev = ufs_dev; + hba->ops = hba_ops; + + if (device_is_on_pci_bus(ufs_dev)) { + mmio_base = dm_pci_map_bar(ufs_dev, PCI_BASE_ADDRESS_0, 0, 0, + PCI_REGION_TYPE, PCI_REGION_MEM); + } else { + mmio_base = dev_read_addr_ptr(ufs_dev); + } + hba->mmio_base = mmio_base; + + /* Set descriptor lengths to specification defaults */ + ufshcd_def_desc_sizes(hba); + + ufshcd_ops_init(hba); + + /* Read capabilities registers */ + hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES); + if (hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS) + hba->capabilities &= ~MASK_64_ADDRESSING_SUPPORT; + + /* Get UFS version supported by the controller */ + hba->version = ufshcd_get_ufs_version(hba); + if (hba->version != UFSHCI_VERSION_10 && + hba->version != UFSHCI_VERSION_11 && + hba->version != UFSHCI_VERSION_20 && + hba->version != UFSHCI_VERSION_21 && + hba->version != UFSHCI_VERSION_30 && + hba->version != UFSHCI_VERSION_31 && + hba->version != UFSHCI_VERSION_40) + dev_err(hba->dev, "invalid UFS version 0x%x\n", + hba->version); + + /* Get Interrupt bit mask per version */ + hba->intr_mask = ufshcd_get_intr_mask(hba); + + /* Allocate memory for host memory space */ + err = ufshcd_memory_alloc(hba); + if (err) { + dev_err(hba->dev, "Memory allocation failed\n"); + return err; + } + + /* Configure Local data structures */ + ufshcd_host_memory_configure(hba); + + /* + * In order to avoid any spurious interrupt immediately after + * registering UFS controller interrupt handler, clear any pending UFS + * interrupt status and disable all the UFS interrupts. + */ + ufshcd_writel(hba, ufshcd_readl(hba, REG_INTERRUPT_STATUS), + REG_INTERRUPT_STATUS); + ufshcd_writel(hba, 0, REG_INTERRUPT_ENABLE); + + mb(); /* flush previous writes */ + + /* Reset the attached device */ + ufshcd_device_reset(hba); + + err = ufshcd_hba_enable(hba); + if (err) { + dev_err(hba->dev, "Host controller enable failed\n"); + return err; + } + + err = ufs_start(hba); + if (err) + return err; + + return 0; +} + +#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) +static int ufs_scsi_buffer_aligned(struct udevice *scsi_dev, struct bounce_buffer *state) +{ +#ifdef CONFIG_PHYS_64BIT + struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent); + uintptr_t ubuf = (uintptr_t)state->user_buffer; + size_t len = state->len_aligned; + + /* Check if below 32bit boundary */ + if ((hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS) && + ((ubuf >> 32) || (ubuf + len) >> 32)) { + dev_dbg(scsi_dev, "Buffer above 32bit boundary %lx-%lx\n", + ubuf, ubuf + len); + return 0; + } +#endif + return 1; +} +#endif /* CONFIG_BOUNCE_BUFFER */ + +static struct scsi_ops ufs_ops = { + .exec = ufs_scsi_exec, +#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) + .buffer_aligned = ufs_scsi_buffer_aligned, +#endif /* CONFIG_BOUNCE_BUFFER */ +}; + +int ufs_probe_dev(int index) +{ + struct udevice *dev; + + return uclass_get_device(UCLASS_UFS, index, &dev); +} + +int ufs_probe(void) +{ + struct udevice *dev; + int ret, i; + + for (i = 0;; i++) { + ret = uclass_get_device(UCLASS_UFS, i, &dev); + if (ret == -ENODEV) + break; + } + + return 0; +} + +U_BOOT_DRIVER(ufs_scsi) = { + .id = UCLASS_SCSI, + .name = "ufs_scsi", + .ops = &ufs_ops, +}; + +static int ufs_post_bind(struct udevice *dev) +{ + return device_bind_driver(dev, "ufs_scsi", "ufs_scsi", NULL); +} UCLASS_DRIVER(ufs) = { - .id = UCLASS_UFS, - .name = "ufs", + .id = UCLASS_UFS, + .name = "ufs", + .post_bind = ufs_post_bind, .per_device_auto = sizeof(struct ufs_hba), }; diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c deleted file mode 100644 index 57e6e8c013b..00000000000 --- a/drivers/ufs/ufs.c +++ /dev/null @@ -1,2093 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/** - * ufs.c - Universal Flash Storage (UFS) driver - * - * Taken from Linux Kernel v5.2 (drivers/scsi/ufs/ufshcd.c) and ported - * to u-boot. - * - * Copyright (C) 2019 Texas Instruments Incorporated - https://www.ti.com - */ - -#include <bouncebuf.h> -#include <charset.h> -#include <dm.h> -#include <log.h> -#include <dm/device_compat.h> -#include <dm/devres.h> -#include <dm/lists.h> -#include <dm/device-internal.h> -#include <malloc.h> -#include <hexdump.h> -#include <scsi.h> -#include <ufs.h> -#include <asm/io.h> -#include <asm/dma-mapping.h> -#include <linux/bitops.h> -#include <linux/delay.h> -#include <linux/dma-mapping.h> - -#include "ufs.h" - -#define UFSHCD_ENABLE_INTRS (UTP_TRANSFER_REQ_COMPL |\ - UTP_TASK_REQ_COMPL |\ - UFSHCD_ERROR_MASK) -/* maximum number of link-startup retries */ -#define DME_LINKSTARTUP_RETRIES 3 - -/* maximum number of retries for a general UIC command */ -#define UFS_UIC_COMMAND_RETRIES 3 - -/* Query request retries */ -#define QUERY_REQ_RETRIES 3 -/* Query request timeout */ -#define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */ - -/* maximum timeout in ms for a general UIC command */ -#define UFS_UIC_CMD_TIMEOUT 1000 -/* NOP OUT retries waiting for NOP IN response */ -#define NOP_OUT_RETRIES 10 -/* Timeout after 30 msecs if NOP OUT hangs without response */ -#define NOP_OUT_TIMEOUT 30 /* msecs */ - -/* Only use one Task Tag for all requests */ -#define TASK_TAG 0 - -/* Expose the flag value from utp_upiu_query.value */ -#define MASK_QUERY_UPIU_FLAG_LOC 0xFF - -#define MAX_PRDT_ENTRY 262144 - -/* maximum bytes per request */ -#define UFS_MAX_BYTES (128 * 256 * 1024) - -static inline bool ufshcd_is_hba_active(struct ufs_hba *hba); -static inline void ufshcd_hba_stop(struct ufs_hba *hba); -static int ufshcd_hba_enable(struct ufs_hba *hba); - -/* - * ufshcd_wait_for_register - wait for register value to change - */ -static int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, - u32 val, unsigned long timeout_ms) -{ - int err = 0; - unsigned long start = get_timer(0); - - /* ignore bits that we don't intend to wait on */ - val = val & mask; - - while ((ufshcd_readl(hba, reg) & mask) != val) { - if (get_timer(start) > timeout_ms) { - if ((ufshcd_readl(hba, reg) & mask) != val) - err = -ETIMEDOUT; - break; - } - } - - return err; -} - -/** - * ufshcd_init_pwr_info - setting the POR (power on reset) - * values in hba power info - */ -static void ufshcd_init_pwr_info(struct ufs_hba *hba) -{ - hba->pwr_info.gear_rx = UFS_PWM_G1; - hba->pwr_info.gear_tx = UFS_PWM_G1; - hba->pwr_info.lane_rx = 1; - hba->pwr_info.lane_tx = 1; - hba->pwr_info.pwr_rx = SLOWAUTO_MODE; - hba->pwr_info.pwr_tx = SLOWAUTO_MODE; - hba->pwr_info.hs_rate = 0; -} - -/** - * ufshcd_print_pwr_info - print power params as saved in hba - * power info - */ -static void ufshcd_print_pwr_info(struct ufs_hba *hba) -{ - static const char * const names[] = { - "INVALID MODE", - "FAST MODE", - "SLOW_MODE", - "INVALID MODE", - "FASTAUTO_MODE", - "SLOWAUTO_MODE", - "INVALID MODE", - }; - - dev_err(hba->dev, "[RX, TX]: gear=[%d, %d], lane[%d, %d], pwr[%s, %s], rate = %d\n", - hba->pwr_info.gear_rx, hba->pwr_info.gear_tx, - hba->pwr_info.lane_rx, hba->pwr_info.lane_tx, - names[hba->pwr_info.pwr_rx], - names[hba->pwr_info.pwr_tx], - hba->pwr_info.hs_rate); -} - -static void ufshcd_device_reset(struct ufs_hba *hba) -{ - ufshcd_vops_device_reset(hba); -} - -/** - * ufshcd_ready_for_uic_cmd - Check if controller is ready - * to accept UIC commands - */ -static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba) -{ - if (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY) - return true; - else - return false; -} - -/** - * ufshcd_get_uic_cmd_result - Get the UIC command result - */ -static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba) -{ - return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_2) & - MASK_UIC_COMMAND_RESULT; -} - -/** - * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command - */ -static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba) -{ - return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3); -} - -/** - * ufshcd_is_device_present - Check if any device connected to - * the host controller - */ -static inline bool ufshcd_is_device_present(struct ufs_hba *hba) -{ - return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) & - DEVICE_PRESENT) ? true : false; -} - -/** - * ufshcd_send_uic_cmd - UFS Interconnect layer command API - * - */ -static int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) -{ - unsigned long start = 0; - u32 intr_status; - u32 enabled_intr_status; - - if (!ufshcd_ready_for_uic_cmd(hba)) { - dev_err(hba->dev, - "Controller not ready to accept UIC commands\n"); - return -EIO; - } - - debug("sending uic command:%d\n", uic_cmd->command); - - /* Write Args */ - ufshcd_writel(hba, uic_cmd->argument1, REG_UIC_COMMAND_ARG_1); - ufshcd_writel(hba, uic_cmd->argument2, REG_UIC_COMMAND_ARG_2); - ufshcd_writel(hba, uic_cmd->argument3, REG_UIC_COMMAND_ARG_3); - - /* Write UIC Cmd */ - ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK, - REG_UIC_COMMAND); - - start = get_timer(0); - do { - intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); - enabled_intr_status = intr_status & hba->intr_mask; - ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS); - - if (get_timer(start) > UFS_UIC_CMD_TIMEOUT) { - dev_err(hba->dev, - "Timedout waiting for UIC response\n"); - - return -ETIMEDOUT; - } - - if (enabled_intr_status & UFSHCD_ERROR_MASK) { - dev_err(hba->dev, "Error in status:%08x\n", - enabled_intr_status); - - return -1; - } - } while (!(enabled_intr_status & UFSHCD_UIC_MASK)); - - uic_cmd->argument2 = ufshcd_get_uic_cmd_result(hba); - uic_cmd->argument3 = ufshcd_get_dme_attr_val(hba); - - debug("Sent successfully\n"); - - return 0; -} - -int ufshcd_dme_configure_adapt(struct ufs_hba *hba, - int agreed_gear, - int adapt_val) -{ - int ret; - - if (agreed_gear < UFS_HS_G4) - adapt_val = PA_NO_ADAPT; - - ret = ufshcd_dme_set(hba, - UIC_ARG_MIB(PA_TXHSADAPTTYPE), - adapt_val); - return ret; -} - -/** - * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET - * - */ -int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, u8 attr_set, - u32 mib_val, u8 peer) -{ - struct uic_command uic_cmd = {0}; - static const char *const action[] = { - "dme-set", - "dme-peer-set" - }; - const char *set = action[!!peer]; - int ret; - int retries = UFS_UIC_COMMAND_RETRIES; - - uic_cmd.command = peer ? - UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET; - uic_cmd.argument1 = attr_sel; - uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set); - uic_cmd.argument3 = mib_val; - - do { - /* for peer attributes we retry upon failure */ - ret = ufshcd_send_uic_cmd(hba, &uic_cmd); - if (ret) - dev_dbg(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n", - set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret); - } while (ret && peer && --retries); - - if (ret) - dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x failed %d retries\n", - set, UIC_GET_ATTR_ID(attr_sel), mib_val, - UFS_UIC_COMMAND_RETRIES - retries); - - return ret; -} - -/** - * ufshcd_dme_get_attr - UIC command for DME_GET, DME_PEER_GET - * - */ -int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, - u32 *mib_val, u8 peer) -{ - struct uic_command uic_cmd = {0}; - static const char *const action[] = { - "dme-get", - "dme-peer-get" - }; - const char *get = action[!!peer]; - int ret; - int retries = UFS_UIC_COMMAND_RETRIES; - - uic_cmd.command = peer ? - UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET; - uic_cmd.argument1 = attr_sel; - - do { - /* for peer attributes we retry upon failure */ - ret = ufshcd_send_uic_cmd(hba, &uic_cmd); - if (ret) - dev_dbg(hba->dev, "%s: attr-id 0x%x error code %d\n", - get, UIC_GET_ATTR_ID(attr_sel), ret); - } while (ret && peer && --retries); - - if (ret) - dev_err(hba->dev, "%s: attr-id 0x%x failed %d retries\n", - get, UIC_GET_ATTR_ID(attr_sel), - UFS_UIC_COMMAND_RETRIES - retries); - - if (mib_val && !ret) - *mib_val = uic_cmd.argument3; - - return ret; -} - -static int ufshcd_disable_tx_lcc(struct ufs_hba *hba, bool peer) -{ - u32 tx_lanes, i, err = 0; - - if (!peer) - ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), - &tx_lanes); - else - ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), - &tx_lanes); - for (i = 0; i < tx_lanes; i++) { - unsigned int val = UIC_ARG_MIB_SEL(TX_LCC_ENABLE, - UIC_ARG_MPHY_TX_GEN_SEL_INDEX(i)); - if (!peer) - err = ufshcd_dme_set(hba, val, 0); - else - err = ufshcd_dme_peer_set(hba, val, 0); - if (err) { - dev_err(hba->dev, "%s: TX LCC Disable failed, peer = %d, lane = %d, err = %d\n", - __func__, peer, i, err); - break; - } - } - - return err; -} - -static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba) -{ - return ufshcd_disable_tx_lcc(hba, true); -} - -/** - * ufshcd_dme_link_startup - Notify Unipro to perform link startup - * - */ -static int ufshcd_dme_link_startup(struct ufs_hba *hba) -{ - struct uic_command uic_cmd = {0}; - int ret; - - uic_cmd.command = UIC_CMD_DME_LINK_STARTUP; - - ret = ufshcd_send_uic_cmd(hba, &uic_cmd); - if (ret) - dev_dbg(hba->dev, - "dme-link-startup: error code %d\n", ret); - return ret; -} - -/** - * ufshcd_disable_intr_aggr - Disables interrupt aggregation. - * - */ -static inline void ufshcd_disable_intr_aggr(struct ufs_hba *hba) -{ - ufshcd_writel(hba, 0, REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL); -} - -/** - * ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY - */ -static inline int ufshcd_get_lists_status(u32 reg) -{ - return !((reg & UFSHCD_STATUS_READY) == UFSHCD_STATUS_READY); -} - -/** - * ufshcd_enable_run_stop_reg - Enable run-stop registers, - * When run-stop registers are set to 1, it indicates the - * host controller that it can process the requests - */ -static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba) -{ - ufshcd_writel(hba, UTP_TASK_REQ_LIST_RUN_STOP_BIT, - REG_UTP_TASK_REQ_LIST_RUN_STOP); - ufshcd_writel(hba, UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT, - REG_UTP_TRANSFER_REQ_LIST_RUN_STOP); -} - -/** - * ufshcd_enable_intr - enable interrupts - */ -static void ufshcd_enable_intr(struct ufs_hba *hba, u32 intrs) -{ - u32 set = ufshcd_readl(hba, REG_INTERRUPT_ENABLE); - u32 rw; - - if (hba->version == UFSHCI_VERSION_10) { - rw = set & INTERRUPT_MASK_RW_VER_10; - set = rw | ((set ^ intrs) & intrs); - } else { - set |= intrs; - } - - ufshcd_writel(hba, set, REG_INTERRUPT_ENABLE); - - hba->intr_mask = set; -} - -/** - * ufshcd_make_hba_operational - Make UFS controller operational - * - * To bring UFS host controller to operational state, - * 1. Enable required interrupts - * 2. Configure interrupt aggregation - * 3. Program UTRL and UTMRL base address - * 4. Configure run-stop-registers - * - */ -static int ufshcd_make_hba_operational(struct ufs_hba *hba) -{ - int err = 0; - u32 reg; - - /* Enable required interrupts */ - ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS); - - /* Disable interrupt aggregation */ - ufshcd_disable_intr_aggr(hba); - - /* Configure UTRL and UTMRL base address registers */ - ufshcd_writel(hba, lower_32_bits((dma_addr_t)hba->utrdl), - REG_UTP_TRANSFER_REQ_LIST_BASE_L); - ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utrdl), - REG_UTP_TRANSFER_REQ_LIST_BASE_H); - ufshcd_writel(hba, lower_32_bits((dma_addr_t)hba->utmrdl), - REG_UTP_TASK_REQ_LIST_BASE_L); - ufshcd_writel(hba, upper_32_bits((dma_addr_t)hba->utmrdl), - REG_UTP_TASK_REQ_LIST_BASE_H); - - /* - * Make sure base address and interrupt setup are updated before - * enabling the run/stop registers below. - */ - wmb(); - - /* - * UCRDY, UTMRLDY and UTRLRDY bits must be 1 - */ - reg = ufshcd_readl(hba, REG_CONTROLLER_STATUS); - if (!(ufshcd_get_lists_status(reg))) { - ufshcd_enable_run_stop_reg(hba); - } else { - dev_err(hba->dev, - "Host controller not ready to process requests\n"); - err = -EIO; - goto out; - } - -out: - return err; -} - -/** - * ufshcd_link_startup - Initialize unipro link startup - */ -static int ufshcd_link_startup(struct ufs_hba *hba) -{ - int ret; - int retries = DME_LINKSTARTUP_RETRIES; - - do { - ufshcd_ops_link_startup_notify(hba, PRE_CHANGE); - - ret = ufshcd_dme_link_startup(hba); - - /* check if device is detected by inter-connect layer */ - if (!ret && !ufshcd_is_device_present(hba)) { - dev_err(hba->dev, "%s: Device not present\n", __func__); - ret = -ENXIO; - goto out; - } - - /* - * DME link lost indication is only received when link is up, - * but we can't be sure if the link is up until link startup - * succeeds. So reset the local Uni-Pro and try again. - */ - if (ret && ufshcd_hba_enable(hba)) - goto out; - } while (ret && retries--); - - if (ret) - /* failed to get the link up... retire */ - goto out; - - /* Mark that link is up in PWM-G1, 1-lane, SLOW-AUTO mode */ - ufshcd_init_pwr_info(hba); - - if (hba->quirks & UFSHCD_QUIRK_BROKEN_LCC) { - ret = ufshcd_disable_device_tx_lcc(hba); - if (ret) - goto out; - } - - /* Include any host controller configuration via UIC commands */ - ret = ufshcd_ops_link_startup_notify(hba, POST_CHANGE); - if (ret) - goto out; - - /* Clear UECPA once due to LINERESET has happened during LINK_STARTUP */ - ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); - ret = ufshcd_make_hba_operational(hba); -out: - if (ret) - dev_err(hba->dev, "link startup failed %d\n", ret); - - return ret; -} - -/** - * ufshcd_hba_stop - Send controller to reset state - */ -static inline void ufshcd_hba_stop(struct ufs_hba *hba) -{ - int err; - - ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE); - err = ufshcd_wait_for_register(hba, REG_CONTROLLER_ENABLE, - CONTROLLER_ENABLE, CONTROLLER_DISABLE, - 10); - if (err) - dev_err(hba->dev, "%s: Controller disable failed\n", __func__); -} - -/** - * ufshcd_is_hba_active - Get controller state - */ -static inline bool ufshcd_is_hba_active(struct ufs_hba *hba) -{ - return (ufshcd_readl(hba, REG_CONTROLLER_ENABLE) & CONTROLLER_ENABLE) - ? false : true; -} - -/** - * ufshcd_hba_start - Start controller initialization sequence - */ -static inline void ufshcd_hba_start(struct ufs_hba *hba) -{ - ufshcd_writel(hba, CONTROLLER_ENABLE, REG_CONTROLLER_ENABLE); -} - -/** - * ufshcd_hba_enable - initialize the controller - */ -static int ufshcd_hba_enable(struct ufs_hba *hba) -{ - int retry; - - if (!ufshcd_is_hba_active(hba)) - /* change controller state to "reset state" */ - ufshcd_hba_stop(hba); - - ufshcd_ops_hce_enable_notify(hba, PRE_CHANGE); - - /* start controller initialization sequence */ - ufshcd_hba_start(hba); - - /* - * To initialize a UFS host controller HCE bit must be set to 1. - * During initialization the HCE bit value changes from 1->0->1. - * When the host controller completes initialization sequence - * it sets the value of HCE bit to 1. The same HCE bit is read back - * to check if the controller has completed initialization sequence. - * So without this delay the value HCE = 1, set in the previous - * instruction might be read back. - * This delay can be changed based on the controller. - */ - mdelay(1); - - /* wait for the host controller to complete initialization */ - retry = 10; - while (ufshcd_is_hba_active(hba)) { - if (retry) { - retry--; - } else { - dev_err(hba->dev, "Controller enable failed\n"); - return -EIO; - } - mdelay(5); - } - - /* enable UIC related interrupts */ - ufshcd_enable_intr(hba, UFSHCD_UIC_MASK); - - ufshcd_ops_hce_enable_notify(hba, POST_CHANGE); - - return 0; -} - -/** - * ufshcd_host_memory_configure - configure local reference block with - * memory offsets - */ -static void ufshcd_host_memory_configure(struct ufs_hba *hba) -{ - struct utp_transfer_req_desc *utrdlp; - dma_addr_t cmd_desc_dma_addr; - u16 response_offset; - u16 prdt_offset; - - utrdlp = hba->utrdl; - cmd_desc_dma_addr = (dma_addr_t)hba->ucdl; - - utrdlp->command_desc_base_addr_lo = - cpu_to_le32(lower_32_bits(cmd_desc_dma_addr)); - utrdlp->command_desc_base_addr_hi = - cpu_to_le32(upper_32_bits(cmd_desc_dma_addr)); - - response_offset = offsetof(struct utp_transfer_cmd_desc, response_upiu); - prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table); - - utrdlp->response_upiu_offset = cpu_to_le16(response_offset >> 2); - utrdlp->prd_table_offset = cpu_to_le16(prdt_offset >> 2); - utrdlp->response_upiu_length = cpu_to_le16(ALIGNED_UPIU_SIZE >> 2); - - hba->ucd_req_ptr = (struct utp_upiu_req *)hba->ucdl; - hba->ucd_rsp_ptr = - (struct utp_upiu_rsp *)&hba->ucdl->response_upiu; - hba->ucd_prdt_ptr = - (struct ufshcd_sg_entry *)&hba->ucdl->prd_table; -} - -/** - * ufshcd_memory_alloc - allocate memory for host memory space data structures - */ -static int ufshcd_memory_alloc(struct ufs_hba *hba) -{ - /* Allocate one Transfer Request Descriptor - * Should be aligned to 1k boundary. - */ - hba->utrdl = memalign(1024, - ALIGN(sizeof(struct utp_transfer_req_desc), - ARCH_DMA_MINALIGN)); - if (!hba->utrdl) { - dev_err(hba->dev, "Transfer Descriptor memory allocation failed\n"); - return -ENOMEM; - } - - /* Allocate one Command Descriptor - * Should be aligned to 1k boundary. - */ - hba->ucdl = memalign(1024, - ALIGN(sizeof(struct utp_transfer_cmd_desc), - ARCH_DMA_MINALIGN)); - if (!hba->ucdl) { - dev_err(hba->dev, "Command descriptor memory allocation failed\n"); - return -ENOMEM; - } - - return 0; -} - -/** - * ufshcd_get_intr_mask - Get the interrupt bit mask - */ -static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba) -{ - u32 intr_mask = 0; - - switch (hba->version) { - case UFSHCI_VERSION_10: - intr_mask = INTERRUPT_MASK_ALL_VER_10; - break; - case UFSHCI_VERSION_11: - case UFSHCI_VERSION_20: - intr_mask = INTERRUPT_MASK_ALL_VER_11; - break; - case UFSHCI_VERSION_21: - default: - intr_mask = INTERRUPT_MASK_ALL_VER_21; - break; - } - - return intr_mask; -} - -/** - * ufshcd_get_ufs_version - Get the UFS version supported by the HBA - */ -static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba) -{ - return ufshcd_readl(hba, REG_UFS_VERSION); -} - -/** - * ufshcd_get_upmcrs - Get the power mode change request status - */ -static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba) -{ - return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7; -} - -/** - * ufshcd_cache_flush - Flush cache - * - * Flush cache in aligned address..address+size range. - */ -static void ufshcd_cache_flush(void *addr, unsigned long size) -{ - uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); - uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN); - - flush_dcache_range(start_addr, end_addr); -} - -/** - * ufshcd_cache_invalidate - Invalidate cache - * - * Invalidate cache in aligned address..address+size range. - */ -static void ufshcd_cache_invalidate(void *addr, unsigned long size) -{ - uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1); - uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN); - - invalidate_dcache_range(start_addr, end_addr); -} - -/** - * ufshcd_prepare_req_desc_hdr() - Fills the requests header - * descriptor according to request - */ -static void ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba, - u32 *upiu_flags, - enum dma_data_direction cmd_dir) -{ - struct utp_transfer_req_desc *req_desc = hba->utrdl; - u32 data_direction; - u32 dword_0; - - if (cmd_dir == DMA_FROM_DEVICE) { - data_direction = UTP_DEVICE_TO_HOST; - *upiu_flags = UPIU_CMD_FLAGS_READ; - } else if (cmd_dir == DMA_TO_DEVICE) { - data_direction = UTP_HOST_TO_DEVICE; - *upiu_flags = UPIU_CMD_FLAGS_WRITE; - } else { - data_direction = UTP_NO_DATA_TRANSFER; - *upiu_flags = UPIU_CMD_FLAGS_NONE; - } - - dword_0 = data_direction | (0x1 << UPIU_COMMAND_TYPE_OFFSET); - - /* Enable Interrupt for command */ - dword_0 |= UTP_REQ_DESC_INT_CMD; - - /* Transfer request descriptor header fields */ - req_desc->header.dword_0 = cpu_to_le32(dword_0); - /* dword_1 is reserved, hence it is set to 0 */ - req_desc->header.dword_1 = 0; - /* - * assigning invalid value for command status. Controller - * updates OCS on command completion, with the command - * status - */ - req_desc->header.dword_2 = - cpu_to_le32(OCS_INVALID_COMMAND_STATUS); - /* dword_3 is reserved, hence it is set to 0 */ - req_desc->header.dword_3 = 0; - - req_desc->prd_table_length = 0; - - ufshcd_cache_flush(req_desc, sizeof(*req_desc)); -} - -static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, - u32 upiu_flags) -{ - struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr; - struct ufs_query *query = &hba->dev_cmd.query; - u16 len = be16_to_cpu(query->request.upiu_req.length); - - /* Query request header */ - ucd_req_ptr->header.dword_0 = - UPIU_HEADER_DWORD(UPIU_TRANSACTION_QUERY_REQ, - upiu_flags, 0, TASK_TAG); - ucd_req_ptr->header.dword_1 = - UPIU_HEADER_DWORD(0, query->request.query_func, - 0, 0); - - /* Data segment length only need for WRITE_DESC */ - if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) - ucd_req_ptr->header.dword_2 = - UPIU_HEADER_DWORD(0, 0, (len >> 8), (u8)len); - else - ucd_req_ptr->header.dword_2 = 0; - - /* Copy the Query Request buffer as is */ - memcpy(&ucd_req_ptr->qr, &query->request.upiu_req, QUERY_OSF_SIZE); - - /* Copy the Descriptor */ - if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) { - memcpy(ucd_req_ptr + 1, query->descriptor, len); - ufshcd_cache_flush(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr)); - } else { - ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); - } - - memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); -} - -static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba) -{ - struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr; - - memset(ucd_req_ptr, 0, sizeof(struct utp_upiu_req)); - - /* command descriptor fields */ - ucd_req_ptr->header.dword_0 = - UPIU_HEADER_DWORD(UPIU_TRANSACTION_NOP_OUT, 0, 0, TASK_TAG); - /* clear rest of the fields of basic header */ - ucd_req_ptr->header.dword_1 = 0; - ucd_req_ptr->header.dword_2 = 0; - - memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - - ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); - ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); -} - -/** - * ufshcd_comp_devman_upiu - UFS Protocol Information Unit(UPIU) - * for Device Management Purposes - */ -static int ufshcd_comp_devman_upiu(struct ufs_hba *hba, - enum dev_cmd_type cmd_type) -{ - u32 upiu_flags; - int ret = 0; - - hba->dev_cmd.type = cmd_type; - - ufshcd_prepare_req_desc_hdr(hba, &upiu_flags, DMA_NONE); - switch (cmd_type) { - case DEV_CMD_TYPE_QUERY: - ufshcd_prepare_utp_query_req_upiu(hba, upiu_flags); - break; - case DEV_CMD_TYPE_NOP: - ufshcd_prepare_utp_nop_upiu(hba); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static int ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) -{ - unsigned long start; - u32 intr_status; - u32 enabled_intr_status; - - ufshcd_writel(hba, 1 << task_tag, REG_UTP_TRANSFER_REQ_DOOR_BELL); - - /* Make sure doorbell reg is updated before reading interrupt status */ - wmb(); - - start = get_timer(0); - do { - intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); - enabled_intr_status = intr_status & hba->intr_mask; - ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS); - - if (get_timer(start) > QUERY_REQ_TIMEOUT) { - dev_err(hba->dev, - "Timedout waiting for UTP response\n"); - - return -ETIMEDOUT; - } - - if (enabled_intr_status & UFSHCD_ERROR_MASK) { - dev_err(hba->dev, "Error in status:%08x\n", - enabled_intr_status); - - return -1; - } - } while (!(enabled_intr_status & UTP_TRANSFER_REQ_COMPL)); - - return 0; -} - -/** - * ufshcd_get_req_rsp - returns the TR response transaction type - */ -static inline int ufshcd_get_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr) -{ - ufshcd_cache_invalidate(ucd_rsp_ptr, sizeof(*ucd_rsp_ptr)); - - return be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24; -} - -/** - * ufshcd_get_tr_ocs - Get the UTRD Overall Command Status - * - */ -static inline int ufshcd_get_tr_ocs(struct ufs_hba *hba) -{ - struct utp_transfer_req_desc *req_desc = hba->utrdl; - - ufshcd_cache_invalidate(req_desc, sizeof(*req_desc)); - - return le32_to_cpu(req_desc->header.dword_2) & MASK_OCS; -} - -static inline int ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr) -{ - return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT; -} - -static int ufshcd_check_query_response(struct ufs_hba *hba) -{ - struct ufs_query_res *query_res = &hba->dev_cmd.query.response; - - /* Get the UPIU response */ - query_res->response = ufshcd_get_rsp_upiu_result(hba->ucd_rsp_ptr) >> - UPIU_RSP_CODE_OFFSET; - return query_res->response; -} - -/** - * ufshcd_copy_query_response() - Copy the Query Response and the data - * descriptor - */ -static int ufshcd_copy_query_response(struct ufs_hba *hba) -{ - struct ufs_query_res *query_res = &hba->dev_cmd.query.response; - - memcpy(&query_res->upiu_res, &hba->ucd_rsp_ptr->qr, QUERY_OSF_SIZE); - - /* Get the descriptor */ - if (hba->dev_cmd.query.descriptor && - hba->ucd_rsp_ptr->qr.opcode == UPIU_QUERY_OPCODE_READ_DESC) { - u8 *descp = (u8 *)hba->ucd_rsp_ptr + - GENERAL_UPIU_REQUEST_SIZE; - u16 resp_len; - u16 buf_len; - - /* data segment length */ - resp_len = be32_to_cpu(hba->ucd_rsp_ptr->header.dword_2) & - MASK_QUERY_DATA_SEG_LEN; - buf_len = - be16_to_cpu(hba->dev_cmd.query.request.upiu_req.length); - if (likely(buf_len >= resp_len)) { - memcpy(hba->dev_cmd.query.descriptor, descp, resp_len); - } else { - dev_warn(hba->dev, - "%s: Response size is bigger than buffer\n", - __func__); - return -EINVAL; - } - } - - return 0; -} - -/** - * ufshcd_exec_dev_cmd - API for sending device management requests - */ -static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, enum dev_cmd_type cmd_type, - int timeout) -{ - int err; - int resp; - - err = ufshcd_comp_devman_upiu(hba, cmd_type); - if (err) - return err; - - err = ufshcd_send_command(hba, TASK_TAG); - if (err) - return err; - - err = ufshcd_get_tr_ocs(hba); - if (err) { - dev_err(hba->dev, "Error in OCS:%d\n", err); - return -EINVAL; - } - - resp = ufshcd_get_req_rsp(hba->ucd_rsp_ptr); - switch (resp) { - case UPIU_TRANSACTION_NOP_IN: - break; - case UPIU_TRANSACTION_QUERY_RSP: - err = ufshcd_check_query_response(hba); - if (!err) - err = ufshcd_copy_query_response(hba); - break; - case UPIU_TRANSACTION_REJECT_UPIU: - /* TODO: handle Reject UPIU Response */ - err = -EPERM; - dev_err(hba->dev, "%s: Reject UPIU not fully implemented\n", - __func__); - break; - default: - err = -EINVAL; - dev_err(hba->dev, "%s: Invalid device management cmd response: %x\n", - __func__, resp); - } - - return err; -} - -/** - * ufshcd_init_query() - init the query response and request parameters - */ -static inline void ufshcd_init_query(struct ufs_hba *hba, - struct ufs_query_req **request, - struct ufs_query_res **response, - enum query_opcode opcode, - u8 idn, u8 index, u8 selector) -{ - *request = &hba->dev_cmd.query.request; - *response = &hba->dev_cmd.query.response; - memset(*request, 0, sizeof(struct ufs_query_req)); - memset(*response, 0, sizeof(struct ufs_query_res)); - (*request)->upiu_req.opcode = opcode; - (*request)->upiu_req.idn = idn; - (*request)->upiu_req.index = index; - (*request)->upiu_req.selector = selector; -} - -/** - * ufshcd_query_flag() - API function for sending flag query requests - */ -static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, - enum flag_idn idn, bool *flag_res) -{ - struct ufs_query_req *request = NULL; - struct ufs_query_res *response = NULL; - int err, index = 0, selector = 0; - int timeout = QUERY_REQ_TIMEOUT; - - ufshcd_init_query(hba, &request, &response, opcode, idn, index, - selector); - - switch (opcode) { - case UPIU_QUERY_OPCODE_SET_FLAG: - case UPIU_QUERY_OPCODE_CLEAR_FLAG: - case UPIU_QUERY_OPCODE_TOGGLE_FLAG: - request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST; - break; - case UPIU_QUERY_OPCODE_READ_FLAG: - request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; - if (!flag_res) { - /* No dummy reads */ - dev_err(hba->dev, "%s: Invalid argument for read request\n", - __func__); - err = -EINVAL; - goto out; - } - break; - default: - dev_err(hba->dev, - "%s: Expected query flag opcode but got = %d\n", - __func__, opcode); - err = -EINVAL; - goto out; - } - - err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, timeout); - - if (err) { - dev_err(hba->dev, - "%s: Sending flag query for idn %d failed, err = %d\n", - __func__, idn, err); - goto out; - } - - if (flag_res) - *flag_res = (be32_to_cpu(response->upiu_res.value) & - MASK_QUERY_UPIU_FLAG_LOC) & 0x1; - -out: - return err; -} - -static int ufshcd_query_flag_retry(struct ufs_hba *hba, - enum query_opcode opcode, - enum flag_idn idn, bool *flag_res) -{ - int ret; - int retries; - - for (retries = 0; retries < QUERY_REQ_RETRIES; retries++) { - ret = ufshcd_query_flag(hba, opcode, idn, flag_res); - if (ret) - dev_dbg(hba->dev, - "%s: failed with error %d, retries %d\n", - __func__, ret, retries); - else - break; - } - - if (ret) - dev_err(hba->dev, - "%s: query attribute, opcode %d, idn %d, failed with error %d after %d retires\n", - __func__, opcode, idn, ret, retries); - return ret; -} - -static int __ufshcd_query_descriptor(struct ufs_hba *hba, - enum query_opcode opcode, - enum desc_idn idn, u8 index, u8 selector, - u8 *desc_buf, int *buf_len) -{ - struct ufs_query_req *request = NULL; - struct ufs_query_res *response = NULL; - int err; - - if (!desc_buf) { - dev_err(hba->dev, "%s: descriptor buffer required for opcode 0x%x\n", - __func__, opcode); - err = -EINVAL; - goto out; - } - - if (*buf_len < QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) { - dev_err(hba->dev, "%s: descriptor buffer size (%d) is out of range\n", - __func__, *buf_len); - err = -EINVAL; - goto out; - } - - ufshcd_init_query(hba, &request, &response, opcode, idn, index, - selector); - hba->dev_cmd.query.descriptor = desc_buf; - request->upiu_req.length = cpu_to_be16(*buf_len); - - switch (opcode) { - case UPIU_QUERY_OPCODE_WRITE_DESC: - request->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST; - break; - case UPIU_QUERY_OPCODE_READ_DESC: - request->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; - break; - default: - dev_err(hba->dev, "%s: Expected query descriptor opcode but got = 0x%.2x\n", - __func__, opcode); - err = -EINVAL; - goto out; - } - - err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, QUERY_REQ_TIMEOUT); - - if (err) { - dev_err(hba->dev, "%s: opcode 0x%.2x for idn %d failed, index %d, err = %d\n", - __func__, opcode, idn, index, err); - goto out; - } - - hba->dev_cmd.query.descriptor = NULL; - *buf_len = be16_to_cpu(response->upiu_res.length); - -out: - return err; -} - -/** - * ufshcd_query_descriptor_retry - API function for sending descriptor requests - */ -static int ufshcd_query_descriptor_retry(struct ufs_hba *hba, enum query_opcode opcode, - enum desc_idn idn, u8 index, u8 selector, - u8 *desc_buf, int *buf_len) -{ - int err; - int retries; - - for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) { - err = __ufshcd_query_descriptor(hba, opcode, idn, index, - selector, desc_buf, buf_len); - if (!err || err == -EINVAL) - break; - } - - return err; -} - -/** - * ufshcd_read_desc_length - read the specified descriptor length from header - */ -static int ufshcd_read_desc_length(struct ufs_hba *hba, enum desc_idn desc_id, - int desc_index, int *desc_length) -{ - int ret; - u8 header[QUERY_DESC_HDR_SIZE]; - int header_len = QUERY_DESC_HDR_SIZE; - - if (desc_id >= QUERY_DESC_IDN_MAX) - return -EINVAL; - - ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, - desc_id, desc_index, 0, header, - &header_len); - - if (ret) { - dev_err(hba->dev, "%s: Failed to get descriptor header id %d\n", - __func__, desc_id); - return ret; - } else if (desc_id != header[QUERY_DESC_DESC_TYPE_OFFSET]) { - dev_warn(hba->dev, "%s: descriptor header id %d and desc_id %d mismatch\n", - __func__, header[QUERY_DESC_DESC_TYPE_OFFSET], - desc_id); - ret = -EINVAL; - } - - *desc_length = header[QUERY_DESC_LENGTH_OFFSET]; - - return ret; -} - -static void ufshcd_init_desc_sizes(struct ufs_hba *hba) -{ - int err; - - err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_DEVICE, 0, - &hba->desc_size.dev_desc); - if (err) - hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; - - err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_POWER, 0, - &hba->desc_size.pwr_desc); - if (err) - hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; - - err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_INTERCONNECT, 0, - &hba->desc_size.interc_desc); - if (err) - hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; - - err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_CONFIGURATION, 0, - &hba->desc_size.conf_desc); - if (err) - hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; - - err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_UNIT, 0, - &hba->desc_size.unit_desc); - if (err) - hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; - - err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_GEOMETRY, 0, - &hba->desc_size.geom_desc); - if (err) - hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; - - err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_HEALTH, 0, - &hba->desc_size.hlth_desc); - if (err) - hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE; -} - -/** - * ufshcd_map_desc_id_to_length - map descriptor IDN to its length - * - */ -static int ufshcd_map_desc_id_to_length(struct ufs_hba *hba, enum desc_idn desc_id, - int *desc_len) -{ - switch (desc_id) { - case QUERY_DESC_IDN_DEVICE: - *desc_len = hba->desc_size.dev_desc; - break; - case QUERY_DESC_IDN_POWER: - *desc_len = hba->desc_size.pwr_desc; - break; - case QUERY_DESC_IDN_GEOMETRY: - *desc_len = hba->desc_size.geom_desc; - break; - case QUERY_DESC_IDN_CONFIGURATION: - *desc_len = hba->desc_size.conf_desc; - break; - case QUERY_DESC_IDN_UNIT: - *desc_len = hba->desc_size.unit_desc; - break; - case QUERY_DESC_IDN_INTERCONNECT: - *desc_len = hba->desc_size.interc_desc; - break; - case QUERY_DESC_IDN_STRING: - *desc_len = QUERY_DESC_MAX_SIZE; - break; - case QUERY_DESC_IDN_HEALTH: - *desc_len = hba->desc_size.hlth_desc; - break; - case QUERY_DESC_IDN_RFU_0: - case QUERY_DESC_IDN_RFU_1: - *desc_len = 0; - break; - default: - *desc_len = 0; - return -EINVAL; - } - return 0; -} - -/** - * ufshcd_read_desc_param - read the specified descriptor parameter - * - */ -static int ufshcd_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id, - int desc_index, u8 param_offset, - u8 *param_read_buf, u8 param_size) -{ - int ret; - u8 *desc_buf; - int buff_len; - bool is_kmalloc = true; - - /* Safety check */ - if (desc_id >= QUERY_DESC_IDN_MAX || !param_size) - return -EINVAL; - - /* Get the max length of descriptor from structure filled up at probe - * time. - */ - ret = ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len); - - /* Sanity checks */ - if (ret || !buff_len) { - dev_err(hba->dev, "%s: Failed to get full descriptor length\n", - __func__); - return ret; - } - - /* Check whether we need temp memory */ - if (param_offset != 0 || param_size < buff_len) { - desc_buf = kmalloc(buff_len, GFP_KERNEL); - if (!desc_buf) - return -ENOMEM; - } else { - desc_buf = param_read_buf; - is_kmalloc = false; - } - - /* Request for full descriptor */ - ret = ufshcd_query_descriptor_retry(hba, UPIU_QUERY_OPCODE_READ_DESC, - desc_id, desc_index, 0, desc_buf, - &buff_len); - - if (ret) { - dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d\n", - __func__, desc_id, desc_index, param_offset, ret); - goto out; - } - - /* Sanity check */ - if (desc_buf[QUERY_DESC_DESC_TYPE_OFFSET] != desc_id) { - dev_err(hba->dev, "%s: invalid desc_id %d in descriptor header\n", - __func__, desc_buf[QUERY_DESC_DESC_TYPE_OFFSET]); - ret = -EINVAL; - goto out; - } - - /* Check wherher we will not copy more data, than available */ - if (is_kmalloc && param_size > buff_len) - param_size = buff_len; - - if (is_kmalloc) - memcpy(param_read_buf, &desc_buf[param_offset], param_size); -out: - if (is_kmalloc) - kfree(desc_buf); - return ret; -} - -/* replace non-printable or non-ASCII characters with spaces */ -static inline void ufshcd_remove_non_printable(uint8_t *val) -{ - if (!val) - return; - - if (*val < 0x20 || *val > 0x7e) - *val = ' '; -} - -/** - * ufshcd_uic_pwr_ctrl - executes UIC commands (which affects the link power - * state) and waits for it to take effect. - * - */ -static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) -{ - unsigned long start = 0; - u8 status; - int ret; - - ret = ufshcd_send_uic_cmd(hba, cmd); - if (ret) { - dev_err(hba->dev, - "pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n", - cmd->command, cmd->argument3, ret); - - return ret; - } - - start = get_timer(0); - do { - status = ufshcd_get_upmcrs(hba); - if (get_timer(start) > UFS_UIC_CMD_TIMEOUT) { - dev_err(hba->dev, - "pwr ctrl cmd 0x%x failed, host upmcrs:0x%x\n", - cmd->command, status); - ret = (status != PWR_OK) ? status : -1; - break; - } - } while (status != PWR_LOCAL); - - return ret; -} - -/** - * ufshcd_uic_change_pwr_mode - Perform the UIC power mode change - * using DME_SET primitives. - */ -static int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode) -{ - struct uic_command uic_cmd = {0}; - int ret; - - uic_cmd.command = UIC_CMD_DME_SET; - uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE); - uic_cmd.argument3 = mode; - ret = ufshcd_uic_pwr_ctrl(hba, &uic_cmd); - - return ret; -} - -static -void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufs_hba *hba, - struct scsi_cmd *pccb, u32 upiu_flags) -{ - struct utp_upiu_req *ucd_req_ptr = hba->ucd_req_ptr; - unsigned int cdb_len; - - /* command descriptor fields */ - ucd_req_ptr->header.dword_0 = - UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND, upiu_flags, - pccb->lun, TASK_TAG); - ucd_req_ptr->header.dword_1 = - UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI, 0, 0, 0); - - /* Total EHS length and Data segment length will be zero */ - ucd_req_ptr->header.dword_2 = 0; - - ucd_req_ptr->sc.exp_data_transfer_len = cpu_to_be32(pccb->datalen); - - cdb_len = min_t(unsigned short, pccb->cmdlen, UFS_CDB_SIZE); - memset(ucd_req_ptr->sc.cdb, 0, UFS_CDB_SIZE); - memcpy(ucd_req_ptr->sc.cdb, pccb->cmd, cdb_len); - - memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp)); - ufshcd_cache_flush(ucd_req_ptr, sizeof(*ucd_req_ptr)); - ufshcd_cache_flush(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr)); -} - -static inline void prepare_prdt_desc(struct ufshcd_sg_entry *entry, - unsigned char *buf, ulong len) -{ - entry->size = cpu_to_le32(len) | GENMASK(1, 0); - entry->base_addr = cpu_to_le32(lower_32_bits((unsigned long)buf)); - entry->upper_addr = cpu_to_le32(upper_32_bits((unsigned long)buf)); -} - -static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb) -{ - struct utp_transfer_req_desc *req_desc = hba->utrdl; - struct ufshcd_sg_entry *prd_table = hba->ucd_prdt_ptr; - ulong datalen = pccb->datalen; - int table_length; - u8 *buf; - int i; - - if (!datalen) { - req_desc->prd_table_length = 0; - ufshcd_cache_flush(req_desc, sizeof(*req_desc)); - return; - } - - table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY); - buf = pccb->pdata; - i = table_length; - while (--i) { - prepare_prdt_desc(&prd_table[table_length - i - 1], buf, - MAX_PRDT_ENTRY - 1); - buf += MAX_PRDT_ENTRY; - datalen -= MAX_PRDT_ENTRY; - } - - prepare_prdt_desc(&prd_table[table_length - i - 1], buf, datalen - 1); - - req_desc->prd_table_length = table_length; - ufshcd_cache_flush(prd_table, sizeof(*prd_table) * table_length); - ufshcd_cache_flush(req_desc, sizeof(*req_desc)); -} - -static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb) -{ - struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent); - u32 upiu_flags; - int ocs, result = 0; - u8 scsi_status; - - ufshcd_prepare_req_desc_hdr(hba, &upiu_flags, pccb->dma_dir); - ufshcd_prepare_utp_scsi_cmd_upiu(hba, pccb, upiu_flags); - prepare_prdt_table(hba, pccb); - - ufshcd_cache_flush(pccb->pdata, pccb->datalen); - - ufshcd_send_command(hba, TASK_TAG); - - ufshcd_cache_invalidate(pccb->pdata, pccb->datalen); - - ocs = ufshcd_get_tr_ocs(hba); - switch (ocs) { - case OCS_SUCCESS: - result = ufshcd_get_req_rsp(hba->ucd_rsp_ptr); - switch (result) { - case UPIU_TRANSACTION_RESPONSE: - result = ufshcd_get_rsp_upiu_result(hba->ucd_rsp_ptr); - - scsi_status = result & MASK_SCSI_STATUS; - if (scsi_status) - return -EINVAL; - - break; - case UPIU_TRANSACTION_REJECT_UPIU: - /* TODO: handle Reject UPIU Response */ - dev_err(hba->dev, - "Reject UPIU not fully implemented\n"); - return -EINVAL; - default: - dev_err(hba->dev, - "Unexpected request response code = %x\n", - result); - return -EINVAL; - } - break; - default: - dev_err(hba->dev, "OCS error from controller = %x\n", ocs); - return -EINVAL; - } - - return 0; -} - -static inline int ufshcd_read_desc(struct ufs_hba *hba, enum desc_idn desc_id, - int desc_index, u8 *buf, u32 size) -{ - return ufshcd_read_desc_param(hba, desc_id, desc_index, 0, buf, size); -} - -static int ufshcd_read_device_desc(struct ufs_hba *hba, u8 *buf, u32 size) -{ - return ufshcd_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, buf, size); -} - -/** - * ufshcd_read_string_desc - read string descriptor - * - */ -static int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, - u8 *buf, u32 size, bool ascii) -{ - int err = 0; - - err = ufshcd_read_desc(hba, QUERY_DESC_IDN_STRING, desc_index, buf, - size); - - if (err) { - dev_err(hba->dev, "%s: reading String Desc failed after %d retries. err = %d\n", - __func__, QUERY_REQ_RETRIES, err); - goto out; - } - - if (ascii) { - int desc_len; - int ascii_len; - int i; - u8 *buff_ascii; - - desc_len = buf[0]; - /* remove header and divide by 2 to move from UTF16 to UTF8 */ - ascii_len = (desc_len - QUERY_DESC_HDR_SIZE) / 2 + 1; - if (size < ascii_len + QUERY_DESC_HDR_SIZE) { - dev_err(hba->dev, "%s: buffer allocated size is too small\n", - __func__); - err = -ENOMEM; - goto out; - } - - buff_ascii = kmalloc(ascii_len, GFP_KERNEL); - if (!buff_ascii) { - err = -ENOMEM; - goto out; - } - - /* - * the descriptor contains string in UTF16 format - * we need to convert to utf-8 so it can be displayed - */ - utf16_to_utf8(buff_ascii, - (uint16_t *)&buf[QUERY_DESC_HDR_SIZE], ascii_len); - - /* replace non-printable or non-ASCII characters with spaces */ - for (i = 0; i < ascii_len; i++) - ufshcd_remove_non_printable(&buff_ascii[i]); - - memset(buf + QUERY_DESC_HDR_SIZE, 0, - size - QUERY_DESC_HDR_SIZE); - memcpy(buf + QUERY_DESC_HDR_SIZE, buff_ascii, ascii_len); - buf[QUERY_DESC_LENGTH_OFFSET] = ascii_len + QUERY_DESC_HDR_SIZE; - kfree(buff_ascii); - } -out: - return err; -} - -static int ufs_get_device_desc(struct ufs_hba *hba, - struct ufs_dev_desc *dev_desc) -{ - int err; - size_t buff_len; - u8 model_index; - u8 *desc_buf; - - buff_len = max_t(size_t, hba->desc_size.dev_desc, - QUERY_DESC_MAX_SIZE + 1); - desc_buf = kmalloc(buff_len, GFP_KERNEL); - if (!desc_buf) { - err = -ENOMEM; - goto out; - } - - err = ufshcd_read_device_desc(hba, desc_buf, hba->desc_size.dev_desc); - if (err) { - dev_err(hba->dev, "%s: Failed reading Device Desc. err = %d\n", - __func__, err); - goto out; - } - - /* - * getting vendor (manufacturerID) and Bank Index in big endian - * format - */ - dev_desc->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | - desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; - - model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; - - /* Zero-pad entire buffer for string termination. */ - memset(desc_buf, 0, buff_len); - - err = ufshcd_read_string_desc(hba, model_index, desc_buf, - QUERY_DESC_MAX_SIZE, true/*ASCII*/); - if (err) { - dev_err(hba->dev, "%s: Failed reading Product Name. err = %d\n", - __func__, err); - goto out; - } - - desc_buf[QUERY_DESC_MAX_SIZE] = '\0'; - strlcpy(dev_desc->model, (char *)(desc_buf + QUERY_DESC_HDR_SIZE), - min_t(u8, desc_buf[QUERY_DESC_LENGTH_OFFSET], - MAX_MODEL_LEN)); - - /* Null terminate the model string */ - dev_desc->model[MAX_MODEL_LEN] = '\0'; - -out: - kfree(desc_buf); - return err; -} - -/** - * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device - */ -static int ufshcd_get_max_pwr_mode(struct ufs_hba *hba) -{ - struct ufs_pa_layer_attr *pwr_info = &hba->max_pwr_info.info; - - if (hba->max_pwr_info.is_valid) - return 0; - - if (hba->quirks & UFSHCD_QUIRK_HIBERN_FASTAUTO) { - pwr_info->pwr_tx = FASTAUTO_MODE; - pwr_info->pwr_rx = FASTAUTO_MODE; - } else { - pwr_info->pwr_tx = FAST_MODE; - pwr_info->pwr_rx = FAST_MODE; - } - pwr_info->hs_rate = PA_HS_MODE_B; - - /* Get the connected lane count */ - ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), - &pwr_info->lane_rx); - ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), - &pwr_info->lane_tx); - - if (!pwr_info->lane_rx || !pwr_info->lane_tx) { - dev_err(hba->dev, "%s: invalid connected lanes value. rx=%d, tx=%d\n", - __func__, pwr_info->lane_rx, pwr_info->lane_tx); - return -EINVAL; - } - - /* - * First, get the maximum gears of HS speed. - * If a zero value, it means there is no HSGEAR capability. - * Then, get the maximum gears of PWM speed. - */ - ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &pwr_info->gear_rx); - if (!pwr_info->gear_rx) { - ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), - &pwr_info->gear_rx); - if (!pwr_info->gear_rx) { - dev_err(hba->dev, "%s: invalid max pwm rx gear read = %d\n", - __func__, pwr_info->gear_rx); - return -EINVAL; - } - pwr_info->pwr_rx = SLOW_MODE; - } - - ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), - &pwr_info->gear_tx); - if (!pwr_info->gear_tx) { - ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), - &pwr_info->gear_tx); - if (!pwr_info->gear_tx) { - dev_err(hba->dev, "%s: invalid max pwm tx gear read = %d\n", - __func__, pwr_info->gear_tx); - return -EINVAL; - } - pwr_info->pwr_tx = SLOW_MODE; - } - - hba->max_pwr_info.is_valid = true; - return ufshcd_ops_get_max_pwr_mode(hba, &hba->max_pwr_info); -} - -static int ufshcd_change_power_mode(struct ufs_hba *hba, - struct ufs_pa_layer_attr *pwr_mode) -{ - int ret; - - /* if already configured to the requested pwr_mode */ - if (pwr_mode->gear_rx == hba->pwr_info.gear_rx && - pwr_mode->gear_tx == hba->pwr_info.gear_tx && - pwr_mode->lane_rx == hba->pwr_info.lane_rx && - pwr_mode->lane_tx == hba->pwr_info.lane_tx && - pwr_mode->pwr_rx == hba->pwr_info.pwr_rx && - pwr_mode->pwr_tx == hba->pwr_info.pwr_tx && - pwr_mode->hs_rate == hba->pwr_info.hs_rate) { - dev_dbg(hba->dev, "%s: power already configured\n", __func__); - return 0; - } - - /* - * Configure attributes for power mode change with below. - * - PA_RXGEAR, PA_ACTIVERXDATALANES, PA_RXTERMINATION, - * - PA_TXGEAR, PA_ACTIVETXDATALANES, PA_TXTERMINATION, - * - PA_HSSERIES - */ - ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), pwr_mode->gear_rx); - ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES), - pwr_mode->lane_rx); - if (pwr_mode->pwr_rx == FASTAUTO_MODE || pwr_mode->pwr_rx == FAST_MODE) - ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), TRUE); - else - ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), FALSE); - - ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), pwr_mode->gear_tx); - ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES), - pwr_mode->lane_tx); - if (pwr_mode->pwr_tx == FASTAUTO_MODE || pwr_mode->pwr_tx == FAST_MODE) - ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), TRUE); - else - ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), FALSE); - - if (pwr_mode->pwr_rx == FASTAUTO_MODE || - pwr_mode->pwr_tx == FASTAUTO_MODE || - pwr_mode->pwr_rx == FAST_MODE || - pwr_mode->pwr_tx == FAST_MODE) - ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES), - pwr_mode->hs_rate); - - ret = ufshcd_uic_change_pwr_mode(hba, pwr_mode->pwr_rx << 4 | - pwr_mode->pwr_tx); - - if (ret) { - dev_err(hba->dev, - "%s: power mode change failed %d\n", __func__, ret); - - return ret; - } - - /* Copy new Power Mode to power info */ - memcpy(&hba->pwr_info, pwr_mode, sizeof(struct ufs_pa_layer_attr)); - - return ret; -} - -/** - * ufshcd_verify_dev_init() - Verify device initialization - * - */ -static int ufshcd_verify_dev_init(struct ufs_hba *hba) -{ - int retries; - int err; - - for (retries = NOP_OUT_RETRIES; retries > 0; retries--) { - err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_NOP, - NOP_OUT_TIMEOUT); - if (!err || err == -ETIMEDOUT) - break; - - dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err); - } - - if (err) - dev_err(hba->dev, "%s: NOP OUT failed %d\n", __func__, err); - - return err; -} - -/** - * ufshcd_complete_dev_init() - checks device readiness - */ -static int ufshcd_complete_dev_init(struct ufs_hba *hba) -{ - int i; - int err; - bool flag_res = 1; - - err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG, - QUERY_FLAG_IDN_FDEVICEINIT, NULL); - if (err) { - dev_err(hba->dev, - "%s setting fDeviceInit flag failed with error %d\n", - __func__, err); - goto out; - } - - /* poll for max. 1000 iterations for fDeviceInit flag to clear */ - for (i = 0; i < 1000 && !err && flag_res; i++) - err = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_READ_FLAG, - QUERY_FLAG_IDN_FDEVICEINIT, - &flag_res); - - if (err) - dev_err(hba->dev, - "%s reading fDeviceInit flag failed with error %d\n", - __func__, err); - else if (flag_res) - dev_err(hba->dev, - "%s fDeviceInit was not cleared by the device\n", - __func__); - -out: - return err; -} - -static void ufshcd_def_desc_sizes(struct ufs_hba *hba) -{ - hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; - hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; - hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; - hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; - hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; - hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; - hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE; -} - -static int ufs_start(struct ufs_hba *hba) -{ - struct ufs_dev_desc card = {0}; - int ret; - - ret = ufshcd_link_startup(hba); - if (ret) - return ret; - - ret = ufshcd_verify_dev_init(hba); - if (ret) - return ret; - - ret = ufshcd_complete_dev_init(hba); - if (ret) - return ret; - - /* Init check for device descriptor sizes */ - ufshcd_init_desc_sizes(hba); - - ret = ufs_get_device_desc(hba, &card); - if (ret) { - dev_err(hba->dev, "%s: Failed getting device info. err = %d\n", - __func__, ret); - - return ret; - } - - if (ufshcd_get_max_pwr_mode(hba)) { - dev_err(hba->dev, - "%s: Failed getting max supported power mode\n", - __func__); - } else { - ret = ufshcd_change_power_mode(hba, &hba->max_pwr_info.info); - if (ret) { - dev_err(hba->dev, "%s: Failed setting power mode, err = %d\n", - __func__, ret); - - return ret; - } - - debug("UFS Device %s is up!\n", hba->dev->name); - ufshcd_print_pwr_info(hba); - } - - return 0; -} - -int ufshcd_probe(struct udevice *ufs_dev, struct ufs_hba_ops *hba_ops) -{ - struct ufs_hba *hba = dev_get_uclass_priv(ufs_dev); - struct scsi_plat *scsi_plat; - struct udevice *scsi_dev; - void __iomem *mmio_base; - int err; - - device_find_first_child(ufs_dev, &scsi_dev); - if (!scsi_dev) - return -ENODEV; - - scsi_plat = dev_get_uclass_plat(scsi_dev); - scsi_plat->max_id = UFSHCD_MAX_ID; - scsi_plat->max_lun = UFS_MAX_LUNS; - scsi_plat->max_bytes_per_req = UFS_MAX_BYTES; - - hba->dev = ufs_dev; - hba->ops = hba_ops; - - if (device_is_on_pci_bus(ufs_dev)) { - mmio_base = dm_pci_map_bar(ufs_dev, PCI_BASE_ADDRESS_0, 0, 0, - PCI_REGION_TYPE, PCI_REGION_MEM); - } else { - mmio_base = dev_read_addr_ptr(ufs_dev); - } - hba->mmio_base = mmio_base; - - /* Set descriptor lengths to specification defaults */ - ufshcd_def_desc_sizes(hba); - - ufshcd_ops_init(hba); - - /* Read capabilities registers */ - hba->capabilities = ufshcd_readl(hba, REG_CONTROLLER_CAPABILITIES); - if (hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS) - hba->capabilities &= ~MASK_64_ADDRESSING_SUPPORT; - - /* Get UFS version supported by the controller */ - hba->version = ufshcd_get_ufs_version(hba); - if (hba->version != UFSHCI_VERSION_10 && - hba->version != UFSHCI_VERSION_11 && - hba->version != UFSHCI_VERSION_20 && - hba->version != UFSHCI_VERSION_21 && - hba->version != UFSHCI_VERSION_30 && - hba->version != UFSHCI_VERSION_31 && - hba->version != UFSHCI_VERSION_40) - dev_err(hba->dev, "invalid UFS version 0x%x\n", - hba->version); - - /* Get Interrupt bit mask per version */ - hba->intr_mask = ufshcd_get_intr_mask(hba); - - /* Allocate memory for host memory space */ - err = ufshcd_memory_alloc(hba); - if (err) { - dev_err(hba->dev, "Memory allocation failed\n"); - return err; - } - - /* Configure Local data structures */ - ufshcd_host_memory_configure(hba); - - /* - * In order to avoid any spurious interrupt immediately after - * registering UFS controller interrupt handler, clear any pending UFS - * interrupt status and disable all the UFS interrupts. - */ - ufshcd_writel(hba, ufshcd_readl(hba, REG_INTERRUPT_STATUS), - REG_INTERRUPT_STATUS); - ufshcd_writel(hba, 0, REG_INTERRUPT_ENABLE); - - mb(); /* flush previous writes */ - - /* Reset the attached device */ - ufshcd_device_reset(hba); - - err = ufshcd_hba_enable(hba); - if (err) { - dev_err(hba->dev, "Host controller enable failed\n"); - return err; - } - - err = ufs_start(hba); - if (err) - return err; - - return 0; -} - -int ufs_scsi_bind(struct udevice *ufs_dev, struct udevice **scsi_devp) -{ - int ret = device_bind_driver(ufs_dev, "ufs_scsi", "ufs_scsi", - scsi_devp); - - return ret; -} - -#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) -static int ufs_scsi_buffer_aligned(struct udevice *scsi_dev, struct bounce_buffer *state) -{ -#ifdef CONFIG_PHYS_64BIT - struct ufs_hba *hba = dev_get_uclass_priv(scsi_dev->parent); - uintptr_t ubuf = (uintptr_t)state->user_buffer; - size_t len = state->len_aligned; - - /* Check if below 32bit boundary */ - if ((hba->quirks & UFSHCD_QUIRK_BROKEN_64BIT_ADDRESS) && - ((ubuf >> 32) || (ubuf + len) >> 32)) { - dev_dbg(scsi_dev, "Buffer above 32bit boundary %lx-%lx\n", - ubuf, ubuf + len); - return 0; - } -#endif - return 1; -} -#endif /* CONFIG_BOUNCE_BUFFER */ - -static struct scsi_ops ufs_ops = { - .exec = ufs_scsi_exec, -#if IS_ENABLED(CONFIG_BOUNCE_BUFFER) - .buffer_aligned = ufs_scsi_buffer_aligned, -#endif /* CONFIG_BOUNCE_BUFFER */ -}; - -int ufs_probe_dev(int index) -{ - struct udevice *dev; - - return uclass_get_device(UCLASS_UFS, index, &dev); -} - -int ufs_probe(void) -{ - struct udevice *dev; - int ret, i; - - for (i = 0;; i++) { - ret = uclass_get_device(UCLASS_UFS, i, &dev); - if (ret == -ENODEV) - break; - } - - return 0; -} - -U_BOOT_DRIVER(ufs_scsi) = { - .id = UCLASS_SCSI, - .name = "ufs_scsi", - .ops = &ufs_ops, -}; diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h index 0337ac5996b..bc839a43704 100644 --- a/drivers/ufs/ufs.h +++ b/drivers/ufs/ufs.h @@ -77,6 +77,9 @@ enum { /* UTP Transfer Request Command Offset */ #define UPIU_COMMAND_TYPE_OFFSET 28 +/* UTP Transfer Request Data Direction Offset */ +#define UPIU_DATA_DIRECTION_OFFSET 25 + /* Offset of the response code in the UPIU header */ #define UPIU_RSP_CODE_OFFSET 8 @@ -172,6 +175,15 @@ enum query_opcode { UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8, }; +/* bRefClkFreq attribute values */ +enum ufs_ref_clk_freq { + REF_CLK_FREQ_19_2_MHZ = 0, + REF_CLK_FREQ_26_MHZ = 1, + REF_CLK_FREQ_38_4_MHZ = 2, + REF_CLK_FREQ_52_MHZ = 3, + REF_CLK_FREQ_INVAL = -1, +}; + /* Query response result code */ enum { QUERY_RESULT_SUCCESS = 0x00, @@ -435,6 +447,8 @@ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, u8 attr_set, u32 mib_val, u8 peer); int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, u32 *mib_val, u8 peer); +int ufshcd_dme_enable(struct ufs_hba *hba); +int ufshcd_dme_reset(struct ufs_hba *hba); static inline int ufshcd_dme_set(struct ufs_hba *hba, u32 attr_sel, u32 mib_val) diff --git a/drivers/ufs/unipro.h b/drivers/ufs/unipro.h index 56833602b77..bde1490397c 100644 --- a/drivers/ufs/unipro.h +++ b/drivers/ufs/unipro.h @@ -125,6 +125,7 @@ #define PA_RXPWRSTATUS 0x1582 #define PA_RXGEAR 0x1583 #define PA_RXTERMINATION 0x1584 +#define PA_SCRAMBLING 0x1585 #define PA_MAXRXPWMGEAR 0x1586 #define PA_MAXRXHSGEAR 0x1587 #define PA_PACPREQTIMEOUT 0x1590 diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index daf2240ffd9..93c5ee69b25 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -78,8 +78,6 @@ source "drivers/usb/dwc3/Kconfig" source "drivers/usb/mtu3/Kconfig" -source "drivers/usb/musb/Kconfig" - source "drivers/usb/musb-new/Kconfig" source "drivers/usb/emul/Kconfig" diff --git a/drivers/usb/common/fsl-dt-fixup.c b/drivers/usb/common/fsl-dt-fixup.c index 6a68bd76c27..55176f7a871 100644 --- a/drivers/usb/common/fsl-dt-fixup.c +++ b/drivers/usb/common/fsl-dt-fixup.c @@ -99,7 +99,7 @@ static int fsl_fdt_fixup_usb_erratum(void *blob, const char *prop_erratum, else node_name = node_type; if (strcmp(node_name, controller_type)) - return err; + return -EINVAL; err = fdt_setprop(blob, node_offset, prop_erratum, NULL, 0); if (err < 0) { diff --git a/drivers/usb/common/fsl-errata.c b/drivers/usb/common/fsl-errata.c index 89ae73f2ba4..66ff93b2982 100644 --- a/drivers/usb/common/fsl-errata.c +++ b/drivers/usb/common/fsl-errata.c @@ -7,7 +7,7 @@ #include <hwconfig.h> #include <fsl_errata.h> -#include<fsl_usb.h> +#include <fsl_usb.h> #if defined(CONFIG_FSL_LSCH2) || defined(CONFIG_FSL_LSCH3) || \ defined(CONFIG_ARM) #include <asm/arch/clock.h> diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 682a6910655..744dfa90463 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -17,6 +17,7 @@ comment "Platform Glue Driver Support" config USB_DWC3_OMAP bool "Texas Instruments OMAP5 and similar Platforms" + depends on ARCH_OMAP2PLUS help Some platforms from Texas Instruments like OMAP5, DRA7xxx and AM437x use this IP for USB2/3 functionality. @@ -39,14 +40,14 @@ config SPL_USB_DWC3_GENERIC config SPL_USB_DWC3_AM62 bool "TI AM62 USB wrapper" - depends on SPL_DM_USB && SPL_USB_DWC3_GENERIC && SPL_SYSCON + depends on SPL_DM_USB && SPL_USB_DWC3_GENERIC && SPL_SYSCON && ARCH_K3 help Select this for TI AM62 Platforms. This wrapper supports Host and Peripheral operation modes. config USB_DWC3_AM62 bool "TI AM62 USB wrapper" - depends on DM_USB && USB_DWC3_GENERIC && SYSCON + depends on DM_USB && USB_DWC3_GENERIC && SYSCON && ARCH_K3 help Select this for TI AM62 Platforms. This wrapper supports Host and Peripheral operation modes. @@ -80,7 +81,7 @@ config USB_DWC3_UNIPHIER config USB_DWC3_LAYERSCAPE bool "Freescale Layerscape platform support" depends on DM_USB && USB_DWC3 - depends on !USB_XHCI_FSL + depends on !USB_XHCI_FSL && ARM help Select this for Freescale Layerscape Platforms. @@ -99,12 +100,14 @@ menu "PHY Subsystem" config USB_DWC3_PHY_OMAP bool "TI OMAP SoC series USB DRD PHY driver" + depends on ARCH_OMAP2PLUS help Enable single driver for both USB2 PHY programming and USB3 PHY programming for TI SoCs. config USB_DWC3_PHY_SAMSUNG bool "Exynos5 SoC series USB DRD PHY driver" + depends on ARCH_EXYNOS help Enable USB DRD PHY support for Exynos 5 SoC series. This driver provides PHY interface for USB 3.0 DRD controller diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index c656cbe25ce..680756532f0 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -799,10 +799,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, status = DWC3_TRB_SIZE_TRBSTS(trb->size); if (status == DWC3_TRBSTS_SETUP_PENDING) { dev_dbg(dwc->dev, "Setup Pending received"); - - if (r) - dwc3_gadget_giveback(ep0, r, -ECONNRESET); - + dwc3_gadget_giveback(ep0, r, -ECONNRESET); return; } diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 0121f9872ae..7e08aeab904 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -39,6 +39,7 @@ menuconfig USB_GADGET config SPL_USB_GADGET bool "USB Gadget Support in SPL" + depends on SPL_FRAMEWORK help Enable USB Gadget API which allows to enable USB device functions in SPL. @@ -60,6 +61,7 @@ config USB_GADGET_VENDOR_NUM default 0x0955 if ARCH_TEGRA default 0x1f3a if ARCH_SUNXI default 0x2207 if ARCH_ROCKCHIP + default 0x18d1 if ARCH_QCOM default 0x0 help Vendor ID of the USB device emulated, reported to the host device. @@ -87,28 +89,26 @@ config USB_GADGET_PRODUCT_NUM default 0x350b if ROCKCHIP_RK3588 default 0x350c if ROCKCHIP_RK3528 default 0x350e if ROCKCHIP_RK3576 + default 0x4ee0 if ARCH_QCOM default 0x0 help Product ID of the USB device emulated, reported to the host device. config USB_GADGET_ATMEL_USBA bool "Atmel USBA" + depends on ARCH_AT91 select USB_GADGET_DUALSPEED help USBA is the integrated high-speed USB Device controller on the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. -config USB_GADGET_BCM_UDC_OTG_PHY - bool "Broadcom UDC OTG PHY" - help - Enable the Broadcom UDC OTG physical device interface. - config USB_GADGET_AT91 bool "Atmel AT91 USB Gadget Controller" depends on ARCH_AT91 config USB_GADGET_DWC2_OTG bool "DesignWare USB2.0 HS OTG controller (gadget mode)" + depends on ARM select USB_GADGET_DUALSPEED help The Designware USB2.0 high-speed gadget controller @@ -151,17 +151,12 @@ config USB_GADGET_OS_DESCRIPTORS config CI_UDC bool "ChipIdea device controller" + depends on !DM_USB_GADGET select USB_GADGET_DUALSPEED help Say Y here to enable device controller functionality of the ChipIdea driver. -config USB_GADGET_MAX3420 - bool "MAX3420 USB Over SPI" - depends on DM_SPI - help - MAX3420, from MAXIM, implements USB-over-SPI Full-Speed device controller. - config USB_GADGET_VBUS_DRAW int "Maximum VBUS Power usage (2-500 mA)" range 2 500 diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index db5f8895a33..f2aebf4e480 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -17,10 +17,8 @@ endif ifdef CONFIG_USB_GADGET obj-$(CONFIG_USB_GADGET_AT91) += at91_udc.o obj-$(CONFIG_USB_GADGET_ATMEL_USBA) += atmel_usba_udc.o -obj-$(CONFIG_USB_GADGET_BCM_UDC_OTG_PHY) += bcm_udc_otg_phy.o obj-$(CONFIG_USB_GADGET_DWC2_OTG) += dwc2_udc_otg.o obj-$(CONFIG_USB_GADGET_DWC2_OTG_PHY) += dwc2_udc_otg_phy.o -obj-$(CONFIG_USB_GADGET_MAX3420) += max3420_udc.o obj-$(CONFIG_USB_RENESAS_USBHS) += rcar/ ifndef CONFIG_XPL_BUILD obj-$(CONFIG_USB_GADGET_DOWNLOAD) += g_dnl.o diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 72f68dba3a7..f7a92ded6da 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1147,7 +1147,7 @@ static int usba_udc_irq(struct usba_udc *udc) reset_all_endpoints(udc); if (udc->gadget.speed != USB_SPEED_UNKNOWN && - udc->driver->disconnect) { + udc->driver && udc->driver->disconnect) { udc->gadget.speed = USB_SPEED_UNKNOWN; spin_unlock(&udc->lock); udc->driver->disconnect(&udc->gadget); diff --git a/drivers/usb/gadget/bcm_udc_otg.h b/drivers/usb/gadget/bcm_udc_otg.h deleted file mode 100644 index 48370f37d8a..00000000000 --- a/drivers/usb/gadget/bcm_udc_otg.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright 2015 Broadcom Corporation. - */ - -#ifndef __BCM_UDC_OTG_H -#define __BCM_UDC_OTG_H - -static inline void wfld_set(uintptr_t addr, uint32_t fld_val, uint32_t fld_mask) -{ - writel(((readl(addr) & ~(fld_mask)) | (fld_val)), (addr)); -} - -static inline void wfld_clear(uintptr_t addr, uint32_t fld_mask) -{ - writel((readl(addr) & ~(fld_mask)), (addr)); -} - -#endif diff --git a/drivers/usb/gadget/bcm_udc_otg_phy.c b/drivers/usb/gadget/bcm_udc_otg_phy.c deleted file mode 100644 index 9875191091c..00000000000 --- a/drivers/usb/gadget/bcm_udc_otg_phy.c +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright 2015 Broadcom Corporation. - */ - -#include <config.h> -#include <asm/io.h> -#include <asm/arch/sysmap.h> -#include <asm/kona-common/clk.h> -#include <linux/delay.h> - -#include "dwc2_udc_otg_priv.h" -#include "bcm_udc_otg.h" - -void otg_phy_init(struct dwc2_udc *dev) -{ - /* turn on the USB OTG clocks */ - clk_usb_otg_enable((void *)HSOTG_BASE_ADDR); - - /* set Phy to driving mode */ - wfld_clear(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET, - HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK); - - udelay(100); - - /* clear Soft Disconnect */ - wfld_clear(HSOTG_BASE_ADDR + HSOTG_DCTL_OFFSET, - HSOTG_DCTL_SFTDISCON_MASK); - - /* invoke Reset (active low) */ - wfld_clear(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET, - HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK); - - /* Reset needs to be asserted for 2ms */ - udelay(2000); - - /* release Reset */ - wfld_set(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET, - HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK, - HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK); -} - -void otg_phy_off(struct dwc2_udc *dev) -{ - /* Soft Disconnect */ - wfld_set(HSOTG_BASE_ADDR + HSOTG_DCTL_OFFSET, - HSOTG_DCTL_SFTDISCON_MASK, - HSOTG_DCTL_SFTDISCON_MASK); - - /* set Phy to non-driving (reset) mode */ - wfld_set(HSOTG_CTRL_BASE_ADDR + HSOTG_CTRL_PHY_P1CTL_OFFSET, - HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK, - HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK); -} diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c index fca052b4556..5a7f50ebaa5 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c +++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c @@ -526,7 +526,7 @@ static int dwc2_udc_irq(int irq, void *_dev) if (gotgint & GOTGINT_SES_END_DET) { debug_cond(DEBUG_ISR, "\t\tSession End Detected\n"); /* Let gadget detect disconnected state */ - if (dev->driver->disconnect) { + if (dev->driver && dev->driver->disconnect) { spin_unlock_irqrestore(&dev->lock, flags); dev->driver->disconnect(&dev->gadget); spin_lock_irqsave(&dev->lock, flags); diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c index 647001d8dd0..f72e27028b7 100644 --- a/drivers/usb/gadget/f_sdp.c +++ b/drivers/usb/gadget/f_sdp.c @@ -765,7 +765,7 @@ static ulong search_container_header(ulong p, int size) for (i = 0; i < size; i += 4) { hdr = (u8 *)(p + i); - if (*(hdr + 3) == 0x87 && *hdr == 0) + if (*(hdr + 3) == 0x87 && (*hdr == 0 || *hdr == 2)) if (*(hdr + 1) != 0 || *(hdr + 2) != 0) return p + i; } diff --git a/drivers/usb/gadget/max3420_udc.c b/drivers/usb/gadget/max3420_udc.c deleted file mode 100644 index 557a1f0644e..00000000000 --- a/drivers/usb/gadget/max3420_udc.c +++ /dev/null @@ -1,879 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ - -#include <linux/errno.h> -#include <linux/delay.h> -#include <asm/gpio.h> -#include <linux/list.h> -#include <linux/bitfield.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <malloc.h> -#include <spi.h> -#include <dm.h> -#include <g_dnl.h> - -#define MAX3420_MAX_EPS 4 -#define EP_MAX_PACKET 64 /* Same for all Endpoints */ -#define EPNAME_SIZE 16 /* Buffer size for endpoint name */ - -#define MAX3420_SPI_DIR_RD 0 /* read register from MAX3420 */ -#define MAX3420_SPI_DIR_WR 1 /* write register to MAX3420 */ - -/* SPI commands: */ -#define MAX3420_SPI_ACK_MASK BIT(0) -#define MAX3420_SPI_DIR_MASK BIT(1) -#define MAX3420_SPI_REG_MASK GENMASK(7, 3) - -#define MAX3420_REG_EP0FIFO 0 -#define MAX3420_REG_EP1FIFO 1 -#define MAX3420_REG_EP2FIFO 2 -#define MAX3420_REG_EP3FIFO 3 -#define MAX3420_REG_SUDFIFO 4 -#define MAX3420_REG_EP0BC 5 -#define MAX3420_REG_EP1BC 6 -#define MAX3420_REG_EP2BC 7 -#define MAX3420_REG_EP3BC 8 - -#define MAX3420_REG_EPSTALLS 9 - #define bACKSTAT BIT(6) - #define bSTLSTAT BIT(5) - #define bSTLEP3IN BIT(4) - #define bSTLEP2IN BIT(3) - #define bSTLEP1OUT BIT(2) - #define bSTLEP0OUT BIT(1) - #define bSTLEP0IN BIT(0) - -#define MAX3420_REG_CLRTOGS 10 - #define bEP3DISAB BIT(7) - #define bEP2DISAB BIT(6) - #define bEP1DISAB BIT(5) - #define bCTGEP3IN BIT(4) - #define bCTGEP2IN BIT(3) - #define bCTGEP1OUT BIT(2) - -#define MAX3420_REG_EPIRQ 11 -#define MAX3420_REG_EPIEN 12 - #define bSUDAVIRQ BIT(5) - #define bIN3BAVIRQ BIT(4) - #define bIN2BAVIRQ BIT(3) - #define bOUT1DAVIRQ BIT(2) - #define bOUT0DAVIRQ BIT(1) - #define bIN0BAVIRQ BIT(0) - -#define MAX3420_REG_USBIRQ 13 -#define MAX3420_REG_USBIEN 14 - #define bOSCOKIRQ BIT(0) - #define bRWUDNIRQ BIT(1) - #define bBUSACTIRQ BIT(2) - #define bURESIRQ BIT(3) - #define bSUSPIRQ BIT(4) - #define bNOVBUSIRQ BIT(5) - #define bVBUSIRQ BIT(6) - #define bURESDNIRQ BIT(7) - -#define MAX3420_REG_USBCTL 15 - #define bHOSCSTEN BIT(7) - #define bVBGATE BIT(6) - #define bCHIPRES BIT(5) - #define bPWRDOWN BIT(4) - #define bCONNECT BIT(3) - #define bSIGRWU BIT(2) - -#define MAX3420_REG_CPUCTL 16 - #define bIE BIT(0) - -#define MAX3420_REG_PINCTL 17 - #define bEP3INAK BIT(7) - #define bEP2INAK BIT(6) - #define bEP0INAK BIT(5) - #define bFDUPSPI BIT(4) - #define bINTLEVEL BIT(3) - #define bPOSINT BIT(2) - #define bGPXB BIT(1) - #define bGPXA BIT(0) - -#define MAX3420_REG_REVISION 18 - -#define MAX3420_REG_FNADDR 19 - #define FNADDR_MASK 0x7f - -#define MAX3420_REG_IOPINS 20 -#define MAX3420_REG_IOPINS2 21 -#define MAX3420_REG_GPINIRQ 22 -#define MAX3420_REG_GPINIEN 23 -#define MAX3420_REG_GPINPOL 24 -#define MAX3420_REG_HIRQ 25 -#define MAX3420_REG_HIEN 26 -#define MAX3420_REG_MODE 27 -#define MAX3420_REG_PERADDR 28 -#define MAX3420_REG_HCTL 29 -#define MAX3420_REG_HXFR 30 -#define MAX3420_REG_HRSL 31 - -struct max3420_req { - struct usb_request usb_req; - struct list_head queue; - struct max3420_ep *ep; -}; - -struct max3420_ep { - struct max3420_udc *udc; - struct list_head queue; - char name[EPNAME_SIZE]; - unsigned int maxpacket; - struct usb_ep ep_usb; - int halted; - int id; -}; - -struct max3420_udc { - struct max3420_ep ep[MAX3420_MAX_EPS]; - struct usb_gadget_driver *driver; - bool softconnect; - struct usb_ctrlrequest setup; - struct max3420_req ep0req; - struct usb_gadget gadget; - struct spi_slave *slave; - struct udevice *dev; - u8 ep0buf[64]; - int remote_wkp; - bool suspended; -}; - -#define to_max3420_req(r) container_of((r), struct max3420_req, usb_req) -#define to_max3420_ep(e) container_of((e), struct max3420_ep, ep_usb) -#define to_udc(g) container_of((g), struct max3420_udc, gadget) - -static void spi_ack_ctrl(struct max3420_udc *udc) -{ - struct spi_slave *slave = udc->slave; - u8 txdata[1]; - - txdata[0] = FIELD_PREP(MAX3420_SPI_ACK_MASK, 1); - spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_ONCE); -} - -static u8 spi_rd8_ack(struct max3420_udc *udc, u8 reg, int ackstat) -{ - struct spi_slave *slave = udc->slave; - u8 txdata[2], rxdata[2]; - - txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) | - FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_RD) | - FIELD_PREP(MAX3420_SPI_ACK_MASK, ackstat ? 1 : 0); - - rxdata[0] = 0; - rxdata[1] = 0; - spi_xfer(slave, sizeof(txdata), txdata, rxdata, SPI_XFER_ONCE); - - return rxdata[1]; -} - -static u8 spi_rd8(struct max3420_udc *udc, u8 reg) -{ - return spi_rd8_ack(udc, reg, 0); -} - -static void spi_wr8_ack(struct max3420_udc *udc, u8 reg, u8 val, int ackstat) -{ - struct spi_slave *slave = udc->slave; - u8 txdata[2]; - - txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) | - FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_WR) | - FIELD_PREP(MAX3420_SPI_ACK_MASK, ackstat ? 1 : 0); - txdata[1] = val; - - spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_ONCE); -} - -static void spi_wr8(struct max3420_udc *udc, u8 reg, u8 val) -{ - spi_wr8_ack(udc, reg, val, 0); -} - -static void spi_rd_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len) -{ - struct spi_slave *slave = udc->slave; - u8 txdata[1]; - - txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) | - FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_RD); - - spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_BEGIN); - spi_xfer(slave, len * 8, NULL, buf, SPI_XFER_END); -} - -static void spi_wr_buf(struct max3420_udc *udc, u8 reg, void *buf, u8 len) -{ - struct spi_slave *slave = udc->slave; - u8 txdata[1]; - - txdata[0] = FIELD_PREP(MAX3420_SPI_REG_MASK, reg) | - FIELD_PREP(MAX3420_SPI_DIR_MASK, MAX3420_SPI_DIR_WR); - - spi_xfer(slave, sizeof(txdata), txdata, NULL, SPI_XFER_BEGIN); - spi_xfer(slave, len * 8, buf, NULL, SPI_XFER_END); -} - -/* 0 if not-connected */ -int g_dnl_board_usb_cable_connected(void) -{ - return 1; -} - -static void spi_max3420_enable(struct max3420_ep *ep, int enable) -{ - struct max3420_udc *udc = ep->udc; - u8 epdis, epien; - - if (ep->id == 0) - return; - - epien = spi_rd8(udc, MAX3420_REG_EPIEN); - epdis = spi_rd8(udc, MAX3420_REG_CLRTOGS); - - if (enable) { - epdis &= ~BIT(ep->id + 4); - epien |= BIT(ep->id + 1); - } else { - epdis |= BIT(ep->id + 4); - epien &= ~BIT(ep->id + 1); - } - - spi_wr8(udc, MAX3420_REG_CLRTOGS, epdis); - spi_wr8(udc, MAX3420_REG_EPIEN, epien); -} - -static int -max3420_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct max3420_ep *ep = to_max3420_ep(_ep); - - _ep->desc = desc; - _ep->maxpacket = usb_endpoint_maxp(desc) & 0x7ff; - - spi_max3420_enable(ep, 1); - - return 0; -} - -static void max3420_req_done(struct max3420_req *req, int status) -{ - struct max3420_ep *ep = req->ep; - - if (req->usb_req.status == -EINPROGRESS) - req->usb_req.status = status; - else - status = req->usb_req.status; - - if (status && status != -ESHUTDOWN) - dev_err(ep->udc->dev, "%s done %p, status %d\n", - ep->ep_usb.name, req, status); - - if (req->usb_req.complete) - req->usb_req.complete(&ep->ep_usb, &req->usb_req); -} - -static void max3420_ep_nuke(struct max3420_ep *ep, int status) -{ - struct max3420_req *req, *r; - - list_for_each_entry_safe(req, r, &ep->queue, queue) { - list_del_init(&req->queue); - max3420_req_done(req, status); - } -} - -static int max3420_ep_disable(struct usb_ep *_ep) -{ - struct max3420_ep *ep = to_max3420_ep(_ep); - - _ep->desc = NULL; - max3420_ep_nuke(ep, -ESHUTDOWN); - spi_max3420_enable(ep, 0); - - return 0; -} - -static struct usb_request * -max3420_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct max3420_ep *ep = to_max3420_ep(_ep); - struct max3420_req *req = kzalloc(sizeof(*req), gfp_flags); - - if (!req) - return NULL; - - req->ep = ep; - INIT_LIST_HEAD(&req->queue); - - return &req->usb_req; -} - -static void -max3420_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - kfree(to_max3420_req(_req)); -} - -static int -max3420_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct max3420_req *req = to_max3420_req(_req); - struct max3420_ep *ep = to_max3420_ep(_ep); - - _req->status = -EINPROGRESS; - _req->actual = 0; - list_add_tail(&req->queue, &ep->queue); - - return 0; -} - -static int max3420_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct max3420_req *req = to_max3420_req(_req); - - list_del_init(&req->queue); - max3420_req_done(req, -ECONNRESET); - - return 0; -} - -static int max3420_ep_set_halt(struct usb_ep *_ep, int halt) -{ - struct max3420_ep *ep = to_max3420_ep(_ep); - struct max3420_udc *udc = ep->udc; - u8 epstalls; - - if (ep->id == 0) /* can't stall EP0 */ - return 0; - - epstalls = spi_rd8(udc, MAX3420_REG_EPSTALLS); - if (halt) { - ep->halted = 1; - epstalls |= BIT(ep->id + 1); - } else { - u8 clrtogs; - - ep->halted = 0; - epstalls &= ~BIT(ep->id + 1); - clrtogs = spi_rd8(udc, MAX3420_REG_CLRTOGS); - clrtogs |= BIT(ep->id + 1); - spi_wr8(udc, MAX3420_REG_CLRTOGS, clrtogs); - } - spi_wr8(udc, MAX3420_REG_EPSTALLS, epstalls | bACKSTAT); - - return 0; -} - -static const struct usb_ep_ops max3420_ep_ops = { - .enable = max3420_ep_enable, - .disable = max3420_ep_disable, - .alloc_request = max3420_ep_alloc_request, - .free_request = max3420_ep_free_request, - .queue = max3420_ep_queue, - .dequeue = max3420_ep_dequeue, - .set_halt = max3420_ep_set_halt, -}; - -static void __max3420_stop(struct max3420_udc *udc) -{ - u8 val; - - /* Disable IRQ to CPU */ - spi_wr8(udc, MAX3420_REG_CPUCTL, 0); - - val = spi_rd8(udc, MAX3420_REG_USBCTL); - val |= bPWRDOWN; - val |= bHOSCSTEN; - spi_wr8(udc, MAX3420_REG_USBCTL, val); -} - -static void __max3420_start(struct max3420_udc *udc) -{ - u8 val; - - /* configure SPI */ - spi_wr8(udc, MAX3420_REG_PINCTL, bFDUPSPI); - - /* Chip Reset */ - spi_wr8(udc, MAX3420_REG_USBCTL, bCHIPRES); - mdelay(5); - spi_wr8(udc, MAX3420_REG_USBCTL, 0); - - /* Poll for OSC to stabilize */ - while (1) { - val = spi_rd8(udc, MAX3420_REG_USBIRQ); - if (val & bOSCOKIRQ) - break; - cond_resched(); - } - - /* Enable PULL-UP only when Vbus detected */ - val = spi_rd8(udc, MAX3420_REG_USBCTL); - val |= bVBGATE | bCONNECT; - spi_wr8(udc, MAX3420_REG_USBCTL, val); - - val = bURESDNIRQ | bURESIRQ; - spi_wr8(udc, MAX3420_REG_USBIEN, val); - - /* Enable only EP0 interrupts */ - val = bIN0BAVIRQ | bOUT0DAVIRQ | bSUDAVIRQ; - spi_wr8(udc, MAX3420_REG_EPIEN, val); - - /* Enable IRQ to CPU */ - spi_wr8(udc, MAX3420_REG_CPUCTL, bIE); -} - -static int max3420_udc_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) -{ - struct max3420_udc *udc = to_udc(gadget); - - udc->driver = driver; - udc->remote_wkp = 0; - udc->softconnect = true; - - __max3420_start(udc); - - return 0; -} - -static int max3420_udc_stop(struct usb_gadget *gadget) -{ - struct max3420_udc *udc = to_udc(gadget); - - udc->driver = NULL; - udc->softconnect = false; - - __max3420_stop(udc); - - return 0; -} - -static int max3420_wakeup(struct usb_gadget *gadget) -{ - struct max3420_udc *udc = to_udc(gadget); - u8 usbctl; - - /* Only if wakeup allowed by host */ - if (!udc->remote_wkp || !udc->suspended) - return 0; - - /* Set Remote-Wakeup Signal*/ - usbctl = spi_rd8(udc, MAX3420_REG_USBCTL); - usbctl |= bSIGRWU; - spi_wr8(udc, MAX3420_REG_USBCTL, usbctl); - - mdelay(5); - - /* Clear Remote-WkUp Signal*/ - usbctl = spi_rd8(udc, MAX3420_REG_USBCTL); - usbctl &= ~bSIGRWU; - spi_wr8(udc, MAX3420_REG_USBCTL, usbctl); - - udc->suspended = false; - - return 0; -} - -static const struct usb_gadget_ops max3420_udc_ops = { - .udc_start = max3420_udc_start, - .udc_stop = max3420_udc_stop, - .wakeup = max3420_wakeup, -}; - -static struct usb_endpoint_descriptor ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = cpu_to_le16(EP_MAX_PACKET), -}; - -static void max3420_getstatus(struct max3420_udc *udc) -{ - struct max3420_ep *ep; - u16 status = 0; - - switch (udc->setup.bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - /* Get device status */ - status = 0 << USB_DEVICE_SELF_POWERED; - status |= (udc->remote_wkp << USB_DEVICE_REMOTE_WAKEUP); - break; - case USB_RECIP_INTERFACE: - if (udc->driver->setup(&udc->gadget, &udc->setup) < 0) - goto stall; - break; - case USB_RECIP_ENDPOINT: - ep = &udc->ep[udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK]; - if (ep->halted) - status = 1 << USB_ENDPOINT_HALT; - break; - default: - goto stall; - } - - status = cpu_to_le16(status); - spi_wr_buf(udc, MAX3420_REG_EP0FIFO, &status, 2); - spi_wr8_ack(udc, MAX3420_REG_EP0BC, 2, 1); - return; -stall: - dev_err(udc->dev, "Can't respond to getstatus request\n"); - spi_wr8(udc, MAX3420_REG_EPSTALLS, bSTLEP0IN | bSTLEP0OUT | bSTLSTAT); -} - -static void max3420_set_clear_feature(struct max3420_udc *udc) -{ - int set = udc->setup.bRequest == USB_REQ_SET_FEATURE; - struct max3420_ep *ep; - int id; - - switch (udc->setup.bRequestType) { - case USB_RECIP_DEVICE: - if (udc->setup.wValue != USB_DEVICE_REMOTE_WAKEUP) - break; - - if (udc->setup.bRequest == USB_REQ_SET_FEATURE) - udc->remote_wkp = 1; - else - udc->remote_wkp = 0; - - return spi_ack_ctrl(udc); - - case USB_RECIP_ENDPOINT: - if (udc->setup.wValue != USB_ENDPOINT_HALT) - break; - - id = udc->setup.wIndex & USB_ENDPOINT_NUMBER_MASK; - ep = &udc->ep[id]; - - max3420_ep_set_halt(&ep->ep_usb, set); - return; - default: - break; - } - - dev_err(udc->dev, "Can't respond to SET/CLEAR FEATURE\n"); - spi_wr8(udc, MAX3420_REG_EPSTALLS, bSTLEP0IN | bSTLEP0OUT | bSTLSTAT); -} - -static void max3420_handle_setup(struct max3420_udc *udc) -{ - struct usb_ctrlrequest setup; - u8 addr; - - spi_rd_buf(udc, MAX3420_REG_SUDFIFO, (void *)&setup, 8); - - udc->setup = setup; - udc->setup.wValue = cpu_to_le16(setup.wValue); - udc->setup.wIndex = cpu_to_le16(setup.wIndex); - udc->setup.wLength = cpu_to_le16(setup.wLength); - - switch (udc->setup.bRequest) { - case USB_REQ_GET_STATUS: - /* Data+Status phase form udc */ - if ((udc->setup.bRequestType & - (USB_DIR_IN | USB_TYPE_MASK)) != - (USB_DIR_IN | USB_TYPE_STANDARD)) { - break; - } - return max3420_getstatus(udc); - case USB_REQ_SET_ADDRESS: - /* Status phase from udc */ - if (udc->setup.bRequestType != (USB_DIR_OUT | - USB_TYPE_STANDARD | USB_RECIP_DEVICE)) - break; - addr = spi_rd8_ack(udc, MAX3420_REG_FNADDR, 1); - dev_dbg(udc->dev, "Assigned Address=%d/%d\n", - udc->setup.wValue, addr); - return; - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - /* Requests with no data phase, status phase from udc */ - if ((udc->setup.bRequestType & USB_TYPE_MASK) - != USB_TYPE_STANDARD) - break; - return max3420_set_clear_feature(udc); - default: - break; - } - - if (udc->driver->setup(&udc->gadget, &setup) < 0) { - /* Stall EP0 */ - spi_wr8(udc, MAX3420_REG_EPSTALLS, - bSTLEP0IN | bSTLEP0OUT | bSTLSTAT); - } -} - -static int do_data(struct max3420_udc *udc, int ep_id, int in) -{ - struct max3420_ep *ep = &udc->ep[ep_id]; - struct max3420_req *req; - int done, length, psz; - void *buf; - - if (list_empty(&ep->queue)) - return 0; - - req = list_first_entry(&ep->queue, struct max3420_req, queue); - buf = req->usb_req.buf + req->usb_req.actual; - - psz = ep->ep_usb.maxpacket; - length = req->usb_req.length - req->usb_req.actual; - length = min(length, psz); - - if (length == 0) { - done = 1; - goto xfer_done; - } - - done = 0; - if (in) { - spi_wr_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length); - spi_wr8(udc, MAX3420_REG_EP0BC + ep_id, length); - if (length < psz) - done = 1; - } else { - psz = spi_rd8(udc, MAX3420_REG_EP0BC + ep_id); - length = min(length, psz); - spi_rd_buf(udc, MAX3420_REG_EP0FIFO + ep_id, buf, length); - if (length < ep->ep_usb.maxpacket) - done = 1; - } - - req->usb_req.actual += length; - - if (req->usb_req.actual == req->usb_req.length) - done = 1; - -xfer_done: - if (done) { - list_del_init(&req->queue); - - if (ep_id == 0) - spi_ack_ctrl(udc); - - max3420_req_done(req, 0); - } - - return 1; -} - -static int max3420_handle_irqs(struct max3420_udc *udc) -{ - u8 epien, epirq, usbirq, usbien, reg[4]; - int ret = 0; - - spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 4); - epirq = reg[0]; - epien = reg[1]; - usbirq = reg[2]; - usbien = reg[3]; - - usbirq &= usbien; - epirq &= epien; - - if (epirq & bSUDAVIRQ) { - spi_wr8(udc, MAX3420_REG_EPIRQ, bSUDAVIRQ); - max3420_handle_setup(udc); - return 1; - } - - if (usbirq & bVBUSIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bVBUSIRQ); - dev_dbg(udc->dev, "Cable plugged in\n"); - g_dnl_clear_detach(); - return 1; - } - - if (usbirq & bNOVBUSIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bNOVBUSIRQ); - dev_dbg(udc->dev, "Cable pulled out\n"); - g_dnl_trigger_detach(); - return 1; - } - - if (usbirq & bURESIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bURESIRQ); - return 1; - } - - if (usbirq & bURESDNIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bURESDNIRQ); - spi_wr8(udc, MAX3420_REG_USBIEN, bURESDNIRQ | bURESIRQ); - spi_wr8(udc, MAX3420_REG_EPIEN, bSUDAVIRQ - | bIN0BAVIRQ | bOUT0DAVIRQ); - return 1; - } - - if (usbirq & bSUSPIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bSUSPIRQ); - dev_dbg(udc->dev, "USB Suspend - Enter\n"); - udc->suspended = true; - return 1; - } - - if (usbirq & bBUSACTIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bBUSACTIRQ); - dev_dbg(udc->dev, "USB Suspend - Exit\n"); - udc->suspended = false; - return 1; - } - - if (usbirq & bRWUDNIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bRWUDNIRQ); - dev_dbg(udc->dev, "Asked Host to wakeup\n"); - return 1; - } - - if (usbirq & bOSCOKIRQ) { - spi_wr8(udc, MAX3420_REG_USBIRQ, bOSCOKIRQ); - dev_dbg(udc->dev, "Osc stabilized, start work\n"); - return 1; - } - - if (epirq & bOUT0DAVIRQ && do_data(udc, 0, 0)) { - spi_wr8_ack(udc, MAX3420_REG_EPIRQ, bOUT0DAVIRQ, 1); - ret = 1; - } - - if (epirq & bIN0BAVIRQ && do_data(udc, 0, 1)) - ret = 1; - - if (epirq & bOUT1DAVIRQ && do_data(udc, 1, 0)) { - spi_wr8_ack(udc, MAX3420_REG_EPIRQ, bOUT1DAVIRQ, 1); - ret = 1; - } - - if (epirq & bIN2BAVIRQ && do_data(udc, 2, 1)) - ret = 1; - - if (epirq & bIN3BAVIRQ && do_data(udc, 3, 1)) - ret = 1; - - return ret; -} - -static int max3420_irq(struct max3420_udc *udc) -{ - do_data(udc, 0, 1); /* get done with the EP0 ZLP */ - - return max3420_handle_irqs(udc); -} - -static void max3420_setup_eps(struct max3420_udc *udc) -{ - int i; - - INIT_LIST_HEAD(&udc->gadget.ep_list); - INIT_LIST_HEAD(&udc->ep[0].ep_usb.ep_list); - - for (i = 0; i < MAX3420_MAX_EPS; i++) { - struct max3420_ep *ep = &udc->ep[i]; - - INIT_LIST_HEAD(&ep->queue); - - ep->id = i; - ep->udc = udc; - ep->ep_usb.ops = &max3420_ep_ops; - ep->ep_usb.name = ep->name; - ep->ep_usb.maxpacket = EP_MAX_PACKET; - - if (i == 0) { - ep->ep_usb.desc = &ep0_desc; - snprintf(ep->name, EPNAME_SIZE, "ep0"); - continue; - } - - list_add_tail(&ep->ep_usb.ep_list, &udc->gadget.ep_list); - - if (i == 1) - snprintf(ep->name, EPNAME_SIZE, "ep1out-bulk"); - else - snprintf(ep->name, EPNAME_SIZE, "ep%din-bulk", i); - }; -} - -static void max3420_setup_spi(struct max3420_udc *udc) -{ - u8 reg[8]; - - spi_claim_bus(udc->slave); - spi_rd_buf(udc, MAX3420_REG_EPIRQ, reg, 8); - /* configure SPI */ - spi_wr8(udc, MAX3420_REG_PINCTL, bFDUPSPI); -} - -static int max3420_udc_probe(struct udevice *dev) -{ - struct max3420_udc *udc = dev_get_priv(dev); - struct dm_spi_slave_plat *slave_pdata; - struct udevice *bus = dev->parent; - int busnum = dev_seq(bus); - unsigned int cs; - uint speed, mode; - struct udevice *spid; - - slave_pdata = dev_get_parent_plat(dev); - cs = slave_pdata->cs; - speed = slave_pdata->max_hz; - mode = slave_pdata->mode; - _spi_get_bus_and_cs(busnum, cs, speed, mode, false, "spi_generic_drv", - NULL, &spid, &udc->slave); - - udc->dev = dev; - udc->gadget.ep0 = &udc->ep[0].ep_usb; - udc->gadget.max_speed = USB_SPEED_FULL; - udc->gadget.speed = USB_SPEED_FULL; - udc->gadget.is_dualspeed = 0; - udc->gadget.ops = &max3420_udc_ops; - udc->gadget.name = "max3420-udc"; - - max3420_setup_eps(udc); - max3420_setup_spi(udc); - - usb_add_gadget_udc((struct device *)dev, &udc->gadget); - - return 0; -} - -static int max3420_udc_remove(struct udevice *dev) -{ - struct max3420_udc *udc = dev_get_priv(dev); - - usb_del_gadget_udc(&udc->gadget); - - spi_release_bus(udc->slave); - - return 0; -} - -static int max3420_gadget_handle_interrupts(struct udevice *dev) -{ - struct max3420_udc *udc = dev_get_priv(dev); - - return max3420_irq(udc); -} - -static const struct usb_gadget_generic_ops max3420_gadget_ops = { - .handle_interrupts = max3420_gadget_handle_interrupts, -}; - -static const struct udevice_id max3420_ids[] = { - { .compatible = "maxim,max3421-udc" }, - { } -}; - -U_BOOT_DRIVER(max3420_generic_udc) = { - .name = "max3420-udc", - .id = UCLASS_USB_GADGET_GENERIC, - .of_match = max3420_ids, - .ops = &max3420_gadget_ops, - .probe = max3420_udc_probe, - .remove = max3420_udc_remove, - .priv_auto = sizeof(struct max3420_udc), -}; diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 5c9e8fc9d15..427b62e934b 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -121,8 +121,9 @@ config USB_XHCI_DRA7XX_INDEX config USB_XHCI_FSL bool "Support for NXP Layerscape on-chip xHCI USB controller" - default y if ARCH_LS1021A || FSL_LSCH3 || FSL_LSCH2 + depends on ARCH_LS1021A || FSL_LSCH3 || FSL_LSCH2 depends on !SPL_NO_USB + default y help Enables support for the on-chip xHCI controller on NXP Layerscape SoCs. @@ -209,10 +210,10 @@ config USB_EHCI_MX6 config USB_EHCI_MX7 bool "Support for i.MX7/i.MX8M/i.MX9 on-chip EHCI USB controller" - depends on ARCH_MX7 || IMX8M || IMX93 || IMX95 + depends on ARCH_MX7 || IMX8M || IMX9 select EHCI_HCD_INIT_AFTER_RESET if ARCH_MX7 - select PHY if IMX8M || IMX93 || IMX95 - select NOP_PHY if IMX8M || IMX93 || IMX95 + select PHY if IMX8M || IMX9 + select NOP_PHY if IMX8M || IMX9 default y ---help--- Enables support for the on-chip EHCI controller on i.MX7/i.MX8M/i.MX9 SoCs. @@ -286,7 +287,8 @@ config USB_EHCI_TEGRA config USB_EHCI_ZYNQ bool "Support for Xilinx Zynq on-chip EHCI USB controller" - default y if ARCH_ZYNQ + depends on ARCH_ZYNQ + default y select USB_EHCI_IS_TDI ---help--- Enable support for Zynq on-chip EHCI USB controller @@ -303,6 +305,7 @@ config EHCI_HCD_INIT_AFTER_RESET config USB_EHCI_FSL bool "Support for FSL on-chip EHCI USB controller" + depends on PPC select EHCI_HCD_INIT_AFTER_RESET select SYS_FSL_USB_INTERNAL_UTMI_PHY if MPC85xx && \ !(ARCH_B4860 || ARCH_B4420 || ARCH_P4080 || ARCH_P1020 || ARCH_P2020) @@ -362,6 +365,7 @@ config USB_OHCI_GENERIC config USB_OHCI_DA8XX bool "Support for da850 OHCI USB controller" + depends on ARCH_DAVINCI help Enable support for the da850 USB controller. diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index 1e4a5a0b6f6..e1fc04efd2e 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -47,8 +47,7 @@ static int ehci_usb_of_to_plat(struct udevice *dev) { struct exynos_ehci_plat *plat = dev_get_plat(dev); const void *blob = gd->fdt_blob; - unsigned int node; - int depth; + int node, depth; /* * Get the base address for XHCI controller from the device node diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index a759aea9db3..8aeb6a91556 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -24,10 +24,11 @@ struct msm_ehci_priv { struct ehci_ctrl ctrl; /* Needed by EHCI */ struct usb_ehci *ehci; /* Start of IP core*/ - struct ulpi_viewport ulpi_vp; /* ULPI Viewport */ struct phy phy; - struct clk iface_clk; - struct clk core_clk; +}; + +struct qcom_ci_hdrc_priv { + struct clk_bulk clks; }; static int msm_init_after_reset(struct ehci_ctrl *dev) @@ -56,64 +57,31 @@ static int ehci_usb_probe(struct udevice *dev) struct ehci_hcor *hcor; int ret; - ret = clk_get_by_name(dev, "core", &p->core_clk); - if (ret) { - dev_err(dev, "Failed to get core clock: %d\n", ret); - return ret; - } - - ret = clk_get_by_name(dev, "iface", &p->iface_clk); - if (ret) { - dev_err(dev, "Failed to get iface clock: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(&p->core_clk); - if (ret) - return ret; - - ret = clk_prepare_enable(&p->iface_clk); - if (ret) - goto cleanup_core; - hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength); hcor = (struct ehci_hcor *)((phys_addr_t)hccr + HC_LENGTH(ehci_readl(&(hccr)->cr_capbase))); ret = generic_setup_phy(dev, &p->phy, 0, PHY_MODE_USB_HOST, 0); if (ret) - goto cleanup_iface; + return ret; ret = board_usb_init(0, plat->init_type); if (ret < 0) - goto cleanup_iface; + return ret; return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0, plat->init_type); - -cleanup_iface: - clk_disable_unprepare(&p->iface_clk); -cleanup_core: - clk_disable_unprepare(&p->core_clk); - return ret; } static int ehci_usb_remove(struct udevice *dev) { struct msm_ehci_priv *p = dev_get_priv(dev); - struct usb_ehci *ehci = p->ehci; int ret; ret = ehci_deregister(dev); if (ret) return ret; - /* Stop controller. */ - clrbits_le32(&ehci->usbcmd, CMD_RUN); - - clk_disable_unprepare(&p->iface_clk); - clk_disable_unprepare(&p->core_clk); - ret = generic_shutdown_phy(&p->phy); if (ret) return ret; @@ -122,15 +90,6 @@ static int ehci_usb_remove(struct udevice *dev) if (ret < 0) return ret; - /* Reset controller */ - setbits_le32(&ehci->usbcmd, CMD_RESET); - - /* Wait for reset */ - if (wait_for_bit_le32(&ehci->usbcmd, CMD_RESET, false, 30, false)) { - printf("Stuck on USB reset.\n"); - return -ETIMEDOUT; - } - return 0; } @@ -138,38 +97,14 @@ static int ehci_usb_of_to_plat(struct udevice *dev) { struct msm_ehci_priv *priv = dev_get_priv(dev); - priv->ulpi_vp.port_num = 0; priv->ehci = dev_read_addr_ptr(dev); - if (priv->ehci == (void *)FDT_ADDR_T_NONE) + if (!priv->ehci) return -EINVAL; - /* Warning: this will not work if viewport address is > 64 bit due to - * ULPI design. - */ - priv->ulpi_vp.viewport_addr = (phys_addr_t)&priv->ehci->ulpi_viewpoint; - return 0; } -static int ehci_usb_of_bind(struct udevice *dev) -{ - ofnode ulpi_node = ofnode_first_subnode(dev_ofnode(dev)); - ofnode phy_node; - - if (!ofnode_valid(ulpi_node)) - return 0; - - phy_node = ofnode_first_subnode(ulpi_node); - if (!ofnode_valid(phy_node)) { - printf("%s: ulpi subnode with no phy\n", __func__); - return -ENOENT; - } - - return device_bind_driver_to_node(dev, "msm8916_usbphy", "msm8916_usbphy", - phy_node, NULL); -} - #if defined(CONFIG_CI_UDC) /* Little quirk that MSM needs with Chipidea controller * Must reinit phy after reset @@ -182,17 +117,10 @@ void ci_init_after_reset(struct ehci_ctrl *ctrl) } #endif -static const struct udevice_id ehci_usb_ids[] = { - { .compatible = "qcom,ci-hdrc", }, - { } -}; - U_BOOT_DRIVER(usb_ehci) = { .name = "ehci_msm", .id = UCLASS_USB, - .of_match = ehci_usb_ids, .of_to_plat = ehci_usb_of_to_plat, - .bind = ehci_usb_of_bind, .probe = ehci_usb_probe, .remove = ehci_usb_remove, .ops = &ehci_usb_ops, @@ -200,3 +128,63 @@ U_BOOT_DRIVER(usb_ehci) = { .plat_auto = sizeof(struct usb_plat), .flags = DM_FLAG_ALLOC_PRIV_DMA, }; + +static int qcom_ci_hdrc_probe(struct udevice *dev) +{ + struct qcom_ci_hdrc_priv *p = dev_get_priv(dev); + int ret; + + ret = clk_get_bulk(dev, &p->clks); + if (ret && (ret != -ENOSYS && ret != -ENOENT)) { + dev_err(dev, "Failed to get clocks: %d\n", ret); + return ret; + } + + return clk_enable_bulk(&p->clks); +} + +static int qcom_ci_hdrc_remove(struct udevice *dev) +{ + struct qcom_ci_hdrc_priv *p = dev_get_priv(dev); + + return clk_release_bulk(&p->clks); +} + +static int qcom_ci_hdrc_bind(struct udevice *dev) +{ + ofnode ulpi_node = ofnode_first_subnode(dev_ofnode(dev)); + ofnode phy_node; + int ret; + + ret = device_bind_driver_to_node(dev, "ehci_msm", "ehci_msm", + dev_ofnode(dev), NULL); + if (ret) + return ret; + + if (!ofnode_valid(ulpi_node)) + return 0; + + phy_node = ofnode_first_subnode(ulpi_node); + if (!ofnode_valid(phy_node)) { + printf("%s: ulpi subnode with no phy\n", __func__); + return -ENOENT; + } + + return device_bind_driver_to_node(dev, "msm8916_usbphy", "msm8916_usbphy", + phy_node, NULL); +} + +static const struct udevice_id qcom_ci_hdrc_ids[] = { + { .compatible = "qcom,ci-hdrc", }, + { } +}; + +U_BOOT_DRIVER(qcom_ci_hdrc) = { + .name = "qcom_ci_hdrc", + .id = UCLASS_NOP, + .of_match = qcom_ci_hdrc_ids, + .bind = qcom_ci_hdrc_bind, + .probe = qcom_ci_hdrc_probe, + .remove = qcom_ci_hdrc_remove, + .priv_auto = sizeof(struct qcom_ci_hdrc_priv), +}; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 234a6f3645d..1d6711ccec4 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1040,9 +1040,11 @@ static void dl_transfer_length(td_t *td) static void check_status(td_t *td_list) { urb_priv_t *lurb_priv = td_list->ed->purb; - int urb_len = lurb_priv->length; __u32 *phwHeadP = &td_list->ed->hwHeadP; - int cc; + int cc, urb_len; + + if (lurb_priv) + urb_len = lurb_priv->length; cc = TD_CC_GET(m32_swap(td_list->hwINFO)); if (cc) { diff --git a/drivers/usb/host/xhci-brcm.c b/drivers/usb/host/xhci-brcm.c index 2ffad148dea..595839fac3c 100644 --- a/drivers/usb/host/xhci-brcm.c +++ b/drivers/usb/host/xhci-brcm.c @@ -85,7 +85,7 @@ static const struct udevice_id xhci_brcm_ids[] = { { } }; -U_BOOT_DRIVER(usb_xhci) = { +U_BOOT_DRIVER(xhci_brcm) = { .name = "xhci_brcm", .id = UCLASS_USB, .probe = xhci_brcm_probe, diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c index 6a2d422c4b8..500696ccae7 100644 --- a/drivers/usb/host/xhci-exynos5.c +++ b/drivers/usb/host/xhci-exynos5.c @@ -56,8 +56,7 @@ static int xhci_usb_of_to_plat(struct udevice *dev) { struct exynos_xhci_plat *plat = dev_get_plat(dev); const void *blob = gd->fdt_blob; - unsigned int node; - int depth; + int node, depth; /* * Get the base address for XHCI controller from the device node @@ -247,7 +246,7 @@ static const struct udevice_id xhci_usb_ids[] = { { } }; -U_BOOT_DRIVER(usb_xhci) = { +U_BOOT_DRIVER(xhci_exynos) = { .name = "xhci_exynos", .id = UCLASS_USB, .of_match = xhci_usb_ids, diff --git a/drivers/usb/host/xhci-generic.c b/drivers/usb/host/xhci-generic.c index 355d4883176..8bb4e277423 100644 --- a/drivers/usb/host/xhci-generic.c +++ b/drivers/usb/host/xhci-generic.c @@ -61,7 +61,7 @@ static const struct udevice_id xhci_usb_ids[] = { { } }; -U_BOOT_DRIVER(usb_xhci) = { +U_BOOT_DRIVER(xhci_generic) = { .name = "xhci_generic", .id = UCLASS_USB, .of_match = xhci_usb_ids, diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 7e288f0575b..ffe80c0bbdc 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -357,7 +357,7 @@ static const struct udevice_id xhci_mtk_ids[] = { { } }; -U_BOOT_DRIVER(usb_xhci) = { +U_BOOT_DRIVER(xhci_mtk) = { .name = "xhci-mtk", .id = UCLASS_USB, .of_match = xhci_mtk_ids, diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c index 1338b1021c6..12dc61aee9d 100644 --- a/drivers/usb/host/xhci-mvebu.c +++ b/drivers/usb/host/xhci-mvebu.c @@ -87,7 +87,7 @@ static const struct udevice_id xhci_usb_ids[] = { { } }; -U_BOOT_DRIVER(usb_xhci) = { +U_BOOT_DRIVER(xhci_mvebu) = { .name = "xhci_mvebu", .id = UCLASS_USB, .of_match = xhci_usb_ids, diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index b72807053c4..95dfa2c3f87 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -149,7 +149,7 @@ static const struct udevice_id xhci_rcar_ids[] = { { } }; -U_BOOT_DRIVER(usb_xhci) = { +U_BOOT_DRIVER(xhci_rcar) = { .name = "xhci_rcar", .id = UCLASS_USB, .probe = xhci_rcar_probe, diff --git a/drivers/usb/musb-new/Kconfig b/drivers/usb/musb-new/Kconfig index ad9072a5327..f8daaddc657 100644 --- a/drivers/usb/musb-new/Kconfig +++ b/drivers/usb/musb-new/Kconfig @@ -40,6 +40,7 @@ config USB_MUSB_DA8XX config USB_MUSB_TI bool "Enable TI OTG USB controller" depends on AM33XX + select MISC if OF_CONTROL select USB_MUSB_DSPS help Say y here to enable support for the dual role high @@ -52,9 +53,11 @@ config USB_MUSB_OMAP2PLUS config USB_MUSB_AM35X bool "AM35x" + depends on ARCH_OMAP2PLUS config USB_MUSB_DSPS bool "TI DSPS platforms" + depends on ARCH_OMAP2PLUS config USB_MUSB_MT85XX bool "Enable Mediatek MT85XX DRC USB controller" diff --git a/drivers/usb/musb-new/am35x.c b/drivers/usb/musb-new/am35x.c index 42bc816e4f1..ca4d798642e 100644 --- a/drivers/usb/musb-new/am35x.c +++ b/drivers/usb/musb-new/am35x.c @@ -402,7 +402,7 @@ static int am35x_musb_init(struct musb *musb) #endif /* Reset the musb */ - if (data->reset) + if (data && data->reset) data->reset(data->dev); /* Reset the controller */ @@ -417,7 +417,7 @@ static int am35x_musb_init(struct musb *musb) musb->isr = am35x_musb_interrupt; /* clear level interrupt */ - if (data->clear_irq) + if (data && data->clear_irq) data->clear_irq(data->dev); return 0; diff --git a/drivers/usb/musb-new/musb_core.c b/drivers/usb/musb-new/musb_core.c index a14b127dc37..17ec0d3acbd 100644 --- a/drivers/usb/musb-new/musb_core.c +++ b/drivers/usb/musb-new/musb_core.c @@ -1954,7 +1954,7 @@ musb_init_controller(struct musb_hdrc_platform_data *plat, struct device *dev, /* The musb_platform_init() call: * - adjusts musb->mregs and musb->isr if needed, - * - may initialize an integrated tranceiver + * - may initialize an integrated transceiver * - initializes musb->xceiv, usually by otg_get_phy() * - stops powering VBUS * diff --git a/drivers/usb/musb-new/musb_gadget.c b/drivers/usb/musb-new/musb_gadget.c index 08fac829ce7..7daff5850f1 100644 --- a/drivers/usb/musb-new/musb_gadget.c +++ b/drivers/usb/musb-new/musb_gadget.c @@ -728,7 +728,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) * mode 0 only. So we do not get endpoint interrupts due to DMA * completion. We only get interrupts from DMA controller. * - * We could operate in DMA mode 1 if we knew the size of the tranfer + * We could operate in DMA mode 1 if we knew the size of the transfer * in advance. For mass storage class, request->length = what the host * sends, so that'd work. But for pretty much everything else, * request->length is routinely more than what the host sends. For @@ -1422,7 +1422,7 @@ done: } /* - * Set or clear the halt bit of an endpoint. A halted enpoint won't tx/rx any + * Set or clear the halt bit of an endpoint. A halted endpoint won't tx/rx any * data but will queue requests. * * exported to ep0 code diff --git a/drivers/usb/musb-new/musb_gadget_ep0.c b/drivers/usb/musb-new/musb_gadget_ep0.c index ea65326ab62..25b1de6e58f 100644 --- a/drivers/usb/musb-new/musb_gadget_ep0.c +++ b/drivers/usb/musb-new/musb_gadget_ep0.c @@ -96,6 +96,9 @@ static int service_tx_status_request( if (!epnum) { result[0] = 0; break; + } else if (epnum >= MUSB_C_NUM_EPS) { + handled = -EINVAL; + break; } is_in = epnum & USB_DIR_IN; @@ -107,7 +110,7 @@ static int service_tx_status_request( } regs = musb->endpoints[epnum].regs; - if (epnum >= MUSB_C_NUM_EPS || !ep->desc) { + if (!ep->desc) { handled = -EINVAL; break; } diff --git a/drivers/usb/musb-new/musb_host.c b/drivers/usb/musb-new/musb_host.c index 7528a53d73e..7f296d15984 100644 --- a/drivers/usb/musb-new/musb_host.c +++ b/drivers/usb/musb-new/musb_host.c @@ -1862,7 +1862,7 @@ static int musb_schedule( head = &musb->out_bulk; /* Enable bulk RX NAK timeout scheme when bulk requests are - * multiplexed. This scheme doen't work in high speed to full + * multiplexed. This scheme doesn't work in high speed to full * speed scenario as NAK interrupts are not coming from a * full speed device connected to a high speed device. * NAK timeout interval is 8 (128 uframe or 16ms) for HS and diff --git a/drivers/usb/musb-new/omap2430.c b/drivers/usb/musb-new/omap2430.c index ba600d01102..7fd6639013a 100644 --- a/drivers/usb/musb-new/omap2430.c +++ b/drivers/usb/musb-new/omap2430.c @@ -142,41 +142,49 @@ static int omap2430_musb_of_to_plat(struct udevice *dev) struct omap2430_musb_plat *plat = dev_get_plat(dev); const void *fdt = gd->fdt_blob; int node = dev_of_offset(dev); + int ret; plat->base = (void *)dev_read_addr_ptr(dev); - plat->musb_config.multipoint = fdtdec_get_int(fdt, node, "multipoint", - -1); - if (plat->musb_config.multipoint < 0) { + ret = fdtdec_get_int(fdt, node, "multipoint", -1); + if (ret < 0) { pr_err("MUSB multipoint DT entry missing\n"); return -ENOENT; + } else { + plat->musb_config.multipoint = ret; } plat->musb_config.dyn_fifo = 1; - plat->musb_config.num_eps = fdtdec_get_int(fdt, node, "num-eps", -1); - if (plat->musb_config.num_eps < 0) { + ret = fdtdec_get_int(fdt, node, "num-eps", -1); + if (ret < 0) { pr_err("MUSB num-eps DT entry missing\n"); return -ENOENT; + } else { + plat->musb_config.num_eps = ret; } - plat->musb_config.ram_bits = fdtdec_get_int(fdt, node, "ram-bits", -1); - if (plat->musb_config.ram_bits < 0) { + ret = fdtdec_get_int(fdt, node, "ram-bits", -1); + if (ret < 0) { pr_err("MUSB ram-bits DT entry missing\n"); return -ENOENT; + } else { + plat->musb_config.ram_bits = ret; } - plat->plat.power = fdtdec_get_int(fdt, node, "power", -1); - if (plat->plat.power < 0) { + ret = fdtdec_get_int(fdt, node, "power", -1); + if (ret < 0) { pr_err("MUSB power DT entry missing\n"); return -ENOENT; + } else { + plat->plat.power = ret; } - plat->otg_board_data.interface_type = fdtdec_get_int(fdt, node, - "interface-type", - -1); - if (plat->otg_board_data.interface_type < 0) { + ret = fdtdec_get_int(fdt, node, "interface-type", -1); + if (ret < 0) { pr_err("MUSB interface-type DT entry missing\n"); return -ENOENT; + } else { + plat->otg_board_data.interface_type = ret; } #if 0 /* In a perfect world, mode would be set to OTG, mode 3 from DT */ diff --git a/drivers/usb/musb-new/ti-musb.c b/drivers/usb/musb-new/ti-musb.c index 967d0953875..bcd31adba52 100644 --- a/drivers/usb/musb-new/ti-musb.c +++ b/drivers/usb/musb-new/ti-musb.c @@ -86,6 +86,7 @@ static int ti_musb_of_to_plat(struct udevice *dev) int phys; int ctrl_mod; int usb_index; + int ret; struct musb_hdrc_config *musb_config; plat->base = devfdt_get_addr_index_ptr(dev, 1); @@ -108,35 +109,40 @@ static int ti_musb_of_to_plat(struct udevice *dev) musb_config = malloc(sizeof(struct musb_hdrc_config)); memset(musb_config, 0, sizeof(struct musb_hdrc_config)); - musb_config->multipoint = fdtdec_get_int(fdt, node, - "mentor,multipoint", -1); - if (musb_config->multipoint < 0) { + ret = fdtdec_get_int(fdt, node, "mentor,multipoint", -1); + if (ret < 0) { pr_err("MUSB multipoint DT entry missing\n"); return -ENOENT; + } else { + musb_config->multipoint = ret; } musb_config->dyn_fifo = 1; - musb_config->num_eps = fdtdec_get_int(fdt, node, "mentor,num-eps", - -1); - if (musb_config->num_eps < 0) { + ret = fdtdec_get_int(fdt, node, "mentor,num-eps", -1); + if (ret < 0) { pr_err("MUSB num-eps DT entry missing\n"); return -ENOENT; + } else { + musb_config->num_eps = ret; } - musb_config->ram_bits = fdtdec_get_int(fdt, node, "mentor,ram-bits", - -1); - if (musb_config->ram_bits < 0) { + ret = fdtdec_get_int(fdt, node, "mentor,ram-bits", -1); + if (ret < 0) { pr_err("MUSB ram-bits DT entry missing\n"); return -ENOENT; + } else { + musb_config->ram_bits = ret; } plat->plat.config = musb_config; - plat->plat.power = fdtdec_get_int(fdt, node, "mentor,power", -1); - if (plat->plat.power < 0) { + ret = fdtdec_get_int(fdt, node, "mentor,power", -1); + if (ret < 0) { pr_err("MUSB mentor,power DT entry missing\n"); return -ENOENT; + } else { + plat->plat.power = ret; } plat->plat.platform_ops = &musb_dsps_ops; diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig deleted file mode 100644 index 2508b6ed0d1..00000000000 --- a/drivers/usb/musb/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0+ -# -# (C) Copyright 2017 -# Adam Ford, Logic PD, aford173@gmail.com - -comment "Legacy MUSB Support" - -config USB_MUSB_HCD - bool "Legacy MUSB Host Controller" - -config USB_MUSB_UDC - bool "Legacy USB Device Controller" - -config USB_OMAP3 - bool "Legacy MUSB OMAP3 / OMAP4" - depends on ARCH_OMAP2PLUS - -config USB_AM35X - bool"Legacy MUSB AM35x" - depends on ARCH_OMAP2PLUS && !USB_OMAP3 diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile deleted file mode 100644 index 744f2cfaa29..00000000000 --- a/drivers/usb/musb/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0+ -# -# (C) Copyright 2000-2007 -# Wolfgang Denk, DENX Software Engineering, wd@denx.de. - -obj-$(CONFIG_USB_MUSB_HCD) += musb_hcd.o musb_core.o -obj-$(CONFIG_USB_MUSB_UDC) += musb_udc.o musb_core.o -obj-$(CONFIG_USB_OMAP3) += omap3.o -obj-$(CONFIG_USB_AM35X) += am35x.o diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c deleted file mode 100644 index 2c23043d40e..00000000000 --- a/drivers/usb/musb/am35x.c +++ /dev/null @@ -1,138 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * am35x.c - TI's AM35x platform specific usb wrapper functions. - * - * Author: Ajay Kumar Gupta <ajay.gupta@ti.com> - * - * Based on drivers/usb/musb/da8xx.c - * - * Copyright (c) 2010 Texas Instruments Incorporated - */ - -#include <linux/delay.h> - -#include "am35x.h" - -/* MUSB platform configuration */ -struct musb_config musb_cfg = { - .regs = (struct musb_regs *)AM35X_USB_OTG_CORE_BASE, - .timeout = AM35X_USB_OTG_TIMEOUT, - .musb_speed = 0, -}; - -/* - * Enable the USB phy - */ -static u8 phy_on(void) -{ - u32 devconf2; - u32 timeout; - - devconf2 = readl(&am35x_scm_general_regs->devconf2); - - devconf2 &= ~(DEVCONF2_RESET | DEVCONF2_PHYPWRDN | DEVCONF2_OTGPWRDN | - DEVCONF2_OTGMODE | DEVCONF2_REFFREQ | - DEVCONF2_PHY_GPIOMODE); - devconf2 |= DEVCONF2_SESENDEN | DEVCONF2_VBDTCTEN | DEVCONF2_PHY_PLLON | - DEVCONF2_REFFREQ_13MHZ | DEVCONF2_DATPOL; - - writel(devconf2, &am35x_scm_general_regs->devconf2); - - /* wait until the USB phy is turned on */ - timeout = musb_cfg.timeout; - while (timeout--) - if (readl(&am35x_scm_general_regs->devconf2) & DEVCONF2_PHYCKGD) - return 1; - - /* USB phy was not turned on */ - return 0; -} - -/* - * Disable the USB phy - */ -static void phy_off(void) -{ - u32 devconf2; - - /* - * Power down the on-chip PHY. - */ - devconf2 = readl(&am35x_scm_general_regs->devconf2); - - devconf2 &= ~DEVCONF2_PHY_PLLON; - devconf2 |= DEVCONF2_PHYPWRDN | DEVCONF2_OTGPWRDN; - writel(devconf2, &am35x_scm_general_regs->devconf2); -} - -/* - * This function performs platform specific initialization for usb0. - */ -int musb_platform_init(void) -{ - u32 revision; - u32 sw_reset; - - /* global usb reset */ - sw_reset = readl(&am35x_scm_general_regs->ip_sw_reset); - sw_reset |= (1 << 0); - writel(sw_reset, &am35x_scm_general_regs->ip_sw_reset); - sw_reset &= ~(1 << 0); - writel(sw_reset, &am35x_scm_general_regs->ip_sw_reset); - - /* reset the controller */ - writel(0x1, &am35x_usb_regs->control); - udelay(5000); - - /* start the on-chip usb phy and its pll */ - if (phy_on() == 0) - return -1; - - /* Returns zero if e.g. not clocked */ - revision = readl(&am35x_usb_regs->revision); - if (revision == 0) - return -1; - - return 0; -} - -/* - * This function performs platform specific deinitialization for usb0. - */ -void musb_platform_deinit(void) -{ - /* Turn off the phy */ - phy_off(); -} - -/* - * This function reads data from endpoint fifo for AM35x - * which supports only 32bit read operation. - * - * ep - endpoint number - * length - number of bytes to read from FIFO - * fifo_data - pointer to data buffer into which data is read - */ -__attribute__((weak)) -void read_fifo(u8 ep, u32 length, void *fifo_data) -{ - u8 *data = (u8 *)fifo_data; - u32 val; - int i; - - /* select the endpoint index */ - writeb(ep, &musbr->index); - - if (length > 4) { - for (i = 0; i < (length >> 2); i++) { - val = readl(&musbr->fifox[ep]); - memcpy(data, &val, 4); - data += 4; - } - length %= 4; - } - if (length > 0) { - val = readl(&musbr->fifox[ep]); - memcpy(data, &val, length); - } -} diff --git a/drivers/usb/musb/am35x.h b/drivers/usb/musb/am35x.h deleted file mode 100644 index 82ad94329cb..00000000000 --- a/drivers/usb/musb/am35x.h +++ /dev/null @@ -1,81 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * am35x.h - TI's AM35x platform specific usb wrapper definitions. - * - * Author: Ajay Kumar Gupta <ajay.gupta@ti.com> - * - * Based on drivers/usb/musb/da8xx.h - * - * Copyright (c) 2010 Texas Instruments Incorporated - */ - -#ifndef __AM35X_USB_H__ -#define __AM35X_USB_H__ - -#include <asm/arch/am35x_def.h> -#include "musb_core.h" - -/* Base address of musb wrapper */ -#define AM35X_USB_OTG_BASE 0x5C040000 - -/* Base address of musb core */ -#define AM35X_USB_OTG_CORE_BASE (AM35X_USB_OTG_BASE + 0x400) - -/* Timeout for AM35x usb module */ -#define AM35X_USB_OTG_TIMEOUT 0x3FFFFFF - -/* - * AM35x platform USB wrapper register overlay. - */ -struct am35x_usb_regs { - u32 revision; - u32 control; - u32 status; - u32 emulation; - u32 reserved0[1]; - u32 autoreq; - u32 srpfixtime; - u32 ep_intsrc; - u32 ep_intsrcset; - u32 ep_intsrcclr; - u32 ep_intmsk; - u32 ep_intmskset; - u32 ep_intmskclr; - u32 ep_intsrcmsked; - u32 reserved1[1]; - u32 core_intsrc; - u32 core_intsrcset; - u32 core_intsrcclr; - u32 core_intmsk; - u32 core_intmskset; - u32 core_intmskclr; - u32 core_intsrcmsked; - u32 reserved2[1]; - u32 eoi; - u32 mop_sop_en; - u32 reserved3[2]; - u32 txmode; - u32 rxmode; - u32 epcount_mode; -}; - -#define am35x_usb_regs ((struct am35x_usb_regs *)AM35X_USB_OTG_BASE) - -/* USB 2.0 PHY Control */ -#define DEVCONF2_PHY_GPIOMODE (1 << 23) -#define DEVCONF2_OTGMODE (3 << 14) -#define DEVCONF2_SESENDEN (1 << 13) /* Vsess_end comparator */ -#define DEVCONF2_VBDTCTEN (1 << 12) /* Vbus comparator */ -#define DEVCONF2_REFFREQ_24MHZ (2 << 8) -#define DEVCONF2_REFFREQ_26MHZ (7 << 8) -#define DEVCONF2_REFFREQ_13MHZ (6 << 8) -#define DEVCONF2_REFFREQ (0xf << 8) -#define DEVCONF2_PHYCKGD (1 << 7) -#define DEVCONF2_VBUSSENSE (1 << 6) -#define DEVCONF2_PHY_PLLON (1 << 5) /* override PLL suspend */ -#define DEVCONF2_RESET (1 << 4) -#define DEVCONF2_PHYPWRDN (1 << 3) -#define DEVCONF2_OTGPWRDN (1 << 2) -#define DEVCONF2_DATPOL (1 << 1) - -#endif /* __AM35X_USB_H__ */ diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c deleted file mode 100644 index 260552e4dbd..00000000000 --- a/drivers/usb/musb/musb_core.c +++ /dev/null @@ -1,150 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Mentor USB OTG Core functionality common for both Host and Device - * functionality. - * - * Copyright (c) 2008 Texas Instruments - * - * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments - */ - -#include <linux/bitops.h> - -#include "musb_core.h" -struct musb_regs *musbr; - -/* - * program the mentor core to start (enable interrupts, dma, etc.) - */ -void musb_start(void) -{ -#if defined(CONFIG_USB_MUSB_HCD) - u8 devctl; - u8 busctl; -#endif - - /* disable all interrupts */ - writew(0, &musbr->intrtxe); - writew(0, &musbr->intrrxe); - writeb(0, &musbr->intrusbe); - writeb(0, &musbr->testmode); - - /* put into basic highspeed mode and start session */ - writeb(MUSB_POWER_HSENAB, &musbr->power); -#if defined(CONFIG_USB_MUSB_HCD) - /* Program PHY to use EXT VBUS if required */ - if (musb_cfg.extvbus == 1) { - busctl = musb_read_ulpi_buscontrol(musbr); - musb_write_ulpi_buscontrol(musbr, busctl | ULPI_USE_EXTVBUS); - } - - devctl = readb(&musbr->devctl); - writeb(devctl | MUSB_DEVCTL_SESSION, &musbr->devctl); -#endif -} - -#ifdef MUSB_NO_DYNAMIC_FIFO -# define config_fifo(dir, idx, addr) -#else -# define config_fifo(dir, idx, addr) \ - do { \ - writeb(idx, &musbr->dir##fifosz); \ - writew(addr, &musbr->dir##fifoadd); \ - } while (0) -#endif - -/* - * This function configures the endpoint configuration. The musb hcd or musb - * device implementation can use this function to configure the endpoints - * and set the FIFO sizes. Note: The summation of FIFO sizes of all endpoints - * should not be more than the available FIFO size. - * - * epinfo - Pointer to EP configuration table - * cnt - Number of entries in the EP conf table. - */ -void musb_configure_ep(const struct musb_epinfo *epinfo, u8 cnt) -{ - u16 csr; - u16 fifoaddr = 64 >> 3; /* First 64 bytes of FIFO reserved for EP0 */ - u32 fifosize; - u8 idx; - - while (cnt--) { - /* prepare fifosize to write to register */ - fifosize = epinfo->epsize >> 3; - idx = fifosize ? ((ffs(fifosize) - 1) & 0xF) : 0; - - writeb(epinfo->epnum, &musbr->index); - if (epinfo->epdir) { - /* Configure fifo size and fifo base address */ - config_fifo(tx, idx, fifoaddr); - - csr = readw(&musbr->txcsr); - /* clear the data toggle bit */ - writew(csr | MUSB_TXCSR_CLRDATATOG, &musbr->txcsr); - /* Flush fifo if required */ - if (csr & MUSB_TXCSR_TXPKTRDY) - writew(csr | MUSB_TXCSR_FLUSHFIFO, - &musbr->txcsr); - } else { - /* Configure fifo size and fifo base address */ - config_fifo(rx, idx, fifoaddr); - - csr = readw(&musbr->rxcsr); - /* clear the data toggle bit */ - writew(csr | MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr); - /* Flush fifo if required */ - if (csr & MUSB_RXCSR_RXPKTRDY) - writew(csr | MUSB_RXCSR_FLUSHFIFO, - &musbr->rxcsr); - } - fifoaddr += 1 << idx; - epinfo++; - } -} - -/* - * This function writes data to endpoint fifo - * - * ep - endpoint number - * length - number of bytes to write to FIFO - * fifo_data - Pointer to data buffer that contains the data to write - */ -__attribute__((weak)) -void write_fifo(u8 ep, u32 length, void *fifo_data) -{ - u8 *data = (u8 *)fifo_data; - - /* select the endpoint index */ - writeb(ep, &musbr->index); - - /* write the data to the fifo */ - while (length--) - writeb(*data++, &musbr->fifox[ep]); -} - -/* - * AM35x supports only 32bit read operations so - * use seperate read_fifo() function for it. - */ -#ifndef CONFIG_USB_AM35X -/* - * This function reads data from endpoint fifo - * - * ep - endpoint number - * length - number of bytes to read from FIFO - * fifo_data - pointer to data buffer into which data is read - */ -__attribute__((weak)) -void read_fifo(u8 ep, u32 length, void *fifo_data) -{ - u8 *data = (u8 *)fifo_data; - - /* select the endpoint index */ - writeb(ep, &musbr->index); - - /* read the data to the fifo */ - while (length--) - *data++ = readb(&musbr->fifox[ep]); -} -#endif /* CONFIG_USB_AM35X */ diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h deleted file mode 100644 index 47b839c0835..00000000000 --- a/drivers/usb/musb/musb_core.h +++ /dev/null @@ -1,343 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************** - * Copyright 2008 Mentor Graphics Corporation - * Copyright (C) 2008 by Texas Instruments - * - * This file is part of the Inventra Controller Driver for Linux. - ******************************************************************/ - -#ifndef __MUSB_HDRC_DEFS_H__ -#define __MUSB_HDRC_DEFS_H__ - -#include <usb_defs.h> -#include <asm/io.h> - -#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */ - -/* EP0 */ -struct musb_ep0_regs { - u16 reserved4; - u16 csr0; - u16 reserved5; - u16 reserved6; - u16 count0; - u8 host_type0; - u8 host_naklimit0; - u8 reserved7; - u8 reserved8; - u8 reserved9; - u8 configdata; -}; - -/* EP 1-15 */ -struct musb_epN_regs { - u16 txmaxp; - u16 txcsr; - u16 rxmaxp; - u16 rxcsr; - u16 rxcount; - u8 txtype; - u8 txinterval; - u8 rxtype; - u8 rxinterval; - u8 reserved0; - u8 fifosize; -}; - -/* Mentor USB core register overlay structure */ -#ifndef musb_regs -struct musb_regs { - /* common registers */ - u8 faddr; - u8 power; - u16 intrtx; - u16 intrrx; - u16 intrtxe; - u16 intrrxe; - u8 intrusb; - u8 intrusbe; - u16 frame; - u8 index; - u8 testmode; - /* indexed registers */ - u16 txmaxp; - u16 txcsr; - u16 rxmaxp; - u16 rxcsr; - u16 rxcount; - u8 txtype; - u8 txinterval; - u8 rxtype; - u8 rxinterval; - u8 reserved0; - u8 fifosize; - /* fifo */ - u32 fifox[16]; - /* OTG, dynamic FIFO, version & vendor registers */ - u8 devctl; - u8 reserved1; - u8 txfifosz; - u8 rxfifosz; - u16 txfifoadd; - u16 rxfifoadd; - u32 vcontrol; - u16 hwvers; - u16 reserved2a[1]; - u8 ulpi_busctl; - u8 reserved2b[1]; - u16 reserved2[3]; - u8 epinfo; - u8 raminfo; - u8 linkinfo; - u8 vplen; - u8 hseof1; - u8 fseof1; - u8 lseof1; - u8 reserved3; - /* target address registers */ - struct musb_tar_regs { - u8 txfuncaddr; - u8 reserved0; - u8 txhubaddr; - u8 txhubport; - u8 rxfuncaddr; - u8 reserved1; - u8 rxhubaddr; - u8 rxhubport; - } tar[16]; - /* - * endpoint registers - * ep0 elements are valid when array index is 0 - * otherwise epN is valid - */ - union musb_ep_regs { - struct musb_ep0_regs ep0; - struct musb_epN_regs epN; - } ep[16]; - -} __attribute__((packed)); -#endif - -/* - * MUSB Register bits - */ - -/* POWER */ -#define MUSB_POWER_ISOUPDATE 0x80 -#define MUSB_POWER_SOFTCONN 0x40 -#define MUSB_POWER_HSENAB 0x20 -#define MUSB_POWER_HSMODE 0x10 -#define MUSB_POWER_RESET 0x08 -#define MUSB_POWER_RESUME 0x04 -#define MUSB_POWER_SUSPENDM 0x02 -#define MUSB_POWER_ENSUSPEND 0x01 -#define MUSB_POWER_HSMODE_SHIFT 4 - -/* INTRUSB */ -#define MUSB_INTR_SUSPEND 0x01 -#define MUSB_INTR_RESUME 0x02 -#define MUSB_INTR_RESET 0x04 -#define MUSB_INTR_BABBLE 0x04 -#define MUSB_INTR_SOF 0x08 -#define MUSB_INTR_CONNECT 0x10 -#define MUSB_INTR_DISCONNECT 0x20 -#define MUSB_INTR_SESSREQ 0x40 -#define MUSB_INTR_VBUSERROR 0x80 /* For SESSION end */ - -/* DEVCTL */ -#define MUSB_DEVCTL_BDEVICE 0x80 -#define MUSB_DEVCTL_FSDEV 0x40 -#define MUSB_DEVCTL_LSDEV 0x20 -#define MUSB_DEVCTL_VBUS 0x18 -#define MUSB_DEVCTL_VBUS_SHIFT 3 -#define MUSB_DEVCTL_HM 0x04 -#define MUSB_DEVCTL_HR 0x02 -#define MUSB_DEVCTL_SESSION 0x01 - -/* ULPI VBUSCONTROL */ -#define ULPI_USE_EXTVBUS 0x01 -#define ULPI_USE_EXTVBUSIND 0x02 - -/* TESTMODE */ -#define MUSB_TEST_FORCE_HOST 0x80 -#define MUSB_TEST_FIFO_ACCESS 0x40 -#define MUSB_TEST_FORCE_FS 0x20 -#define MUSB_TEST_FORCE_HS 0x10 -#define MUSB_TEST_PACKET 0x08 -#define MUSB_TEST_K 0x04 -#define MUSB_TEST_J 0x02 -#define MUSB_TEST_SE0_NAK 0x01 - -/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */ -#define MUSB_FIFOSZ_DPB 0x10 -/* Allocation size (8, 16, 32, ... 4096) */ -#define MUSB_FIFOSZ_SIZE 0x0f - -/* CSR0 */ -#define MUSB_CSR0_FLUSHFIFO 0x0100 -#define MUSB_CSR0_TXPKTRDY 0x0002 -#define MUSB_CSR0_RXPKTRDY 0x0001 - -/* CSR0 in Peripheral mode */ -#define MUSB_CSR0_P_SVDSETUPEND 0x0080 -#define MUSB_CSR0_P_SVDRXPKTRDY 0x0040 -#define MUSB_CSR0_P_SENDSTALL 0x0020 -#define MUSB_CSR0_P_SETUPEND 0x0010 -#define MUSB_CSR0_P_DATAEND 0x0008 -#define MUSB_CSR0_P_SENTSTALL 0x0004 - -/* CSR0 in Host mode */ -#define MUSB_CSR0_H_DIS_PING 0x0800 -#define MUSB_CSR0_H_WR_DATATOGGLE 0x0400 /* Set to allow setting: */ -#define MUSB_CSR0_H_DATATOGGLE 0x0200 /* Data toggle control */ -#define MUSB_CSR0_H_NAKTIMEOUT 0x0080 -#define MUSB_CSR0_H_STATUSPKT 0x0040 -#define MUSB_CSR0_H_REQPKT 0x0020 -#define MUSB_CSR0_H_ERROR 0x0010 -#define MUSB_CSR0_H_SETUPPKT 0x0008 -#define MUSB_CSR0_H_RXSTALL 0x0004 - -/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */ -#define MUSB_CSR0_P_WZC_BITS \ - (MUSB_CSR0_P_SENTSTALL) -#define MUSB_CSR0_H_WZC_BITS \ - (MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \ - | MUSB_CSR0_RXPKTRDY) - -/* TxType/RxType */ -#define MUSB_TYPE_SPEED 0xc0 -#define MUSB_TYPE_SPEED_SHIFT 6 -#define MUSB_TYPE_SPEED_HIGH 1 -#define MUSB_TYPE_SPEED_FULL 2 -#define MUSB_TYPE_SPEED_LOW 3 -#define MUSB_TYPE_PROTO 0x30 /* Implicitly zero for ep0 */ -#define MUSB_TYPE_PROTO_SHIFT 4 -#define MUSB_TYPE_REMOTE_END 0xf /* Implicitly zero for ep0 */ -#define MUSB_TYPE_PROTO_BULK 2 -#define MUSB_TYPE_PROTO_INTR 3 - -/* CONFIGDATA */ -#define MUSB_CONFIGDATA_MPRXE 0x80 /* Auto bulk pkt combining */ -#define MUSB_CONFIGDATA_MPTXE 0x40 /* Auto bulk pkt splitting */ -#define MUSB_CONFIGDATA_BIGENDIAN 0x20 -#define MUSB_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */ -#define MUSB_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */ -#define MUSB_CONFIGDATA_DYNFIFO 0x04 /* Dynamic FIFO sizing */ -#define MUSB_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */ -#define MUSB_CONFIGDATA_UTMIDW 0x01 /* Data width 0/1 => 8/16bits */ - -/* TXCSR in Peripheral and Host mode */ -#define MUSB_TXCSR_AUTOSET 0x8000 -#define MUSB_TXCSR_MODE 0x2000 -#define MUSB_TXCSR_DMAENAB 0x1000 -#define MUSB_TXCSR_FRCDATATOG 0x0800 -#define MUSB_TXCSR_DMAMODE 0x0400 -#define MUSB_TXCSR_CLRDATATOG 0x0040 -#define MUSB_TXCSR_FLUSHFIFO 0x0008 -#define MUSB_TXCSR_FIFONOTEMPTY 0x0002 -#define MUSB_TXCSR_TXPKTRDY 0x0001 - -/* TXCSR in Peripheral mode */ -#define MUSB_TXCSR_P_ISO 0x4000 -#define MUSB_TXCSR_P_INCOMPTX 0x0080 -#define MUSB_TXCSR_P_SENTSTALL 0x0020 -#define MUSB_TXCSR_P_SENDSTALL 0x0010 -#define MUSB_TXCSR_P_UNDERRUN 0x0004 - -/* TXCSR in Host mode */ -#define MUSB_TXCSR_H_WR_DATATOGGLE 0x0200 -#define MUSB_TXCSR_H_DATATOGGLE 0x0100 -#define MUSB_TXCSR_H_NAKTIMEOUT 0x0080 -#define MUSB_TXCSR_H_RXSTALL 0x0020 -#define MUSB_TXCSR_H_ERROR 0x0004 -#define MUSB_TXCSR_H_DATATOGGLE_SHIFT 8 - -/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */ -#define MUSB_TXCSR_P_WZC_BITS \ - (MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \ - | MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY) -#define MUSB_TXCSR_H_WZC_BITS \ - (MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \ - | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY) - -/* RXCSR in Peripheral and Host mode */ -#define MUSB_RXCSR_AUTOCLEAR 0x8000 -#define MUSB_RXCSR_DMAENAB 0x2000 -#define MUSB_RXCSR_DISNYET 0x1000 -#define MUSB_RXCSR_PID_ERR 0x1000 -#define MUSB_RXCSR_DMAMODE 0x0800 -#define MUSB_RXCSR_INCOMPRX 0x0100 -#define MUSB_RXCSR_CLRDATATOG 0x0080 -#define MUSB_RXCSR_FLUSHFIFO 0x0010 -#define MUSB_RXCSR_DATAERROR 0x0008 -#define MUSB_RXCSR_FIFOFULL 0x0002 -#define MUSB_RXCSR_RXPKTRDY 0x0001 - -/* RXCSR in Peripheral mode */ -#define MUSB_RXCSR_P_ISO 0x4000 -#define MUSB_RXCSR_P_SENTSTALL 0x0040 -#define MUSB_RXCSR_P_SENDSTALL 0x0020 -#define MUSB_RXCSR_P_OVERRUN 0x0004 - -/* RXCSR in Host mode */ -#define MUSB_RXCSR_H_AUTOREQ 0x4000 -#define MUSB_RXCSR_H_WR_DATATOGGLE 0x0400 -#define MUSB_RXCSR_H_DATATOGGLE 0x0200 -#define MUSB_RXCSR_H_RXSTALL 0x0040 -#define MUSB_RXCSR_H_REQPKT 0x0020 -#define MUSB_RXCSR_H_ERROR 0x0004 -#define MUSB_S_RXCSR_H_DATATOGGLE 9 - -/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */ -#define MUSB_RXCSR_P_WZC_BITS \ - (MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \ - | MUSB_RXCSR_RXPKTRDY) -#define MUSB_RXCSR_H_WZC_BITS \ - (MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \ - | MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY) - -/* HUBADDR */ -#define MUSB_HUBADDR_MULTI_TT 0x80 - -/* Endpoint configuration information. Note: The value of endpoint fifo size - * element should be either 8,16,32,64,128,256,512,1024,2048 or 4096. Other - * values are not supported - */ -struct musb_epinfo { - u8 epnum; /* endpoint number */ - u8 epdir; /* endpoint direction */ - u16 epsize; /* endpoint FIFO size */ -}; - -/* - * Platform specific MUSB configuration. Any platform using the musb - * functionality should create one instance of this structure in the - * platform specific file. - */ -struct musb_config { - struct musb_regs *regs; - u32 timeout; - u8 musb_speed; - u8 extvbus; -}; - -/* externally defined data */ -extern struct musb_config musb_cfg; -extern struct musb_regs *musbr; - -/* exported functions */ -extern void musb_start(void); -extern void musb_configure_ep(const struct musb_epinfo *epinfo, u8 cnt); -extern void write_fifo(u8 ep, u32 length, void *fifo_data); -extern void read_fifo(u8 ep, u32 length, void *fifo_data); - -static inline u8 musb_read_ulpi_buscontrol(struct musb_regs *musbr) -{ - return readb(&musbr->ulpi_busctl); -} -static inline void musb_write_ulpi_buscontrol(struct musb_regs *musbr, u8 val) -{ - writeb(val, &musbr->ulpi_busctl); -} - -#endif /* __MUSB_HDRC_DEFS_H__ */ diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h deleted file mode 100644 index 2c5e192ab21..00000000000 --- a/drivers/usb/musb/musb_debug.h +++ /dev/null @@ -1,191 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 2009 Wind River Systems, Inc. - * Tom Rix <Tom.Rix@windriver.com> - */ - -/* Define MUSB_DEBUG before including this file to get debug macros */ -#ifdef MUSB_DEBUG - -#define MUSB_FLAGS_PRINT(v, x, y) \ - if (((v) & MUSB_##x##_##y)) \ - serial_printf("\t\t"#y"\n") - -static inline void musb_print_pwr(u8 b) -{ - serial_printf("\tpower 0x%2.2x\n", b); - MUSB_FLAGS_PRINT(b, POWER, ISOUPDATE); - MUSB_FLAGS_PRINT(b, POWER, SOFTCONN); - MUSB_FLAGS_PRINT(b, POWER, HSENAB); - MUSB_FLAGS_PRINT(b, POWER, HSMODE); - MUSB_FLAGS_PRINT(b, POWER, RESET); - MUSB_FLAGS_PRINT(b, POWER, RESUME); - MUSB_FLAGS_PRINT(b, POWER, SUSPENDM); - MUSB_FLAGS_PRINT(b, POWER, ENSUSPEND); -} - -static inline void musb_print_csr0(u16 w) -{ - serial_printf("\tcsr0 0x%4.4x\n", w); - MUSB_FLAGS_PRINT(w, CSR0, FLUSHFIFO); - MUSB_FLAGS_PRINT(w, CSR0_P, SVDSETUPEND); - MUSB_FLAGS_PRINT(w, CSR0_P, SVDRXPKTRDY); - MUSB_FLAGS_PRINT(w, CSR0_P, SENDSTALL); - MUSB_FLAGS_PRINT(w, CSR0_P, SETUPEND); - MUSB_FLAGS_PRINT(w, CSR0_P, DATAEND); - MUSB_FLAGS_PRINT(w, CSR0_P, SENTSTALL); - MUSB_FLAGS_PRINT(w, CSR0, TXPKTRDY); - MUSB_FLAGS_PRINT(w, CSR0, RXPKTRDY); -} - -static inline void musb_print_intrusb(u8 b) -{ - serial_printf("\tintrusb 0x%2.2x\n", b); - MUSB_FLAGS_PRINT(b, INTR, VBUSERROR); - MUSB_FLAGS_PRINT(b, INTR, SESSREQ); - MUSB_FLAGS_PRINT(b, INTR, DISCONNECT); - MUSB_FLAGS_PRINT(b, INTR, CONNECT); - MUSB_FLAGS_PRINT(b, INTR, SOF); - MUSB_FLAGS_PRINT(b, INTR, RESUME); - MUSB_FLAGS_PRINT(b, INTR, SUSPEND); - - if (b & MUSB_INTR_BABBLE) - serial_printf("\t\tMUSB_INTR_RESET or MUSB_INTR_BABBLE\n"); - -} - -static inline void musb_print_intrtx(u16 w) -{ - serial_printf("\tintrtx 0x%4.4x\n", w); -} - -static inline void musb_print_intrrx(u16 w) -{ - serial_printf("\tintrx 0x%4.4x\n", w); -} - -static inline void musb_print_devctl(u8 b) -{ - serial_printf("\tdevctl 0x%2.2x\n", b); - if (b & MUSB_DEVCTL_BDEVICE) - serial_printf("\t\tB device\n"); - else - serial_printf("\t\tA device\n"); - if (b & MUSB_DEVCTL_FSDEV) - serial_printf("\t\tFast Device -(host mode)\n"); - if (b & MUSB_DEVCTL_LSDEV) - serial_printf("\t\tSlow Device -(host mode)\n"); - if (b & MUSB_DEVCTL_HM) - serial_printf("\t\tHost mode\n"); - else - serial_printf("\t\tPeripherial mode\n"); - if (b & MUSB_DEVCTL_HR) - serial_printf("\t\tHost request started(B device)\n"); - else - serial_printf("\t\tHost request finished(B device)\n"); - if (b & MUSB_DEVCTL_BDEVICE) { - if (b & MUSB_DEVCTL_SESSION) - serial_printf("\t\tStart of session(B device)\n"); - else - serial_printf("\t\tEnd of session(B device)\n"); - } else { - if (b & MUSB_DEVCTL_SESSION) - serial_printf("\t\tStart of session(A device)\n"); - else - serial_printf("\t\tEnd of session(A device)\n"); - } -} - -static inline void musb_print_config(u8 b) -{ - serial_printf("\tconfig 0x%2.2x\n", b); - if (b & MUSB_CONFIGDATA_MPRXE) - serial_printf("\t\tAuto combine rx bulk packets\n"); - if (b & MUSB_CONFIGDATA_MPTXE) - serial_printf("\t\tAuto split tx bulk packets\n"); - if (b & MUSB_CONFIGDATA_BIGENDIAN) - serial_printf("\t\tBig Endian ordering\n"); - else - serial_printf("\t\tLittle Endian ordering\n"); - if (b & MUSB_CONFIGDATA_HBRXE) - serial_printf("\t\tHigh speed rx iso endpoint\n"); - if (b & MUSB_CONFIGDATA_HBTXE) - serial_printf("\t\tHigh speed tx iso endpoint\n"); - if (b & MUSB_CONFIGDATA_DYNFIFO) - serial_printf("\t\tDynamic fifo sizing\n"); - if (b & MUSB_CONFIGDATA_SOFTCONE) - serial_printf("\t\tSoft Connect\n"); - if (b & MUSB_CONFIGDATA_UTMIDW) - serial_printf("\t\t16 bit data width\n"); - else - serial_printf("\t\t8 bit data width\n"); -} - -static inline void musb_print_rxmaxp(u16 w) -{ - serial_printf("\trxmaxp 0x%4.4x\n", w); -} - -static inline void musb_print_rxcsr(u16 w) -{ - serial_printf("\trxcsr 0x%4.4x\n", w); - MUSB_FLAGS_PRINT(w, RXCSR, AUTOCLEAR); - MUSB_FLAGS_PRINT(w, RXCSR, DMAENAB); - MUSB_FLAGS_PRINT(w, RXCSR, DISNYET); - MUSB_FLAGS_PRINT(w, RXCSR, PID_ERR); - MUSB_FLAGS_PRINT(w, RXCSR, DMAMODE); - MUSB_FLAGS_PRINT(w, RXCSR, CLRDATATOG); - MUSB_FLAGS_PRINT(w, RXCSR, FLUSHFIFO); - MUSB_FLAGS_PRINT(w, RXCSR, DATAERROR); - MUSB_FLAGS_PRINT(w, RXCSR, FIFOFULL); - MUSB_FLAGS_PRINT(w, RXCSR, RXPKTRDY); - MUSB_FLAGS_PRINT(w, RXCSR_P, SENTSTALL); - MUSB_FLAGS_PRINT(w, RXCSR_P, SENDSTALL); - MUSB_FLAGS_PRINT(w, RXCSR_P, OVERRUN); - - if (w & MUSB_RXCSR_P_ISO) - serial_printf("\t\tiso mode\n"); - else - serial_printf("\t\tbulk mode\n"); - -} - -static inline void musb_print_txmaxp(u16 w) -{ - serial_printf("\ttxmaxp 0x%4.4x\n", w); -} - -static inline void musb_print_txcsr(u16 w) -{ - serial_printf("\ttxcsr 0x%4.4x\n", w); - MUSB_FLAGS_PRINT(w, TXCSR, TXPKTRDY); - MUSB_FLAGS_PRINT(w, TXCSR, FIFONOTEMPTY); - MUSB_FLAGS_PRINT(w, TXCSR, FLUSHFIFO); - MUSB_FLAGS_PRINT(w, TXCSR, CLRDATATOG); - MUSB_FLAGS_PRINT(w, TXCSR_P, UNDERRUN); - MUSB_FLAGS_PRINT(w, TXCSR_P, SENTSTALL); - MUSB_FLAGS_PRINT(w, TXCSR_P, SENDSTALL); - - if (w & MUSB_TXCSR_MODE) - serial_printf("\t\tTX mode\n"); - else - serial_printf("\t\tRX mode\n"); -} - -#else - -/* stubs */ - -#define musb_print_pwr(b) -#define musb_print_csr0(w) -#define musb_print_intrusb(b) -#define musb_print_intrtx(w) -#define musb_print_intrrx(w) -#define musb_print_devctl(b) -#define musb_print_config(b) -#define musb_print_rxmaxp(w) -#define musb_print_rxcsr(w) -#define musb_print_txmaxp(w) -#define musb_print_txcsr(w) - -#endif /* MUSB_DEBUG */ diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c deleted file mode 100644 index c95c6a48281..00000000000 --- a/drivers/usb/musb/musb_hcd.c +++ /dev/null @@ -1,1161 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Mentor USB OTG Core host controller driver. - * - * Copyright (c) 2008 Texas Instruments - * - * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments - */ - -#include <log.h> -#include <usb.h> -#include <linux/delay.h> -#include "musb_hcd.h" - -/* MSC control transfers */ -#define USB_MSC_BBB_RESET 0xFF -#define USB_MSC_BBB_GET_MAX_LUN 0xFE - -/* Endpoint configuration information */ -static const struct musb_epinfo epinfo[3] = { - {MUSB_BULK_EP, 1, 512}, /* EP1 - Bluk Out - 512 Bytes */ - {MUSB_BULK_EP, 0, 512}, /* EP1 - Bluk In - 512 Bytes */ - {MUSB_INTR_EP, 0, 64} /* EP2 - Interrupt IN - 64 Bytes */ -}; - -/* --- Virtual Root Hub ---------------------------------------------------- */ -#ifdef MUSB_NO_MULTIPOINT -static int rh_devnum; -static u32 port_status; - -#include <usbroothubdes.h> - -#endif - -/* - * This function writes the data toggle value. - */ -static void write_toggle(struct usb_device *dev, u8 ep, u8 dir_out) -{ - u16 toggle = usb_gettoggle(dev, ep, dir_out); - u16 csr; - - if (dir_out) { - csr = readw(&musbr->txcsr); - if (!toggle) { - if (csr & MUSB_TXCSR_MODE) - csr = MUSB_TXCSR_CLRDATATOG; - else - csr = 0; - writew(csr, &musbr->txcsr); - } else { - csr |= MUSB_TXCSR_H_WR_DATATOGGLE; - writew(csr, &musbr->txcsr); - csr |= (toggle << MUSB_TXCSR_H_DATATOGGLE_SHIFT); - writew(csr, &musbr->txcsr); - } - } else { - if (!toggle) { - csr = readw(&musbr->txcsr); - if (csr & MUSB_TXCSR_MODE) - csr = MUSB_RXCSR_CLRDATATOG; - else - csr = 0; - writew(csr, &musbr->rxcsr); - } else { - csr = readw(&musbr->rxcsr); - csr |= MUSB_RXCSR_H_WR_DATATOGGLE; - writew(csr, &musbr->rxcsr); - csr |= (toggle << MUSB_S_RXCSR_H_DATATOGGLE); - writew(csr, &musbr->rxcsr); - } - } -} - -/* - * This function checks if RxStall has occurred on the endpoint. If a RxStall - * has occurred, the RxStall is cleared and 1 is returned. If RxStall has - * not occurred, 0 is returned. - */ -static u8 check_stall(u8 ep, u8 dir_out) -{ - u16 csr; - - /* For endpoint 0 */ - if (!ep) { - csr = readw(&musbr->txcsr); - if (csr & MUSB_CSR0_H_RXSTALL) { - csr &= ~MUSB_CSR0_H_RXSTALL; - writew(csr, &musbr->txcsr); - return 1; - } - } else { /* For non-ep0 */ - if (dir_out) { /* is it tx ep */ - csr = readw(&musbr->txcsr); - if (csr & MUSB_TXCSR_H_RXSTALL) { - csr &= ~MUSB_TXCSR_H_RXSTALL; - writew(csr, &musbr->txcsr); - return 1; - } - } else { /* is it rx ep */ - csr = readw(&musbr->rxcsr); - if (csr & MUSB_RXCSR_H_RXSTALL) { - csr &= ~MUSB_RXCSR_H_RXSTALL; - writew(csr, &musbr->rxcsr); - return 1; - } - } - } - return 0; -} - -/* - * waits until ep0 is ready. Returns 0 if ep is ready, -1 for timeout - * error and -2 for stall. - */ -static int wait_until_ep0_ready(struct usb_device *dev, u32 bit_mask) -{ - u16 csr; - int result = 1; - int timeout = MUSB_TIMEOUT; - - while (result > 0) { - csr = readw(&musbr->txcsr); - if (csr & MUSB_CSR0_H_ERROR) { - csr &= ~MUSB_CSR0_H_ERROR; - writew(csr, &musbr->txcsr); - dev->status = USB_ST_CRC_ERR; - result = -1; - break; - } - - switch (bit_mask) { - case MUSB_CSR0_TXPKTRDY: - if (!(csr & MUSB_CSR0_TXPKTRDY)) { - if (check_stall(MUSB_CONTROL_EP, 0)) { - dev->status = USB_ST_STALLED; - result = -2; - } else - result = 0; - } - break; - - case MUSB_CSR0_RXPKTRDY: - if (check_stall(MUSB_CONTROL_EP, 0)) { - dev->status = USB_ST_STALLED; - result = -2; - } else - if (csr & MUSB_CSR0_RXPKTRDY) - result = 0; - break; - - case MUSB_CSR0_H_REQPKT: - if (!(csr & MUSB_CSR0_H_REQPKT)) { - if (check_stall(MUSB_CONTROL_EP, 0)) { - dev->status = USB_ST_STALLED; - result = -2; - } else - result = 0; - } - break; - } - - /* Check the timeout */ - if (--timeout) - udelay(1); - else { - dev->status = USB_ST_CRC_ERR; - result = -1; - break; - } - } - - return result; -} - -/* - * waits until tx ep is ready. Returns 1 when ep is ready and 0 on error. - */ -static int wait_until_txep_ready(struct usb_device *dev, u8 ep) -{ - u16 csr; - int timeout = MUSB_TIMEOUT; - - do { - if (check_stall(ep, 1)) { - dev->status = USB_ST_STALLED; - return 0; - } - - csr = readw(&musbr->txcsr); - if (csr & MUSB_TXCSR_H_ERROR) { - dev->status = USB_ST_CRC_ERR; - return 0; - } - - /* Check the timeout */ - if (--timeout) - udelay(1); - else { - dev->status = USB_ST_CRC_ERR; - return -1; - } - - } while (csr & MUSB_TXCSR_TXPKTRDY); - return 1; -} - -/* - * waits until rx ep is ready. Returns 1 when ep is ready and 0 on error. - */ -static int wait_until_rxep_ready(struct usb_device *dev, u8 ep) -{ - u16 csr; - int timeout = MUSB_TIMEOUT; - - do { - if (check_stall(ep, 0)) { - dev->status = USB_ST_STALLED; - return 0; - } - - csr = readw(&musbr->rxcsr); - if (csr & MUSB_RXCSR_H_ERROR) { - dev->status = USB_ST_CRC_ERR; - return 0; - } - - /* Check the timeout */ - if (--timeout) - udelay(1); - else { - dev->status = USB_ST_CRC_ERR; - return -1; - } - - } while (!(csr & MUSB_RXCSR_RXPKTRDY)); - return 1; -} - -/* - * This function performs the setup phase of the control transfer - */ -static int ctrlreq_setup_phase(struct usb_device *dev, struct devrequest *setup) -{ - int result; - u16 csr; - - /* write the control request to ep0 fifo */ - write_fifo(MUSB_CONTROL_EP, sizeof(struct devrequest), (void *)setup); - - /* enable transfer of setup packet */ - csr = readw(&musbr->txcsr); - csr |= (MUSB_CSR0_TXPKTRDY|MUSB_CSR0_H_SETUPPKT); - writew(csr, &musbr->txcsr); - - /* wait until the setup packet is transmitted */ - result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY); - dev->act_len = 0; - return result; -} - -/* - * This function handles the control transfer in data phase - */ -static int ctrlreq_in_data_phase(struct usb_device *dev, u32 len, void *buffer) -{ - u16 csr; - u32 rxlen = 0; - u32 nextlen = 0; - u8 maxpktsize = (1 << dev->maxpacketsize) * 8; - u8 *rxbuff = (u8 *)buffer; - u8 rxedlength; - int result; - - while (rxlen < len) { - /* Determine the next read length */ - nextlen = ((len-rxlen) > maxpktsize) ? maxpktsize : (len-rxlen); - - /* Set the ReqPkt bit */ - csr = readw(&musbr->txcsr); - writew(csr | MUSB_CSR0_H_REQPKT, &musbr->txcsr); - result = wait_until_ep0_ready(dev, MUSB_CSR0_RXPKTRDY); - if (result < 0) - return result; - - /* Actual number of bytes received by usb */ - rxedlength = readb(&musbr->rxcount); - - /* Read the data from the RxFIFO */ - read_fifo(MUSB_CONTROL_EP, rxedlength, &rxbuff[rxlen]); - - /* Clear the RxPktRdy Bit */ - csr = readw(&musbr->txcsr); - csr &= ~MUSB_CSR0_RXPKTRDY; - writew(csr, &musbr->txcsr); - - /* short packet? */ - if (rxedlength != nextlen) { - dev->act_len += rxedlength; - break; - } - rxlen += nextlen; - dev->act_len = rxlen; - } - return 0; -} - -/* - * This function handles the control transfer out data phase - */ -static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer) -{ - u16 csr; - u32 txlen = 0; - u32 nextlen = 0; - u8 maxpktsize = (1 << dev->maxpacketsize) * 8; - u8 *txbuff = (u8 *)buffer; - int result = 0; - - while (txlen < len) { - /* Determine the next write length */ - nextlen = ((len-txlen) > maxpktsize) ? maxpktsize : (len-txlen); - - /* Load the data to send in FIFO */ - write_fifo(MUSB_CONTROL_EP, txlen, &txbuff[txlen]); - - /* Set TXPKTRDY bit */ - csr = readw(&musbr->txcsr); - - csr |= MUSB_CSR0_TXPKTRDY; - csr |= MUSB_CSR0_H_DIS_PING; - writew(csr, &musbr->txcsr); - result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY); - if (result < 0) - break; - - txlen += nextlen; - dev->act_len = txlen; - } - return result; -} - -/* - * This function handles the control transfer out status phase - */ -static int ctrlreq_out_status_phase(struct usb_device *dev) -{ - u16 csr; - int result; - - /* Set the StatusPkt bit */ - csr = readw(&musbr->txcsr); - csr |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_H_STATUSPKT); - csr |= MUSB_CSR0_H_DIS_PING; - writew(csr, &musbr->txcsr); - - /* Wait until TXPKTRDY bit is cleared */ - result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY); - return result; -} - -/* - * This function handles the control transfer in status phase - */ -static int ctrlreq_in_status_phase(struct usb_device *dev) -{ - u16 csr; - int result; - - /* Set the StatusPkt bit and ReqPkt bit */ - csr = MUSB_CSR0_H_REQPKT | MUSB_CSR0_H_STATUSPKT; - csr |= MUSB_CSR0_H_DIS_PING; - writew(csr, &musbr->txcsr); - result = wait_until_ep0_ready(dev, MUSB_CSR0_H_REQPKT); - - /* clear StatusPkt bit and RxPktRdy bit */ - csr = readw(&musbr->txcsr); - csr &= ~(MUSB_CSR0_RXPKTRDY | MUSB_CSR0_H_STATUSPKT); - writew(csr, &musbr->txcsr); - return result; -} - -/* - * determines the speed of the device (High/Full/Slow) - */ -static u8 get_dev_speed(struct usb_device *dev) -{ - return (dev->speed == USB_SPEED_HIGH) ? MUSB_TYPE_SPEED_HIGH : - ((dev->speed == USB_SPEED_LOW) ? MUSB_TYPE_SPEED_LOW : - MUSB_TYPE_SPEED_FULL); -} - -/* - * configure the hub address and the port address. - */ -static void config_hub_port(struct usb_device *dev, u8 ep) -{ - u8 chid; - u8 hub; - - /* Find out the nearest parent which is high speed */ - while (dev->parent->parent != NULL) - if (get_dev_speed(dev->parent) != MUSB_TYPE_SPEED_HIGH) - dev = dev->parent; - else - break; - - /* determine the port address at that hub */ - hub = dev->parent->devnum; - for (chid = 0; chid < USB_MAXCHILDREN; chid++) - if (dev->parent->children[chid] == dev) - break; - -#ifndef MUSB_NO_MULTIPOINT - /* configure the hub address and the port address */ - writeb(hub, &musbr->tar[ep].txhubaddr); - writeb((chid + 1), &musbr->tar[ep].txhubport); - writeb(hub, &musbr->tar[ep].rxhubaddr); - writeb((chid + 1), &musbr->tar[ep].rxhubport); -#endif -} - -#ifdef MUSB_NO_MULTIPOINT - -static void musb_port_reset(int do_reset) -{ - u8 power = readb(&musbr->power); - - if (do_reset) { - power &= 0xf0; - writeb(power | MUSB_POWER_RESET, &musbr->power); - port_status |= USB_PORT_STAT_RESET; - port_status &= ~USB_PORT_STAT_ENABLE; - udelay(30000); - } else { - writeb(power & ~MUSB_POWER_RESET, &musbr->power); - - power = readb(&musbr->power); - if (power & MUSB_POWER_HSMODE) - port_status |= USB_PORT_STAT_HIGH_SPEED; - - port_status &= ~(USB_PORT_STAT_RESET | (USB_PORT_STAT_C_CONNECTION << 16)); - port_status |= USB_PORT_STAT_ENABLE - | (USB_PORT_STAT_C_RESET << 16) - | (USB_PORT_STAT_C_ENABLE << 16); - } -} - -/* - * root hub control - */ -static int musb_submit_rh_msg(struct usb_device *dev, unsigned long pipe, - void *buffer, int transfer_len, - struct devrequest *cmd) -{ - int leni = transfer_len; - int len = 0; - int stat = 0; - u32 datab[4]; - const u8 *data_buf = (u8 *) datab; - u16 bmRType_bReq; - u16 wValue; - u16 wIndex; - u16 wLength; - u16 int_usb; - - if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) { - debug("Root-Hub submit IRQ: NOT implemented\n"); - return 0; - } - - bmRType_bReq = cmd->requesttype | (cmd->request << 8); - wValue = swap_16(cmd->value); - wIndex = swap_16(cmd->index); - wLength = swap_16(cmd->length); - - debug("--- HUB ----------------------------------------\n"); - debug("submit rh urb, req=%x val=%#x index=%#x len=%d\n", - bmRType_bReq, wValue, wIndex, wLength); - debug("------------------------------------------------\n"); - - switch (bmRType_bReq) { - case RH_GET_STATUS: - debug("RH_GET_STATUS\n"); - - *(__u16 *) data_buf = swap_16(1); - len = 2; - break; - - case RH_GET_STATUS | RH_INTERFACE: - debug("RH_GET_STATUS | RH_INTERFACE\n"); - - *(__u16 *) data_buf = swap_16(0); - len = 2; - break; - - case RH_GET_STATUS | RH_ENDPOINT: - debug("RH_GET_STATUS | RH_ENDPOINT\n"); - - *(__u16 *) data_buf = swap_16(0); - len = 2; - break; - - case RH_GET_STATUS | RH_CLASS: - debug("RH_GET_STATUS | RH_CLASS\n"); - - *(__u32 *) data_buf = swap_32(0); - len = 4; - break; - - case RH_GET_STATUS | RH_OTHER | RH_CLASS: - debug("RH_GET_STATUS | RH_OTHER | RH_CLASS\n"); - - int_usb = readw(&musbr->intrusb); - if (int_usb & MUSB_INTR_CONNECT) { - port_status |= USB_PORT_STAT_CONNECTION - | (USB_PORT_STAT_C_CONNECTION << 16); - port_status |= USB_PORT_STAT_HIGH_SPEED - | USB_PORT_STAT_ENABLE; - } - - if (port_status & USB_PORT_STAT_RESET) - musb_port_reset(0); - - *(__u32 *) data_buf = swap_32(port_status); - len = 4; - break; - - case RH_CLEAR_FEATURE | RH_ENDPOINT: - debug("RH_CLEAR_FEATURE | RH_ENDPOINT\n"); - - switch (wValue) { - case RH_ENDPOINT_STALL: - debug("C_HUB_ENDPOINT_STALL\n"); - len = 0; - break; - } - port_status &= ~(1 << wValue); - break; - - case RH_CLEAR_FEATURE | RH_CLASS: - debug("RH_CLEAR_FEATURE | RH_CLASS\n"); - - switch (wValue) { - case RH_C_HUB_LOCAL_POWER: - debug("C_HUB_LOCAL_POWER\n"); - len = 0; - break; - - case RH_C_HUB_OVER_CURRENT: - debug("C_HUB_OVER_CURRENT\n"); - len = 0; - break; - } - port_status &= ~(1 << wValue); - break; - - case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: - debug("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS\n"); - - switch (wValue) { - case RH_PORT_ENABLE: - len = 0; - break; - - case RH_PORT_SUSPEND: - len = 0; - break; - - case RH_PORT_POWER: - len = 0; - break; - - case RH_C_PORT_CONNECTION: - len = 0; - break; - - case RH_C_PORT_ENABLE: - len = 0; - break; - - case RH_C_PORT_SUSPEND: - len = 0; - break; - - case RH_C_PORT_OVER_CURRENT: - len = 0; - break; - - case RH_C_PORT_RESET: - len = 0; - break; - - default: - debug("invalid wValue\n"); - stat = USB_ST_STALLED; - } - - port_status &= ~(1 << wValue); - break; - - case RH_SET_FEATURE | RH_OTHER | RH_CLASS: - debug("RH_SET_FEATURE | RH_OTHER | RH_CLASS\n"); - - switch (wValue) { - case RH_PORT_SUSPEND: - len = 0; - break; - - case RH_PORT_RESET: - musb_port_reset(1); - len = 0; - break; - - case RH_PORT_POWER: - len = 0; - break; - - case RH_PORT_ENABLE: - len = 0; - break; - - default: - debug("invalid wValue\n"); - stat = USB_ST_STALLED; - } - - port_status |= 1 << wValue; - break; - - case RH_SET_ADDRESS: - debug("RH_SET_ADDRESS\n"); - - rh_devnum = wValue; - len = 0; - break; - - case RH_GET_DESCRIPTOR: - debug("RH_GET_DESCRIPTOR: %x, %d\n", wValue, wLength); - - switch (wValue) { - case (USB_DT_DEVICE << 8): /* device descriptor */ - len = min_t(unsigned int, - leni, min_t(unsigned int, - sizeof(root_hub_dev_des), - wLength)); - data_buf = root_hub_dev_des; - break; - - case (USB_DT_CONFIG << 8): /* configuration descriptor */ - len = min_t(unsigned int, - leni, min_t(unsigned int, - sizeof(root_hub_config_des), - wLength)); - data_buf = root_hub_config_des; - break; - - case ((USB_DT_STRING << 8) | 0x00): /* string 0 descriptors */ - len = min_t(unsigned int, - leni, min_t(unsigned int, - sizeof(root_hub_str_index0), - wLength)); - data_buf = root_hub_str_index0; - break; - - case ((USB_DT_STRING << 8) | 0x01): /* string 1 descriptors */ - len = min_t(unsigned int, - leni, min_t(unsigned int, - sizeof(root_hub_str_index1), - wLength)); - data_buf = root_hub_str_index1; - break; - - default: - debug("invalid wValue\n"); - stat = USB_ST_STALLED; - } - - break; - - case RH_GET_DESCRIPTOR | RH_CLASS: { - u8 *_data_buf = (u8 *) datab; - debug("RH_GET_DESCRIPTOR | RH_CLASS\n"); - - _data_buf[0] = 0x09; /* min length; */ - _data_buf[1] = 0x29; - _data_buf[2] = 0x1; /* 1 port */ - _data_buf[3] = 0x01; /* per-port power switching */ - _data_buf[3] |= 0x10; /* no overcurrent reporting */ - - /* Corresponds to data_buf[4-7] */ - _data_buf[4] = 0; - _data_buf[5] = 5; - _data_buf[6] = 0; - _data_buf[7] = 0x02; - _data_buf[8] = 0xff; - - len = min_t(unsigned int, leni, - min_t(unsigned int, data_buf[0], wLength)); - break; - } - - case RH_GET_CONFIGURATION: - debug("RH_GET_CONFIGURATION\n"); - - *(__u8 *) data_buf = 0x01; - len = 1; - break; - - case RH_SET_CONFIGURATION: - debug("RH_SET_CONFIGURATION\n"); - - len = 0; - break; - - default: - debug("*** *** *** unsupported root hub command *** *** ***\n"); - stat = USB_ST_STALLED; - } - - len = min_t(int, len, leni); - if (buffer != data_buf) - memcpy(buffer, data_buf, len); - - dev->act_len = len; - dev->status = stat; - debug("dev act_len %d, status %lu\n", dev->act_len, dev->status); - - return stat; -} - -static void musb_rh_init(void) -{ - rh_devnum = 0; - port_status = 0; -} - -#else - -static void musb_rh_init(void) {} - -#endif - -/* - * do a control transfer - */ -int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int len, struct devrequest *setup) -{ - int devnum = usb_pipedevice(pipe); - u8 devspeed; - -#ifdef MUSB_NO_MULTIPOINT - /* Control message is for the HUB? */ - if (devnum == rh_devnum) { - int stat = musb_submit_rh_msg(dev, pipe, buffer, len, setup); - if (stat) - return stat; - } -#endif - - /* select control endpoint */ - writeb(MUSB_CONTROL_EP, &musbr->index); - readw(&musbr->txcsr); - -#ifndef MUSB_NO_MULTIPOINT - /* target addr and (for multipoint) hub addr/port */ - writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr); - writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr); -#endif - - /* configure the hub address and the port number as required */ - devspeed = get_dev_speed(dev); - if ((musb_ishighspeed()) && (dev->parent != NULL) && - (devspeed != MUSB_TYPE_SPEED_HIGH)) { - config_hub_port(dev, MUSB_CONTROL_EP); - writeb(devspeed << 6, &musbr->txtype); - } else { - writeb(musb_cfg.musb_speed << 6, &musbr->txtype); -#ifndef MUSB_NO_MULTIPOINT - writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubaddr); - writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubport); - writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubaddr); - writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubport); -#endif - } - - /* Control transfer setup phase */ - if (ctrlreq_setup_phase(dev, setup) < 0) - return 0; - - switch (setup->request) { - case USB_REQ_GET_DESCRIPTOR: - case USB_REQ_GET_CONFIGURATION: - case USB_REQ_GET_INTERFACE: - case USB_REQ_GET_STATUS: - case USB_MSC_BBB_GET_MAX_LUN: - /* control transfer in-data-phase */ - if (ctrlreq_in_data_phase(dev, len, buffer) < 0) - return 0; - /* control transfer out-status-phase */ - if (ctrlreq_out_status_phase(dev) < 0) - return 0; - break; - - case USB_REQ_SET_ADDRESS: - case USB_REQ_SET_CONFIGURATION: - case USB_REQ_SET_FEATURE: - case USB_REQ_SET_INTERFACE: - case USB_REQ_CLEAR_FEATURE: - case USB_MSC_BBB_RESET: - /* control transfer in status phase */ - if (ctrlreq_in_status_phase(dev) < 0) - return 0; - break; - - case USB_REQ_SET_DESCRIPTOR: - /* control transfer out data phase */ - if (ctrlreq_out_data_phase(dev, len, buffer) < 0) - return 0; - /* control transfer in status phase */ - if (ctrlreq_in_status_phase(dev) < 0) - return 0; - break; - - default: - /* unhandled control transfer */ - return -1; - } - - dev->status = 0; - dev->act_len = len; - -#ifdef MUSB_NO_MULTIPOINT - /* Set device address to USB_FADDR register */ - if (setup->request == USB_REQ_SET_ADDRESS) - writeb(dev->devnum, &musbr->faddr); -#endif - - return len; -} - -/* - * do a bulk transfer - */ -int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, - void *buffer, int len) -{ - int dir_out = usb_pipeout(pipe); - int ep = usb_pipeendpoint(pipe); -#ifndef MUSB_NO_MULTIPOINT - int devnum = usb_pipedevice(pipe); -#endif - u8 type; - u16 csr; - u32 txlen = 0; - u32 nextlen = 0; - u8 devspeed; - - /* select bulk endpoint */ - writeb(MUSB_BULK_EP, &musbr->index); - -#ifndef MUSB_NO_MULTIPOINT - /* write the address of the device */ - if (dir_out) - writeb(devnum, &musbr->tar[MUSB_BULK_EP].txfuncaddr); - else - writeb(devnum, &musbr->tar[MUSB_BULK_EP].rxfuncaddr); -#endif - - /* configure the hub address and the port number as required */ - devspeed = get_dev_speed(dev); - if ((musb_ishighspeed()) && (dev->parent != NULL) && - (devspeed != MUSB_TYPE_SPEED_HIGH)) { - /* - * MUSB is in high speed and the destination device is full - * speed device. So configure the hub address and port - * address registers. - */ - config_hub_port(dev, MUSB_BULK_EP); - } else { -#ifndef MUSB_NO_MULTIPOINT - if (dir_out) { - writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr); - writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport); - } else { - writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr); - writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport); - } -#endif - devspeed = musb_cfg.musb_speed; - } - - /* Write the saved toggle bit value */ - write_toggle(dev, ep, dir_out); - - if (dir_out) { /* bulk-out transfer */ - /* Program the TxType register */ - type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | - (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) | - (ep & MUSB_TYPE_REMOTE_END); - writeb(type, &musbr->txtype); - - /* Write maximum packet size to the TxMaxp register */ - writew(dev->epmaxpacketout[ep], &musbr->txmaxp); - while (txlen < len) { - nextlen = ((len-txlen) < dev->epmaxpacketout[ep]) ? - (len-txlen) : dev->epmaxpacketout[ep]; - - /* Write the data to the FIFO */ - write_fifo(MUSB_BULK_EP, nextlen, - (void *)(((u8 *)buffer) + txlen)); - - /* Set the TxPktRdy bit */ - csr = readw(&musbr->txcsr); - writew(csr | MUSB_TXCSR_TXPKTRDY, &musbr->txcsr); - - /* Wait until the TxPktRdy bit is cleared */ - if (wait_until_txep_ready(dev, MUSB_BULK_EP) != 1) { - readw(&musbr->txcsr); - usb_settoggle(dev, ep, dir_out, - (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1); - dev->act_len = txlen; - return 0; - } - txlen += nextlen; - } - - /* Keep a copy of the data toggle bit */ - csr = readw(&musbr->txcsr); - usb_settoggle(dev, ep, dir_out, - (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1); - } else { /* bulk-in transfer */ - /* Write the saved toggle bit value */ - write_toggle(dev, ep, dir_out); - - /* Program the RxType register */ - type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | - (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) | - (ep & MUSB_TYPE_REMOTE_END); - writeb(type, &musbr->rxtype); - - /* Write the maximum packet size to the RxMaxp register */ - writew(dev->epmaxpacketin[ep], &musbr->rxmaxp); - while (txlen < len) { - nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ? - (len-txlen) : dev->epmaxpacketin[ep]; - - /* Set the ReqPkt bit */ - csr = readw(&musbr->rxcsr); - writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); - - /* Wait until the RxPktRdy bit is set */ - if (wait_until_rxep_ready(dev, MUSB_BULK_EP) != 1) { - csr = readw(&musbr->rxcsr); - usb_settoggle(dev, ep, dir_out, - (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); - csr &= ~MUSB_RXCSR_RXPKTRDY; - writew(csr, &musbr->rxcsr); - dev->act_len = txlen; - return 0; - } - - /* Read the data from the FIFO */ - read_fifo(MUSB_BULK_EP, nextlen, - (void *)(((u8 *)buffer) + txlen)); - - /* Clear the RxPktRdy bit */ - csr = readw(&musbr->rxcsr); - csr &= ~MUSB_RXCSR_RXPKTRDY; - writew(csr, &musbr->rxcsr); - txlen += nextlen; - } - - /* Keep a copy of the data toggle bit */ - csr = readw(&musbr->rxcsr); - usb_settoggle(dev, ep, dir_out, - (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); - } - - /* bulk transfer is complete */ - dev->status = 0; - dev->act_len = len; - return 0; -} - -/* - * This function initializes the usb controller module. - */ -int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) -{ - u8 power; - u32 timeout; - - musb_rh_init(); - - if (musb_platform_init() == -1) - return -1; - - /* Configure all the endpoint FIFO's and start usb controller */ - musbr = musb_cfg.regs; - musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo)); - musb_start(); - - /* - * Wait until musb is enabled in host mode with a timeout. There - * should be a usb device connected. - */ - timeout = musb_cfg.timeout; - while (--timeout) - if (readb(&musbr->devctl) & MUSB_DEVCTL_HM) - break; - - /* if musb core is not in host mode, then return */ - if (!timeout) - return -1; - - /* start usb bus reset */ - power = readb(&musbr->power); - writeb(power | MUSB_POWER_RESET, &musbr->power); - - /* After initiating a usb reset, wait for about 20ms to 30ms */ - udelay(30000); - - /* stop usb bus reset */ - power = readb(&musbr->power); - power &= ~MUSB_POWER_RESET; - writeb(power, &musbr->power); - - /* Determine if the connected device is a high/full/low speed device */ - musb_cfg.musb_speed = (readb(&musbr->power) & MUSB_POWER_HSMODE) ? - MUSB_TYPE_SPEED_HIGH : - ((readb(&musbr->devctl) & MUSB_DEVCTL_FSDEV) ? - MUSB_TYPE_SPEED_FULL : MUSB_TYPE_SPEED_LOW); - return 0; -} - -/* - * This function stops the operation of the davinci usb module. - */ -int usb_lowlevel_stop(int index) -{ - /* Reset the USB module */ - musb_platform_deinit(); - writeb(0, &musbr->devctl); - return 0; -} - -/* - * This function supports usb interrupt transfers. Currently, usb interrupt - * transfers are not supported. - */ -int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int len, int interval, bool nonblock) -{ - int dir_out = usb_pipeout(pipe); - int ep = usb_pipeendpoint(pipe); -#ifndef MUSB_NO_MULTIPOINT - int devnum = usb_pipedevice(pipe); -#endif - u8 type; - u16 csr; - u32 txlen = 0; - u32 nextlen = 0; - u8 devspeed; - - /* select interrupt endpoint */ - writeb(MUSB_INTR_EP, &musbr->index); - -#ifndef MUSB_NO_MULTIPOINT - /* write the address of the device */ - if (dir_out) - writeb(devnum, &musbr->tar[MUSB_INTR_EP].txfuncaddr); - else - writeb(devnum, &musbr->tar[MUSB_INTR_EP].rxfuncaddr); -#endif - - /* configure the hub address and the port number as required */ - devspeed = get_dev_speed(dev); - if ((musb_ishighspeed()) && (dev->parent != NULL) && - (devspeed != MUSB_TYPE_SPEED_HIGH)) { - /* - * MUSB is in high speed and the destination device is full - * speed device. So configure the hub address and port - * address registers. - */ - config_hub_port(dev, MUSB_INTR_EP); - } else { -#ifndef MUSB_NO_MULTIPOINT - if (dir_out) { - writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr); - writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport); - } else { - writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr); - writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport); - } -#endif - devspeed = musb_cfg.musb_speed; - } - - /* Write the saved toggle bit value */ - write_toggle(dev, ep, dir_out); - - if (!dir_out) { /* intrrupt-in transfer */ - /* Write the saved toggle bit value */ - write_toggle(dev, ep, dir_out); - writeb(interval, &musbr->rxinterval); - - /* Program the RxType register */ - type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | - (MUSB_TYPE_PROTO_INTR << MUSB_TYPE_PROTO_SHIFT) | - (ep & MUSB_TYPE_REMOTE_END); - writeb(type, &musbr->rxtype); - - /* Write the maximum packet size to the RxMaxp register */ - writew(dev->epmaxpacketin[ep], &musbr->rxmaxp); - - while (txlen < len) { - nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ? - (len-txlen) : dev->epmaxpacketin[ep]; - - /* Set the ReqPkt bit */ - csr = readw(&musbr->rxcsr); - writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); - - /* Wait until the RxPktRdy bit is set */ - if (wait_until_rxep_ready(dev, MUSB_INTR_EP) != 1) { - csr = readw(&musbr->rxcsr); - usb_settoggle(dev, ep, dir_out, - (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); - csr &= ~MUSB_RXCSR_RXPKTRDY; - writew(csr, &musbr->rxcsr); - dev->act_len = txlen; - return 0; - } - - /* Read the data from the FIFO */ - read_fifo(MUSB_INTR_EP, nextlen, - (void *)(((u8 *)buffer) + txlen)); - - /* Clear the RxPktRdy bit */ - csr = readw(&musbr->rxcsr); - csr &= ~MUSB_RXCSR_RXPKTRDY; - writew(csr, &musbr->rxcsr); - txlen += nextlen; - } - - /* Keep a copy of the data toggle bit */ - csr = readw(&musbr->rxcsr); - usb_settoggle(dev, ep, dir_out, - (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); - } - - /* interrupt transfer is complete */ - dev->irq_status = 0; - dev->irq_act_len = len; - dev->irq_handle(dev); - dev->status = 0; - dev->act_len = len; - return 0; -} diff --git a/drivers/usb/musb/musb_hcd.h b/drivers/usb/musb/musb_hcd.h deleted file mode 100644 index a492e99ef9d..00000000000 --- a/drivers/usb/musb/musb_hcd.h +++ /dev/null @@ -1,93 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Mentor USB OTG Core host controller driver. - * - * Copyright (c) 2008 Texas Instruments - * - * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments - */ - -#ifndef __MUSB_HCD_H__ -#define __MUSB_HCD_H__ - -#include "musb_core.h" -#ifdef CONFIG_USB_KEYBOARD -#include <stdio_dev.h> -extern unsigned char new[]; -#endif - -#define MUSB_TIMEOUT 100000 - -/* This defines the endpoint number used for control transfers */ -#define MUSB_CONTROL_EP 0 - -/* This defines the endpoint number used for bulk transfer */ -#ifndef MUSB_BULK_EP -# define MUSB_BULK_EP 1 -#endif - -/* This defines the endpoint number used for interrupt transfer */ -#define MUSB_INTR_EP 2 - -/* Determine the operating speed of MUSB core */ -#define musb_ishighspeed() \ - ((readb(&musbr->power) & MUSB_POWER_HSMODE) \ - >> MUSB_POWER_HSMODE_SHIFT) - -/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */ - -/* destination of request */ -#define RH_INTERFACE 0x01 -#define RH_ENDPOINT 0x02 -#define RH_OTHER 0x03 - -#define RH_CLASS 0x20 -#define RH_VENDOR 0x40 - -/* Requests: bRequest << 8 | bmRequestType */ -#define RH_GET_STATUS 0x0080 -#define RH_CLEAR_FEATURE 0x0100 -#define RH_SET_FEATURE 0x0300 -#define RH_SET_ADDRESS 0x0500 -#define RH_GET_DESCRIPTOR 0x0680 -#define RH_SET_DESCRIPTOR 0x0700 -#define RH_GET_CONFIGURATION 0x0880 -#define RH_SET_CONFIGURATION 0x0900 -#define RH_GET_STATE 0x0280 -#define RH_GET_INTERFACE 0x0A80 -#define RH_SET_INTERFACE 0x0B00 -#define RH_SYNC_FRAME 0x0C80 -/* Our Vendor Specific Request */ -#define RH_SET_EP 0x2000 - -/* Hub port features */ -#define RH_PORT_CONNECTION 0x00 -#define RH_PORT_ENABLE 0x01 -#define RH_PORT_SUSPEND 0x02 -#define RH_PORT_OVER_CURRENT 0x03 -#define RH_PORT_RESET 0x04 -#define RH_PORT_POWER 0x08 -#define RH_PORT_LOW_SPEED 0x09 - -#define RH_C_PORT_CONNECTION 0x10 -#define RH_C_PORT_ENABLE 0x11 -#define RH_C_PORT_SUSPEND 0x12 -#define RH_C_PORT_OVER_CURRENT 0x13 -#define RH_C_PORT_RESET 0x14 - -/* Hub features */ -#define RH_C_HUB_LOCAL_POWER 0x00 -#define RH_C_HUB_OVER_CURRENT 0x01 - -#define RH_DEVICE_REMOTE_WAKEUP 0x00 -#define RH_ENDPOINT_STALL 0x01 - -#define RH_ACK 0x01 -#define RH_REQ_ERR -1 -#define RH_NACK 0x00 - -/* extern functions */ -extern int musb_platform_init(void); -extern void musb_platform_deinit(void); - -#endif /* __MUSB_HCD_H__ */ diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c deleted file mode 100644 index 696855ee3a6..00000000000 --- a/drivers/usb/musb/musb_udc.c +++ /dev/null @@ -1,953 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2009 Wind River Systems, Inc. - * Tom Rix <Tom.Rix@windriver.com> - * - * This file is a rewrite of the usb device part of - * repository git.omapzoom.org/repo/u-boot.git, branch master, - * file cpu/omap3/fastboot.c - * - * This is the unique part of its copyright : - * - * ------------------------------------------------------------------------- - * - * (C) Copyright 2008 - 2009 - * Windriver, <www.windriver.com> - * Tom Rix <Tom.Rix@windriver.com> - * - * ------------------------------------------------------------------------- - * - * The details of connecting the device to the uboot usb device subsystem - * came from the old omap3 repository www.sakoman.net/u-boot-omap3.git, - * branch omap3-dev-usb, file drivers/usb/usbdcore_musb.c - * - * This is the unique part of its copyright : - * - * ------------------------------------------------------------------------- - * - * (C) Copyright 2008 Texas Instruments Incorporated. - * - * Based on - * u-boot OMAP1510 USB drivers (drivers/usbdcore_omap1510.c) - * twl4030 init based on linux (drivers/i2c/chips/twl4030_usb.c) - * - * Author: Diego Dompe (diego.dompe@ridgerun.com) - * Atin Malaviya (atin.malaviya@gmail.com) - * - * ------------------------------------------------------------------------- - */ - -#include <hang.h> -#include <serial.h> -#include <usbdevice.h> -#include <linux/delay.h> -#include <usb/udc.h> -#include "../gadget/ep0.h" -#include "musb_core.h" -#if defined(CONFIG_USB_OMAP3) -#include "omap3.h" -#elif defined(CONFIG_USB_AM35X) -#include "am35x.h" -#endif - -/* Define MUSB_DEBUG for debugging */ -/* #define MUSB_DEBUG */ -#include "musb_debug.h" - -#define MAX_ENDPOINT 15 - -#define GET_ENDPOINT(dev,ep) \ -(((struct usb_device_instance *)(dev))->bus->endpoint_array + ep) - -#define SET_EP0_STATE(s) \ -do { \ - if ((0 <= (s)) && (SET_ADDRESS >= (s))) { \ - if ((s) != ep0_state) { \ - if ((debug_setup) && (debug_level > 1)) \ - serial_printf("INFO : Changing state " \ - "from %s to %s in %s at " \ - "line %d\n", \ - ep0_state_strings[ep0_state],\ - ep0_state_strings[s], \ - __PRETTY_FUNCTION__, \ - __LINE__); \ - ep0_state = s; \ - } \ - } else { \ - if (debug_level > 0) \ - serial_printf("Error at %s %d with setting " \ - "state %d is invalid\n", \ - __PRETTY_FUNCTION__, __LINE__, s); \ - } \ -} while (0) - -/* static implies these initialized to 0 or NULL */ -static int debug_setup; -static int debug_level; -static struct musb_epinfo epinfo[MAX_ENDPOINT * 2 + 2]; -static enum ep0_state_enum { - IDLE = 0, - TX, - RX, - SET_ADDRESS -} ep0_state = IDLE; -static char *ep0_state_strings[4] = { - "IDLE", - "TX", - "RX", - "SET_ADDRESS", -}; - -static struct urb *ep0_urb; -struct usb_endpoint_instance *ep0_endpoint; -static struct usb_device_instance *udc_device; -static int enabled; - -static u16 pending_intrrx; - -#ifdef MUSB_DEBUG -static void musb_db_regs(void) -{ - u8 b; - u16 w; - - b = readb(&musbr->faddr); - serial_printf("\tfaddr 0x%2.2x\n", b); - - b = readb(&musbr->power); - musb_print_pwr(b); - - w = readw(&musbr->ep[0].ep0.csr0); - musb_print_csr0(w); - - b = readb(&musbr->devctl); - musb_print_devctl(b); - - b = readb(&musbr->ep[0].ep0.configdata); - musb_print_config(b); - - w = readw(&musbr->frame); - serial_printf("\tframe 0x%4.4x\n", w); - - b = readb(&musbr->index); - serial_printf("\tindex 0x%2.2x\n", b); - - w = readw(&musbr->ep[1].epN.rxmaxp); - musb_print_rxmaxp(w); - - w = readw(&musbr->ep[1].epN.rxcsr); - musb_print_rxcsr(w); - - w = readw(&musbr->ep[1].epN.txmaxp); - musb_print_txmaxp(w); - - w = readw(&musbr->ep[1].epN.txcsr); - musb_print_txcsr(w); -} -#else -#define musb_db_regs() -#endif /* DEBUG_MUSB */ - -static void musb_peri_softconnect(void) -{ - u8 power, devctl; - - /* Power off MUSB */ - power = readb(&musbr->power); - power &= ~MUSB_POWER_SOFTCONN; - writeb(power, &musbr->power); - - /* Read intr to clear */ - readb(&musbr->intrusb); - readw(&musbr->intrrx); - readw(&musbr->intrtx); - - udelay(1000 * 1000); /* 1 sec */ - - /* Power on MUSB */ - power = readb(&musbr->power); - power |= MUSB_POWER_SOFTCONN; - /* - * The usb device interface is usb 1.1 - * Disable 2.0 high speed by clearring the hsenable bit. - */ - power &= ~MUSB_POWER_HSENAB; - writeb(power, &musbr->power); - - /* Check if device is in b-peripheral mode */ - devctl = readb(&musbr->devctl); - if (!(devctl & MUSB_DEVCTL_BDEVICE) || - (devctl & MUSB_DEVCTL_HM)) { - serial_printf("ERROR : Unsupport USB mode\n"); - serial_printf("Check that mini-B USB cable is attached " - "to the device\n"); - } - - if (debug_setup && (debug_level > 1)) - musb_db_regs(); -} - -static void musb_peri_reset(void) -{ - if ((debug_setup) && (debug_level > 1)) - serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__); - - if (ep0_endpoint) - ep0_endpoint->endpoint_address = 0xff; - - /* Sync sw and hw addresses */ - writeb(udc_device->address, &musbr->faddr); - - SET_EP0_STATE(IDLE); -} - -static void musb_peri_resume(void) -{ - /* noop */ -} - -static void musb_peri_ep0_stall(void) -{ - u16 csr0; - - csr0 = readw(&musbr->ep[0].ep0.csr0); - csr0 |= MUSB_CSR0_P_SENDSTALL; - writew(csr0, &musbr->ep[0].ep0.csr0); - if ((debug_setup) && (debug_level > 1)) - serial_printf("INFO : %s stall\n", __PRETTY_FUNCTION__); -} - -static void musb_peri_ep0_ack_req(void) -{ - u16 csr0; - - csr0 = readw(&musbr->ep[0].ep0.csr0); - csr0 |= MUSB_CSR0_P_SVDRXPKTRDY; - writew(csr0, &musbr->ep[0].ep0.csr0); -} - -static void musb_ep0_tx_ready(void) -{ - u16 csr0; - - csr0 = readw(&musbr->ep[0].ep0.csr0); - csr0 |= MUSB_CSR0_TXPKTRDY; - writew(csr0, &musbr->ep[0].ep0.csr0); -} - -static void musb_ep0_tx_ready_and_last(void) -{ - u16 csr0; - - csr0 = readw(&musbr->ep[0].ep0.csr0); - csr0 |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_P_DATAEND); - writew(csr0, &musbr->ep[0].ep0.csr0); -} - -static void musb_peri_ep0_last(void) -{ - u16 csr0; - - csr0 = readw(&musbr->ep[0].ep0.csr0); - csr0 |= MUSB_CSR0_P_DATAEND; - writew(csr0, &musbr->ep[0].ep0.csr0); -} - -static void musb_peri_ep0_set_address(void) -{ - u8 faddr; - writeb(udc_device->address, &musbr->faddr); - - /* Verify */ - faddr = readb(&musbr->faddr); - if (udc_device->address == faddr) { - SET_EP0_STATE(IDLE); - usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0); - if ((debug_setup) && (debug_level > 1)) - serial_printf("INFO : %s Address set to %d\n", - __PRETTY_FUNCTION__, udc_device->address); - } else { - if (debug_level > 0) - serial_printf("ERROR : %s Address mismatch " - "sw %d vs hw %d\n", - __PRETTY_FUNCTION__, - udc_device->address, faddr); - } -} - -static void musb_peri_rx_ack(unsigned int ep) -{ - u16 peri_rxcsr; - - peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr); - peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY; - writew(peri_rxcsr, &musbr->ep[ep].epN.rxcsr); -} - -static void musb_peri_tx_ready(unsigned int ep) -{ - u16 peri_txcsr; - - peri_txcsr = readw(&musbr->ep[ep].epN.txcsr); - peri_txcsr |= MUSB_TXCSR_TXPKTRDY; - writew(peri_txcsr, &musbr->ep[ep].epN.txcsr); -} - -static void musb_peri_ep0_zero_data_request(int err) -{ - musb_peri_ep0_ack_req(); - - if (err) { - musb_peri_ep0_stall(); - SET_EP0_STATE(IDLE); - } else { - - musb_peri_ep0_last(); - - /* USBD state */ - switch (ep0_urb->device_request.bRequest) { - case USB_REQ_SET_ADDRESS: - if ((debug_setup) && (debug_level > 1)) - serial_printf("INFO : %s received set " - "address\n", __PRETTY_FUNCTION__); - break; - - case USB_REQ_SET_CONFIGURATION: - if ((debug_setup) && (debug_level > 1)) - serial_printf("INFO : %s Configured\n", - __PRETTY_FUNCTION__); - usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); - break; - } - - /* EP0 state */ - if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) { - SET_EP0_STATE(SET_ADDRESS); - } else { - SET_EP0_STATE(IDLE); - } - } -} - -static void musb_peri_ep0_rx_data_request(void) -{ - /* - * This is the completion of the data OUT / RX - * - * Host is sending data to ep0 that is not - * part of setup. This comes from the cdc_recv_setup - * op that is device specific. - * - */ - musb_peri_ep0_ack_req(); - - ep0_endpoint->rcv_urb = ep0_urb; - ep0_urb->actual_length = 0; - SET_EP0_STATE(RX); -} - -static void musb_peri_ep0_tx_data_request(int err) -{ - if (err) { - musb_peri_ep0_stall(); - SET_EP0_STATE(IDLE); - } else { - musb_peri_ep0_ack_req(); - - ep0_endpoint->tx_urb = ep0_urb; - ep0_endpoint->sent = 0; - SET_EP0_STATE(TX); - } -} - -static void musb_peri_ep0_idle(void) -{ - u16 count0; - int err; - u16 csr0; - - /* - * Verify addresses - * A lot of confusion can be caused if the address - * in software, udc layer, does not agree with the - * hardware. Since the setting of the hardware address - * must be set after the set address request, the - * usb state machine is out of sync for a few frame. - * It is a good idea to run this check when changes - * are made to the state machine. - */ - if ((debug_level > 0) && - (ep0_state != SET_ADDRESS)) { - u8 faddr; - - faddr = readb(&musbr->faddr); - if (udc_device->address != faddr) { - serial_printf("ERROR : %s addresses do not" - "match sw %d vs hw %d\n", - __PRETTY_FUNCTION__, - udc_device->address, faddr); - udelay(1000 * 1000); - hang(); - } - } - - csr0 = readw(&musbr->ep[0].ep0.csr0); - - if (!(MUSB_CSR0_RXPKTRDY & csr0)) - goto end; - - count0 = readw(&musbr->ep[0].ep0.count0); - if (count0 == 0) - goto end; - - if (count0 != 8) { - if ((debug_setup) && (debug_level > 1)) - serial_printf("WARN : %s SETUP incorrect size %d\n", - __PRETTY_FUNCTION__, count0); - musb_peri_ep0_stall(); - goto end; - } - - read_fifo(0, count0, &ep0_urb->device_request); - - if (debug_level > 2) - print_usb_device_request(&ep0_urb->device_request); - - if (ep0_urb->device_request.wLength == 0) { - err = ep0_recv_setup(ep0_urb); - - /* Zero data request */ - musb_peri_ep0_zero_data_request(err); - } else { - /* Is data coming or going ? */ - u8 reqType = ep0_urb->device_request.bmRequestType; - - if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) { - err = ep0_recv_setup(ep0_urb); - /* Device to host */ - musb_peri_ep0_tx_data_request(err); - } else { - /* - * Host to device - * - * The RX routine will call ep0_recv_setup - * when the data packet has arrived. - */ - musb_peri_ep0_rx_data_request(); - } - } - -end: - return; -} - -static void musb_peri_ep0_rx(void) -{ - /* - * This is the completion of the data OUT / RX - * - * Host is sending data to ep0 that is not - * part of setup. This comes from the cdc_recv_setup - * op that is device specific. - * - * Pass the data back to driver ep0_recv_setup which - * should give the cdc_recv_setup the chance to handle - * the rx - */ - u16 csr0; - u16 count0; - - if (debug_level > 3) { - if (0 != ep0_urb->actual_length) { - serial_printf("%s finished ? %d of %d\n", - __PRETTY_FUNCTION__, - ep0_urb->actual_length, - ep0_urb->device_request.wLength); - } - } - - if (ep0_urb->device_request.wLength == ep0_urb->actual_length) { - musb_peri_ep0_last(); - SET_EP0_STATE(IDLE); - ep0_recv_setup(ep0_urb); - return; - } - - csr0 = readw(&musbr->ep[0].ep0.csr0); - if (!(MUSB_CSR0_RXPKTRDY & csr0)) - return; - - count0 = readw(&musbr->ep[0].ep0.count0); - - if (count0) { - struct usb_endpoint_instance *endpoint; - u32 length; - u8 *data; - - endpoint = ep0_endpoint; - if (endpoint && endpoint->rcv_urb) { - struct urb *urb = endpoint->rcv_urb; - unsigned int remaining_space = urb->buffer_length - - urb->actual_length; - - if (remaining_space) { - int urb_bad = 0; /* urb is good */ - - if (count0 > remaining_space) - length = remaining_space; - else - length = count0; - - data = (u8 *) urb->buffer_data; - data += urb->actual_length; - - /* The common musb fifo reader */ - read_fifo(0, length, data); - - musb_peri_ep0_ack_req(); - - /* - * urb's actual_length is updated in - * usbd_rcv_complete - */ - usbd_rcv_complete(endpoint, length, urb_bad); - - } else { - if (debug_level > 0) - serial_printf("ERROR : %s no space in " - "rcv buffer\n", - __PRETTY_FUNCTION__); - } - } else { - if (debug_level > 0) - serial_printf("ERROR : %s problem with " - "endpoint\n", - __PRETTY_FUNCTION__); - } - } else { - if (debug_level > 0) - serial_printf("ERROR : %s with nothing to do\n", - __PRETTY_FUNCTION__); - } -} - -static void musb_peri_ep0_tx(void) -{ - u16 csr0; - int transfer_size = 0; - unsigned int p, pm; - - csr0 = readw(&musbr->ep[0].ep0.csr0); - - /* Check for pending tx */ - if (csr0 & MUSB_CSR0_TXPKTRDY) - goto end; - - /* Check if this is the last packet sent */ - if (ep0_endpoint->sent >= ep0_urb->actual_length) { - SET_EP0_STATE(IDLE); - goto end; - } - - transfer_size = ep0_urb->actual_length - ep0_endpoint->sent; - /* Is the transfer size negative ? */ - if (transfer_size <= 0) { - if (debug_level > 0) - serial_printf("ERROR : %s problem with the" - " transfer size %d\n", - __PRETTY_FUNCTION__, - transfer_size); - SET_EP0_STATE(IDLE); - goto end; - } - - /* Truncate large transfers to the fifo size */ - if (transfer_size > ep0_endpoint->tx_packetSize) - transfer_size = ep0_endpoint->tx_packetSize; - - write_fifo(0, transfer_size, &ep0_urb->buffer[ep0_endpoint->sent]); - ep0_endpoint->sent += transfer_size; - - /* Done or more to send ? */ - if (ep0_endpoint->sent >= ep0_urb->actual_length) - musb_ep0_tx_ready_and_last(); - else - musb_ep0_tx_ready(); - - /* Wait a bit */ - pm = 10; - for (p = 0; p < pm; p++) { - csr0 = readw(&musbr->ep[0].ep0.csr0); - if (!(csr0 & MUSB_CSR0_TXPKTRDY)) - break; - - /* Double the delay. */ - udelay(1 << pm); - } - - if ((ep0_endpoint->sent >= ep0_urb->actual_length) && (p < pm)) - SET_EP0_STATE(IDLE); - -end: - return; -} - -static void musb_peri_ep0(void) -{ - u16 csr0; - - if (SET_ADDRESS == ep0_state) - return; - - csr0 = readw(&musbr->ep[0].ep0.csr0); - - /* Error conditions */ - if (MUSB_CSR0_P_SENTSTALL & csr0) { - csr0 &= ~MUSB_CSR0_P_SENTSTALL; - writew(csr0, &musbr->ep[0].ep0.csr0); - SET_EP0_STATE(IDLE); - } - if (MUSB_CSR0_P_SETUPEND & csr0) { - csr0 |= MUSB_CSR0_P_SVDSETUPEND; - writew(csr0, &musbr->ep[0].ep0.csr0); - SET_EP0_STATE(IDLE); - if ((debug_setup) && (debug_level > 1)) - serial_printf("WARN: %s SETUPEND\n", - __PRETTY_FUNCTION__); - } - - /* Normal states */ - if (IDLE == ep0_state) - musb_peri_ep0_idle(); - - if (TX == ep0_state) - musb_peri_ep0_tx(); - - if (RX == ep0_state) - musb_peri_ep0_rx(); -} - -static void musb_peri_rx_ep(unsigned int ep) -{ - u16 peri_rxcount; - u16 peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr); - - if (!(peri_rxcsr & MUSB_RXCSR_RXPKTRDY)) { - if (debug_level > 0) - serial_printf("ERROR : %s %d without MUSB_RXCSR_RXPKTRDY set\n", - __PRETTY_FUNCTION__, ep); - return; - } - - peri_rxcount = readw(&musbr->ep[ep].epN.rxcount); - if (peri_rxcount) { - struct usb_endpoint_instance *endpoint; - u32 length; - u8 *data; - - endpoint = GET_ENDPOINT(udc_device, ep); - if (endpoint && endpoint->rcv_urb) { - struct urb *urb = endpoint->rcv_urb; - unsigned int remaining_space = urb->buffer_length - - urb->actual_length; - - if (remaining_space) { - int urb_bad = 0; /* urb is good */ - - if (peri_rxcount > remaining_space) - length = remaining_space; - else - length = peri_rxcount; - - data = (u8 *) urb->buffer_data; - data += urb->actual_length; - - /* The common musb fifo reader */ - read_fifo(ep, length, data); - - if (length == peri_rxcount) - musb_peri_rx_ack(ep); - else - pending_intrrx |= (1 << ep); - - /* - * urb's actual_length is updated in - * usbd_rcv_complete - */ - usbd_rcv_complete(endpoint, length, urb_bad); - - } else { - if (debug_level > 0) - serial_printf("ERROR : %s %d no space " - "in rcv buffer\n", - __PRETTY_FUNCTION__, ep); - - pending_intrrx |= (1 << ep); - } - } else { - if (debug_level > 0) - serial_printf("ERROR : %s %d problem with " - "endpoint\n", - __PRETTY_FUNCTION__, ep); - - pending_intrrx |= (1 << ep); - } - - } else { - if (debug_level > 0) - serial_printf("ERROR : %s %d with nothing to do\n", - __PRETTY_FUNCTION__, ep); - - musb_peri_rx_ack(ep); - } -} - -static void musb_peri_rx(u16 intr) -{ - unsigned int ep; - - /* First bit is reserved and does not indicate interrupt for EP0 */ - - for (ep = 1; ep < 16; ep++) { - if ((1 << ep) & intr) - musb_peri_rx_ep(ep); - } -} - -static void musb_peri_tx(u16 intr) -{ - unsigned int ep; - - /* Check for EP0: first bit indicates interrupt for both RX and TX */ - if (0x01 & intr) - musb_peri_ep0(); - - for (ep = 1; ep < 16; ep++) { - if ((1 << ep) & intr) - udc_endpoint_write(GET_ENDPOINT(udc_device, ep)); - } -} - -void udc_irq(void) -{ - /* This is a high freq called function */ - if (enabled) { - u8 intrusb; - - intrusb = readb(&musbr->intrusb); - - /* - * See drivers/usb/gadget/mpc8xx_udc.c for - * state diagram going from detached through - * configuration. - */ - if (MUSB_INTR_RESUME & intrusb) { - usbd_device_event_irq(udc_device, - DEVICE_BUS_ACTIVITY, 0); - musb_peri_resume(); - } - - if (MUSB_INTR_RESET & intrusb) { - usbd_device_event_irq(udc_device, DEVICE_RESET, 0); - musb_peri_reset(); - } - - if (MUSB_INTR_DISCONNECT & intrusb) { - /* cable unplugged from hub/host */ - usbd_device_event_irq(udc_device, DEVICE_RESET, 0); - musb_peri_reset(); - usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0); - } - - if (MUSB_INTR_SOF & intrusb) { - usbd_device_event_irq(udc_device, - DEVICE_BUS_ACTIVITY, 0); - musb_peri_resume(); - } - - if (MUSB_INTR_SUSPEND & intrusb) { - usbd_device_event_irq(udc_device, - DEVICE_BUS_INACTIVE, 0); - } - - if (ep0_state != SET_ADDRESS) { - u16 intrrx, intrtx; - - intrrx = readw(&musbr->intrrx); - intrtx = readw(&musbr->intrtx); - - intrrx |= pending_intrrx; - pending_intrrx = 0; - - if (intrrx) - musb_peri_rx(intrrx); - - if (intrtx) - musb_peri_tx(intrtx); - } else { - if (readw(&musbr->intrtx) & 0x1) { - u8 faddr; - faddr = readb(&musbr->faddr); - /* - * Setting of the address can fail. - * Normally it succeeds the second time. - */ - if (udc_device->address != faddr) - musb_peri_ep0_set_address(); - } - } - } -} - -void udc_set_nak(int ep_num) -{ - /* noop */ -} - -void udc_unset_nak(int ep_num) -{ - /* noop */ -} - -int udc_endpoint_write(struct usb_endpoint_instance *endpoint) -{ - int ret = 0; - - /* Transmit only if the hardware is available */ - if (endpoint->tx_urb && endpoint->state == 0) { - unsigned int ep = endpoint->endpoint_address & - USB_ENDPOINT_NUMBER_MASK; - - u16 peri_txcsr = readw(&musbr->ep[ep].epN.txcsr); - - /* Error conditions */ - if (peri_txcsr & MUSB_TXCSR_P_UNDERRUN) { - peri_txcsr &= ~MUSB_TXCSR_P_UNDERRUN; - writew(peri_txcsr, &musbr->ep[ep].epN.txcsr); - } - - if (debug_level > 1) - musb_print_txcsr(peri_txcsr); - - /* Check if a packet is waiting to be sent */ - if (!(peri_txcsr & MUSB_TXCSR_TXPKTRDY)) { - u32 length; - u8 *data; - struct urb *urb = endpoint->tx_urb; - unsigned int remaining_packet = urb->actual_length - - endpoint->sent; - - if (endpoint->tx_packetSize < remaining_packet) - length = endpoint->tx_packetSize; - else - length = remaining_packet; - - data = (u8 *) urb->buffer; - data += endpoint->sent; - - /* common musb fifo function */ - write_fifo(ep, length, data); - - musb_peri_tx_ready(ep); - - endpoint->last = length; - /* usbd_tx_complete will take care of updating 'sent' */ - usbd_tx_complete(endpoint); - } - } else { - if (debug_level > 0) - serial_printf("ERROR : %s Problem with urb %p " - "or ep state %d\n", - __PRETTY_FUNCTION__, - endpoint->tx_urb, endpoint->state); - } - - return ret; -} - -void udc_setup_ep(struct usb_device_instance *device, unsigned int id, - struct usb_endpoint_instance *endpoint) -{ - if (0 == id) { - /* EP0 */ - ep0_endpoint = endpoint; - ep0_endpoint->endpoint_address = 0xff; - ep0_urb = usbd_alloc_urb(device, endpoint); - } else if (MAX_ENDPOINT >= id) { - epinfo[(id * 2) + 0].epsize = endpoint->rcv_packetSize; - epinfo[(id * 2) + 1].epsize = endpoint->tx_packetSize; - musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo)); - } else { - if (debug_level > 0) - serial_printf("ERROR : %s endpoint request %d " - "exceeds maximum %d\n", - __PRETTY_FUNCTION__, id, MAX_ENDPOINT); - } -} - -void udc_connect(void) -{ - /* noop */ -} - -void udc_disconnect(void) -{ - /* noop */ -} - -void udc_enable(struct usb_device_instance *device) -{ - /* Save the device structure pointer */ - udc_device = device; - - enabled = 1; -} - -void udc_disable(void) -{ - enabled = 0; -} - -void udc_startup_events(struct usb_device_instance *device) -{ - /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */ - usbd_device_event_irq(device, DEVICE_INIT, 0); - - /* - * The DEVICE_CREATE event puts the USB device in the state - * STATE_ATTACHED. - */ - usbd_device_event_irq(device, DEVICE_CREATE, 0); - - /* Resets the address to 0 */ - usbd_device_event_irq(device, DEVICE_RESET, 0); - - udc_enable(device); -} - -int udc_init(void) -{ - int ret; - int ep_loop; - - ret = musb_platform_init(); - if (ret < 0) - goto end; - - /* Configure all the endpoint FIFO's and start usb controller */ - musbr = musb_cfg.regs; - - /* Initialize the endpoints */ - for (ep_loop = 0; ep_loop <= MAX_ENDPOINT * 2; ep_loop++) { - epinfo[ep_loop].epnum = (ep_loop / 2) + 1; - epinfo[ep_loop].epdir = ep_loop % 2; /* OUT, IN */ - epinfo[ep_loop].epsize = 0; - } - - musb_peri_softconnect(); - - ret = 0; -end: - - return ret; -} diff --git a/drivers/usb/musb/omap3.c b/drivers/usb/musb/omap3.c deleted file mode 100644 index e5238bc02f8..00000000000 --- a/drivers/usb/musb/omap3.c +++ /dev/null @@ -1,129 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2009 Wind River Systems, Inc. - * Tom Rix <Tom.Rix@windriver.com> - * - * This is file is based on - * repository git.gitorious.org/u-boot-omap3/mainline.git, - * branch omap3-dev-usb, file drivers/usb/host/omap3530_usb.c - * - * This is the unique part of its copyright : - * - * ------------------------------------------------------------------------ - * - * Copyright (c) 2009 Texas Instruments - * - * ------------------------------------------------------------------------ - */ - -#include <serial.h> -#include <asm/omap_common.h> -#include <twl4030.h> -#include "omap3.h" - -static int platform_needs_initialization = 1; - -struct musb_config musb_cfg = { - .regs = (struct musb_regs *)MENTOR_USB0_BASE, - .timeout = OMAP3_USB_TIMEOUT, - .musb_speed = 0, -}; - -/* - * OMAP3 USB OTG registers. - */ -struct omap3_otg_regs { - u32 revision; - u32 sysconfig; - u32 sysstatus; - u32 interfsel; - u32 simenable; - u32 forcestdby; -}; - -static struct omap3_otg_regs *otg; - -#define OMAP3_OTG_SYSCONFIG_SMART_STANDBY_MODE 0x2000 -#define OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE 0x1000 -#define OMAP3_OTG_SYSCONFIG_SMART_IDLE_MODE 0x0010 -#define OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE 0x0008 -#define OMAP3_OTG_SYSCONFIG_ENABLEWAKEUP 0x0004 -#define OMAP3_OTG_SYSCONFIG_SOFTRESET 0x0002 -#define OMAP3_OTG_SYSCONFIG_AUTOIDLE 0x0001 - -#define OMAP3_OTG_SYSSTATUS_RESETDONE 0x0001 - -#define OMAP3_OTG_INTERFSEL_OMAP 0x0001 - -#define OMAP3_OTG_FORCESTDBY_STANDBY 0x0001 - -#ifdef DEBUG_MUSB_OMAP3 -static void musb_db_otg_regs(void) -{ - u32 l; - l = readl(&otg->revision); - serial_printf("OTG_REVISION 0x%x\n", l); - l = readl(&otg->sysconfig); - serial_printf("OTG_SYSCONFIG 0x%x\n", l); - l = readl(&otg->sysstatus); - serial_printf("OTG_SYSSTATUS 0x%x\n", l); - l = readl(&otg->interfsel); - serial_printf("OTG_INTERFSEL 0x%x\n", l); - l = readl(&otg->forcestdby); - serial_printf("OTG_FORCESTDBY 0x%x\n", l); -} -#endif - -int musb_platform_init(void) -{ - int ret = -1; - - if (platform_needs_initialization) { - u32 stdby; - - /* - * OMAP3EVM uses ISP1504 phy and so - * twl4030 related init is not required. - */ -#ifdef CONFIG_TWL4030_USB - if (twl4030_usb_ulpi_init()) { - serial_printf("ERROR: %s Could not initialize PHY\n", - __PRETTY_FUNCTION__); - goto end; - } -#endif - - otg = (struct omap3_otg_regs *)OMAP3_OTG_BASE; - - /* Set OTG to always be on */ - writel(OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE | - OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE, &otg->sysconfig); - - /* Set the interface */ - writel(OMAP3_OTG_INTERFSEL_OMAP, &otg->interfsel); - - /* Clear force standby */ - stdby = readl(&otg->forcestdby); - stdby &= ~OMAP3_OTG_FORCESTDBY_STANDBY; - writel(stdby, &otg->forcestdby); - -#ifdef CONFIG_TARGET_OMAP3_EVM - musb_cfg.extvbus = omap3_evm_need_extvbus(); -#endif - - platform_needs_initialization = 0; - } - - ret = platform_needs_initialization; - -#ifdef CONFIG_TWL4030_USB -end: -#endif - return ret; - -} - -void musb_platform_deinit(void) -{ - /* noop */ -} diff --git a/drivers/usb/musb/omap3.h b/drivers/usb/musb/omap3.h deleted file mode 100644 index 78fdb2959bb..00000000000 --- a/drivers/usb/musb/omap3.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 2009 Wind River Systems, Inc. - * Tom Rix <Tom.Rix@windriver.com> - * - * This file is based on the file drivers/usb/musb/davinci.h - * - * This is the unique part of its copyright: - * - * -------------------------------------------------------------------- - * - * Copyright (c) 2008 Texas Instruments - * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments - * - * -------------------------------------------------------------------- - */ -#ifndef _MUSB_OMAP3_H_ -#define _MUSB_OMAP3_H_ - -#include <asm/arch/cpu.h> -#include "musb_core.h" - -/* Base address of MUSB registers */ -#define MENTOR_USB0_BASE MUSB_BASE - -/* Base address of OTG registers */ -#define OMAP3_OTG_BASE (MENTOR_USB0_BASE + 0x400) - -/* Timeout for USB module */ -#define OMAP3_USB_TIMEOUT 0x3FFFFFF - -int musb_platform_init(void); - -#ifdef CONFIG_TARGET_OMAP3_EVM -extern u8 omap3_evm_need_extvbus(void); -#endif - -#endif /* _MUSB_OMAP3_H */ diff --git a/drivers/usb/ulpi/ulpi.c b/drivers/usb/ulpi/ulpi.c index 128adcbde13..0e0f0e4983d 100644 --- a/drivers/usb/ulpi/ulpi.c +++ b/drivers/usb/ulpi/ulpi.c @@ -127,7 +127,7 @@ int ulpi_set_vbus_indicator(struct ulpi_viewport *ulpi_vp, int external, if (val == ULPI_ERROR) return val; - val = val & ~(ULPI_IFACE_PASSTHRU & ULPI_IFACE_EXTVBUS_COMPLEMENT); + val = val & ~(ULPI_IFACE_PASSTHRU | ULPI_IFACE_EXTVBUS_COMPLEMENT); val |= flags; val = ulpi_write(ulpi_vp, &ulpi->iface_ctrl, val); if (val) diff --git a/drivers/video/efi.c b/drivers/video/efi.c index 78d123fad4b..8ce2ef9dc67 100644 --- a/drivers/video/efi.c +++ b/drivers/video/efi.c @@ -104,7 +104,7 @@ static int get_mode_info(struct vesa_mode_info *vesa, u64 *fbp, static int get_mode_from_entry(struct vesa_mode_info *vesa, u64 *fbp, struct efi_gop_mode_info **infop) { - struct efi_gop_mode *mode; + struct efi_entry_gopmode *mode; int size; int ret; diff --git a/drivers/video/simple_panel.c b/drivers/video/simple_panel.c index b6c5b058b2e..0f23df701bc 100644 --- a/drivers/video/simple_panel.c +++ b/drivers/video/simple_panel.c @@ -191,6 +191,7 @@ static const struct mipi_dsi_panel_plat panasonic_vvx10f004b00 = { static const struct udevice_id simple_panel_ids[] = { { .compatible = "simple-panel" }, + { .compatible = "panel-lvds" }, { .compatible = "auo,b133xtn01" }, { .compatible = "auo,b116xw03" }, { .compatible = "auo,b133htn01" }, diff --git a/drivers/video/stm32/Kconfig b/drivers/video/stm32/Kconfig index c354c402c28..4cb8a841caf 100644 --- a/drivers/video/stm32/Kconfig +++ b/drivers/video/stm32/Kconfig @@ -23,6 +23,15 @@ config VIDEO_STM32_DSI This option enables support DSI internal bridge which can be used on devices which have DSI devices connected. +config VIDEO_STM32_LVDS + bool "Enable STM32 LVDS video support" + depends on VIDEO_STM32 + select VIDEO_BRIDGE + select VIDEO_DW_MIPI_DSI + help + This enables Low Voltage Differential Signaling (LVDS) display + support. + config VIDEO_STM32_MAX_XRES int "Maximum horizontal resolution (for memory allocation purposes)" depends on VIDEO_STM32 diff --git a/drivers/video/stm32/Makefile b/drivers/video/stm32/Makefile index f8b42d1a4d1..059d9000c1d 100644 --- a/drivers/video/stm32/Makefile +++ b/drivers/video/stm32/Makefile @@ -7,3 +7,4 @@ obj-${CONFIG_VIDEO_STM32} = stm32_ltdc.o obj-${CONFIG_VIDEO_STM32_DSI} += stm32_dsi.o +obj-${CONFIG_VIDEO_STM32_LVDS} += stm32_lvds.o diff --git a/drivers/video/stm32/stm32_ltdc.c b/drivers/video/stm32/stm32_ltdc.c index 0a062c8939d..834bfb625d2 100644 --- a/drivers/video/stm32/stm32_ltdc.c +++ b/drivers/video/stm32/stm32_ltdc.c @@ -17,6 +17,7 @@ #include <video_bridge.h> #include <asm/io.h> #include <dm/device-internal.h> +#include <dm/uclass-internal.h> #include <dm/device_compat.h> #include <linux/bitops.h> #include <linux/printk.h> @@ -262,6 +263,7 @@ static const u32 layer_regs_a2[] = { #define HWVER_10300 0x010300 #define HWVER_20101 0x020101 #define HWVER_40100 0x040100 +#define HWVER_40101 0x040101 enum stm32_ltdc_pix_fmt { PF_ARGB8888 = 0, /* ARGB [32 bits] */ @@ -494,6 +496,101 @@ static void stm32_ltdc_set_layer1(struct stm32_ltdc_priv *priv, ulong fb_addr) setbits_le32(priv->regs + LTDC_L1CR, LXCR_LEN); } +static int stm32_ltdc_get_remote_device(struct udevice *dev, ofnode ep_node, + enum uclass_id id, struct udevice **remote_dev) +{ + u32 remote_phandle; + ofnode remote; + int ret = 0; + + ret = ofnode_read_u32(ep_node, "remote-endpoint", &remote_phandle); + if (ret) { + dev_err(dev, "%s(%s): Could not find remote-endpoint property\n", + __func__, dev_read_name(dev)); + return ret; + } + + remote = ofnode_get_by_phandle(remote_phandle); + if (!ofnode_valid(remote)) + return -EINVAL; + + while (ofnode_valid(remote)) { + remote = ofnode_get_parent(remote); + if (!ofnode_valid(remote)) { + dev_dbg(dev, "%s(%s): no uclass_id %d for remote-endpoint\n", + __func__, dev_read_name(dev), id); + continue; + } + + ret = uclass_find_device_by_ofnode(id, remote, remote_dev); + if (*remote_dev && !ret) { + ret = uclass_get_device_by_ofnode(id, remote, remote_dev); + if (ret) + dev_dbg(dev, "%s(%s): failed to get remote device %s\n", + __func__, dev_read_name(dev), dev_read_name(*remote_dev)); + break; + } + }; + + return ret; +} + +static int stm32_ltdc_get_panel(struct udevice *dev, struct udevice **panel) +{ + ofnode ep_node, node, ports; + int ret = 0; + + if (!dev) + return -EINVAL; + + ports = ofnode_find_subnode(dev_ofnode(dev), "ports"); + if (!ofnode_valid(ports)) { + dev_err(dev, "Remote bridge subnode\n"); + return ret; + } + + for (node = ofnode_first_subnode(ports); + ofnode_valid(node); + node = dev_read_next_subnode(node)) { + ep_node = ofnode_first_subnode(node); + if (!ofnode_valid(ep_node)) + continue; + + ret = stm32_ltdc_get_remote_device(dev, ep_node, UCLASS_PANEL, panel); + } + + /* Sanity check, we can get out of the loop without having a clean ofnode */ + if (!(*panel)) + ret = -EINVAL; + else + if (!ofnode_valid(dev_ofnode(*panel))) + ret = -EINVAL; + + return ret; +} + +static int stm32_ltdc_display_init(struct udevice *dev, ofnode *ep_node, + struct udevice **panel, struct udevice **bridge) +{ + int ret; + + if (*panel) + return -EINVAL; + + if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) { + ret = stm32_ltdc_get_remote_device(dev, *ep_node, UCLASS_VIDEO_BRIDGE, bridge); + if (ret) + return ret; + + ret = stm32_ltdc_get_panel(*bridge, panel); + } else { + /* no bridge, search a panel from display controller node */ + ret = stm32_ltdc_get_remote_device(dev, *ep_node, UCLASS_PANEL, panel); + } + + return ret; +} + #if IS_ENABLED(CONFIG_TARGET_STM32F469_DISCOVERY) static int stm32_ltdc_alloc_fb(struct udevice *dev) { @@ -529,8 +626,9 @@ static int stm32_ltdc_probe(struct udevice *dev) struct udevice *bridge = NULL; struct udevice *panel = NULL; struct display_timing timings; - struct clk pclk; + struct clk pclk, bclk; struct reset_ctl rst; + ofnode node, port; ulong rate; int ret; @@ -540,7 +638,21 @@ static int stm32_ltdc_probe(struct udevice *dev) return -EINVAL; } - ret = clk_get_by_index(dev, 0, &pclk); + ret = clk_get_by_name(dev, "bus", &bclk); + if (ret) { + if (ret != -ENODATA) { + dev_err(dev, "bus clock get error %d\n", ret); + return ret; + } + } else { + ret = clk_enable(&bclk); + if (ret) { + dev_err(dev, "bus clock enable error %d\n", ret); + return ret; + } + } + + ret = clk_get_by_name(dev, "lcd", &pclk); if (ret) { dev_err(dev, "peripheral clock get error %d\n", ret); return ret; @@ -553,7 +665,7 @@ static int stm32_ltdc_probe(struct udevice *dev) } priv->hw_version = readl(priv->regs + LTDC_IDR); - debug("%s: LTDC hardware 0x%x\n", __func__, priv->hw_version); + dev_dbg(dev, "%s: LTDC hardware 0x%x\n", __func__, priv->hw_version); switch (priv->hw_version) { case HWVER_10200: @@ -566,6 +678,7 @@ static int stm32_ltdc_probe(struct udevice *dev) priv->pix_fmt_hw = pix_fmt_a1; break; case HWVER_40100: + case HWVER_40101: priv->layer_regs = layer_regs_a2; priv->pix_fmt_hw = pix_fmt_a2; break; @@ -573,13 +686,35 @@ static int stm32_ltdc_probe(struct udevice *dev) return -ENODEV; } - ret = uclass_first_device_err(UCLASS_PANEL, &panel); - if (ret) { - if (ret != -ENODEV) - dev_err(dev, "panel device error %d\n", ret); - return ret; + /* + * Try all the ports until one working. + * + * This is done in two times. First is checks for the + * UCLASS_VIDEO_BRIDGE available, and then for this bridge + * it scans for a UCLASS_PANEL. + */ + + port = dev_read_subnode(dev, "port"); + if (!ofnode_valid(port)) { + dev_err(dev, "%s(%s): 'port' subnode not found\n", + __func__, dev_read_name(dev)); + return -EINVAL; } + for (node = ofnode_first_subnode(port); + ofnode_valid(node); + node = dev_read_next_subnode(node)) { + ret = stm32_ltdc_display_init(dev, &node, &panel, &bridge); + if (ret) + dev_dbg(dev, "Device failed ret=%d\n", ret); + else + break; + } + + /* Sanity check */ + if (ret) + return ret; + ret = panel_get_display_timing(panel, &timings); if (ret) { ret = ofnode_decode_display_timing(dev_ofnode(panel), @@ -608,11 +743,6 @@ static int stm32_ltdc_probe(struct udevice *dev) reset_deassert(&rst); if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) { - ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &bridge); - if (ret) - dev_dbg(dev, - "No video bridge, or no backlight on bridge\n"); - if (bridge) { ret = video_bridge_attach(bridge); if (ret) { @@ -688,6 +818,8 @@ static int stm32_ltdc_bind(struct udevice *dev) static const struct udevice_id stm32_ltdc_ids[] = { { .compatible = "st,stm32-ltdc" }, + { .compatible = "st,stm32mp251-ltdc" }, + { .compatible = "st,stm32mp255-ltdc" }, { } }; diff --git a/drivers/video/stm32/stm32_lvds.c b/drivers/video/stm32/stm32_lvds.c new file mode 100644 index 00000000000..bf1393c9e87 --- /dev/null +++ b/drivers/video/stm32/stm32_lvds.c @@ -0,0 +1,693 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause +/* + * Copyright (C) 2025 STMicroelectronics - All Rights Reserved + * Author(s): RaphaĆ«l Gallais-Pou <raphael.gallais-pou@foss.st.com> for STMicroelectronics. + * + * This Low Voltage Differential Signal controller driver is based on the Linux Kernel driver from + * drivers/gpu/drm/stm/ltdc.c + */ + +#define LOG_CATEGORY UCLASS_VIDEO_BRIDGE + +#include <clk.h> +#include <dm.h> +#include <log.h> +#include <media_bus_format.h> +#include <panel.h> +#include <reset.h> +#include <video.h> +#include <video_bridge.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <dm/ofnode.h> +#include <linux/iopoll.h> + +/* LVDS Host registers */ +#define LVDS_CR 0x0000 /* configuration register */ +#define LVDS_DMLCR0 0x0004 /* data mapping lsb configuration register 0 */ +#define LVDS_DMMCR0 0x0008 /* data mapping msb configuration register 0 */ +#define LVDS_DMLCR1 0x000C /* data mapping lsb configuration register 1 */ +#define LVDS_DMMCR1 0x0010 /* data mapping msb configuration register 1 */ +#define LVDS_DMLCR2 0x0014 /* data mapping lsb configuration register 2 */ +#define LVDS_DMMCR2 0x0018 /* data mapping msb configuration register 2 */ +#define LVDS_DMLCR3 0x001C /* data mapping lsb configuration register 3 */ +#define LVDS_DMMCR3 0x0020 /* data mapping msb configuration register 3 */ +#define LVDS_DMLCR4 0x0024 /* data mapping lsb configuration register 4 */ +#define LVDS_DMMCR4 0x0028 /* data mapping msb configuration register 4 */ +#define LVDS_DMLCR(id) (LVDS_DMLCR0 + 8U * (id)) +#define LVDS_DMMCR(id) (LVDS_DMMCR0 + 8U * (id)) +#define LVDS_CDL1CR 0x002C /* channel distrib link 1 configuration register */ +#define LVDS_CDL2CR 0x0030 /* channel distrib link 2 configuration register */ + +#define CDL1CR_DEFAULT 0x4321 +#define CDL2CR_DEFAULT 0x59876 + +/* LVDS Host registers */ +#define LVDS_PHY_MASTER 0x0 +#define LVDS_PHY_SLAVE 0x100 + +/* phy parameter can only be one of those two above */ +#define LVDS_PXGCR(phy) ((phy) + 0x1000) /* Global Control Register */ +#define LVDS_PXCMCR1(phy) ((phy) + 0x100C) /* Current Mode Control Register 1 */ +#define LVDS_PXCMCR2(phy) ((phy) + 0x1010) /* Current Mode Control Register 2 */ +#define LVDS_PXSCR(phy) ((phy) + 0x1020) /* Serial Control Register */ +#define LVDS_PXBCR1(phy) ((phy) + 0x102C) /* Bias Control Register 1 */ +#define LVDS_PXBCR2(phy) ((phy) + 0x1030) /* Bias Control Register 2 */ +#define LVDS_PXBCR3(phy) ((phy) + 0x1034) /* Bias Control Register 3 */ +#define LVDS_PXMPLCR(phy) ((phy) + 0x1064) /* Monitor PLL Lock Control Register */ +#define LVDS_PXDCR(phy) ((phy) + 0x1084) /* Debug Control Register */ +#define LVDS_PXSSR1(phy) ((phy) + 0x1088) /* Spare Status Register 1 */ +#define LVDS_PXCFGCR(phy) ((phy) + 0x10A0) /* Configuration Control Register */ +#define LVDS_PXPLLCR1(phy) ((phy) + 0x10C0) /* PLL_MODE 1 Control Register */ +#define LVDS_PXPLLCR2(phy) ((phy) + 0x10C4) /* PLL_MODE 2 Control Register */ +#define LVDS_PXPLLSR(phy) ((phy) + 0x10C8) /* PLL Status Register */ +#define LVDS_PXPLLSDCR1(phy) ((phy) + 0x10CC) /* PLL_SD_1 Control Register */ +#define LVDS_PXPLLSDCR2(phy) ((phy) + 0x10D0) /* PLL_SD_2 Control Register */ +#define LVDS_PXPLLTWGCR1(phy) ((phy) + 0x10D4) /* PLL_TWG_1 Control Register */ +#define LVDS_PXPLLTWGCR2(phy) ((phy) + 0x10D8) /* PLL_TWG_2 Control Register */ +#define LVDS_PXPLLCPCR(phy) ((phy) + 0x10E0) /* PLL_CP Control Register */ +#define LVDS_PXPLLTESTCR(phy) ((phy) + 0x10E8) /* PLL_TEST Control Register */ + +/* LVDS Wrapper registers */ +#define LVDS_WCLKCR 0x11B0 /* Wrapper clock control register */ +#define LVDS_HWCFGR 0x1FF0 /* HW configuration register */ +#define LVDS_VERR 0x1FF4 /* Version register */ +#define LVDS_IPIDR 0x1FF8 /* Identification register */ +#define LVDS_SIDR 0x1FFC /* Size Identification register */ + +#define CR_LVDSEN BIT(0) /* LVDS PHY Enable */ +#define CR_HSPOL BIT(1) /* HS Polarity (horizontal sync) */ +#define CR_VSPOL BIT(2) /* VS Polarity (vertical sync) */ +#define CR_DEPOL BIT(3) /* DE Polarity (data enable) */ +#define CR_CI BIT(4) /* Control Internal (software controlled bit) */ +#define CR_LKMOD BIT(5) /* Link Mode, for both Links */ +#define CR_LKPHA BIT(6) /* Link Phase, for both Links */ +#define CR_LK1POL GENMASK(20, 16) /* Link-1 output Polarity */ +#define CR_LK2POL GENMASK(25, 21) /* Link-2 output Polarity */ + +#define DMMCRX_MAP0 GENMASK(4, 0) +#define DMMCRX_MAP1 GENMASK(9, 5) +#define DMMCRX_MAP2 GENMASK(14, 10) +#define DMMCRX_MAP3 GENMASK(19, 15) +#define DMLCRX_MAP4 GENMASK(4, 0) +#define DMLCRX_MAP5 GENMASK(9, 5) +#define DMLCRX_MAP6 GENMASK(14, 10) + +#define CDLCRX_DISTR0 GENMASK(3, 0) +#define CDLCRX_DISTR1 GENMASK(7, 4) +#define CDLCRX_DISTR2 GENMASK(11, 8) +#define CDLCRX_DISTR3 GENMASK(15, 12) +#define CDLCRX_DISTR4 GENMASK(19, 16) + +#define FREF_INDEX 0 +#define NDIV_INDEX 1 +#define FPFD_INDEX 2 +#define MDIV_INDEX 3 +#define FVCO_INDEX 4 +#define BDIV_INDEX 5 +#define FBIT_INDEX 6 +#define FLS_INDEX 7 +#define FDP_INDEX 8 + +#define PXGCR_BIT_CLK_OUT BIT(0) +#define PXGCR_LS_CLK_OUT BIT(4) +#define PXGCR_DP_CLK_OUT BIT(8) +#define PXGCR_RSTZ BIT(24) +#define PXGCR_DIV_RSTN BIT(25) + +#define PXCMCR1_CM_EN_DL (BIT(28) | BIT(20) | BIT(12) | BIT(4)) +#define PXCMCR2_CM_EN_DL4 BIT(4) +#define PXSCR_SER_DATA_OK BIT(16) +#define PXBCR1_EN_BIAS_DL (BIT(16) | BIT(12) | BIT(8) | BIT(4) | BIT(0)) +#define PXBCR2_BIAS_EN BIT(28) +#define PXBCR3_VM_EN_DL (BIT(16) | BIT(12) | BIT(8) | BIT(4) | BIT(0)) +#define PXDCR_POWER_OK BIT(12) +#define PXCFGCR_EN_DIG_DL GENMASK(4, 0) + +#define PXPLLCR1_PLL_EN BIT(0) +#define PxPLLCR1_SD_EN BIT(1) +#define PXPLLCR1_TWG_EN BIT(2) +#define PXPLLCR1_PLL_DIVIDERS_EN BIT(8) +#define PXPLLCR2_NDIV GENMASK(25, 16) +#define PXPLLCR2_BDIV GENMASK(9, 0) +#define PXPLLSR_PLL_LOCK BIT(0) +#define PXPLLSDCR1_MDIV GENMASK(9, 0) +#define PXPLLCPCR_CPCTRL_DEFAULT 0x1 +#define PXPLLTESTCR_PLL_TEST_CLK_EN BIT(0) +#define PXPLLTESTCR_PLL_TDIV_EN BIT(8) +#define PXPLLTESTCR_TDIV GENMASK(25, 16) +#define PXPLLTESTCR_TDIV_VALUE 70 + +#define WCLKCR_SLV_CLKPIX_SEL BIT(0) +#define WCLKCR_SRCSEL BIT(8) + +/* Sleep & timeout for pll lock/unlock */ +#define SLEEP_US 1000 +#define TIMEOUT_US 20000000 + +#define PHY_SLV_OFS 0x100 + +/* PLL parameters */ +#define NDIV_MIN 2 +#define NDIV_MAX 6 +#define BDIV_MIN 2 +#define BDIV_MAX 6 +#define MDIV_MIN 1 +#define MDIV_MAX 1023 + +struct stm32_lvds_plat { + void __iomem *base; + struct udevice *panel; + struct reset_ctl rst; + struct clk pclk; + struct clk refclk; +}; + +struct stm32_lvds_priv { + struct display_timing timings; + u32 refclk_rate; + int dual_link; + int bus_format; +}; + +/* + * enum lvds_pixels_order - Pixel order of an LVDS connection + * @LVDS_DUAL_LINK_EVEN_ODD_PIXELS: Even pixels are expected to be generated + * from the first port, odd pixels from the second port + * @LVDS_DUAL_LINK_ODD_EVEN_PIXELS: Odd pixels are expected to be generated + * from the first port, even pixels from the second port + */ +enum lvds_pixels_order { + LVDS_DUAL_LINK_EVEN_ODD_PIXELS = BIT(0), + LVDS_DUAL_LINK_ODD_EVEN_PIXELS = BIT(1), +}; + +enum lvds_pixel { + PIX_R_0 = 0x00, + PIX_R_1 = 0x01, + PIX_R_2 = 0x02, + PIX_R_3 = 0x03, + PIX_R_4 = 0x04, + PIX_R_5 = 0x05, + PIX_R_6 = 0x06, + PIX_R_7 = 0x07, + PIX_G_0 = 0x08, + PIX_G_1 = 0x09, + PIX_G_2 = 0x0A, + PIX_G_3 = 0x0B, + PIX_G_4 = 0x0C, + PIX_G_5 = 0x0D, + PIX_G_6 = 0x0E, + PIX_G_7 = 0x0F, + PIX_B_0 = 0x10, + PIX_B_1 = 0x11, + PIX_B_2 = 0x12, + PIX_B_3 = 0x13, + PIX_B_4 = 0x14, + PIX_B_5 = 0x15, + PIX_B_6 = 0x16, + PIX_B_7 = 0x17, + PIX_H_S = 0x18, + PIX_V_S = 0x19, + PIX_D_E = 0x1A, + PIX_C_E = 0x1B, + PIX_C_I = 0x1C, + PIX_TOG = 0x1D, + PIX_ONE = 0x1E, + PIX_ZER = 0x1F, +}; + +/* + * Expected JEIDA-RGB888 data to be sent in LSB format + * bit6 ............................bit0 + */ +const enum lvds_pixel lvds_bitmap_jeida_rgb888[5][7] = { + { PIX_ONE, PIX_ONE, PIX_ZER, PIX_ZER, PIX_ZER, PIX_ONE, PIX_ONE }, + { PIX_G_2, PIX_R_7, PIX_R_6, PIX_R_5, PIX_R_4, PIX_R_3, PIX_R_2 }, + { PIX_B_3, PIX_B_2, PIX_G_7, PIX_G_6, PIX_G_5, PIX_G_4, PIX_G_3 }, + { PIX_D_E, PIX_V_S, PIX_H_S, PIX_B_7, PIX_B_6, PIX_B_5, PIX_B_4 }, + { PIX_C_E, PIX_B_1, PIX_B_0, PIX_G_1, PIX_G_0, PIX_R_1, PIX_R_0 } +}; + +/* + * Expected VESA-RGB888 data to be sent in LSB format + * bit6 ............................bit0 + */ +const enum lvds_pixel lvds_bitmap_vesa_rgb888[5][7] = { + { PIX_ONE, PIX_ONE, PIX_ZER, PIX_ZER, PIX_ZER, PIX_ONE, PIX_ONE }, + { PIX_G_0, PIX_R_5, PIX_R_4, PIX_R_3, PIX_R_2, PIX_R_1, PIX_R_0 }, + { PIX_B_1, PIX_B_0, PIX_G_5, PIX_G_4, PIX_G_3, PIX_G_2, PIX_G_1 }, + { PIX_D_E, PIX_V_S, PIX_H_S, PIX_B_5, PIX_B_4, PIX_B_3, PIX_B_2 }, + { PIX_C_E, PIX_B_7, PIX_B_6, PIX_G_7, PIX_G_6, PIX_R_7, PIX_R_6 } +}; + +static inline void lvds_writel(void __iomem *base, u32 reg, u32 val) +{ + writel(val, base + reg); +} + +static inline u32 lvds_readl(void __iomem *base, u32 reg) +{ + return readl(base + reg); +} + +static inline void lvds_set(void __iomem *base, u32 reg, u32 mask) +{ + lvds_writel(base, reg, lvds_readl(base, reg) | mask); +} + +static inline void lvds_clear(void __iomem *base, u32 reg, u32 mask) +{ + lvds_writel(base, reg, lvds_readl(base, reg) & ~mask); +} + +static u32 pll_get_clkout_khz(u32 clkin_khz, u32 bdiv, u32 mdiv, u32 ndiv) +{ + int divisor = ndiv * bdiv; + + /* Prevents from division by 0 */ + if (!divisor) + return 0; + + return clkin_khz * mdiv / divisor; +} + +static int lvds_pll_get_params(u32 clkin_khz, u32 clkout_khz, + u32 *bdiv, u32 *mdiv, u32 *ndiv) +{ + u32 i, o, n; + u32 delta, best_delta; /* all in khz */ + + /* Early checks preventing division by 0 & odd results */ + if (clkin_khz == 0 || clkout_khz == 0) + return -EINVAL; + + best_delta = 1000000; /* big started value (1000000khz) */ + + for (i = NDIV_MIN; i <= NDIV_MAX; i++) { + for (o = BDIV_MIN; o <= BDIV_MAX; o++) { + n = DIV_ROUND_CLOSEST(i * o * clkout_khz, clkin_khz); + /* Check ndiv according to vco range */ + if (n < MDIV_MIN || n > MDIV_MAX) + continue; + /* Check if new delta is better & saves parameters */ + delta = abs(pll_get_clkout_khz(clkin_khz, i, n, o) - clkout_khz); + if (delta < best_delta) { + *ndiv = i; + *mdiv = n; + *bdiv = o; + best_delta = delta; + } + /* fast return in case of "perfect result" */ + if (!delta) + return 0; + } + } + + return 0; +} + +static int stm32_lvds_pll_enable(struct udevice *dev, + int phy) +{ + struct stm32_lvds_plat *plat = dev_get_plat(dev); + struct stm32_lvds_priv *priv = dev_get_priv(dev); + struct display_timing timings = priv->timings; + u32 pll_in_khz, bdiv = 0, mdiv = 0, ndiv = 0; + int ret, val, multiplier; + + /* Release PHY from reset */ + lvds_set(plat->base, LVDS_PXGCR(phy), PXGCR_DIV_RSTN | PXGCR_RSTZ); + + /* lvds_pll_config */ + /* Set PLL Slv & Mst configs and timings */ + pll_in_khz = priv->refclk_rate / 1000; + + if (priv->dual_link) + multiplier = 2; + else + multiplier = 1; + + ret = lvds_pll_get_params(pll_in_khz, timings.pixelclock.typ * 7 / 1000 / multiplier, + &bdiv, &mdiv, &ndiv); + if (ret) + return ret; + + /* Set PLL parameters */ + lvds_writel(plat->base, LVDS_PXPLLCR2(phy), (ndiv << 16) | bdiv); + lvds_writel(plat->base, LVDS_PXPLLSDCR1(phy), mdiv); + lvds_writel(plat->base, LVDS_PXPLLTESTCR(phy), PXPLLTESTCR_TDIV_VALUE << 16); + + /* Disable TWG and SD: for now, PLL just need to be in integer mode */ + lvds_clear(plat->base, LVDS_PXPLLCR1(phy), PXPLLCR1_TWG_EN | PxPLLCR1_SD_EN); + + /* Power up bias and PLL dividers */ + lvds_set(plat->base, LVDS_PXDCR(phy), PXDCR_POWER_OK); + + lvds_set(plat->base, LVDS_PXCMCR1(phy), PXCMCR1_CM_EN_DL); + lvds_set(plat->base, LVDS_PXCMCR2(phy), PXCMCR2_CM_EN_DL4); + + lvds_set(plat->base, LVDS_PXPLLCPCR(phy), PXPLLCPCR_CPCTRL_DEFAULT); + lvds_set(plat->base, LVDS_PXBCR3(phy), PXBCR3_VM_EN_DL); + lvds_set(plat->base, LVDS_PXBCR1(phy), PXBCR1_EN_BIAS_DL); + lvds_set(plat->base, LVDS_PXCFGCR(phy), PXCFGCR_EN_DIG_DL); + + /* lvds_pll_enable */ + /* PLL lock timing control for the monitor unmask after startup (pll_en) */ + /* Adjust the value so that the masking window is opened at start-up */ + /* MST_MON_PLL_LOCK_UNMASK_TUNE */ + lvds_writel(plat->base, LVDS_PXMPLCR(phy), (0x200 - 0x160) << 16); + + lvds_writel(plat->base, LVDS_PXBCR2(phy), PXBCR2_BIAS_EN); + + lvds_set(plat->base, LVDS_PXGCR(phy), + PXGCR_DP_CLK_OUT | PXGCR_LS_CLK_OUT | PXGCR_BIT_CLK_OUT); + + lvds_set(plat->base, LVDS_PXPLLTESTCR(phy), PXPLLTESTCR_PLL_TDIV_EN); + lvds_set(plat->base, LVDS_PXPLLCR1(phy), PXPLLCR1_PLL_DIVIDERS_EN); + lvds_set(plat->base, LVDS_PXSCR(phy), PXSCR_SER_DATA_OK); + + /* Enable the LVDS PLL & wait for its lock */ + lvds_set(plat->base, LVDS_PXPLLCR1(phy), PXPLLCR1_PLL_EN); + ret = readl_poll_sleep_timeout(plat->base + LVDS_PXPLLSR(phy), + val, val & PXPLLSR_PLL_LOCK, SLEEP_US, TIMEOUT_US); + if (ret) + return ret; + + /* Select MST PHY clock as pixel clock for the LDITX instead of FREF */ + /* WCLKCR_SLV_CLKPIX_SEL is for dual link */ + lvds_writel(plat->base, LVDS_WCLKCR, WCLKCR_SLV_CLKPIX_SEL); + + lvds_set(plat->base, LVDS_PXPLLTESTCR(phy), PXPLLTESTCR_PLL_TEST_CLK_EN); + + return 0; +} + +static int stm32_lvds_enable(struct udevice *dev) +{ + struct stm32_lvds_plat *plat = dev_get_plat(dev); + struct stm32_lvds_priv *priv = dev_get_priv(dev); + struct display_timing timings = priv->timings; + u32 lvds_cdl1cr = 0; + u32 lvds_cdl2cr = 0; + u32 lvds_dmlcr = 0; + u32 lvds_dmmcr = 0; + u32 lvds_cr = 0; + int i; + + lvds_clear(plat->base, LVDS_CDL1CR, CDLCRX_DISTR0 | CDLCRX_DISTR1 | CDLCRX_DISTR2 + | CDLCRX_DISTR3 | CDLCRX_DISTR4); + lvds_clear(plat->base, LVDS_CDL2CR, CDLCRX_DISTR0 | CDLCRX_DISTR1 | CDLCRX_DISTR2 + | CDLCRX_DISTR3 | CDLCRX_DISTR4); + + /* Set channel distribution */ + lvds_cr &= ~CR_LKMOD; + lvds_cdl1cr = CDL1CR_DEFAULT; + + if (priv->dual_link) { + lvds_cr |= CR_LKMOD; + lvds_cdl2cr = CDL2CR_DEFAULT; + } + + /* Set signal polarity */ + if (timings.flags & DISPLAY_FLAGS_DE_LOW) + lvds_cr |= CR_DEPOL; + + if (timings.flags & DISPLAY_FLAGS_HSYNC_LOW) + lvds_cr |= CR_HSPOL; + + if (timings.flags & DISPLAY_FLAGS_VSYNC_LOW) + lvds_cr |= CR_VSPOL; + + /* Set link phase */ + switch (priv->dual_link) { + case LVDS_DUAL_LINK_EVEN_ODD_PIXELS: /* LKPHA = 0 */ + lvds_cr &= ~CR_LKPHA; + break; + case LVDS_DUAL_LINK_ODD_EVEN_PIXELS: /* LKPHA = 1 */ + lvds_cr |= CR_LKPHA; + break; + default: + dev_dbg(dev, "No phase precised, setting default\n"); + lvds_cr &= ~CR_LKPHA; + break; + } + + /* Set Data Mapping */ + switch (priv->bus_format) { + case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: /* VESA-RGB888 */ + for (i = 0; i < 5; i++) { + lvds_dmlcr = ((lvds_bitmap_vesa_rgb888[i][0]) + + (lvds_bitmap_vesa_rgb888[i][1] << 5) + + (lvds_bitmap_vesa_rgb888[i][2] << 10) + + (lvds_bitmap_vesa_rgb888[i][3] << 15)); + lvds_dmmcr = ((lvds_bitmap_vesa_rgb888[i][4]) + + (lvds_bitmap_vesa_rgb888[i][5] << 5) + + (lvds_bitmap_vesa_rgb888[i][6] << 10)); + + /* Write registers at the end of computations */ + lvds_writel(plat->base, LVDS_DMLCR(i), lvds_dmlcr); + lvds_writel(plat->base, LVDS_DMMCR(i), lvds_dmmcr); + } + break; + case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: /* JEIDA-RGB888 */ + for (i = 0; i < 5; i++) { + lvds_dmlcr = ((lvds_bitmap_jeida_rgb888[i][0]) + + (lvds_bitmap_jeida_rgb888[i][1] << 5) + + (lvds_bitmap_jeida_rgb888[i][2] << 10) + + (lvds_bitmap_jeida_rgb888[i][3] << 15)); + lvds_dmmcr = ((lvds_bitmap_jeida_rgb888[i][4]) + + (lvds_bitmap_jeida_rgb888[i][5] << 5) + + (lvds_bitmap_jeida_rgb888[i][6] << 10)); + + /* Write registers at the end of computations */ + lvds_writel(plat->base, LVDS_DMLCR(i), lvds_dmlcr); + lvds_writel(plat->base, LVDS_DMMCR(i), lvds_dmmcr); + } + break; + default: + dev_dbg(dev, "Unsupported LVDS bus format 0x%04x\n", priv->bus_format); + } + + /* Turn the output on */ + lvds_cr |= CR_LVDSEN; + + /* Commit config to registers */ + lvds_set(plat->base, LVDS_CR, lvds_cr); + lvds_writel(plat->base, LVDS_CDL1CR, lvds_cdl1cr); + lvds_writel(plat->base, LVDS_CDL2CR, lvds_cdl2cr); + + return 0; +} + +static int stm32_lvds_attach(struct udevice *dev) +{ + struct stm32_lvds_plat *plat = dev_get_plat(dev); + struct stm32_lvds_priv *priv = dev_get_priv(dev); + int ret; + + ret = panel_get_display_timing(plat->panel, &priv->timings); + if (ret) { + ret = ofnode_decode_display_timing(dev_ofnode(plat->panel), + 0, &priv->timings); + if (ret) { + dev_err(dev, "decode display timing error %d\n", ret); + return ret; + } + } + + ret = stm32_lvds_enable(dev); + + return ret; +} + +static int stm32_lvds_set_backlight(struct udevice *dev, int percent) +{ + struct stm32_lvds_plat *plat = dev_get_plat(dev); + int ret; + + ret = panel_enable_backlight(plat->panel); + if (ret) { + dev_err(dev, "panel %s enable backlight error %d\n", + plat->panel->name, ret); + } + + return ret; +} + +static int lvds_handle_pixel_order(struct stm32_lvds_plat *plat) +{ + ofnode parent, panel_port0, panel_port1; + bool even_pixels, odd_pixels; + int port0, port1; + + /* + * In case we are operating in single link, + * there is only one port linked to the LVDS. + * Check whether we are in this case and exit if yes. + */ + parent = ofnode_find_subnode(dev_ofnode(plat->panel), "ports"); + if (!ofnode_valid(parent)) + return 0; + + panel_port0 = ofnode_first_subnode(parent); + if (!ofnode_valid(panel_port0)) + return -EPIPE; + + even_pixels = ofnode_read_bool(panel_port0, "dual-lvds-even-pixels"); + odd_pixels = ofnode_read_bool(panel_port0, "dual-lvds-odd-pixels"); + if (even_pixels && odd_pixels) + return -EINVAL; + + port0 = even_pixels ? LVDS_DUAL_LINK_EVEN_ODD_PIXELS : + LVDS_DUAL_LINK_ODD_EVEN_PIXELS; + + panel_port1 = ofnode_next_subnode(panel_port0); + if (!ofnode_valid(panel_port1)) + return -EPIPE; + + even_pixels = ofnode_read_bool(panel_port1, "dual-lvds-even-pixels"); + odd_pixels = ofnode_read_bool(panel_port1, "dual-lvds-odd-pixels"); + if (even_pixels && odd_pixels) + return -EINVAL; + + port1 = even_pixels ? LVDS_DUAL_LINK_EVEN_ODD_PIXELS : + LVDS_DUAL_LINK_ODD_EVEN_PIXELS; + + /* + * A valid dual-LVDS bus is found when one port is marked with + * "dual-lvds-even-pixels", and the other port is marked with + * "dual-lvds-odd-pixels", bail out if the markers are not right. + */ + if (port0 + port1 != LVDS_DUAL_LINK_EVEN_ODD_PIXELS + LVDS_DUAL_LINK_ODD_EVEN_PIXELS) + return -EINVAL; + + return port0; +} + +static int stm32_lvds_of_to_plat(struct udevice *dev) +{ + struct stm32_lvds_plat *plat = dev_get_plat(dev); + struct stm32_lvds_priv *priv = dev_get_priv(dev); + const char *data_mapping; + int ret; + + plat->base = dev_read_addr_ptr(dev); + if ((fdt_addr_t)plat->base == FDT_ADDR_T_NONE) { + dev_err(dev, "Unable to read LVDS base address\n"); + return -EINVAL; + } + + ret = clk_get_by_name(dev, "pclk", &plat->pclk); + if (ret) { + dev_err(dev, "Unable to get peripheral clock: %d\n", ret); + return ret; + } + + ret = clk_get_by_name(dev, "ref", &plat->refclk); + if (ret) { + dev_err(dev, "Unable to get reference clock: %d\n", ret); + return ret; + } + + ret = reset_get_by_index(dev, 0, &plat->rst); + if (ret) { + dev_err(dev, "Failed to get LVDS reset: %d\n", ret); + return ret; + } + + ret = uclass_get_device_by_driver(UCLASS_PANEL, + DM_DRIVER_GET(simple_panel), &plat->panel); + if (ret) { + dev_err(dev, "panel device error %d\n", ret); + return ret; + } + + ret = panel_get_display_timing(plat->panel, &priv->timings); + if (ret) { + ret = ofnode_decode_display_timing(dev_ofnode(plat->panel), + 0, &priv->timings); + if (ret) { + dev_err(dev, "decode display timing error %d\n", ret); + return ret; + } + } + + data_mapping = ofnode_read_string(dev_ofnode(plat->panel), "data-mapping"); + if (!strcmp(data_mapping, "vesa-24")) + priv->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG; + else if (!strcmp(data_mapping, "jeida-24")) + priv->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA; + else + priv->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG; + + return 0; +} + +static int stm32_lvds_probe(struct udevice *dev) +{ + struct stm32_lvds_plat *plat = dev_get_plat(dev); + struct stm32_lvds_priv *priv = dev_get_priv(dev); + int ret; + + ret = clk_enable(&plat->pclk); + if (ret) { + dev_err(dev, "Failed to enable peripheral clock: %d\n", ret); + return ret; + } + + ret = clk_enable(&plat->refclk); + if (ret) { + dev_err(dev, "Failed to enable reference clock: %d\n", ret); + goto err_clk; + } + + priv->refclk_rate = (unsigned int)clk_get_rate(&plat->refclk); + + reset_deassert(&plat->rst); + + /* Handle dual link config */ + priv->dual_link = lvds_handle_pixel_order(plat); + if (priv->dual_link < 0) + goto err_rst; + + if (priv->dual_link > 0) { + ret = stm32_lvds_pll_enable(dev, LVDS_PHY_SLAVE); + if (ret) + goto err_rst; + } + + ret = stm32_lvds_pll_enable(dev, LVDS_PHY_MASTER); + if (ret) + goto err_rst; + + return 0; + +err_rst: + clk_disable(&plat->refclk); +err_clk: + clk_disable(&plat->pclk); + + return ret; +} + +static const struct video_bridge_ops stm32_lvds_ops = { + .attach = stm32_lvds_attach, + .set_backlight = stm32_lvds_set_backlight, +}; + +static const struct udevice_id stm32_lvds_ids[] = { + {.compatible = "st,stm32mp25-lvds"}, + {} +}; + +U_BOOT_DRIVER(stm32_lvds) = { + .name = "stm32-display-lvds", + .id = UCLASS_VIDEO_BRIDGE, + .of_match = stm32_lvds_ids, + .ops = &stm32_lvds_ops, + .of_to_plat = stm32_lvds_of_to_plat, + .probe = stm32_lvds_probe, + .plat_auto = sizeof(struct stm32_lvds_plat), + .priv_auto = sizeof(struct stm32_lvds_priv), +}; diff --git a/drivers/video/tegra/tegra124/dp.c b/drivers/video/tegra/tegra124/dp.c index b95b14da77d..611bf2f81a6 100644 --- a/drivers/video/tegra/tegra124/dp.c +++ b/drivers/video/tegra/tegra124/dp.c @@ -1515,7 +1515,6 @@ int tegra_dp_enable(struct udevice *dev, int panel_bpp, if (ret || retry >= DP_POWER_ON_MAX_TRIES) { debug("dp: failed to power on panel (0x%x)\n", ret); return -ENETUNREACH; - goto error_enable; } /* Confirm DP plugging status */ @@ -1561,7 +1560,6 @@ int tegra_dp_enable(struct udevice *dev, int panel_bpp, } priv->enabled = true; -error_enable: return 0; } diff --git a/drivers/video/tegra/tegra124/sor.c b/drivers/video/tegra/tegra124/sor.c index 1ce5330c6bc..ccdeefbcbb1 100644 --- a/drivers/video/tegra/tegra124/sor.c +++ b/drivers/video/tegra/tegra124/sor.c @@ -336,7 +336,7 @@ static int tegra_dc_sor_io_set_dpd(struct tegra_dc_sor_data *sor, int up) } reg_val = readl(pmc_base + APBDEV_PMC_IO_DPD2_REQ); - reg_val &= ~(APBDEV_PMC_IO_DPD2_REQ_LVDS_ON || + reg_val &= ~(APBDEV_PMC_IO_DPD2_REQ_LVDS_ON | APBDEV_PMC_IO_DPD2_REQ_CODE_DEFAULT_MASK); reg_val = up ? APBDEV_PMC_IO_DPD2_REQ_LVDS_ON | diff --git a/drivers/video/zynqmp/zynqmp_dpsub.c b/drivers/video/zynqmp/zynqmp_dpsub.c index 52af23c3c83..a0efd3393f5 100644 --- a/drivers/video/zynqmp/zynqmp_dpsub.c +++ b/drivers/video/zynqmp/zynqmp_dpsub.c @@ -240,7 +240,6 @@ static void avbuf_video_select(struct udevice *dev, enum av_buf_video_stream vid static void config_gfx_pipeline(struct udevice *dev) { struct zynqmp_dpsub_priv *dp_sub = dev_get_priv(dev); - u16 *csc_matrix, *offset_matrix; u32 regval = 0, index = 0, *scaling_factors = NULL; u16 rgb_coeffs[] = { 0x1000, 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, @@ -262,19 +261,18 @@ static void config_gfx_pipeline(struct udevice *dev) video->sampling_en; writel(regval, dp_sub->base_addr + AVBUF_V_BLEND_LAYER1_CONTROL); - if (video->is_rgb) { - csc_matrix = rgb_coeffs; - offset_matrix = rgb_offset; - } + if (!video->is_rgb) + return; + /* Program Colorspace conversion coefficients */ for (index = 9; index < 12; index++) { - writel(offset_matrix[index - 9], dp_sub->base_addr + + writel(rgb_offset[index - 9], dp_sub->base_addr + AVBUF_V_BLEND_IN2CSC_COEFF0 + (index * 4)); } /* Program Colorspace conversion matrix */ for (index = 0; index < 9; index++) { - writel(csc_matrix[index], dp_sub->base_addr + + writel(rgb_coeffs[index], dp_sub->base_addr + AVBUF_V_BLEND_IN2CSC_COEFF0 + (index * 4)); } } diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c index 1dbc1a56aa2..ac563991b90 100644 --- a/drivers/virtio/virtio-uclass.c +++ b/drivers/virtio/virtio-uclass.c @@ -328,7 +328,7 @@ static int virtio_uclass_child_pre_probe(struct udevice *vdev) debug("(%s): legacy virtio device\n", vdev->name); uc_priv->features = driver_features_legacy & device_features; } else { - debug("(%s): v1.0 complaint virtio device\n", vdev->name); + debug("(%s): v1.0 compliant virtio device\n", vdev->name); uc_priv->features = driver_features & device_features; } diff --git a/drivers/virtio/virtio_blk.c b/drivers/virtio/virtio_blk.c index 4224e3c17f4..3dd0cf36268 100644 --- a/drivers/virtio/virtio_blk.c +++ b/drivers/virtio/virtio_blk.c @@ -16,7 +16,7 @@ #include "virtio_blk.h" /** - * struct virtio_blk_priv - private date for virtio block device + * struct virtio_blk_priv - private data for virtio block device */ struct virtio_blk_priv { /** @virtqueue - virtqueue to process */ @@ -26,6 +26,7 @@ struct virtio_blk_priv { }; static const u32 feature[] = { + VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_WRITE_ZEROES }; @@ -194,7 +195,7 @@ static int virtio_blk_probe(struct udevice *dev) virtio_cread(dev, struct virtio_blk_config, capacity, &cap); desc->lba = cap; - if (!virtio_has_feature(dev, VIRTIO_BLK_F_BLK_SIZE)) { + if (virtio_has_feature(dev, VIRTIO_BLK_F_BLK_SIZE)) { virtio_cread(dev, struct virtio_blk_config, blk_size, &blk_size); desc->blksz = blk_size; if (!is_power_of_2(blk_size) || desc->blksz < 512) diff --git a/drivers/w1-eeprom/ds24xxx.c b/drivers/w1-eeprom/ds24xxx.c index 413d8bc5881..801fade6f49 100644 --- a/drivers/w1-eeprom/ds24xxx.c +++ b/drivers/w1-eeprom/ds24xxx.c @@ -53,7 +53,7 @@ U_BOOT_DRIVER(ds24xxx) = { .probe = ds24xxx_probe, }; -u8 family_supported[] = { +static u8 family_supported[] = { W1_FAMILY_DS24B33, W1_FAMILY_DS2431, }; diff --git a/drivers/w1-eeprom/ds2502.c b/drivers/w1-eeprom/ds2502.c index db9f41e9726..981b41a34b2 100644 --- a/drivers/w1-eeprom/ds2502.c +++ b/drivers/w1-eeprom/ds2502.c @@ -243,7 +243,7 @@ U_BOOT_DRIVER(ds2502) = { .probe = ds2502_probe, }; -u8 family_supported[] = { +static u8 family_supported[] = { W1_FAMILY_DS2502, }; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 9e149a75e81..35ae7d106b1 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -44,6 +44,7 @@ config HW_WATCHDOG config IMX_WATCHDOG bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP" + depends on MACH_IMX select HW_WATCHDOG if !WDT help Select this to enable the IMX and LSCH2 of Layerscape watchdog @@ -65,6 +66,7 @@ config OMAP_WATCHDOG config ULP_WATCHDOG bool "i.MX7ULP watchdog" + depends on MACH_IMX help Say Y here to enable i.MX7ULP watchdog driver. @@ -117,8 +119,8 @@ config WDT_ARMADA_37XX config WDT_ASPEED bool "Aspeed ast2400/ast2500 watchdog timer support" - depends on WDT - default y if ARCH_ASPEED + depends on WDT && ARCH_ASPEED + default y help Select this to enable watchdog timer for Aspeed ast2500/ast2400 devices. The watchdog timer is stopped when initialized. It performs reset, either @@ -128,8 +130,8 @@ config WDT_ASPEED config WDT_AST2600 bool "Aspeed AST2600 watchdog timer support" - depends on WDT - default y if ASPEED_AST2600 + depends on WDT && ASPEED_AST2600 + default y help Select this to enable watchdog timer for Aspeed ast2500/ast2400 devices. The watchdog timer is stopped when initialized. It performs reset, either @@ -137,7 +139,7 @@ config WDT_AST2600 config WDT_AT91 bool "AT91 watchdog timer support" - depends on WDT + depends on WDT && ARCH_AT91 help Select this to enable Microchip watchdog timer, which can be found on some AT91 devices. @@ -174,7 +176,7 @@ config WDT_CDNS config WDT_CORTINA bool "Cortina Access CAxxxx watchdog timer support" - depends on WDT + depends on WDT && TARGET_PRESIDIO_ASIC help Cortina Access CAxxxx watchdog timer support. This driver support all CPU ISAs supported by Cortina @@ -188,7 +190,7 @@ config WDT_DA9063 config WDT_DAVINCI bool "DaVinci watchdog timer support" - depends on WDT + depends on WDT && (ARCH_DAVINCI || ARCH_KEYSTONE) help Select this to enable the watchdog timer for DaVinci SoCs such as the OMAP-L138. @@ -220,7 +222,7 @@ config WDT_MAX6370 config WDT_MCF bool "ColdFire family watchdog timer support" - depends on WDT + depends on WDT && M68K help Select this to enable ColdFire watchdog timer, which supports mcf52x2 mcf532x mcf523x families. @@ -304,7 +306,7 @@ config WDT_OMAP3 config WDT_ORION bool "Orion watchdog timer support" - depends on WDT + depends on WDT && ARCH_MVEBU select CLK help Select this to enable Orion watchdog timer, which can be found on some @@ -454,6 +456,12 @@ config WDT_TANGIER Intel Tangier SoC. If you're using a board with Intel Tangier SoC, say Y here. +config WDT_TEGRA + bool "Tegra watchdog" + depends on WDT && ARCH_TEGRA + help + Enable support for the watchdog timer found in Tegra SoCs. + config WDT_ARM_SMC bool "ARM SMC watchdog timer support" depends on WDT && ARM_SMCCC diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index d52d17e1c90..02e2674f8af 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_WDT_STARFIVE) += starfive_wdt.o obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o +obj-$(CONFIG_WDT_TEGRA) += tegra_wdt.o obj-$(CONFIG_WDT_XILINX) += xilinx_wwdt.o obj-$(CONFIG_WDT_ADI) += adi_wdt.o obj-$(CONFIG_WDT_QCOM) += qcom-wdt.o diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c new file mode 100644 index 00000000000..adc30da579a --- /dev/null +++ b/drivers/watchdog/tegra_wdt.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NVIDIA Tegra Watchdog driver + * + * Copyright (C) 2025 NABLA Software Engineering + * Lukasz Majewski, NABLA Software Engineering, lukma@nabladev.com + */ + +#include <dm.h> +#include <wdt.h> +#include <hang.h> +#include <asm/io.h> +#include <watchdog.h> + +/* Timer registers */ +#define TIMER_PTV 0x0 +#define TIMER_EN BIT(31) +#define TIMER_PERIODIC BIT(30) + +/* WDT registers */ +#define WDT_CFG 0x0 +#define WDT_CFG_PERIOD_SHIFT 4 +#define WDT_CFG_PERIOD_MASK GENMASK(7, 0) +#define WDT_CFG_INT_EN BIT(12) +#define WDT_CFG_PMC2CAR_RST_EN BIT(15) +#define WDT_CMD 0x8 +#define WDT_CMD_START_COUNTER BIT(0) +#define WDT_CMD_DISABLE_COUNTER BIT(1) +#define WDT_UNLOCK 0xc +#define WDT_UNLOCK_PATTERN 0xc45a + +/* Use watchdog ID 0 */ +#define WDT_BASE 0x100 + +/* Use Timer 5 as WDT counter */ +#define WDT_TIMER_BASE 0x60 +#define WDT_TIMER_ID 5 + +struct tegra_wdt_priv { + void __iomem *wdt_base; + void __iomem *tmr_base; +}; + +static int tegra_wdt_reset(struct udevice *dev) +{ + struct tegra_wdt_priv *priv = dev_get_priv(dev); + + writel(WDT_CMD_START_COUNTER, priv->wdt_base + WDT_CMD); + + return 0; +} + +static int tegra_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct tegra_wdt_priv *priv = dev_get_priv(dev); + u32 timeout_sec = timeout / 1000; + + /* Support for timeout from 1 to 255 seconds */ + if (timeout_sec < 1 || timeout_sec > 255) + return -EINVAL; + + /* + * Timer for WDT has a fixed 1MHz clock, so for 1 second period one + * shall write 1000000ul. + * + * On Tegra the watchdog reset actually occurs on the 4th expiration + * of this counter, so we set the period to 1/4. + */ + writel(TIMER_EN | TIMER_PERIODIC | (1000000ul / 4), + priv->tmr_base + TIMER_PTV); + + writel(WDT_CFG_PMC2CAR_RST_EN | (timeout_sec << WDT_CFG_PERIOD_SHIFT) | + WDT_TIMER_ID, priv->wdt_base + WDT_CFG); + + writel(WDT_CMD_START_COUNTER, priv->wdt_base + WDT_CMD); + + return 0; +} + +static int tegra_wdt_stop(struct udevice *dev) +{ + struct tegra_wdt_priv *priv = dev_get_priv(dev); + + writel(WDT_UNLOCK_PATTERN, priv->wdt_base + WDT_UNLOCK); + writel(WDT_CMD_DISABLE_COUNTER, priv->wdt_base + WDT_CMD); + writel(0, priv->tmr_base + TIMER_PTV); + + return 0; +} + +static int tegra_wdt_probe(struct udevice *dev) +{ + struct tegra_wdt_priv *priv = dev_get_priv(dev); + void __iomem *base; + + base = dev_read_addr_ptr(dev); + if (!base) + return -ENOENT; + + priv->wdt_base = base + WDT_BASE; + priv->tmr_base = base + WDT_TIMER_BASE; + + return 0; +} + +static const struct wdt_ops tegra_wdt_ops = { + .start = tegra_wdt_start, + .stop = tegra_wdt_stop, + .reset = tegra_wdt_reset, +}; + +U_BOOT_DRIVER(tegra_wdt) = { + .name = "tegra_wdt", + .id = UCLASS_WDT, + .probe = tegra_wdt_probe, + .ops = &tegra_wdt_ops, + .priv_auto = sizeof(struct tegra_wdt_priv), +}; |
