diff options
Diffstat (limited to 'drivers')
533 files changed, 40197 insertions, 4416 deletions
diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 2b45f9e5eba..d5ef0795401 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -5,7 +5,7 @@ config ADC This enables ADC API for drivers, which allows driving ADC features by single and multi-channel methods for: - start/stop/get data for conversion of a single-channel selected by - a number or multi-channels selected by a bitmask + a number or multi-channels selected by a bitmask - get data mask (ADC resolution) ADC reference Voltage supply options: - methods for get Vdd/Vss reference Voltage values with polarity diff --git a/drivers/ata/dwc_ahci.c b/drivers/ata/dwc_ahci.c index b480cde4465..0431d370716 100644 --- a/drivers/ata/dwc_ahci.c +++ b/drivers/ata/dwc_ahci.c @@ -39,7 +39,7 @@ static int dwc_ahci_of_to_plat(struct udevice *dev) priv->base = map_physmem(dev_read_addr(dev), sizeof(void *), MAP_NOCACHE); - addr = devfdt_get_addr_index(dev, 1); + addr = dev_read_addr_index(dev, 1); if (addr != FDT_ADDR_T_NONE) { priv->wrapper_base = map_physmem(addr, sizeof(void *), MAP_NOCACHE); diff --git a/drivers/ata/fsl_sata.c b/drivers/ata/fsl_sata.c index 4990148388b..a29735f7609 100644 --- a/drivers/ata/fsl_sata.c +++ b/drivers/ata/fsl_sata.c @@ -960,7 +960,7 @@ static int sata_fsl_scan(struct udevice *dev) return 0; } -struct ahci_ops sata_fsl_ahci_ops = { +static const struct ahci_ops sata_fsl_ahci_ops = { .scan = sata_fsl_scan, }; diff --git a/drivers/ata/mtk_ahci.c b/drivers/ata/mtk_ahci.c index 53aabee0a5e..1d4245ee635 100644 --- a/drivers/ata/mtk_ahci.c +++ b/drivers/ata/mtk_ahci.c @@ -45,7 +45,9 @@ static int mtk_ahci_of_to_plat(struct udevice *dev) { struct mtk_ahci_priv *priv = dev_get_priv(dev); - priv->base = devfdt_remap_addr_index(dev, 0); + priv->base = dev_remap_addr_index(dev, 0); + if (!priv->base) + return -EINVAL; return 0; } @@ -54,11 +56,9 @@ static int mtk_ahci_parse_property(struct ahci_uc_priv *hpriv, struct udevice *dev) { struct mtk_ahci_priv *plat = dev_get_priv(dev); - const void *fdt = gd->fdt_blob; /* enable SATA function if needed */ - if (fdt_get_property(fdt, dev_of_offset(dev), - "mediatek,phy-mode", NULL)) { + if (dev_read_prop(dev, "mediatek,phy-mode", NULL)) { plat->mode = syscon_regmap_lookup_by_phandle(dev, "mediatek,phy-mode"); if (IS_ERR(plat->mode)) { @@ -69,8 +69,8 @@ static int mtk_ahci_parse_property(struct ahci_uc_priv *hpriv, SYS_CFG_SATA_MSK, SYS_CFG_SATA_EN); } - ofnode_read_u32(dev_ofnode(dev), "ports-implemented", - &hpriv->port_map); + dev_read_u32(dev, "ports-implemented", &hpriv->port_map); + return 0; } diff --git a/drivers/ata/sata_bootdev.c b/drivers/ata/sata_bootdev.c index a5ca6f6fd5b..7d5ef3c94bf 100644 --- a/drivers/ata/sata_bootdev.c +++ b/drivers/ata/sata_bootdev.c @@ -37,9 +37,6 @@ static int sata_bootdev_hunt(struct bootdev_hunter *info, bool show) return 0; } -struct bootdev_ops sata_bootdev_ops = { -}; - static const struct udevice_id sata_bootdev_ids[] = { { .compatible = "u-boot,bootdev-sata" }, { } @@ -48,7 +45,6 @@ static const struct udevice_id sata_bootdev_ids[] = { U_BOOT_DRIVER(sata_bootdev) = { .name = "sata_bootdev", .id = UCLASS_BOOTDEV, - .ops = &sata_bootdev_ops, .bind = sata_bootdev_bind, .of_match = sata_bootdev_ids, }; diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index b8c73b4a9dd..3fb1a245698 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1122,7 +1122,7 @@ static const struct udevice_id sata_mv_ids[] = { { } }; -struct ahci_ops sata_mv_ahci_ops = { +static const struct ahci_ops sata_mv_ahci_ops = { .scan = sata_mv_scan, }; diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index adf338ab00c..d44cf4bcb6b 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -68,10 +68,10 @@ config BLKMAP bool "Composable virtual block devices (blkmap)" depends on BLK help - Create virtual block devices that are backed by various sources, - e.g. RAM, or parts of an existing block device. Though much more - rudimentary, it borrows a lot of ideas from Linux's device mapper - subsystem. + Create virtual block devices that are backed by various sources, + e.g. RAM, or parts of an existing block device. Though much more + rudimentary, it borrows a lot of ideas from Linux's device mapper + subsystem. Example use-cases: - Treat a region of RAM as a block device, i.e. a RAM disk. This let's diff --git a/drivers/block/Makefile b/drivers/block/Makefile index f5a9d8637a3..c827fa81a2d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -13,7 +13,7 @@ ifndef CONFIG_XPL_BUILD obj-$(CONFIG_IDE) += ide.o obj-$(CONFIG_RKMTD) += rkmtd.o endif -obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o host_dev.o +obj-$(CONFIG_SANDBOX) += sandbox.o sandbox-bootdev.o host-uclass.o host_dev.o obj-$(CONFIG_$(PHASE_)BLOCK_CACHE) += blkcache.o obj-$(CONFIG_$(PHASE_)BLKMAP) += blkmap.o obj-$(CONFIG_$(PHASE_)BLKMAP) += blkmap_helper.o diff --git a/drivers/block/host-uclass.c b/drivers/block/host-uclass.c index cf42bd1e07a..95b0b0b2ffe 100644 --- a/drivers/block/host-uclass.c +++ b/drivers/block/host-uclass.c @@ -150,6 +150,21 @@ struct udevice *host_find_by_label(const char *label) return NULL; } +int host_set_flags_by_label(const char *label, unsigned int flags) +{ + struct udevice *dev; + struct host_sb_plat *plat; + + dev = host_find_by_label(label); + if (!dev) + return -ENODEV; + + plat = dev_get_plat(dev); + plat->flags = flags; + + return 0; +} + struct udevice *host_get_cur_dev(void) { struct uclass *uc = uclass_find(UCLASS_HOST); diff --git a/drivers/block/ide.c b/drivers/block/ide.c index cab5e1bc92b..c1a46dd2a94 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -969,9 +969,6 @@ static int ide_bootdev_hunt(struct bootdev_hunter *info, bool show) return 0; } -struct bootdev_ops ide_bootdev_ops = { -}; - static const struct udevice_id ide_bootdev_ids[] = { { .compatible = "u-boot,bootdev-ide" }, { } @@ -980,7 +977,6 @@ static const struct udevice_id ide_bootdev_ids[] = { U_BOOT_DRIVER(ide_bootdev) = { .name = "ide_bootdev", .id = UCLASS_BOOTDEV, - .ops = &ide_bootdev_ops, .bind = ide_bootdev_bind, .of_match = ide_bootdev_ids, }; diff --git a/drivers/block/rkmtd.c b/drivers/block/rkmtd.c index f84cacd7ead..9334ab24a61 100644 --- a/drivers/block/rkmtd.c +++ b/drivers/block/rkmtd.c @@ -935,7 +935,7 @@ int rkmtd_detach_mtd(struct udevice *dev) return 0; } -struct rkmtd_ops rkmtd_ops = { +static const struct rkmtd_ops rkmtd_ops = { .attach_mtd = rkmtd_attach_mtd, .detach_mtd = rkmtd_detach_mtd, }; diff --git a/drivers/block/sandbox-bootdev.c b/drivers/block/sandbox-bootdev.c new file mode 100644 index 00000000000..15af0c17d1f --- /dev/null +++ b/drivers/block/sandbox-bootdev.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#define LOG_CATEGORY UCLASS_HOST + +#include <bootdev.h> +#include <dm.h> +#include <log.h> +#include <sandbox_host.h> + +static int sandbox_bootdev_bind(struct udevice *dev) +{ + struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); + + ucp->prio = BOOTDEVP_4_SCAN_FAST; + + return 0; +} + +/** + * sandbox_bootdev_hunt() - Hunt host bootdev. + * + * Note, this hunter exists for bootdev testing to simulate a failure + * mode. Do not use as an example of a real hunter. + * + * @info: Hunter details. + * @show: Enable extra printouts. + * + * Returns: 0 if OK, -ve on error (expected by the test) + */ +static int sandbox_bootdev_hunt(struct bootdev_hunter *info, bool show) +{ + struct udevice *dev; + struct uclass *uc; + int ret; + + uclass_id_foreach_dev(UCLASS_HOST, dev, uc) { + struct host_sb_plat *plat = dev_get_plat(dev); + + log_debug("hunting %s\n", plat->label); + + if (plat->flags & HOST_FLAG_BROKEN) { + ret = -ETIME; + log_debug("cannot hunt sandbox device '%s': %d\n", + plat->label, ret); + return ret; + } + } + + return 0; +} + +static const struct bootdev_ops sandbox_bootdev_ops = { +}; + +static const struct udevice_id sandbox_bootdev_ids[] = { + { .compatible = "u-boot,bootdev-sandbox" }, + { } +}; + +U_BOOT_DRIVER(sandbox_bootdev) = { + .name = "sandbox_bootdev", + .id = UCLASS_BOOTDEV, + .ops = &sandbox_bootdev_ops, + .bind = sandbox_bootdev_bind, + .of_match = sandbox_bootdev_ids, +}; + +BOOTDEV_HUNTER(sandbox_bootdev_hunter) = { + .prio = BOOTDEVP_4_SCAN_FAST, + .uclass = UCLASS_HOST, + .hunt = sandbox_bootdev_hunt, + .drv = DM_DRIVER_REF(sandbox_bootdev), +}; diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig index 99b6c7534fd..af6bd2f1a7d 100644 --- a/drivers/bootcount/Kconfig +++ b/drivers/bootcount/Kconfig @@ -6,7 +6,7 @@ menuconfig BOOTCOUNT_LIMIT bool "Enable support for checking boot count limit" help Enable checking for exceeding the boot count limit. - More information: https://docs.u-boot.org/en/latest/api/bootcount.html + More information: https://docs.u-boot-project.org/en/latest/api/bootcount.html if BOOTCOUNT_LIMIT @@ -68,7 +68,7 @@ config BOOTCOUNT_ENV saveenv on all reboots, the environment variable "upgrade_available" is used. If "upgrade_available" is 0, "bootcount" is always 0. If "upgrade_available" is 1, - "bootcount" is incremented in the environment. + "bootcount" is incremented in the environment. So the Userspace Application must set the "upgrade_available" and "bootcount" variables to 0, if the system booted successfully. @@ -83,7 +83,7 @@ config BOOTCOUNT_AT91 depends on AT91SAM9XE config DM_BOOTCOUNT - bool "Boot counter in a device-model device" + bool "Boot counter in a device-model device" help Enables reading/writing the bootcount in a device-model based backing store. If an entry in /chosen/u-boot,bootcount-device diff --git a/drivers/bootcount/bootcount_ram.c b/drivers/bootcount/bootcount_ram.c index 33e157b865a..f726d9ab016 100644 --- a/drivers/bootcount/bootcount_ram.c +++ b/drivers/bootcount/bootcount_ram.c @@ -27,7 +27,7 @@ void bootcount_store(ulong a) int i; for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) - size += gd->bd->bi_dram[i].size; + size += gd->dram[i].size; save_addr = (ulong *)(size - BOOTCOUNT_ADDR); writel(a, save_addr); writel(CONFIG_SYS_BOOTCOUNT_MAGIC, &save_addr[1]); @@ -50,7 +50,7 @@ ulong bootcount_load(void) int i, tmp; for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) - size += gd->bd->bi_dram[i].size; + size += gd->dram[i].size; save_addr = (ulong *)(size - BOOTCOUNT_ADDR); counter = readl(&save_addr[0]); diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig index 3bf5c7f5dbf..5ebc8842acd 100644 --- a/drivers/cache/Kconfig +++ b/drivers/cache/Kconfig @@ -14,7 +14,7 @@ config CACHE configuring settings that be found from a device tree file. config L2X0_CACHE - tristate "PL310 cache driver" + bool "PL310 cache driver" select CACHE depends on ARM help diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c2da7b3938b..145e4cfa2de 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -134,8 +134,8 @@ config CLK_CDCE9XX bool "Enable CDCD9XX clock driver" depends on CLK && ARCH_OMAP2PLUS help - Enable the clock synthesizer driver for CDCE913/925/937/949 - series of chips. + Enable the clock synthesizer driver for CDCE913/925/937/949 + series of chips. config CLK_ICS8N3QV01 bool "Enable ICS8N3QV01 VCXO driver" @@ -216,7 +216,7 @@ config CLK_HSDK Synopsys ARC HSDK-4xD boards config CLK_VERSACLOCK - tristate "Enable VersaClock 5/6 devices" + bool "Enable VersaClock 5/6 devices" depends on CLK depends on CLK_CCF depends on OF_CONTROL @@ -277,11 +277,12 @@ source "drivers/clk/mvebu/Kconfig" source "drivers/clk/owl/Kconfig" source "drivers/clk/qcom/Kconfig" source "drivers/clk/renesas/Kconfig" -source "drivers/clk/sophgo/Kconfig" -source "drivers/clk/sunxi/Kconfig" source "drivers/clk/sifive/Kconfig" +source "drivers/clk/sophgo/Kconfig" +source "drivers/clk/spacemit/Kconfig" source "drivers/clk/starfive/Kconfig" source "drivers/clk/stm32/Kconfig" +source "drivers/clk/sunxi/Kconfig" source "drivers/clk/tegra/Kconfig" source "drivers/clk/ti/Kconfig" source "drivers/clk/thead/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 5f0c0d8a5c2..2bfa789e48a 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -16,7 +16,7 @@ obj-$(CONFIG_$(PHASE_)CLK_STUB) += clk-stub.o obj-y += adi/ obj-y += airoha/ obj-y += analogbits/ -obj-y += imx/ +obj-$(CONFIG_MACH_IMX) += imx/ obj-$(CONFIG_CLK_JH7110) += starfive/ obj-y += tegra/ obj-y += ti/ @@ -48,6 +48,7 @@ obj-$(CONFIG_CLK_RENESAS) += renesas/ obj-$(CONFIG_$(PHASE_)CLK_SCMI) += clk_scmi.o obj-$(CONFIG_CLK_SIFIVE) += sifive/ obj-$(CONFIG_CLK_SOPHGO) += sophgo/ +obj-$(CONFIG_CLK_SPACEMIT) += spacemit/ obj-$(CONFIG_CLK_SUNXI) += sunxi/ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ obj-$(CONFIG_CLK_VERSACLOCK) += clk_versaclock.o diff --git a/drivers/clk/airoha/clk-airoha.c b/drivers/clk/airoha/clk-airoha.c index 49dbca82135..89a8b4cb1cf 100644 --- a/drivers/clk/airoha/clk-airoha.c +++ b/drivers/clk/airoha/clk-airoha.c @@ -327,7 +327,7 @@ static int airoha_clk_enable(struct clk *clk) struct airoha_clk_soc_data *data = priv->data; int id = clk->id; - if (id > data->num_clocks) + if (id >= data->num_clocks) return -EINVAL; return 0; @@ -349,7 +349,7 @@ static ulong airoha_clk_get_rate(struct clk *clk) ulong rate; int ret; - if (id > data->num_clocks) { + if (id >= data->num_clocks) { dev_err(clk->dev, "Invalid clk ID %d\n", id); return 0; } @@ -412,7 +412,7 @@ static ulong airoha_clk_set_rate(struct clk *clk, ulong rate) int div; int ret; - if (id > data->num_clocks) { + if (id >= data->num_clocks) { dev_err(clk->dev, "Invalid clk ID %d\n", id); return 0; } diff --git a/drivers/clk/altera/clk-mem-n5x.c b/drivers/clk/altera/clk-mem-n5x.c index ac59571a853..149e3016dd3 100644 --- a/drivers/clk/altera/clk-mem-n5x.c +++ b/drivers/clk/altera/clk-mem-n5x.c @@ -103,12 +103,13 @@ static int socfpga_mem_clk_enable(struct clk *clk) static int socfpga_mem_clk_of_to_plat(struct udevice *dev) { struct socfpga_mem_clk_plat *plat = dev_get_plat(dev); - fdt_addr_t addr; + void __iomem *addr; - addr = devfdt_get_addr(dev); - if (addr == FDT_ADDR_T_NONE) + addr = dev_read_addr_ptr(dev); + if (!addr) return -EINVAL; - plat->regs = (void __iomem *)addr; + + plat->regs = addr; return 0; } diff --git a/drivers/clk/altera/clk-n5x.c b/drivers/clk/altera/clk-n5x.c index 185c9028a78..0a3bae38589 100644 --- a/drivers/clk/altera/clk-n5x.c +++ b/drivers/clk/altera/clk-n5x.c @@ -454,12 +454,12 @@ static int socfpga_clk_probe(struct udevice *dev) static int socfpga_clk_of_to_plat(struct udevice *dev) { struct socfpga_clk_plat *plat = dev_get_plat(dev); - fdt_addr_t addr; + void __iomem *addr; - addr = devfdt_get_addr(dev); - if (addr == FDT_ADDR_T_NONE) + addr = dev_read_addr_ptr(dev); + if (!addr) return -EINVAL; - plat->regs = (void __iomem *)addr; + plat->regs = addr; return 0; } diff --git a/drivers/clk/aspeed/Makefile b/drivers/clk/aspeed/Makefile index 84776e5265e..285180b67cf 100644 --- a/drivers/clk/aspeed/Makefile +++ b/drivers/clk/aspeed/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_ASPEED_AST2500) += clk_ast2500.o obj-$(CONFIG_ASPEED_AST2600) += clk_ast2600.o +obj-$(CONFIG_ASPEED_AST2700) += clk_ast2700.o diff --git a/drivers/clk/aspeed/clk_ast2500.c b/drivers/clk/aspeed/clk_ast2500.c index a330dcda4dc..94c7f662319 100644 --- a/drivers/clk/aspeed/clk_ast2500.c +++ b/drivers/clk/aspeed/clk_ast2500.c @@ -534,7 +534,7 @@ static int ast2500_clk_enable(struct clk *clk) return 0; } -struct clk_ops ast2500_clk_ops = { +static const struct clk_ops ast2500_clk_ops = { .get_rate = ast2500_clk_get_rate, .set_rate = ast2500_clk_set_rate, .enable = ast2500_clk_enable, @@ -544,9 +544,9 @@ static int ast2500_clk_of_to_plat(struct udevice *dev) { struct ast2500_clk_priv *priv = dev_get_priv(dev); - priv->scu = devfdt_get_addr_ptr(dev); - if (IS_ERR(priv->scu)) - return PTR_ERR(priv->scu); + priv->scu = dev_read_addr_ptr(dev); + if (!priv->scu) + return -EINVAL; return 0; } diff --git a/drivers/clk/aspeed/clk_ast2600.c b/drivers/clk/aspeed/clk_ast2600.c index 535010b7941..74209e947ed 100644 --- a/drivers/clk/aspeed/clk_ast2600.c +++ b/drivers/clk/aspeed/clk_ast2600.c @@ -1161,7 +1161,7 @@ static void ast2600_clk_dump(struct udevice *dev) } #endif -struct clk_ops ast2600_clk_ops = { +static const struct clk_ops ast2600_clk_ops = { .get_rate = ast2600_clk_get_rate, .set_rate = ast2600_clk_set_rate, .enable = ast2600_clk_enable, @@ -1174,9 +1174,9 @@ static int ast2600_clk_probe(struct udevice *dev) { struct ast2600_clk_priv *priv = dev_get_priv(dev); - priv->scu = devfdt_get_addr_ptr(dev); - if (IS_ERR(priv->scu)) - return PTR_ERR(priv->scu); + priv->scu = dev_read_addr_ptr(dev); + if (!priv->scu) + return -EINVAL; ast2600_init_rgmii_clk(priv->scu, &rgmii_clk_defconfig); ast2600_init_rmii_clk(priv->scu, &rmii_clk_defconfig); diff --git a/drivers/clk/aspeed/clk_ast2700.c b/drivers/clk/aspeed/clk_ast2700.c new file mode 100644 index 00000000000..ca76abef48f --- /dev/null +++ b/drivers/clk/aspeed/clk_ast2700.c @@ -0,0 +1,952 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) ASPEED Technology Inc. + */ + +#include <asm/io.h> +#include <asm/arch/scu_ast2700.h> +#include <clk-uclass.h> +#include <dm.h> +#include <dm/lists.h> +#include <syscon.h> +#include <linux/bitfield.h> + +#include <dt-bindings/clock/aspeed,ast2700-scu.h> + +DECLARE_GLOBAL_DATA_PTR; + +/** + * RGMII clock source tree + * HPLL -->|\ + * | |---->| divider |---->RGMII 125M for MAC#0 & MAC#1 + * APLL -->|/ + */ +#define RGMII_DEFAULT_CLK_SRC SCU1_CLK_HPLL + +struct mac_delay_config { + u32 tx_delay_1000; + u32 rx_delay_1000; + u32 tx_delay_100; + u32 rx_delay_100; + u32 tx_delay_10; + u32 rx_delay_10; +}; + +typedef int (*ast2700_clk_init_fn)(struct udevice *dev); + +struct ast2700_clk_priv { + void __iomem *reg; + ast2700_clk_init_fn init; +}; + +static u32 ast2700_soc1_get_pll_rate(struct ast2700_scu1 *scu, int pll_idx) +{ + union ast2700_pll_reg pll_reg; + u32 mul = 1, div = 1; + + switch (pll_idx) { + case SCU1_CLK_HPLL: + pll_reg.w = readl(&scu->hpll); + break; + case SCU1_CLK_APLL: + pll_reg.w = readl(&scu->apll); + break; + case SCU1_CLK_DPLL: + pll_reg.w = readl(&scu->dpll); + break; + } + + if (!pll_reg.b.bypass) { + mul = (pll_reg.b.m + 1) / (pll_reg.b.n + 1); + div = (pll_reg.b.p + 1); + } + + return ((CLKIN_25M * mul) / div); +} + +#define SCU_CLKSEL2_HCLK_DIV_MASK GENMASK(22, 20) +#define SCU_CLKSEL2_HCLK_DIV_SHIFT 20 + +static u32 ast2700_soc1_get_hclk_rate(struct ast2700_scu1 *scu) +{ + u32 rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + u32 clk_sel2 = readl(&scu->clk_sel2); + u32 hclk_div = (clk_sel2 & SCU_CLKSEL2_HCLK_DIV_MASK) >> + SCU_CLKSEL2_HCLK_DIV_SHIFT; + + if (!hclk_div) + hclk_div = 2; + else + hclk_div++; + + return (rate / hclk_div); +} + +#define SCU1_CLKSEL1_PCLK_DIV_MASK GENMASK(20, 18) +#define SCU1_CLKSEL1_PCLK_DIV_SHIFT 18 + +static u32 ast2700_soc1_get_pclk_rate(struct ast2700_scu1 *scu) +{ + u32 rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + + u32 clk_sel1 = readl(&scu->clk_sel1); + u32 pclk_div = (clk_sel1 & SCU1_CLKSEL1_PCLK_DIV_MASK) >> + SCU1_CLKSEL1_PCLK_DIV_SHIFT; + + return (rate / ((pclk_div + 1) * 2)); +} + +#define SCU_UART_CLKGEN_N_MASK GENMASK(17, 8) +#define SCU_UART_CLKGEN_N_SHIFT 8 +#define SCU_UART_CLKGEN_R_MASK GENMASK(7, 0) +#define SCU_UART_CLKGEN_R_SHIFT 0 + +static u32 ast2700_soc1_get_uart_uxclk_rate(struct ast2700_scu1 *scu) +{ + u32 uxclk_sel = readl(&scu->clk_sel2) & GENMASK(1, 0); + u32 uxclk_ctrl = readl(&scu->uxclk_ctrl); + u32 rate; + + switch (uxclk_sel) { + case 0: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL) / 4; + break; + case 1: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL) / 2; + break; + case 2: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL); + break; + case 3: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + break; + } + + u32 n = (uxclk_ctrl & SCU_UART_CLKGEN_N_MASK) >> + SCU_UART_CLKGEN_N_SHIFT; + u32 r = (uxclk_ctrl & SCU_UART_CLKGEN_R_MASK) >> + SCU_UART_CLKGEN_R_SHIFT; + + return ((rate * r) / (n * 2)); +} + +#define SCU_HUART_CLKGEN_N_MASK GENMASK(17, 8) +#define SCU_HUART_CLKGEN_N_SHIFT 8 +#define SCU_HUART_CLKGEN_R_MASK GENMASK(7, 0) +#define SCU_HUART_CLKGEN_R_SHIFT 0 + +static u32 ast2700_soc1_get_uart_huxclk_rate(struct ast2700_scu1 *scu) +{ + u32 huxclk_sel = (readl(&scu->clk_sel2) & GENMASK(4, 3)) >> 3; + u32 huxclk_ctrl = readl(&scu->huxclk_ctrl); + u32 n = (huxclk_ctrl & SCU_HUART_CLKGEN_N_MASK) >> + SCU_HUART_CLKGEN_N_SHIFT; + u32 r = (huxclk_ctrl & SCU_HUART_CLKGEN_R_MASK) >> + SCU_HUART_CLKGEN_R_SHIFT; + u32 rate; + + switch (huxclk_sel) { + case 0: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL) / 4; + break; + case 1: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL) / 2; + break; + case 2: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL); + break; + case 3: + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + break; + } + + return ((rate * r) / (n * 2)); +} + +#define SCU_CLKSRC1_SDIO_DIV_MASK GENMASK(16, 14) +#define SCU_CLKSRC1_SDIO_DIV_SHIFT 14 +#define SCU_CLKSRC1_SDIO_SEL BIT(13) +const int ast2700_sd_div_tbl[] = { + 2, 2, 3, 4, 5, 6, 7, 8 +}; + +static u32 ast2700_soc1_get_sdio_clk_rate(struct ast2700_scu1 *scu) +{ + u32 rate = 0; + u32 clk_sel1 = readl(&scu->clk_sel1); + u32 div = (clk_sel1 & SCU_CLKSRC1_SDIO_DIV_MASK) >> + SCU_CLKSRC1_SDIO_DIV_SHIFT; + + if (clk_sel1 & SCU_CLKSRC1_SDIO_SEL) + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_APLL); + else + rate = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + + if (!div) + div = 1; + + div++; + + return (rate / div); +} + +static void ast2700_init_sdclk(struct ast2700_scu1 *scu) +{ + u32 src_clk = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + u32 reg_280; + int i; + + for (i = 0; i < 8; i++) { + if (src_clk / ast2700_sd_div_tbl[i] <= 125000000) + break; + } + + reg_280 = readl(&scu->clk_sel1); + reg_280 &= ~(SCU_CLKSRC1_SDIO_DIV_MASK | SCU_CLKSRC1_SDIO_SEL); + reg_280 |= i << SCU_CLKSRC1_SDIO_DIV_SHIFT; + writel(reg_280, &scu->clk_sel1); +} + +static u32 +ast2700_soc1_get_uart_clk_rate(struct ast2700_scu1 *scu, int uart_idx) +{ + u32 rate = 0; + + if (readl(&scu->clk_sel1) & BIT(uart_idx)) + rate = ast2700_soc1_get_uart_huxclk_rate(scu); + else + rate = ast2700_soc1_get_uart_uxclk_rate(scu); + + return rate; +} + +static ulong ast2700_soc1_clk_get_rate(struct clk *clk) +{ + struct ast2700_clk_priv *priv = dev_get_priv(clk->dev); + struct ast2700_scu1 *scu = (struct ast2700_scu1 *)priv->reg; + ulong rate = 0; + + switch (clk->id) { + case SCU1_CLK_HPLL: + case SCU1_CLK_APLL: + case SCU1_CLK_DPLL: + rate = ast2700_soc1_get_pll_rate(scu, clk->id); + break; + case SCU1_CLK_AHB: + rate = ast2700_soc1_get_hclk_rate(scu); + break; + case SCU1_CLK_APB: + rate = ast2700_soc1_get_pclk_rate(scu); + break; + case SCU1_CLK_GATE_UART0CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 0); + break; + case SCU1_CLK_GATE_UART1CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 1); + break; + case SCU1_CLK_GATE_UART2CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 2); + break; + case SCU1_CLK_GATE_UART3CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 3); + break; + case SCU1_CLK_GATE_UART5CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 5); + break; + case SCU1_CLK_GATE_UART6CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 6); + break; + case SCU1_CLK_GATE_UART7CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 7); + break; + case SCU1_CLK_GATE_UART8CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 8); + break; + case SCU1_CLK_GATE_UART9CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 9); + break; + case SCU1_CLK_GATE_UART10CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 10); + break; + case SCU1_CLK_GATE_UART11CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 11); + break; + case SCU1_CLK_GATE_UART12CLK: + rate = ast2700_soc1_get_uart_clk_rate(scu, 12); + break; + case SCU1_CLK_GATE_SDCLK: + rate = ast2700_soc1_get_sdio_clk_rate(scu); + break; + case SCU1_CLK_UXCLK: + rate = ast2700_soc1_get_uart_uxclk_rate(scu); + break; + case SCU1_CLK_HUXCLK: + rate = ast2700_soc1_get_uart_huxclk_rate(scu); + break; + default: + debug("%s: unknown clk %ld\n", __func__, clk->id); + return -ENOENT; + } + + return rate; +} + +static int ast2700_soc1_clk_enable(struct clk *clk) +{ + struct ast2700_clk_priv *priv = dev_get_priv(clk->dev); + struct ast2700_scu1 *scu = (struct ast2700_scu1 *)priv->reg; + u32 clkgate_bit; + + if (clk->id >= 32) + clkgate_bit = BIT(clk->id - 32); + else + clkgate_bit = BIT(clk->id); + + writel(clkgate_bit, &scu->clkgate_clr1); + + return 0; +} + +static const struct clk_ops ast2700_soc1_clk_ops = { + .get_rate = ast2700_soc1_clk_get_rate, + .enable = ast2700_soc1_clk_enable, +}; + +#define SCU_HW_REVISION_ID GENMASK(23, 16) +#define SCU_CPUCLK_MASK GENMASK(4, 2) +#define SCU_CPUCLK_SHIFT 2 +static u32 ast2700_soc0_get_hpll_rate(struct ast2700_scu0 *scu) +{ + u32 chip_id1 = readl(&scu->chip_id1); + u32 hwstrap1 = readl(&scu->hwstrap1); + union ast2700_pll_reg pll_reg; + u32 mul = 1, div = 1; + u32 rate; + + pll_reg.w = readl(&scu->hpll); + + if ((chip_id1 & SCU_HW_REVISION_ID) && (hwstrap1 & BIT(3))) { + switch ((hwstrap1 & GENMASK(4, 2)) >> 2) { + case 2: + rate = 1800000000; + break; + case 3: + rate = 1700000000; + break; + case 6: + rate = 1200000000; + break; + case 7: + rate = 800000000; + break; + default: + rate = 1600000000; + } + } else if (hwstrap1 & GENMASK(3, 2)) { + switch ((hwstrap1 & GENMASK(3, 2)) >> 2) { + case 1U: + rate = 1900000000; + break; + case 2U: + rate = 1800000000; + break; + case 3U: + rate = 1700000000; + break; + default: + rate = 1600000000; + break; + } + } else { + if (pll_reg.b.bypass == 0U) { + /* F = 25Mhz * [(M + 2) / 2 * (n + 1)] / (p + 1) */ + mul = (pll_reg.b.m + 1) / ((pll_reg.b.n + 1) * 2); + div = (pll_reg.b.p + 1); + } + rate = ((CLKIN_25M * mul) / div); + } + + return rate; +} + +static u32 ast2700_soc0_get_pll_rate(struct ast2700_scu0 *scu, int pll_idx) +{ + union ast2700_pll_reg pll_reg; + u32 mul = 1, div = 1; + u32 rate; + + switch (pll_idx) { + case SCU0_CLK_DPLL: + pll_reg.w = readl(&scu->dpll); + break; + case SCU0_CLK_MPLL: + pll_reg.w = readl(&scu->mpll); + break; + default: + pr_err("%s: invalid PSP clock source (%d)\n", __func__, pll_idx); + return 0; + } + + if (pll_reg.b.bypass == 0U) { + if (pll_idx == SCU0_CLK_MPLL) { + /* F = 25Mhz * [M / (n + 1)] / (p + 1) */ + mul = (pll_reg.b.m) / ((pll_reg.b.n + 1)); + div = (pll_reg.b.p + 1); + } else { + /* F = 25Mhz * [(M + 2) / 2 * (n + 1)] / (p + 1) */ + mul = (pll_reg.b.m + 1) / ((pll_reg.b.n + 1) * 2); + div = (pll_reg.b.p + 1); + } + } + + rate = ((CLKIN_25M * mul) / div); + + return rate; +} + +/* + * AST2700A1 + * SCU010[4:2]: + * 000: CPUCLK=MPLL=1.6GHz (MPLL default setting with SCU310, SCU314) + * 001: CPUCLK=HPLL=2.0GHz (HPLL default setting with SCU300, SCU304) + * 010: CPUCLK=HPLL=1.8GHz (HPLL frequency is constance and is not controlled by SCU300, SCU304) + * 011: CPUCLK=HPLL=1.7GHz (HPLL frequency is constance and is not controlled by SCU300, SCU304) + * 100: CPUCLK=MPLL/2=800MHz (MPLL default setting with SCU310, SCU314) + * 101: CPUCLK=HPLL/2=1.0GHz (HPLL default setting with SCU300, SCU304) + * 110: CPUCLK=HPLL=1.2GHz (HPLL frequency is constance and is not controlled by SCU300, SCU304) + * 111: CPUCLK=HPLL=800MHz (HPLL frequency is constance and is not controlled by SCU300, SCU304) + */ + +static u32 ast2700_soc0_get_pspclk_rate(struct ast2700_scu0 *scu) +{ + u32 chip_id1 = readl(&scu->chip_id1); + u32 hwstrap1 = readl(&scu->hwstrap1); + u32 rate; + int cpuclk_set; + + if (chip_id1 & SCU_HW_REVISION_ID) { + cpuclk_set = (hwstrap1 & SCU_CPUCLK_MASK) >> SCU_CPUCLK_SHIFT; + switch (cpuclk_set) { + case 0: + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL); + break; + case 1: + case 2: + case 3: + case 6: + case 7: + rate = ast2700_soc0_get_hpll_rate(scu); + break; + case 4: + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL) / 2; + break; + case 5: + rate = ast2700_soc0_get_hpll_rate(scu) / 2; + break; + default: + rate = ast2700_soc0_get_hpll_rate(scu); + break; + } + } else { + if (hwstrap1 & BIT(4)) + rate = ast2700_soc0_get_hpll_rate(scu); + else + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL); + } + return rate; +} + +static u32 ast2700_soc0_get_axi0clk_rate(struct ast2700_scu0 *scu) +{ + return ast2700_soc0_get_pspclk_rate(scu) / 2; +} + +#define SCU_AHB_DIV_MASK GENMASK(6, 5) +#define SCU_AHB_DIV_SHIFT 5 +static u32 hclk_ast2700a1_div_table[] = { + 6, 5, 4, 7, +}; + +static u32 ast2700_soc0_get_hclk_rate(struct ast2700_scu0 *scu) +{ + u32 hwstrap1 = readl(&scu->hwstrap1); + u32 chip_id1 = readl(&scu->chip_id1); + u32 src_clk; + int div; + + if (chip_id1 & SCU_HW_REVISION_ID) { + if (hwstrap1 & BIT(7)) + src_clk = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL); + else + src_clk = ast2700_soc0_get_hpll_rate(scu); + + div = (hwstrap1 & SCU_AHB_DIV_MASK) >> SCU_AHB_DIV_SHIFT; + div = hclk_ast2700a1_div_table[div]; + } else { + if (hwstrap1 & BIT(7)) + src_clk = ast2700_soc0_get_hpll_rate(scu); + else + src_clk = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL); + + div = (hwstrap1 & SCU_AHB_DIV_MASK) >> SCU_AHB_DIV_SHIFT; + + if (!div) + div = 4; + else + div = (div + 1) * 2; + } + return (src_clk / div); +} + +static u32 ast2700_soc0_get_axi1clk_rate(struct ast2700_scu0 *scu) +{ + if (readl(&scu->chip_id1) & SCU_HW_REVISION_ID) + return ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL) / 4; + else + return ast2700_soc0_get_hclk_rate(scu); +} + +#define SCU0_CLKSEL1_PCLK_DIV_MASK GENMASK(25, 23) +#define SCU0_CLKSEL1_PCLK_DIV_SHIFT 23 + +static u32 ast2700_soc0_get_pclk_rate(struct ast2700_scu0 *scu) +{ + u32 rate = ast2700_soc0_get_axi0clk_rate(scu); + u32 clksel1 = readl(&scu->clk_sel1); + int div; + + div = (clksel1 & SCU0_CLKSEL1_PCLK_DIV_MASK) >> + SCU0_CLKSEL1_PCLK_DIV_SHIFT; + + return (rate / ((div + 1) * 2)); +} + +#define SCU_CLKSEL1_MPHYCLK_SEL_MASK GENMASK(19, 18) +#define SCU_CLKSEL1_MPHYCLK_SEL_SHIFT 18 +#define SCU_CLKSEL1_MPHYCLK_DIV_MASK GENMASK(7, 0) +static u32 ast2700_soc0_get_mphyclk_rate(struct ast2700_scu0 *scu) +{ + int div = readl(&scu->mphyclk_para) & SCU_CLKSEL1_MPHYCLK_DIV_MASK; + u32 chip_id1 = readl(&scu->chip_id1); + u32 clk_sel2; + int clk_sel; + u32 rate = 0; + + if (chip_id1 & SCU_HW_REVISION_ID) { + clk_sel2 = readl(&scu->clk_sel2); + clk_sel = (clk_sel2 & SCU_CLKSEL1_MPHYCLK_SEL_MASK) + >> SCU_CLKSEL1_MPHYCLK_SEL_SHIFT; + switch (clk_sel) { + case 0: + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL); + break; + case 1: + rate = ast2700_soc0_get_hpll_rate(scu); + break; + case 2: + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_DPLL); + break; + case 3: + rate = 26000000; + break; + } + } else { + rate = ast2700_soc0_get_hpll_rate(scu); + } + + return (rate / (div + 1)); +} + +static void ast2700_mphy_clk_init(struct ast2700_scu0 *scu) +{ + u32 clksrc1, rate = 0; + int i; + + /* set mphy clk */ + if (readl(&scu->chip_id1) & SCU_HW_REVISION_ID) { + clksrc1 = (readl(&scu->clk_sel2) & SCU_CLKSEL1_MPHYCLK_SEL_MASK) + >> SCU_CLKSEL1_MPHYCLK_SEL_SHIFT; + switch (clksrc1) { + case 0: + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL); + break; + case 1: + rate = ast2700_soc0_get_hpll_rate(scu); + break; + case 2: + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_DPLL); + break; + case 3: + rate = 26000000; + break; + } + } else { + rate = ast2700_soc0_get_hpll_rate(scu); + } + + for (i = 1; i < 256; i++) { + if ((rate / i) <= 26000000) + break; + } + + /* register defined the value plus 1 is divider*/ + i--; + writel(i, &scu->mphyclk_para); +} + +#define SCU_CLKSRC1_EMMC_DIV_MASK GENMASK(14, 12) +#define SCU_CLKSRC1_EMMC_DIV_SHIFT 12 +#define SCU_CLKSRC1_EMMC_SEL BIT(11) +static u32 ast2700_soc0_get_emmcclk_rate(struct ast2700_scu0 *scu) +{ + u32 clksel1 = readl(&scu->clk_sel1); + u32 rate; + int div; + + div = (clksel1 & SCU_CLKSRC1_EMMC_DIV_MASK) >> SCU_CLKSRC1_EMMC_DIV_SHIFT; + + if (clksel1 & SCU_CLKSRC1_EMMC_SEL) + rate = ast2700_soc0_get_hpll_rate(scu) / 4; + else + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL) / 4; + + return (rate / ((div + 1) * 2)); +} + +static void ast2700_emmc_init(struct ast2700_scu0 *scu) +{ + u32 clksrc1, rate, div; + int i; + + /* set clk/cmd driving */ + writel(2, &scu->gpio18d0_ioctrl); /* clk driving */ + writel(1, &scu->gpio18d1_ioctrl); /* cmd driving */ + writel(1, &scu->gpio18d2_ioctrl); /* data0 driving */ + writel(1, &scu->gpio18d3_ioctrl); /* data1 driving */ + writel(1, &scu->gpio18d4_ioctrl); /* data2 driving */ + writel(1, &scu->gpio18d5_ioctrl); /* data2 driving */ + + /* emmc clk: set clk src mpll/4:400Mhz */ + clksrc1 = readl(&scu->clk_sel1); + rate = ast2700_soc0_get_pll_rate(scu, SCU0_CLK_MPLL) / 4; + for (i = 0; i < 8; i++) { + div = (i + 1) * 2; + if ((rate / div) <= 200000000) + break; + } + + clksrc1 &= ~(SCU_CLKSRC1_EMMC_DIV_MASK | SCU_CLKSRC1_EMMC_SEL); + clksrc1 |= (i << SCU_CLKSRC1_EMMC_DIV_SHIFT); + writel(clksrc1, &scu->clk_sel1); +} + +static void ast2700_vga_clk_init(struct ast2700_scu0 *scu) +{ + if ((readl(&scu->chip_id1) & SCU_HW_REVISION_ID) == 0) + return; + + // Use d0clk/d1clk which generated from hpll for vga0/1 after A0 + // Use CRT1clk as soc display source + setbits_le32(&scu->clk_sel3, BIT(14) | BIT(13) | BIT(12)); +} + +static u32 ast2700_soc0_get_uartclk_rate(struct ast2700_scu0 *scu) +{ + u32 clksel2 = readl(&scu->clk_sel2); + u32 div = 1; + u32 rate; + + if (clksel2 & BIT(15)) + rate = 192000000; + else + rate = 24000000; + + if (clksel2 & BIT(30)) + div = 13; + return (rate / div); +} + +static ulong ast2700_soc0_clk_get_rate(struct clk *clk) +{ + struct ast2700_clk_priv *priv = dev_get_priv(clk->dev); + ulong rate = 0; + + switch (clk->id) { + case SCU0_CLK_PSP: + rate = ast2700_soc0_get_pspclk_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_HPLL: + rate = ast2700_soc0_get_hpll_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_DPLL: + case SCU0_CLK_MPLL: + rate = ast2700_soc0_get_pll_rate((struct ast2700_scu0 *)priv->reg, clk->id); + break; + case SCU0_CLK_AXI0: + rate = ast2700_soc0_get_axi0clk_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_AXI1: + rate = ast2700_soc0_get_axi1clk_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_AHB: + rate = ast2700_soc0_get_hclk_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_APB: + rate = ast2700_soc0_get_pclk_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_GATE_EMMCCLK: + rate = ast2700_soc0_get_emmcclk_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_GATE_UART4CLK: + rate = ast2700_soc0_get_uartclk_rate((struct ast2700_scu0 *)priv->reg); + break; + case SCU0_CLK_MPHY: + rate = ast2700_soc0_get_mphyclk_rate((struct ast2700_scu0 *)priv->reg); + break; + default: + debug("%s: unknown clk %ld\n", __func__, clk->id); + return -ENOENT; + } + + return rate; +} + +static int ast2700_soc0_clk_enable(struct clk *clk) +{ + struct ast2700_clk_priv *priv = dev_get_priv(clk->dev); + struct ast2700_scu0 *scu = (struct ast2700_scu0 *)priv->reg; + u32 clkgate_bit = BIT(clk->id); + + writel(clkgate_bit, &scu->clkgate_clr); + + return 0; +} + +static const struct clk_ops ast2700_soc0_clk_ops = { + .get_rate = ast2700_soc0_clk_get_rate, + .enable = ast2700_soc0_clk_enable, +}; + +static void ast2700_init_mac_clk(struct ast2700_scu1 *scu) +{ + u32 src_clk = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + u32 reg_280; + u8 div_idx; + + /* The MAC source clock selects HPLL only, and the default clock + * setting is 200 Mhz. + * Calculate the corresponding divider: + * 1: div 2 + * 2: div 3 + * ... + * 7: div 8 + */ + for (div_idx = 1; div_idx <= 7; div_idx++) + if (DIV_ROUND_UP(src_clk, div_idx + 1) == 200000000) + break; + + if (div_idx == 8) { + pr_err("MAC clock cannot divide to 200 MHz\n"); + return; + } + + /* set HPLL clock divider */ + reg_280 = readl(&scu->clk_sel1); + reg_280 &= ~GENMASK(31, 29); + reg_280 |= div_idx << 29; + writel(reg_280, &scu->clk_sel1); +} + +static void ast2700_init_rgmii_clk(struct ast2700_scu1 *scu) +{ + u32 reg_284 = readl(&scu->clk_sel2); + u32 src_clk = ast2700_soc1_get_pll_rate(scu, RGMII_DEFAULT_CLK_SRC); + + if (RGMII_DEFAULT_CLK_SRC == SCU1_CLK_HPLL) { + u32 reg_280; + u8 div_idx; + + /* Calculate the corresponding divider: + * 1: div 4 + * 2: div 6 + * ... + * 7: div 16 + */ + for (div_idx = 1; div_idx <= 7; div_idx++) { + u8 div = 4 + 2 * (div_idx - 1); + + if (DIV_ROUND_UP(src_clk, div) == 125000000) + break; + } + if (div_idx == 8) { + pr_err("RGMII using HPLL cannot divide to 125 MHz\n"); + return; + } + + /* set HPLL clock divider */ + reg_280 = readl(&scu->clk_sel1); + reg_280 &= ~GENMASK(27, 25); + reg_280 |= div_idx << 25; + writel(reg_280, &scu->clk_sel1); + + /* select HPLL clock source */ + reg_284 &= ~BIT(18); + } else { + /* APLL clock divider is fixed to 8 */ + if (DIV_ROUND_UP(src_clk, 8) != 125000000) { + pr_err("RGMII using APLL cannot divide to 125 MHz\n"); + return; + } + + /* select APLL clock source */ + reg_284 |= BIT(18); + } + + writel(reg_284, &scu->clk_sel2); +} + +static void ast2700_init_rmii_clk(struct ast2700_scu1 *scu) +{ + u32 src_clk = ast2700_soc1_get_pll_rate(scu, SCU1_CLK_HPLL); + u32 reg_280; + u8 div_idx; + + /* The RMII source clock selects HPLL only. + * Calculate the corresponding divider: + * 1: div 8 + * 2: div 12 + * ... + * 7: div 32 + */ + for (div_idx = 1; div_idx <= 7; div_idx++) { + u8 div = 8 + 4 * (div_idx - 1); + + if (DIV_ROUND_UP(src_clk, div) == 50000000) + break; + } + if (div_idx == 8) { + pr_err("RMII using HPLL cannot divide to 50 MHz\n"); + return; + } + + /* set RMII clock divider */ + reg_280 = readl(&scu->clk_sel1); + reg_280 &= ~GENMASK(23, 21); + reg_280 |= div_idx << 21; + writel(reg_280, &scu->clk_sel1); +} + +static void ast2700_init_spi(struct ast2700_scu1 *scu) +{ + writel(readl(&scu->io_driving8) | 0x0000aaaa, &scu->io_driving8); /* fwspi driving */ + writel(readl(&scu->io_driving3) | 0x00000aaa, &scu->io_driving3); /* spi0 driving */ + writel(readl(&scu->io_driving3) | 0x0aaa0000, &scu->io_driving3); /* spi1 driving */ + writel(readl(&scu->io_driving4) | 0x00002aaa, &scu->io_driving4); /* spi2 driving */ +} + +#define SCU1_CLK_I3C_DIV_MASK GENMASK(25, 23) +#define SCU1_CLK_I3C_DIV(n) ((n) - 1) +static void ast2700_init_i3c_clk(struct ast2700_scu1 *scu) +{ + u32 reg_284; + + /* I3C 250MHz = HPLL/4 */ + reg_284 = readl(&scu->clk_sel2); + reg_284 &= ~SCU1_CLK_I3C_DIV_MASK; + reg_284 |= FIELD_PREP(SCU1_CLK_I3C_DIV_MASK, SCU1_CLK_I3C_DIV(4)); + writel(reg_284, &scu->clk_sel2); +} + +static int ast2700_clk1_init(struct udevice *dev) +{ + struct ast2700_clk_priv *priv = dev_get_priv(dev); + struct ast2700_scu1 *scu = (struct ast2700_scu1 *)priv->reg; + + ast2700_init_spi(scu); + ast2700_init_mac_clk(scu); + ast2700_init_rgmii_clk(scu); + ast2700_init_rmii_clk(scu); + ast2700_init_sdclk(scu); + ast2700_init_i3c_clk(scu); + + return 0; +} + +static int ast2700_clk0_init(struct udevice *dev) +{ + struct ast2700_clk_priv *priv = dev_get_priv(dev); + struct ast2700_scu0 *scu = (struct ast2700_scu0 *)priv->reg; + + ast2700_emmc_init(scu); + ast2700_mphy_clk_init(scu); + ast2700_vga_clk_init(scu); + + return 0; +} + +static int ast2700_clk_probe(struct udevice *dev) +{ + struct ast2700_clk_priv *priv = dev_get_priv(dev); + + priv->init = (ast2700_clk_init_fn)dev_get_driver_data(dev); + priv->reg = (void __iomem *)dev_read_addr_ptr(dev); + + if (priv->init) + return priv->init(dev); + + return 0; +} + +static int ast2700_clk_bind(struct udevice *dev) +{ + struct udevice *sysreset_dev, *rst_dev; + int ret; + + /* The system reset driver does not have a device node, so bind it here */ + ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &sysreset_dev); + if (ret) + debug("Warning: No sysreset driver: ret = %d\n", ret); + + /* Bind the per-SCU reset controller to the same ofnode so that + * <&syscon0/1 RESET_X> phandle references resolve to a UCLASS_RESET + * device. This pairs with the airoha-style binding pattern. + */ + if (CONFIG_IS_ENABLED(RESET_AST2700)) { + ret = device_bind_driver_to_node(dev, "ast2700_reset", "reset", + dev_ofnode(dev), &rst_dev); + if (ret) + debug("Warning: failed to bind reset controller: ret = %d\n", ret); + } + + return 0; +} + +static const struct udevice_id ast2700_soc1_clk_ids[] = { + { .compatible = "aspeed,ast2700-scu1", .data = (ulong)&ast2700_clk1_init }, + { }, +}; + +U_BOOT_DRIVER(aspeed_ast2700_soc1_clk) = { + .name = "aspeed_ast2700_scu1", + .id = UCLASS_CLK, + .of_match = ast2700_soc1_clk_ids, + .priv_auto = sizeof(struct ast2700_clk_priv), + .ops = &ast2700_soc1_clk_ops, + .probe = ast2700_clk_probe, + .bind = ast2700_clk_bind, +}; + +static const struct udevice_id ast2700_soc0_clk_ids[] = { + { .compatible = "aspeed,ast2700-scu0", .data = (ulong)&ast2700_clk0_init }, + { }, +}; + +U_BOOT_DRIVER(aspeed_ast2700_soc0_clk) = { + .name = "aspeed_ast2700_scu0", + .id = UCLASS_CLK, + .of_match = ast2700_soc0_clk_ids, + .priv_auto = sizeof(struct ast2700_clk_priv), + .ops = &ast2700_soc0_clk_ops, + .probe = ast2700_clk_probe, + .bind = ast2700_clk_bind, +}; diff --git a/drivers/clk/at91/sam9x60.c b/drivers/clk/at91/sam9x60.c index 2251e2846fa..0d0e39db57e 100644 --- a/drivers/clk/at91/sam9x60.c +++ b/drivers/clk/at91/sam9x60.c @@ -426,7 +426,7 @@ static const struct pmc_clk_setup sam9x60_clk_setup[] = { static int sam9x60_clk_probe(struct udevice *dev) { - void __iomem *base = (void *)devfdt_get_addr_ptr(dev); + void __iomem *base = dev_read_addr_ptr(dev); unsigned int *clkmuxallocs[64], *muxallocs[64]; const char *p[10]; unsigned int cm[10], m[10], *tmpclkmux, *tmpmux; diff --git a/drivers/clk/at91/sam9x7.c b/drivers/clk/at91/sam9x7.c index 9ea253e6ff8..93f899b6617 100644 --- a/drivers/clk/at91/sam9x7.c +++ b/drivers/clk/at91/sam9x7.c @@ -817,7 +817,7 @@ static const struct { static int sam9x7_clk_probe(struct udevice *dev) { - void __iomem *base = (void *)devfdt_get_addr_ptr(dev); + void __iomem *base = dev_read_addr_ptr(dev); unsigned int *clkmuxallocs[64], *muxallocs[64]; const char *p[10]; unsigned int cm[10], m[10], *tmpclkmux, *tmpmux; diff --git a/drivers/clk/at91/sama7d65.c b/drivers/clk/at91/sama7d65.c index 9f0b394543b..0c17a8cf67b 100644 --- a/drivers/clk/at91/sama7d65.c +++ b/drivers/clk/at91/sama7d65.c @@ -1176,7 +1176,7 @@ static const struct pmc_clk_setup sama7d65_clk_setup[] = { static int sama7d65_clk_probe(struct udevice *dev) { - void __iomem *base = (void *)devfdt_get_addr(dev); + void __iomem *base = dev_read_addr_ptr(dev); unsigned int *clkmuxallocs[SAMA7D65_MAX_MUX_ALLOCS]; unsigned int *muxallocs[SAMA7D65_MAX_MUX_ALLOCS]; const char *p[12]; @@ -1185,8 +1185,8 @@ static int sama7d65_clk_probe(struct udevice *dev) bool main_osc_bypass; int ret, muxallocindex = 0, clkmuxallocindex = 0, i, j; - if (IS_ERR(base)) - return PTR_ERR(base); + if (!base) + return -EINVAL; memset(muxallocs, 0, ARRAY_SIZE(muxallocs)); memset(clkmuxallocs, 0, ARRAY_SIZE(clkmuxallocs)); diff --git a/drivers/clk/at91/sama7g5.c b/drivers/clk/at91/sama7g5.c index f24d251857f..c436038aed2 100644 --- a/drivers/clk/at91/sama7g5.c +++ b/drivers/clk/at91/sama7g5.c @@ -1109,7 +1109,7 @@ static const struct pmc_clk_setup sama7g5_clk_setup[] = { static int sama7g5_clk_probe(struct udevice *dev) { - void __iomem *base = devfdt_get_addr_ptr(dev); + void __iomem *base = dev_read_addr_ptr(dev); unsigned int *clkmuxallocs[SAMA7G5_MAX_MUX_ALLOCS]; unsigned int *muxallocs[SAMA7G5_MAX_MUX_ALLOCS]; const char *p[10]; @@ -1118,8 +1118,8 @@ static int sama7g5_clk_probe(struct udevice *dev) bool main_osc_bypass; int ret, muxallocindex = 0, clkmuxallocindex = 0, i, j; - if (IS_ERR(base)) - return PTR_ERR(base); + if (!base) + return -EINVAL; memset(muxallocs, 0, sizeof(muxallocs)); memset(clkmuxallocs, 0, sizeof(clkmuxallocs)); diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index dcaffd360fd..410bc088248 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -124,12 +124,15 @@ U_BOOT_DRIVER(at91_sam9x60_td_slck) = { static int at91_sam9x60_sckc_probe(struct udevice *dev) { struct sam9x60_sckc *sckc = dev_get_priv(dev); - void __iomem *base = devfdt_get_addr_ptr(dev); + void __iomem *base = dev_read_addr_ptr(dev); const char *slow_rc_osc, *slow_osc; const char *parents[2]; struct clk *clk, c; int ret; + if (!base) + return -EINVAL; + ret = clk_get_by_index(dev, 0, &c); if (ret) return ret; diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index e692b9c2167..d30786a9e6c 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -228,20 +228,30 @@ static struct clk *_register_divider(struct udevice *dev, const char *name, return clk; } -struct clk *clk_register_divider(struct udevice *dev, const char *name, +struct clk *clk_register_divider_table(struct udevice *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, - u8 clk_divider_flags) + u8 clk_divider_flags, const struct clk_div_table *table) { struct clk *clk; clk = _register_divider(dev, name, parent_name, flags, reg, shift, - width, clk_divider_flags, NULL); + width, clk_divider_flags, table); if (IS_ERR(clk)) return ERR_CAST(clk); return clk; } +struct clk *clk_register_divider(struct udevice *dev, const char *name, + const char *parent_name, unsigned long flags, + void __iomem *reg, u8 shift, u8 width, + u8 clk_divider_flags) +{ + return clk_register_divider_table(dev, name, parent_name, flags, reg, + shift, width, clk_divider_flags, + NULL); +} + U_BOOT_DRIVER(ccf_clk_divider) = { .name = UBOOT_DM_CLK_CCF_DIVIDER, .id = UCLASS_CLK, diff --git a/drivers/clk/clk-hsdk-cgu.c b/drivers/clk/clk-hsdk-cgu.c index 53655059279..dbc926a4391 100644 --- a/drivers/clk/clk-hsdk-cgu.c +++ b/drivers/clk/clk-hsdk-cgu.c @@ -753,11 +753,11 @@ static int hsdk_cgu_clk_probe(struct udevice *dev) else hsdk_clk->map = hsdk_4xd_clk_map; - hsdk_clk->cgu_regs = devfdt_get_addr_index_ptr(dev, 0); + hsdk_clk->cgu_regs = dev_read_addr_index_ptr(dev, 0); if (!hsdk_clk->cgu_regs) return -EINVAL; - hsdk_clk->creg_regs = devfdt_get_addr_index_ptr(dev, 1); + hsdk_clk->creg_regs = dev_read_addr_index_ptr(dev, 1); if (!hsdk_clk->creg_regs) return -EINVAL; diff --git a/drivers/clk/clk-stub.c b/drivers/clk/clk-stub.c index 117266ac778..4a6c71016da 100644 --- a/drivers/clk/clk-stub.c +++ b/drivers/clk/clk-stub.c @@ -49,11 +49,13 @@ static struct clk_ops stub_clk_ops = { }; static const struct udevice_id stub_clk_ids[] = { + { .compatible = "qcom,qcs615-rpmh-clk" }, { .compatible = "qcom,rpmcc" }, - { .compatible = "qcom,sdm670-rpmh-clk" }, - { .compatible = "qcom,sdm845-rpmh-clk" }, + { .compatible = "qcom,sa8775p-rpmh-clk" }, { .compatible = "qcom,sc7180-rpmh-clk" }, { .compatible = "qcom,sc7280-rpmh-clk" }, + { .compatible = "qcom,sdm670-rpmh-clk" }, + { .compatible = "qcom,sdm845-rpmh-clk" }, { .compatible = "qcom,sm6350-rpmh-clk" }, { .compatible = "qcom,sm8150-rpmh-clk" }, { .compatible = "qcom,sm8250-rpmh-clk" }, diff --git a/drivers/clk/clk_versal.c b/drivers/clk/clk_versal.c index 78a2410ca21..2e0c382ef30 100644 --- a/drivers/clk/clk_versal.c +++ b/drivers/clk/clk_versal.c @@ -326,6 +326,7 @@ static int __versal_clock_get_parents(struct clock_parent *parents, u32 *data, parent = &parents[i]; parent->id = data[i] & CLK_PARENTS_ID_MASK; if (data[i] == DUMMY_PARENT) { + parent->id = 0; strcpy(parent->name, "dummy_name"); parent->flag = 0; } else { diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index f2fd6ff8ca0..a825ed9988f 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -17,7 +17,7 @@ obj-$(CONFIG_$(PHASE_)CLK_IMX8MN) += clk-imx8mn.o clk-pll14xx.o \ clk-composite-8m.o obj-$(CONFIG_$(PHASE_)CLK_IMX8MP) += clk-imx8mp.o clk-pll14xx.o \ clk-composite-8m.o -obj-$(CONFIG_$(PHASE_)CLK_IMX8MQ) += clk-imx8mq.o clk-pll14xx.o \ +obj-$(CONFIG_$(PHASE_)CLK_IMX8MQ) += clk-imx8mq.o clk-frac-pll.o \ clk-composite-8m.o obj-$(CONFIG_$(PHASE_)CLK_IMX93) += clk-imx93.o clk-fracn-gppll.o \ clk-gate-93.o clk-composite-93.o diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c new file mode 100644 index 00000000000..057389d3069 --- /dev/null +++ b/drivers/clk/imx/clk-frac-pll.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2026 NXP + * + */ + +#include <asm/io.h> +#include <malloc.h> +#include <clk-uclass.h> +#include <dm/device.h> +#include <dm/devres.h> +#include <linux/bitops.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/iopoll.h> +#include <clk.h> +#include <div64.h> +#include <linux/printk.h> +#include <linux/bitfield.h> + +#include "clk.h" + +#define PLL_CFG0 0x0 +#define PLL_CFG1 0x4 + +#define PLL_LOCK_STATUS BIT(31) +#define PLL_PD_MASK BIT(19) +#define PLL_BYPASS_MASK BIT(14) +#define PLL_NEWDIV_VAL BIT(12) +#define PLL_NEWDIV_ACK BIT(11) +#define PLL_FRAC_DIV_MASK GENMASK(30, 7) +#define PLL_INT_DIV_MASK GENMASK(6, 0) +#define PLL_OUTPUT_DIV_MASK GENMASK(4, 0) +#define PLL_FRAC_DENOM 0x1000000 + +#define PLL_FRAC_LOCK_TIMEOUT 10000 +#define PLL_FRAC_ACK_TIMEOUT 500000 + +struct clk_frac_pll { + struct clk clk; + void __iomem *base; +}; + +#define to_clk_frac_pll(_clk) container_of(_clk, struct clk_frac_pll, clk) + +static int clk_wait_lock(struct clk_frac_pll *pll) +{ + u32 val; + + return readl_poll_timeout(pll->base, val, val & PLL_LOCK_STATUS, + PLL_FRAC_LOCK_TIMEOUT); +} + +static int clk_wait_ack(struct clk_frac_pll *pll) +{ + u32 val; + + /* return directly if the pll is in powerdown or in bypass */ + if (readl_relaxed(pll->base) & (PLL_PD_MASK | PLL_BYPASS_MASK)) + return 0; + + /* Wait for the pll's divfi and divff to be reloaded */ + return readl_poll_timeout(pll->base, val, val & PLL_NEWDIV_ACK, + PLL_FRAC_ACK_TIMEOUT); +} + +static int clk_pll_prepare(struct clk *clk) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(clk); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return clk_wait_lock(pll); +} + +static int clk_pll_unprepare(struct clk *clk) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(clk); + u32 val; + + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_PD_MASK; + writel_relaxed(val, pll->base + PLL_CFG0); + + return 0; +} + +static unsigned long clk_pll_recalc_rate(struct clk *clk) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(clk); + u32 val, divff, divfi, divq; + ulong parent_rate = clk_get_parent_rate(clk); + u64 temp64 = parent_rate; + u64 rate; + + val = readl_relaxed(pll->base + PLL_CFG0); + divq = (FIELD_GET(PLL_OUTPUT_DIV_MASK, val) + 1) * 2; + val = readl_relaxed(pll->base + PLL_CFG1); + divff = FIELD_GET(PLL_FRAC_DIV_MASK, val); + divfi = FIELD_GET(PLL_INT_DIV_MASK, val); + + temp64 *= 8; + temp64 *= divff; + do_div(temp64, PLL_FRAC_DENOM); + do_div(temp64, divq); + + rate = parent_rate * 8 * (divfi + 1); + do_div(rate, divq); + rate += temp64; + + return rate; +} + +static ulong clk_pll_set_rate(struct clk *clk, unsigned long rate) +{ + struct clk_frac_pll *pll = to_clk_frac_pll(clk); + ulong parent_rate = clk_get_parent_rate(clk); + u32 val, divfi, divff; + u64 temp64; + int ret; + + parent_rate *= 8; + rate *= 2; + divfi = rate / parent_rate; + temp64 = parent_rate * divfi; + temp64 = rate - temp64; + temp64 *= PLL_FRAC_DENOM; + do_div(temp64, parent_rate); + divff = temp64; + + val = readl_relaxed(pll->base + PLL_CFG1); + val &= ~(PLL_FRAC_DIV_MASK | PLL_INT_DIV_MASK); + val |= (divff << 7) | (divfi - 1); + writel_relaxed(val, pll->base + PLL_CFG1); + + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~0x1f; + writel_relaxed(val, pll->base + PLL_CFG0); + + /* Set the NEV_DIV_VAL to reload the DIVFI and DIVFF */ + val = readl_relaxed(pll->base + PLL_CFG0); + val |= PLL_NEWDIV_VAL; + writel_relaxed(val, pll->base + PLL_CFG0); + + ret = clk_wait_ack(pll); + + /* clear the NEV_DIV_VAL */ + val = readl_relaxed(pll->base + PLL_CFG0); + val &= ~PLL_NEWDIV_VAL; + writel_relaxed(val, pll->base + PLL_CFG0); + + if (ret) + return ret; + + return clk_pll_recalc_rate(clk); +} + +static const struct clk_ops clk_frac_pll_ops = { + .enable = clk_pll_prepare, + .disable = clk_pll_unprepare, + .set_rate = clk_pll_set_rate, + .get_rate = clk_pll_recalc_rate, +}; + +struct clk *imx_clk_frac_pll(const char *name, const char *parent_name, + void __iomem *base) +{ + struct clk_frac_pll *pll; + struct clk *clk; + int ret; + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + pll->base = base; + clk = &pll->clk; + + ret = clk_register(clk, "imx_clk_frac_pll", name, parent_name); + if (ret) { + pr_err("%s: failed to register pll %s %d\n", + __func__, name, ret); + kfree(pll); + return ERR_PTR(ret); + } + + return clk; +} + +U_BOOT_DRIVER(clk_frac_pll) = { + .name = "imx_clk_frac_pll", + .id = UCLASS_CLK, + .ops = &clk_frac_pll_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index f57ac79f8ca..846b8011f5c 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -9,6 +9,7 @@ #include <log.h> #include <asm/arch/clock.h> #include <asm/arch/imx-regs.h> +#include <dm/of_access.h> #include <dt-bindings/clock/imx6qdl-clock.h> #include "clk.h" @@ -46,6 +47,33 @@ static struct clk_ops imx6q_clk_ops = { .disable = ccf_clk_disable, }; +static const char *const pll_bypass_src_sels[] = { + "osc", + "lvds1_in", + "lvds2_in", + "dummy", +}; + +static const char *const pll2_bypass_sels[] = { + "pll2", + "pll2_bypass_src", +}; + +static const char *const pll3_bypass_sels[] = { + "pll3", + "pll3_bypass_src", +}; + +static const char *const pll5_bypass_sels[] = { + "pll5", + "pll5_bypass_src", +}; + +static const char *const pll6_bypass_sels[] = { + "pll6", + "pll6_bypass_src", +}; + static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", @@ -72,6 +100,23 @@ static const char *const ecspi_sels[] = { "pll3_60m", "osc", }; + +static const struct clk_div_table post_div_table[] = { + { .val = 2, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 0, .div = 4, }, + { /* sentinel */ } +}; + +static const struct clk_div_table video_div_table[] = { + { .val = 0, .div = 1, }, + { .val = 1, .div = 2, }, + { .val = 2, .div = 1, }, + { .val = 3, .div = 4, }, + { /* sentinel */ } +}; + +#if CONFIG_IS_ENABLED(VIDEO) static const char *const ipu_sels[] = { "mmdc_ch0_axi", "pll2_pfd2_396m", @@ -113,6 +158,122 @@ static const char *ipu2_di1_sels_2[] = { static unsigned int share_count_mipi_core_cfg; +static void of_assigned_ldb_sels(struct udevice *dev, int *ldb_di0_sel, + int *ldb_di1_sel) +{ + struct ofnode_phandle_args clk_args, parent_args; + ofnode node = dev_ofnode(dev); + int count, err; + + count = dev_count_phandle_with_args(dev, "assigned-clocks", + "#clock-cells", 0); + if (count <= 0) { + if (count == 0) + debug("%s: no assigned_clocks found\n", dev->name); + else + pr_err("%s: failed to get phandle count (%d)\n", + dev->name, count); + return; + } + + for (int i = 0; i < count; i++) { + err = dev_read_phandle_with_args(dev, "assigned-clocks", + "#clock-cells", 0, i, + &clk_args); + if (err == -ENOENT) + /* Skip empty handles */ + continue; + else if (err < 0) + return; + + if (!ofnode_equal(clk_args.node, node) || + clk_args.args[0] >= IMX6QDL_CLK_END) { + pr_err("%s: clock %d not in ccm\n", dev->name, i); + return; + } + + err = dev_read_phandle_with_args(dev, "assigned-clock-parents", + "#clock-cells", 0, i, + &parent_args); + if (err < 0) + return; + + if (!ofnode_equal(parent_args.node, node) || + parent_args.args[0] >= IMX6QDL_CLK_END) { + pr_err("%s: parent clock %d not in ccm\n", dev->name, + i); + return; + } + + if (clk_args.args[0] == IMX6QDL_CLK_LDB_DI0_SEL) + *ldb_di0_sel = parent_args.args[0]; + else if (clk_args.args[0] == IMX6QDL_CLK_LDB_DI1_SEL) + *ldb_di1_sel = parent_args.args[0]; + } +} + +static void imx6q_init_ldb_clks(struct udevice *dev) +{ + int ldb_di_sel[] = { IMX6QDL_CLK_END, IMX6QDL_CLK_END }; + enum ldb_di_clock ldb_di_clk[] = { MXC_MMDC_CH1_CLK, MXC_MMDC_CH1_CLK }; + + of_assigned_ldb_sels(dev, &ldb_di_sel[0], &ldb_di_sel[1]); + for (int i = 0; i < 2; i++) { + switch (ldb_di_sel[i]) { + case IMX6QDL_CLK_PLL5_VIDEO_DIV: + ldb_di_clk[i] = MXC_PLL5_CLK; + break; + case IMX6QDL_CLK_PLL2_PFD0_352M: + ldb_di_clk[i] = MXC_PLL2_PFD0_CLK; + break; + case IMX6QDL_CLK_PLL2_PFD2_396M: { + struct clk *clk, *parent; + + int err = clk_get_by_id(IMX6QDL_CLK_PERIPH_PRE, &clk); + + if (err) { + pr_err("%s: failed to get periph_pre clock " + "(%d)\n", + dev->name, err); + return; + } + + err = clk_get_by_id(IMX6QDL_CLK_PLL2_PFD2_396M, + &parent); + if (err) { + pr_err("%s: failed to get pll2_pfd2_396m clock" + " (%d)\n", + dev->name, err); + return; + } + + if (parent == clk) { + pr_err("%s: ldb_di%d_sel: couldn't disable " + "pll2_pfd2_396m clock\n", + dev->name, i); + return; + } + + ldb_di_clk[i] = MXC_PLL2_PFD2_CLK; + break; + } + case IMX6QDL_CLK_MMDC_CH1_AXI: + case IMX6QDL_CLK_END: + /* use the default clock */ + break; + case IMX6QDL_CLK_PLL3_USB_OTG: + ldb_di_clk[i] = MXC_PLL3_SW_CLK; + break; + default: + pr_err("%s: invalid LDB clock parent\n", dev->name); + return; + } + } + + select_ldb_di_clock_source(ldb_di_clk[0], ldb_di_clk[1]); +} +#endif /* CONFIG_IS_ENABLED(VIDEO) */ + static int imx6q_clk_probe(struct udevice *dev) { void *base; @@ -120,26 +281,70 @@ static int imx6q_clk_probe(struct udevice *dev) /* Anatop clocks */ base = (void *)ANATOP_BASE_ADDR; - clk_dm(IMX6QDL_CLK_PLL2, - imx_clk_pllv3(dev, IMX_PLLV3_GENERIC, "pll2_bus", "osc", - base + 0x30, 0x1)); + clk_dm(IMX6QDL_PLL2_BYPASS_SRC, + imx_clk_mux(dev, "pll2_bypass_src", base + 0x30, 14, 2, + pll_bypass_src_sels, + ARRAY_SIZE(pll_bypass_src_sels))); + clk_dm(IMX6QDL_PLL3_BYPASS_SRC, + imx_clk_mux(dev, "pll3_bypass_src", base + 0x10, 14, 2, + pll_bypass_src_sels, + ARRAY_SIZE(pll_bypass_src_sels))); + clk_dm(IMX6QDL_PLL5_BYPASS_SRC, + imx_clk_mux(dev, "pll5_bypass_src", base + 0xa0, 14, 2, + pll_bypass_src_sels, + ARRAY_SIZE(pll_bypass_src_sels))); + clk_dm(IMX6QDL_PLL6_BYPASS_SRC, + imx_clk_mux(dev, "pll6_bypass_src", base + 0xe0, 14, 2, + pll_bypass_src_sels, + ARRAY_SIZE(pll_bypass_src_sels))); + + clk_dm(IMX6QDL_CLK_PLL2, imx_clk_pllv3(dev, IMX_PLLV3_GENERIC, "pll2", + "osc", base + 0x30, 0x1)); + clk_dm(IMX6QDL_CLK_PLL3, imx_clk_pllv3(dev, IMX_PLLV3_USB, "pll3", + "osc", base + 0x10, 0x3)); + clk_dm(IMX6QDL_CLK_PLL5, imx_clk_pllv3(dev, IMX_PLLV3_AV, "pll5", "osc", + base + 0xa0, 0x7f)); + clk_dm(IMX6QDL_CLK_PLL6, imx_clk_pllv3(dev, IMX_PLLV3_ENET, "pll6", + "osc", base + 0xe0, 0x3)); + + clk_dm(IMX6QDL_PLL2_BYPASS, + imx_clk_mux_flags(dev, "pll2_bypass", base + 0x30, 16, 1, + pll2_bypass_sels, ARRAY_SIZE(pll2_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX6QDL_PLL3_BYPASS, + imx_clk_mux_flags(dev, "pll3_bypass", base + 0x10, 16, 1, + pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX6QDL_PLL5_BYPASS, + imx_clk_mux_flags(dev, "pll5_bypass", base + 0xa0, 16, 1, + pll5_bypass_sels, ARRAY_SIZE(pll5_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX6QDL_PLL6_BYPASS, + imx_clk_mux_flags(dev, "pll6_bypass", base + 0xe0, 16, 1, + pll6_bypass_sels, ARRAY_SIZE(pll6_bypass_sels), + CLK_SET_RATE_PARENT)); + + SET_CLK_PARENT(IMX6QDL_PLL2_BYPASS, IMX6QDL_CLK_PLL2); + SET_CLK_PARENT(IMX6QDL_PLL3_BYPASS, IMX6QDL_CLK_PLL3); + SET_CLK_PARENT(IMX6QDL_PLL5_BYPASS, IMX6QDL_CLK_PLL5); + SET_CLK_PARENT(IMX6QDL_PLL6_BYPASS, IMX6QDL_CLK_PLL6); + + clk_dm(IMX6QDL_CLK_PLL2_BUS, + imx_clk_gate(dev, "pll2_bus", "pll2_bypass", base + 0x30, 13)); clk_dm(IMX6QDL_CLK_PLL3_USB_OTG, - imx_clk_pllv3(dev, IMX_PLLV3_USB, "pll3_usb_otg", "osc", - base + 0x10, 0x3)); + imx_clk_gate(dev, "pll3_usb_otg", "pll3_bypass", base + 0x10, + 13)); + clk_dm(IMX6QDL_CLK_PLL5_VIDEO, + imx_clk_gate(dev, "pll5_video", "pll5_bypass", base + 0xa0, 13)); + clk_dm(IMX6QDL_CLK_PLL6_ENET, + imx_clk_gate(dev, "pll6_enet", "pll6_bypass", base + 0xe0, 13)); + clk_dm(IMX6QDL_CLK_PLL3_60M, imx_clk_fixed_factor(dev, "pll3_60m", "pll3_usb_otg", 1, 8)); clk_dm(IMX6QDL_CLK_PLL3_80M, imx_clk_fixed_factor(dev, "pll3_80m", "pll3_usb_otg", 1, 6)); clk_dm(IMX6QDL_CLK_PLL3_120M, imx_clk_fixed_factor(dev, "pll3_120m", "pll3_usb_otg", 1, 4)); - clk_dm(IMX6QDL_CLK_PLL5, imx_clk_pllv3(dev, IMX_PLLV3_AV, "pll5", "osc", - base + 0xa0, 0x7f)); - clk_dm(IMX6QDL_CLK_PLL5_VIDEO, - imx_clk_gate(dev, "pll5_video", "pll5", base + 0xa0, 13)); - clk_dm(IMX6QDL_CLK_PLL6, imx_clk_pllv3(dev, IMX_PLLV3_ENET, "pll6", - "osc", base + 0xe0, 0x3)); - clk_dm(IMX6QDL_CLK_PLL6_ENET, - imx_clk_gate(dev, "pll6_enet", "pll6", base + 0xe0, 13)); clk_dm(IMX6QDL_CLK_PLL2_PFD0_352M, imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0)); @@ -151,10 +356,14 @@ static int imx6q_clk_probe(struct udevice *dev) clk_dm(IMX6QDL_CLK_PLL2_198M, imx_clk_fixed_factor(dev, "pll2_198m", "pll2_pfd2_396m", 1, 2)); clk_dm(IMX6QDL_CLK_PLL5_POST_DIV, - imx_clk_fixed_factor(dev, "pll5_post_div", "pll5_video", 1, 1)); + clk_register_divider_table(dev, "pll5_post_div", "pll5_video", + CLK_SET_RATE_PARENT, base + 0xa0, 19, + 2, 0, post_div_table)); clk_dm(IMX6QDL_CLK_PLL5_VIDEO_DIV, - imx_clk_fixed_factor(dev, "pll5_video_div", "pll5_post_div", 1, - 1)); + clk_register_divider_table(dev, "pll5_video_div", + "pll5_post_div", CLK_SET_RATE_PARENT, + base + 0x170, 30, 2, 0, + video_div_table)); clk_dm(IMX6QDL_CLK_VIDEO_27M, imx_clk_fixed_factor(dev, "video_27m", "pll3_pfd1_540m", 1, 20)); @@ -263,6 +472,7 @@ static int imx6q_clk_probe(struct udevice *dev) imx_clk_gate2(dev, "mmdc_ch1_axi", "mmdc_ch1_axi_podf", base + 0x74, 22)); +#if CONFIG_IS_ENABLED(VIDEO) clk_dm(IMX6QDL_CLK_IPU1_SEL, imx_clk_mux(dev, "ipu1_sel", base + 0x3c, 9, 2, ipu_sels, ARRAY_SIZE(ipu_sels))); @@ -279,9 +489,12 @@ static int imx6q_clk_probe(struct udevice *dev) ldb_di_sels, ARRAY_SIZE(ldb_di_sels))); } else { /* - * Need to set these as read-only due to a hardware bug. - * Keeping default mux values. Fixed on the i.MX6 QuadPlus - */ + * Need to set these as read-only due to a hardware bug. + * Keeping default mux values. Fixed on the i.MX6 QuadPlus + * Need to set the clocks now and make them read-only due to a + * hardware bug. Fixed on the i.MX6 QuadPlus + */ + imx6q_init_ldb_clks(dev); clk_dm(IMX6QDL_CLK_LDB_DI0_SEL, imx_clk_mux_flags(dev, "ldb_di0_sel", base + 0x2c, 9, 3, ldb_di_sels, ARRAY_SIZE(ldb_di_sels), @@ -413,6 +626,7 @@ static int imx6q_clk_probe(struct udevice *dev) ARRAY_SIZE(ipu2_di1_sels), CLK_SET_RATE_PARENT)); } +#endif /* CONFIG_IS_ENABLED(VIDEO) */ clk_dm(IMX6QDL_CLK_ECSPI1, imx_clk_gate2(dev, "ecspi1", "ecspi_root", base + 0x6c, 0)); @@ -453,6 +667,8 @@ static int imx6q_clk_probe(struct udevice *dev) imx_clk_gate2(dev, "enet", "ipg", base + 0x6c, 10)); clk_dm(IMX6QDL_CLK_ENET_REF, imx_clk_fixed_factor(dev, "enet_ref", "pll6_enet", 1, 1)); + +#if CONFIG_IS_ENABLED(VIDEO) clk_dm(IMX6QDL_CLK_MIPI_CORE_CFG, imx_clk_gate2_shared(dev, "mipi_core_cfg", "video_27m", base + 0x74, 16, @@ -480,6 +696,7 @@ static int imx6q_clk_probe(struct udevice *dev) SET_CLK_PARENT(IMX6QDL_CLK_IPU1_SEL, IMX6QDL_CLK_PLL3_PFD1_540M); } +#endif /* CONFIG_IS_ENABLED(VIDEO) */ return 0; } diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c index fe6cba19758..78156003ad9 100644 --- a/drivers/clk/imx/clk-imx8mq.c +++ b/drivers/clk/imx/clk-imx8mq.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2019 NXP + * Copyright 2019, 2026 NXP * Copyright 2022 Purism * Peng Fan <[email protected]> */ @@ -155,39 +155,52 @@ static int imx8mq_clk_probe(struct udevice *dev) imx_clk_mux(dev, "dram_pll_ref_sel", base + 0x60, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_ARM_PLL_REF_SEL, - imx_clk_mux(dev, "arm_pll_ref_sel", base + 0x28, 0, 2, + imx_clk_mux(dev, "arm_pll_ref_sel", base + 0x28, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_GPU_PLL_REF_SEL, - imx_clk_mux(dev, "gpu_pll_ref_sel", base + 0x18, 0, 2, + imx_clk_mux(dev, "gpu_pll_ref_sel", base + 0x18, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_VPU_PLL_REF_SEL, - imx_clk_mux(dev, "vpu_pll_ref_sel", base + 0x20, 0, 2, + imx_clk_mux(dev, "vpu_pll_ref_sel", base + 0x20, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_SYS3_PLL1_REF_SEL, imx_clk_mux(dev, "sys3_pll_ref_sel", base + 0x48, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_AUDIO_PLL1_REF_SEL, - imx_clk_mux(dev, "audio_pll1_ref_sel", base + 0x0, 0, 2, + imx_clk_mux(dev, "audio_pll1_ref_sel", base + 0x0, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_AUDIO_PLL2_REF_SEL, - imx_clk_mux(dev, "audio_pll2_ref_sel", base + 0x8, 0, 2, + imx_clk_mux(dev, "audio_pll2_ref_sel", base + 0x8, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_VIDEO_PLL1_REF_SEL, - imx_clk_mux(dev, "video_pll1_ref_sel", base + 0x10, 0, 2, + imx_clk_mux(dev, "video_pll1_ref_sel", base + 0x10, 16, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); clk_dm(IMX8MQ_VIDEO2_PLL1_REF_SEL, imx_clk_mux(dev, "video_pll2_ref_sel", base + 0x54, 0, 2, pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MQ_ARM_PLL_REF_DIV, + imx_clk_divider(dev, "arm_pll_ref_div", "arm_pll_ref_sel", base + 0x28, 5, 6)); + clk_dm(IMX8MQ_GPU_PLL_REF_DIV, + imx_clk_divider(dev, "gpu_pll_ref_div", "gpu_pll_ref_sel", base + 0x18, 5, 6)); + clk_dm(IMX8MQ_VPU_PLL_REF_DIV, + imx_clk_divider(dev, "vpu_pll_ref_div", "vpu_pll_ref_sel", base + 0x20, 5, 6)); + clk_dm(IMX8MQ_AUDIO_PLL1_REF_DIV, + imx_clk_divider(dev, "audio_pll1_ref_div", "audio_pll1_ref_sel", base + 0x0, 5, 6)); + clk_dm(IMX8MQ_AUDIO_PLL2_REF_DIV, + imx_clk_divider(dev, "audio_pll2_ref_div", "audio_pll2_ref_sel", base + 0x8, 5, 6)); + clk_dm(IMX8MQ_VIDEO_PLL1_REF_DIV, + imx_clk_divider(dev, "video_pll1_ref_div", "video_pll1_ref_sel", base + 0x10, 5, 6)); + clk_dm(IMX8MQ_ARM_PLL, - imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", - base + 0x28, &imx_1416x_pll)); + imx_clk_frac_pll("arm_pll", "arm_pll_ref_div", + base + 0x28)); clk_dm(IMX8MQ_GPU_PLL, - imx_clk_pll14xx("gpu_pll", "gpu_pll_ref_sel", - base + 0x18, &imx_1416x_pll)); + imx_clk_frac_pll("gpu_pll", "gpu_pll_ref_div", + base + 0x18)); clk_dm(IMX8MQ_VPU_PLL, - imx_clk_pll14xx("vpu_pll", "vpu_pll_ref_sel", - base + 0x20, &imx_1416x_pll)); + imx_clk_frac_pll("vpu_pll", "vpu_pll_ref_div", + base + 0x20)); clk_dm(IMX8MQ_SYS1_PLL1, clk_register_fixed_rate(NULL, "sys1_pll", 800000000)); @@ -196,14 +209,14 @@ static int imx8mq_clk_probe(struct udevice *dev) clk_dm(IMX8MQ_SYS2_PLL1, clk_register_fixed_rate(NULL, "sys3_pll", 1000000000)); clk_dm(IMX8MQ_AUDIO_PLL1, - imx_clk_pll14xx("audio_pll1", "audio_pll1_ref_sel", - base + 0x0, &imx_1443x_pll)); + imx_clk_frac_pll("audio_pll1", "audio_pll1_ref_div", + base + 0x0)); clk_dm(IMX8MQ_AUDIO_PLL2, - imx_clk_pll14xx("audio_pll2", "audio_pll2_ref_sel", - base + 0x8, &imx_1443x_pll)); + imx_clk_frac_pll("audio_pll2", "audio_pll2_ref_div", + base + 0x8)); clk_dm(IMX8MQ_VIDEO_PLL1, - imx_clk_pll14xx("video_pll1", "video_pll1_ref_sel", - base + 0x10, &imx_1443x_pll)); + imx_clk_frac_pll("video_pll1", "video_pll1_ref_div", + base + 0x10)); /* PLL bypass out */ clk_dm(IMX8MQ_ARM_PLL_BYPASS, @@ -356,8 +369,8 @@ static int imx8mq_clk_probe(struct udevice *dev) clk_dm(IMX8MQ_CLK_A53_DIV, imx_clk_divider2(dev, "arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3)); - clk_dm(IMX8MQ_CLK_A53_CORE, - imx_clk_mux2(dev, "arm_a53_src", base + 0x9880, 24, 1, + clk_dm(IMX8MQ_CLK_ARM, + imx_clk_mux2(dev, "arm_a53_core", base + 0x9880, 24, 1, imx8mq_a53_core_sels, ARRAY_SIZE(imx8mq_a53_core_sels))); clk_dm(IMX8MQ_CLK_AHB, diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index b53f35df84f..6aef72c0212 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -78,6 +78,9 @@ struct clk *imx_clk_pll14xx(const char *name, const char *parent_name, void __iomem *base, const struct imx_pll14xx_clk *pll_clk); +struct clk *imx_clk_frac_pll(const char *name, const char *parent_name, + void __iomem *base); + struct clk *clk_register_gate2(struct udevice *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u8 bit_idx, u8 cgr_val, diff --git a/drivers/clk/mediatek/clk-mt8189.c b/drivers/clk/mediatek/clk-mt8189.c index 9e640059f11..d11947ee461 100644 --- a/drivers/clk/mediatek/clk-mt8189.c +++ b/drivers/clk/mediatek/clk-mt8189.c @@ -1641,6 +1641,46 @@ static const struct mtk_gate mminfra_config_clks[] = { GATE_MMINFRA_CONFIG1(CLK_MMINFRA_GCE_26M, CLK_TOP_MMINFRA_SEL, 17), }; +static const struct mtk_gate_regs ufscfg_ao_reg_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0xc, + .sta_ofs = 0x4, +}; + +#define GATE_UFSCFG_AO_REG_EXT(_id, _parent, _shift) \ + GATE_FLAGS(_id, _parent, &ufscfg_ao_reg_cg_regs, _shift, \ + CLK_GATE_SETCLR | CLK_PARENT_EXT) + +#define GATE_UFSCFG_AO_REG_TOP(_id, _parent, _shift) \ + GATE_FLAGS(_id, _parent, &ufscfg_ao_reg_cg_regs, _shift, \ + CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN) + +static const struct mtk_gate ufs_config_ao_clks[] = { + GATE_UFSCFG_AO_REG_EXT(CLK_UFSCFG_AO_REG_UNIPRO_TX_SYM, CLK_PAD_CLK26M, 1), + GATE_UFSCFG_AO_REG_EXT(CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM0, CLK_PAD_CLK26M, 2), + GATE_UFSCFG_AO_REG_EXT(CLK_UFSCFG_AO_REG_UNIPRO_RX_SYM1, CLK_PAD_CLK26M, 3), + GATE_UFSCFG_AO_REG_TOP(CLK_UFSCFG_AO_REG_UNIPRO_SYS, CLK_TOP_U_SEL, 4), + GATE_UFSCFG_AO_REG_EXT(CLK_UFSCFG_AO_REG_U_SAP_CFG, CLK_PAD_CLK26M, 5), + GATE_UFSCFG_AO_REG_TOP(CLK_UFSCFG_AO_REG_U_PHY_TOP_AHB_S_BUS, CLK_TOP_AXI_U_SEL, 6), +}; + +static const struct mtk_gate_regs ufscfg_pdn_reg_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0xc, + .sta_ofs = 0x4, +}; + +#define GATE_UFSCFG_PDN_REG(_id, _parent, _shift) \ + GATE_FLAGS(_id, _parent, &ufscfg_pdn_reg_cg_regs, _shift, \ + CLK_GATE_SETCLR | CLK_PARENT_TOPCKGEN) + +static const struct mtk_gate ufs_config_pdn_clks[] = { + GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_UFS, CLK_TOP_U_SEL, 0), + GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_AES, CLK_TOP_AES_UFSFDE_SEL, 1), + GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_U_AHB, CLK_TOP_AXI_U_SEL, 3), + GATE_UFSCFG_PDN_REG(CLK_UFSCFG_REG_UFSHCI_U_AXI, CLK_TOP_MEM_SUB_U_SEL, 5), +}; + static const struct mtk_parent vlp_26m_oscd10_parents[] = { EXT_PARENT(CLK_PAD_CLK26M), TOP_PARENT(CLK_TOP_OSC_D10), @@ -1955,6 +1995,8 @@ GATE_CLK_DATA(perao_clks); GATE_CLK_DATA(imp_clks); GATE_CLK_DATA(mm_clks); GATE_CLK_DATA(mminfra_config_clks); +GATE_CLK_DATA(ufs_config_ao_clks); +GATE_CLK_DATA(ufs_config_pdn_clks); GATE_CLK_DATA(vlpcfg_ao_clks); static const struct udevice_id of_match_mt8189_clk_gate[] = { @@ -1962,6 +2004,8 @@ static const struct udevice_id of_match_mt8189_clk_gate[] = { { .compatible = "mediatek,mt8189-iic-wrap", .data = (ulong)&imp_clks_data }, { .compatible = "mediatek,mt8189-dispsys", .data = (ulong)&mm_clks_data }, { .compatible = "mediatek,mt8189-mm-infra", .data = (ulong)&mminfra_config_clks_data }, + { .compatible = "mediatek,mt8189-ufscfg-ao", .data = (ulong)&ufs_config_ao_clks_data }, + { .compatible = "mediatek,mt8189-ufscfg-pdn", .data = (ulong)&ufs_config_pdn_clks_data }, { .compatible = "mediatek,mt8189-vlpcfg-ao", .data = (ulong)&vlpcfg_ao_clks_data }, { } }; diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c index 3557aeac3d5..9d0a6cd79cf 100644 --- a/drivers/clk/mediatek/clk-mtk.c +++ b/drivers/clk/mediatek/clk-mtk.c @@ -204,10 +204,6 @@ static ulong mtk_clk_find_parent_rate(struct clk *clk, int id, return clk_get_rate(&parent); } -const struct clk_ops mtk_clk_apmixedsys_ops; -const struct clk_ops mtk_clk_topckgen_ops; -const struct clk_ops mtk_clk_infrasys_ops; - static ulong mtk_find_parent_rate(struct mtk_clk_priv *priv, struct clk *clk, const int parent, u16 flags) { @@ -216,15 +212,21 @@ static ulong mtk_find_parent_rate(struct mtk_clk_priv *priv, struct clk *clk, switch (flags & CLK_PARENT_MASK) { case CLK_PARENT_APMIXED: /* APMIXEDSYS can be parent or grandparent. */ - if (dev_get_driver_ops(clk->dev) == &mtk_clk_apmixedsys_ops) + if (dev_get_driver_ops(clk->dev) == &mtk_clk_apmixedsys_ops || + dev_get_driver_ops(clk->dev) == &mtk_clk_fixed_pll_ops) { parent_dev = clk->dev; - else if (dev_get_driver_ops(priv->parent) == &mtk_clk_apmixedsys_ops) + } else if (dev_get_driver_ops(priv->parent) == &mtk_clk_apmixedsys_ops || + dev_get_driver_ops(priv->parent) == &mtk_clk_fixed_pll_ops) { parent_dev = priv->parent; - else if (dev_get_driver_ops(dev_get_parent(priv->parent)) == &mtk_clk_apmixedsys_ops) - parent_dev = dev_get_parent(priv->parent); - else - return -EINVAL; + } else { + struct udevice *grandparent_dev = dev_get_parent(priv->parent); + if (dev_get_driver_ops(grandparent_dev) == &mtk_clk_apmixedsys_ops || + dev_get_driver_ops(grandparent_dev) == &mtk_clk_fixed_pll_ops) + parent_dev = grandparent_dev; + else + return -EINVAL; + } break; case CLK_PARENT_TOPCKGEN: if (dev_get_driver_ops(clk->dev) == &mtk_clk_topckgen_ops) diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index a7a42b2edb6..f33938e1419 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -946,6 +946,11 @@ static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, case CLKID_HDMI: return meson_clk_set_rate_by_id(clk, CLKID_HDMI_DIV, rate, current_rate); + case CLKID_SD_EMMC_A_CLK0: + case CLKID_SD_EMMC_B_CLK0: + case CLKID_SD_EMMC_C_CLK0: + /* TOFIX: implement rate set for MMC clocks */ + return 0; default: return -ENOENT; } diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 218be45c2cb..bf46f4d50bc 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -900,6 +900,11 @@ static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, case CLKID_HDMI: return meson_clk_set_rate_by_id(clk, CLKID_HDMI_DIV, rate, current_rate); + case CLKID_SD_EMMC_A_CLK0: + case CLKID_SD_EMMC_B_CLK0: + case CLKID_SD_EMMC_C_CLK0: + /* TOFIX: implement rate set for MMC clocks */ + return 0; default: return -ENOENT; } diff --git a/drivers/clk/owl/Kconfig b/drivers/clk/owl/Kconfig index c6afef90034..5f3b8fe8ab4 100644 --- a/drivers/clk/owl/Kconfig +++ b/drivers/clk/owl/Kconfig @@ -1,8 +1,8 @@ config CLK_OWL - bool "Actions Semi OWL clock drivers" - depends on CLK && ARCH_OWL - help - Enable support for clock managemet unit present in Actions Semi + bool "Actions Semi OWL clock drivers" + depends on CLK && ARCH_OWL + help + Enable support for clock managemet unit present in Actions Semi Owl series S900/S700 SoCs. diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 8504ed5d656..9ad233c83ac 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -47,6 +47,14 @@ config CLK_QCOM_IPQ9574 on the Snapdragon IPQ9574 SoC. This driver supports the clocks and resets exposed by the GCC hardware block. +config CLK_QCOM_MILOS + bool "Qualcomm Milos GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon Milos SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + config CLK_QCOM_QCM2290 bool "Qualcomm QCM2290 GCC" select CLK_QCOM @@ -103,6 +111,14 @@ 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_SM6125 + bool "Qualcomm SM6125 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon SM6125 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 diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 82a5b166196..c0d95a6300e 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_CLK_QCOM_APQ8096) += clock-apq8096.o obj-$(CONFIG_CLK_QCOM_IPQ4019) += clock-ipq4019.o obj-$(CONFIG_CLK_QCOM_IPQ5424) += clock-ipq5424.o obj-$(CONFIG_CLK_QCOM_IPQ9574) += clock-ipq9574.o +obj-$(CONFIG_CLK_QCOM_MILOS) += clock-milos.o obj-$(CONFIG_CLK_QCOM_QCM2290) += clock-qcm2290.o obj-$(CONFIG_CLK_QCOM_QCS404) += clock-qcs404.o obj-$(CONFIG_CLK_QCOM_QCS8300) += clock-qcs8300.o @@ -16,6 +17,7 @@ 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_SM6125) += clock-sm6125.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 diff --git a/drivers/clk/qcom/clock-milos.c b/drivers/clk/qcom/clock-milos.c new file mode 100644 index 00000000000..54103adc114 --- /dev/null +++ b/drivers/clk/qcom/clock-milos.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Clock drivers for Qualcomm Milos + * + * (C) Copyright 2024 Linaro Ltd. + * (C) Copyright 2026 Luca Weiss <[email protected]> + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <linux/delay.h> +#include <errno.h> +#include <asm/io.h> +#include <linux/bug.h> +#include <linux/bitops.h> +#include <dt-bindings/clock/qcom,milos-gcc.h> +#include <dt-bindings/clock/qcom,rpmh.h> +#include <dt-bindings/clock/qcom,sm8650-tcsr.h> + +#include "clock-qcom.h" + +/* On-board TCXO, TOFIX get from DT */ +#define TCXO_RATE 76800000 + +/* bi_tcxo_div4 divided after RPMh output */ +#define TCXO_DIV4_RATE (TCXO_RATE / 4) + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_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(51200000, CFG_CLK_SRC_GPLL0_EVEN, 1, 64, 375), + 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 const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), + F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 12, 0, 0), + F(37500000, CFG_CLK_SRC_GPLL0_EVEN, 8, 0, 0), + F(50000000, CFG_CLK_SRC_GPLL0_EVEN, 6, 0, 0), + F(100000000, CFG_CLK_SRC_GPLL0_EVEN, 3, 0, 0), + /* TOFIX F(202000000, CFG_CLK_SRC_GPLL9, 4, 0, 0), */ + { } +}; + +static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { + F(66666667, CFG_CLK_SRC_GPLL0_EVEN, 4.5, 0, 0), + F(133333333, CFG_CLK_SRC_GPLL0, 4.5, 0, 0), + F(200000000, CFG_CLK_SRC_GPLL0, 3, 0, 0), + F(240000000, CFG_CLK_SRC_GPLL0, 2.5, 0, 0), + { } +}; + +static ulong milos_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_QUPV3_WRAP0_S5_CLK: /* UART5 */ + freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s3_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, 0x18500, + freq->pre_div, freq->m, freq->n, freq->src, 16); + 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, 0x14018, + freq->pre_div, freq->m, freq->n, freq->src, 8); + 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, 0x3902c, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_USB30_PRIM_MOCK_UTMI_CLK: + clk_rcg_set_rate(priv->base, 0x39044, 0, 0); + return TCXO_DIV4_RATE; + default: + return 0; + } +} + +static const struct gate_clk milos_clks[] = { + GATE_CLK(GCC_AGGRE_USB3_PRIM_AXI_CLK, 0x39090, BIT(0)), + GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x52008, BIT(27)), + GATE_CLK(GCC_QUPV3_WRAP_0_M_AHB_CLK, 0x52008, BIT(20)), + GATE_CLK(GCC_QUPV3_WRAP_0_S_AHB_CLK, 0x52008, BIT(21)), + GATE_CLK(GCC_SDCC2_AHB_CLK, 0x14010, BIT(0)), + GATE_CLK(GCC_SDCC2_APPS_CLK, 0x14004, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x39018, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x39028, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x39024, BIT(0)), + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x3908c, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x77018, BIT(0)), + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x770e4, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77024, BIT(0)), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x77068, BIT(0)), + GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x77028, BIT(0)), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x7702c, BIT(0)), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_1_CLK, 0x770cc, BIT(0)), +}; + +static int milos_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case GCC_AGGRE_USB3_PRIM_AXI_CLK: + qcom_gate_clk_en(priv, GCC_USB30_PRIM_MASTER_CLK); + break; + } + + return qcom_gate_clk_en(priv, clk->id); +} + +static const struct qcom_reset_map milos_gcc_resets[] = { + [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 }, + [GCC_SDCC1_BCR] = { 0xa3000 }, + [GCC_SDCC2_BCR] = { 0x14000 }, + [GCC_UFS_PHY_BCR] = { 0x77000 }, + [GCC_USB30_PRIM_BCR] = { 0x39000 }, +}; + +static const struct qcom_power_map milos_gdscs[] = { + [UFS_PHY_GDSC] = { 0x77004 }, + [UFS_MEM_PHY_GDSC] = { 0x9e000 }, + [USB30_PRIM_GDSC] = { 0x39004 }, +}; + +static struct msm_clk_data milos_gcc_data = { + .resets = milos_gcc_resets, + .num_resets = ARRAY_SIZE(milos_gcc_resets), + .clks = milos_clks, + .num_clks = ARRAY_SIZE(milos_clks), + .power_domains = milos_gdscs, + .num_power_domains = ARRAY_SIZE(milos_gdscs), + + .enable = milos_enable, + .set_rate = milos_set_rate, +}; + +static const struct udevice_id gcc_milos_of_match[] = { + { + .compatible = "qcom,milos-gcc", + .data = (ulong)&milos_gcc_data, + }, + { } +}; + +U_BOOT_DRIVER(gcc_milos) = { + .name = "gcc_milos", + .id = UCLASS_NOP, + .of_match = gcc_milos_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; + +static ulong milos_rpmh_clk_set_rate(struct clk *clk, ulong rate) +{ + return (clk->rate = rate); +} + +static ulong milos_rpmh_clk_get_rate(struct clk *clk) +{ + switch (clk->id) { + case RPMH_CXO_CLK: + return TCXO_DIV4_RATE; + default: + return clk->rate; + } +} + +static int milos_rpmh_clk_nop(struct clk *clk) +{ + return 0; +} + +static struct clk_ops milos_rpmh_clk_ops = { + .set_rate = milos_rpmh_clk_set_rate, + .get_rate = milos_rpmh_clk_get_rate, + .enable = milos_rpmh_clk_nop, + .disable = milos_rpmh_clk_nop, +}; + +static const struct udevice_id milos_rpmh_clk_ids[] = { + { .compatible = "qcom,milos-rpmh-clk" }, + { } +}; + +U_BOOT_DRIVER(milos_rpmh_clk) = { + .name = "milos_rpmh_clk", + .id = UCLASS_CLK, + .of_match = milos_rpmh_clk_ids, + .ops = &milos_rpmh_clk_ops, + .flags = DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; + +/* TCSRCC */ + +static const struct gate_clk milos_tcsr_clks[] = { + GATE_CLK(TCSR_PCIE_0_CLKREF_EN, 0x31100, BIT(0)), + GATE_CLK(TCSR_PCIE_1_CLKREF_EN, 0x31114, BIT(0)), + GATE_CLK(TCSR_UFS_CLKREF_EN, 0x31118, BIT(0)), + GATE_CLK(TCSR_UFS_PAD_CLKREF_EN, 0x31104, BIT(0)), +}; + +static struct msm_clk_data milos_tcsrcc_data = { + .clks = milos_tcsr_clks, + .num_clks = ARRAY_SIZE(milos_tcsr_clks), +}; + +static int tcsrcc_milos_clk_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + qcom_gate_clk_en(priv, clk->id); + + return 0; +} + +static ulong tcsrcc_milos_clk_get_rate(struct clk *clk) +{ + return TCXO_RATE; +} + +static int tcsrcc_milos_clk_probe(struct udevice *dev) +{ + struct msm_clk_data *data = (struct msm_clk_data *)dev_get_driver_data(dev); + struct msm_clk_priv *priv = dev_get_priv(dev); + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + priv->data = data; + + return 0; +} + +static struct clk_ops tcsrcc_milos_clk_ops = { + .enable = tcsrcc_milos_clk_enable, + .get_rate = tcsrcc_milos_clk_get_rate, +}; + +static const struct udevice_id tcsrcc_milos_of_match[] = { + { + .compatible = "qcom,milos-tcsr", + .data = (ulong)&milos_tcsrcc_data, + }, + { } +}; + +U_BOOT_DRIVER(tcsrcc_milos) = { + .name = "tcsrcc_milos", + .id = UCLASS_CLK, + .of_match = tcsrcc_milos_of_match, + .ops = &tcsrcc_milos_clk_ops, + .priv_auto = sizeof(struct msm_clk_priv), + .probe = tcsrcc_milos_clk_probe, + .flags = DM_FLAG_PRE_RELOC | DM_FLAG_DEFAULT_PD_CTRL_OFF, +}; diff --git a/drivers/clk/qcom/clock-qcm2290.c b/drivers/clk/qcom/clock-qcm2290.c index 5a599085b50..c38ff1a1e4a 100644 --- a/drivers/clk/qcom/clock-qcm2290.c +++ b/drivers/clk/qcom/clock-qcm2290.c @@ -73,7 +73,7 @@ static const struct pll_vote_clk gpll6_clk = { .status = 0x6000, .status_bit = BIT(31), .ena_vote = 0x79000, - .vote_bit = BIT(7), + .vote_bit = BIT(6), }; static const struct gate_clk qcm2290_clks[] = { diff --git a/drivers/clk/qcom/clock-qcs615.c b/drivers/clk/qcom/clock-qcs615.c index 2087fc38f63..7b3fe49de9c 100644 --- a/drivers/clk/qcom/clock-qcs615.c +++ b/drivers/clk/qcom/clock-qcs615.c @@ -19,6 +19,11 @@ #define USB30_PRIM_MASTER_CLK_CMD_RCGR 0xf01c #define USB3_PRIM_PHY_AUX_CMD_RCGR 0xf060 +#define UFS_PHY_AXI_CLK_CMD_RCGR 0x77020 +#define UFS_PHY_ICE_CORE_CLK_CMD_RCGR 0x77048 +#define UFS_PHY_UNIPRO_CORE_CLK_CMD_RCGR 0x77060 +#define UFS_PHY_PHY_AUX_CLK_CMD_RCGR 0x7707c + #define GCC_QUPV3_WRAP0_S0_CLK_ENA_BIT BIT(10) #define GCC_QUPV3_WRAP0_S1_CLK_ENA_BIT BIT(11) #define GCC_QUPV3_WRAP0_S2_CLK_ENA_BIT BIT(12) @@ -33,9 +38,37 @@ #define GCC_QUPV3_WRAP1_S4_CLK_ENA_BIT BIT(26) #define GCC_QUPV3_WRAP1_S5_CLK_ENA_BIT BIT(27) +/* UFS PHY AXI clock frequency table */ +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + 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(200000000, CFG_CLK_SRC_GPLL0, 3, 0, 0), + F(240000000, CFG_CLK_SRC_GPLL0, 2.5, 0, 0), + { } +}; + +/* UFS PHY ICE CORE clock frequency table */ +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(37500000, CFG_CLK_SRC_GPLL0_EVEN, 8, 0, 0), + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0, 4, 0, 0), + F(300000000, CFG_CLK_SRC_GPLL0, 2, 0, 0), + { } +}; + +/* UFS PHY UNIPRO CORE clock frequency table */ +static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_core_clk_src[] = { + F(37500000, CFG_CLK_SRC_GPLL0_EVEN, 8, 0, 0), + F(75000000, CFG_CLK_SRC_GPLL0, 8, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0, 4, 0, 0), + { } +}; + static ulong qcs615_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__, @@ -52,6 +85,24 @@ static ulong qcs615_set_rate(struct clk *clk, ulong rate) 5, 0, 0, CFG_CLK_SRC_GPLL0, 8); clk_rcg_set_rate(priv->base, USB3_PRIM_PHY_AUX_CMD_RCGR, 0, 0); return rate; + case GCC_UFS_PHY_AXI_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_axi_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_AXI_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_UNIPRO_CORE_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_unipro_core_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_UNIPRO_CORE_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_ICE_CORE_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_ice_core_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_ICE_CORE_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_PHY_AUX_CLK: + clk_rcg_set_rate(priv->base, UFS_PHY_PHY_AUX_CLK_CMD_RCGR, 0, CFG_CLK_SRC_CXO); + return 19200000; default: return 0; } @@ -81,7 +132,17 @@ static const struct gate_clk qcs615_clks[] = { GATE_CLK(GCC_QUPV3_WRAP1_S4_CLK, 0x5200c, GCC_QUPV3_WRAP1_S4_CLK_ENA_BIT), GATE_CLK(GCC_QUPV3_WRAP1_S5_CLK, 0x5200c, GCC_QUPV3_WRAP1_S5_CLK_ENA_BIT), GATE_CLK(GCC_DISP_HF_AXI_CLK, 0xb038, BIT(0)), - GATE_CLK(GCC_DISP_AHB_CLK, 0xb032, BIT(0)) + GATE_CLK(GCC_DISP_AHB_CLK, 0xb032, BIT(0)), + /* UFS clocks */ + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x77010, BIT(0)), + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x770c0, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x77014, BIT(0)), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x77040, BIT(0)), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x77044, BIT(0)), + GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x77018, BIT(0)), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x7701c, BIT(0)), + GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x77078, BIT(0)), + GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, BIT(0)), }; static int qcs615_enable(struct clk *clk) diff --git a/drivers/clk/qcom/clock-sa8775p.c b/drivers/clk/qcom/clock-sa8775p.c index 4957abf6f58..7eec4aeae48 100644 --- a/drivers/clk/qcom/clock-sa8775p.c +++ b/drivers/clk/qcom/clock-sa8775p.c @@ -19,6 +19,11 @@ #define USB30_PRIM_MASTER_CLK_CMD_RCGR 0x1b028 #define USB3_PRIM_PHY_AUX_CMD_RCGR 0x1b06c +#define UFS_PHY_AXI_CLK_CMD_RCGR 0x8302c +#define UFS_PHY_ICE_CORE_CLK_CMD_RCGR 0x83074 +#define UFS_PHY_PHY_AUX_CLK_CMD_RCGR 0x830a8 +#define UFS_PHY_UNIPRO_CORE_CLK_CMD_RCGR 0x8308c + #define GCC_QUPV3_WRAP0_S0_CLK_ENA_BIT BIT(10) #define GCC_QUPV3_WRAP0_S1_CLK_ENA_BIT BIT(11) #define GCC_QUPV3_WRAP0_S2_CLK_ENA_BIT BIT(12) @@ -44,9 +49,35 @@ #define GCC_QUPV3_WRAP3_S0_CLK_ENA_BIT BIT(25) +/* UFS AXI clock frequency table */ +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 12, 0, 0), + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0, 4, 0, 0), + F(300000000, CFG_CLK_SRC_GPLL0, 2, 0, 0), + { } +}; + +/* UFS ICE CORE clock frequency table */ +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0, 4, 0, 0), + F(300000000, CFG_CLK_SRC_GPLL0, 2, 0, 0), + { } +}; + +/* UFS UNIPRO CORE clock frequency table */ +static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_core_clk_src[] = { + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0, 4, 0, 0), + F(300000000, CFG_CLK_SRC_GPLL0, 2, 0, 0), + { } +}; + static ulong sa8775p_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__, @@ -63,6 +94,24 @@ static ulong sa8775p_set_rate(struct clk *clk, ulong rate) 5, 0, 0, CFG_CLK_SRC_GPLL0, 8); clk_rcg_set_rate(priv->base, USB3_PRIM_PHY_AUX_CMD_RCGR, 0, 0); return rate; + case GCC_UFS_PHY_AXI_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_axi_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_AXI_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_UNIPRO_CORE_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_unipro_core_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_UNIPRO_CORE_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_ICE_CORE_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_ice_core_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_ICE_CORE_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_PHY_AUX_CLK: + clk_rcg_set_rate(priv->base, UFS_PHY_PHY_AUX_CLK_CMD_RCGR, 0, CFG_CLK_SRC_CXO); + return 19200000; default: return 0; } @@ -106,6 +155,20 @@ static const struct gate_clk sa8775p_clks[] = { /* QUP Wrapper 3 clocks */ GATE_CLK(GCC_QUPV3_WRAP3_S0_CLK, 0x4b000, GCC_QUPV3_WRAP3_S0_CLK_ENA_BIT), + + /* UFS PHY clocks */ + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x83018, 1), + GATE_CLK(GCC_AGGRE_UFS_PHY_AXI_CLK, 0x830d4, 1), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x83020, 1), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x83064, 1), + GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x83024, 1), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x83028, 1), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_1_CLK, 0x830c0, 1), + GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x830a4, 1), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x8306c, 1), + + /* EDP reference clock (used by UFS PHY) */ + GATE_CLK(GCC_EDP_REF_CLKREF_EN, 0x97448, 1), }; static int sa8775p_enable(struct clk *clk) diff --git a/drivers/clk/qcom/clock-sc7280.c b/drivers/clk/qcom/clock-sc7280.c index 7b6ed826023..91e3fcc27cb 100644 --- a/drivers/clk/qcom/clock-sc7280.c +++ b/drivers/clk/qcom/clock-sc7280.c @@ -23,6 +23,10 @@ #define PCIE_1_AUX_CLK_CMD_RCGR 0x8d058 #define PCIE1_PHY_RCHNG_CMD_RCGR 0x8d03c #define PCIE_1_PIPE_CLK_PHY_MUX 0x8d054 +#define UFS_PHY_AXI_CLK_CMD_RCGR 0x77024 +#define UFS_PHY_ICE_CORE_CLK_CMD_RCGR 0x7706c +#define UFS_PHY_PHY_AUX_CLK_CMD_RCGR 0x770a0 +#define UFS_PHY_UNIPRO_CORE_CLK_CMD_RCGR 0x77084 static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = { F(66666667, CFG_CLK_SRC_GPLL0_EVEN, 4.5, 0, 0), @@ -54,6 +58,33 @@ static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s2_clk_src[] = { { } }; +static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = { + F(25000000, CFG_CLK_SRC_GPLL0_EVEN, 12, 0, 0), + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0_EVEN, 2, 0, 0), + F(300000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = { + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0_EVEN, 2, 0, 0), + F(300000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_phy_aux_clk_src[] = { + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_core_clk_src[] = { + F(75000000, CFG_CLK_SRC_GPLL0_EVEN, 4, 0, 0), + F(150000000, CFG_CLK_SRC_GPLL0_EVEN, 2, 0, 0), + F(300000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 0, 0), + { } +}; + static ulong sc7280_set_rate(struct clk *clk, ulong rate) { struct msm_clk_priv *priv = dev_get_priv(clk->dev); @@ -103,6 +134,26 @@ static ulong sc7280_set_rate(struct clk *clk, ulong rate) case GCC_PCIE1_PHY_RCHNG_CLK: clk_rcg_set_rate(priv->base, PCIE1_PHY_RCHNG_CMD_RCGR, 5, CFG_CLK_SRC_GPLL0_EVEN); return 100000000; + case GCC_UFS_PHY_AXI_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_axi_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_AXI_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_ICE_CORE_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_ice_core_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_ICE_CORE_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_PHY_AUX_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_phy_aux_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_PHY_AUX_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; + case GCC_UFS_PHY_UNIPRO_CORE_CLK: + freq = qcom_find_freq(ftbl_gcc_ufs_phy_unipro_core_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, UFS_PHY_UNIPRO_CORE_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, 8); + return freq->freq; default: return rate; } @@ -116,6 +167,7 @@ static const struct gate_clk sc7280_clks[] = { GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0xf01c, 1), GATE_CLK(GCC_USB3_PRIM_PHY_AUX_CLK, 0xf054, 1), GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0xf058, 1), + GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0xf05c, 1), GATE_CLK(GCC_CFG_NOC_USB3_SEC_AXI_CLK, 0x9e07c, 1), GATE_CLK(GCC_USB30_SEC_MASTER_CLK, 0x9e010, 1), GATE_CLK(GCC_AGGRE_USB3_SEC_AXI_CLK, 0x9e080, 1), @@ -147,6 +199,7 @@ static const struct gate_clk sc7280_clks[] = { 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)), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x77064, BIT(0)), GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x7705c, BIT(0)), GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x7709c, BIT(0)), GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x7701c, BIT(0)), @@ -155,6 +208,8 @@ static const struct gate_clk sc7280_clks[] = { GATE_CLK(GCC_UFS_1_CLKREF_EN, 0x8c000, BIT(0)), GATE_CLK(GCC_SDCC2_AHB_CLK, 0x14008, BIT(0)), GATE_CLK(GCC_SDCC2_APPS_CLK, 0x14004, BIT(0)), + GATE_CLK(GCC_SDCC1_AHB_CLK, 0x75004, BIT(0)), + GATE_CLK(GCC_SDCC1_APPS_CLK, 0x75008, BIT(0)), }; static int sc7280_enable(struct clk *clk) diff --git a/drivers/clk/qcom/clock-sm6125.c b/drivers/clk/qcom/clock-sm6125.c new file mode 100644 index 00000000000..1fd72d55e88 --- /dev/null +++ b/drivers/clk/qcom/clock-sm6125.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Clock drivers for Qualcomm sm6125 + * + * (C) Copyright 2026 Biswapriyo Nath <[email protected]> + * + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <linux/delay.h> +#include <asm/io.h> +#include <linux/bitops.h> +#include <linux/bug.h> +#include <dt-bindings/clock/qcom,gcc-sm6125.h> + +#include "clock-qcom.h" + +#define GCC_BASE 0x01400000 + +#define QUPV3_WRAP0_S4_CMD_RCGR 0x1f608 +#define SDCC1_APPS_CLK_CMD_RCGR 0x38028 +#define SDCC2_APPS_CLK_CMD_RCGR 0x1e00c + +#define GCC_GPLL0_MODE 0x0 +#define GCC_GPLL3_MODE 0x3000 +#define GCC_GPLL4_MODE 0x4000 +#define GCC_GPLL5_MODE 0x5000 +#define GCC_GPLL6_MODE 0x6000 +#define GCC_GPLL7_MODE 0x7000 +#define GCC_GPLL8_MODE 0x8000 +#define GCC_GPLL9_MODE 0x9000 + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, CFG_CLK_SRC_GPLL0_AUX2, 1, 384, 15625), + F(14745600, CFG_CLK_SRC_GPLL0_AUX2, 1, 768, 15625), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(29491200, CFG_CLK_SRC_GPLL0_AUX2, 1, 1536, 15625), + F(32000000, CFG_CLK_SRC_GPLL0_AUX2, 1, 8, 75), + F(48000000, CFG_CLK_SRC_GPLL0_AUX2, 1, 4, 25), + F(64000000, CFG_CLK_SRC_GPLL0_AUX2, 1, 16, 75), + F(75000000, CFG_CLK_SRC_GPLL0_AUX2, 4, 0, 0), + F(80000000, CFG_CLK_SRC_GPLL0_AUX2, 1, 4, 15), + F(96000000, CFG_CLK_SRC_GPLL0_AUX2, 1, 8, 25), + F(100000000, CFG_CLK_SRC_GPLL0, 6, 0, 0), + F(102400000, CFG_CLK_SRC_GPLL0_AUX2, 1, 128, 375), + F(112000000, CFG_CLK_SRC_GPLL0_AUX2, 1, 28, 75), + F(117964800, CFG_CLK_SRC_GPLL0_AUX2, 1, 6144, 15625), + F(120000000, CFG_CLK_SRC_GPLL0_AUX2, 2.5, 0, 0), + F(128000000, CFG_CLK_SRC_GPLL6, 3, 0, 0), + {} +}; + +static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = { + F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(25000000, CFG_CLK_SRC_GPLL0_AUX2, 12, 0, 0), + F(50000000, CFG_CLK_SRC_GPLL0_AUX2, 6, 0, 0), + F(100000000, CFG_CLK_SRC_GPLL0_AUX2, 3, 0, 0), + {} +}; + +static const struct pll_vote_clk gpll0_clk = { + .status = 0, + .status_bit = BIT(31), + .ena_vote = 0x79000, + .vote_bit = BIT(0), +}; + +static const struct gate_clk sm6125_clks[] = { + GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x1a084, BIT(0)), + GATE_CLK(GCC_QUPV3_WRAP0_CORE_2X_CLK, 0x7900c, BIT(9)), + GATE_CLK(GCC_QUPV3_WRAP0_CORE_CLK, 0x7900c, BIT(8)), + GATE_CLK(GCC_QUPV3_WRAP0_S0_CLK, 0x7900c, BIT(10)), + GATE_CLK(GCC_QUPV3_WRAP0_S1_CLK, 0x7900c, BIT(11)), + GATE_CLK(GCC_QUPV3_WRAP0_S2_CLK, 0x7900c, BIT(12)), + GATE_CLK(GCC_QUPV3_WRAP0_S3_CLK, 0x7900c, BIT(13)), + GATE_CLK(GCC_QUPV3_WRAP0_S4_CLK, 0x7900c, BIT(14)), + GATE_CLK(GCC_QUPV3_WRAP0_S5_CLK, 0x7900c, BIT(15)), + GATE_CLK(GCC_QUPV3_WRAP_0_M_AHB_CLK, 0x7900c, BIT(6)), + GATE_CLK(GCC_QUPV3_WRAP_0_S_AHB_CLK, 0x7900c, BIT(7)), + GATE_CLK(GCC_SDCC1_AHB_CLK, 0x38008, BIT(0)), + GATE_CLK(GCC_SDCC1_APPS_CLK, 0x38004, BIT(0)), + GATE_CLK(GCC_SDCC1_ICE_CORE_CLK, 0x3800c, BIT(0)), + GATE_CLK(GCC_SDCC2_AHB_CLK, 0x1e008, BIT(0)), + GATE_CLK(GCC_SDCC2_APPS_CLK, 0x1e004, BIT(0)), + GATE_CLK(GCC_SYS_NOC_CPUSS_AHB_CLK, 0x79004, BIT(0)), + GATE_CLK(GCC_SYS_NOC_UFS_PHY_AXI_CLK, 0x45098, BIT(0)), + GATE_CLK(GCC_SYS_NOC_USB3_PRIM_AXI_CLK, 0x1a080, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AHB_CLK, 0x45014, BIT(0)), + GATE_CLK(GCC_UFS_PHY_AXI_CLK, 0x45010, BIT(0)), + GATE_CLK(GCC_UFS_PHY_ICE_CORE_CLK, 0x45044, BIT(0)), + GATE_CLK(GCC_UFS_PHY_PHY_AUX_CLK, 0x45078, BIT(0)), + GATE_CLK(GCC_UFS_PHY_RX_SYMBOL_0_CLK, 0x4501c, BIT(0)), + GATE_CLK(GCC_UFS_PHY_TX_SYMBOL_0_CLK, 0x45018, BIT(0)), + GATE_CLK(GCC_UFS_PHY_UNIPRO_CORE_CLK, 0x45040, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MASTER_CLK, 0x1a010, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_MOCK_UTMI_CLK, 0x1a018, BIT(0)), + GATE_CLK(GCC_USB30_PRIM_SLEEP_CLK, 0x1a014, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_CLKREF_CLK, 0x80278, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_COM_AUX_CLK, 0x1a054, BIT(0)), + GATE_CLK(GCC_USB3_PRIM_PHY_PIPE_CLK, 0x1a058, BIT(0)), + GATE_CLK(GCC_AHB2PHY_USB_CLK, 0x1d008, BIT(0)), + GATE_CLK(GCC_UFS_MEM_CLKREF_CLK, 0x8c000, BIT(0)), +}; + +static ulong sm6125_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + const struct freq_tbl *freq; + + debug("%s: clk %s rate %lu\n", __func__, sm6125_clks[clk->id].name, + rate); + + switch (clk->id) { + case GCC_QUPV3_WRAP0_S4_CLK: + freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s0_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, QUPV3_WRAP0_S4_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, + 16); + return 0; + case GCC_SDCC2_APPS_CLK: + clk_enable_gpll0(priv->base, &gpll0_clk); + freq = qcom_find_freq(ftbl_gcc_sdcc2_apps_clk_src, rate); + WARN(freq->src != CFG_CLK_SRC_GPLL0, + "SDCC2_APPS_CLK_SRC not set to GPLL0, requested rate %lu\n", + rate); + clk_rcg_set_rate_mnd(priv->base, SDCC2_APPS_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, + 8); + return freq->freq; + case GCC_SDCC1_APPS_CLK: + /* The firmware turns this on for us and always sets it to this rate */ + return 384000000; + default: + return rate; + } +} + +static int sm6125_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__, sm6125_clks[clk->id].name); + + switch (clk->id) { + case GCC_USB30_PRIM_MASTER_CLK: + qcom_gate_clk_en(priv, GCC_USB3_PRIM_PHY_COM_AUX_CLK); + qcom_gate_clk_en(priv, GCC_USB3_PRIM_CLKREF_CLK); + break; + } + + return qcom_gate_clk_en(priv, clk->id); +} + +static const struct qcom_reset_map sm6125_gcc_resets[] = { + [GCC_QUSB2PHY_PRIM_BCR] = { 0x1c000 }, + [GCC_QUSB2PHY_SEC_BCR] = { 0x1c004 }, + [GCC_UFS_PHY_BCR] = { 0x45000 }, + [GCC_USB30_PRIM_BCR] = { 0x1a000 }, + [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x1d000 }, + [GCC_USB3PHY_PHY_PRIM_SP0_BCR] = { 0x1b008 }, + [GCC_USB3_PHY_PRIM_SP0_BCR] = { 0x1b000 }, + [GCC_CAMSS_MICRO_BCR] = { 0x560ac }, +}; + +static const struct qcom_power_map sm6125_gdscs[] = { + [USB30_PRIM_GDSC] = { 0x1a004 }, + [UFS_PHY_GDSC] = { 0x45004 }, + [CAMSS_VFE0_GDSC] = { 0x54004 }, + [CAMSS_VFE1_GDSC] = { 0x5403c }, + [CAMSS_TOP_GDSC] = { 0x5607c }, + [CAM_CPP_GDSC] = { 0x560bc }, + [HLOS1_VOTE_TURING_MMU_TBU1_GDSC] = { 0x7d060 }, + [HLOS1_VOTE_MM_SNOC_MMU_TBU_RT_GDSC] = { 0x80074 }, + [HLOS1_VOTE_MM_SNOC_MMU_TBU_NRT_GDSC] = { 0x80084 }, + [HLOS1_VOTE_TURING_MMU_TBU0_GDSC] = { 0x80094 }, +}; + +static const phys_addr_t sm6125_gpll_addrs[] = { + GCC_BASE + GCC_GPLL0_MODE, GCC_BASE + GCC_GPLL3_MODE, + GCC_BASE + GCC_GPLL4_MODE, GCC_BASE + GCC_GPLL5_MODE, + GCC_BASE + GCC_GPLL6_MODE, GCC_BASE + GCC_GPLL7_MODE, + GCC_BASE + GCC_GPLL8_MODE, GCC_BASE + GCC_GPLL9_MODE, +}; + +static const phys_addr_t sm6125_rcg_addrs[] = { + 0x0141a01c, // GCC_USB30_PRIM_MASTER_CMD_RCGR + 0x0141a034, // GCC_USB30_PRIM_MOCK_UTMI_CMD_RCGR + 0x0141a060, // GCC_USB3_PRIM_PHY_AUX_CMD_RCGR + 0x01438028, // GCC_SDCC1_APPS_CMD_RCGR + 0x0141e00c, // GCC_SDCC2_APPS_CMD_RCGR + 0x0141f148, // GCC_QUPV3_WRAP0_S0_CMD_RCGR + 0x0141f278, // GCC_QUPV3_WRAP0_S1_CMD_RCGR + 0x0141f3a8, // GCC_QUPV3_WRAP0_S2_CMD_RCGR + 0x0141f4d8, // GCC_QUPV3_WRAP0_S3_CMD_RCGR + 0x0141f608, // GCC_QUPV3_WRAP0_S4_CMD_RCGR + 0x0141f738, // GCC_QUPV3_WRAP0_S5_CMD_RCGR + 0x01445020, // GCC_UFS_PHY_AXI_CMD_RCGR + 0x01445048, // GCC_UFS_PHY_ICE_CORE_CMD_RCGR + 0x01445060, // GCC_UFS_PHY_UNIPRO_CORE_CMD_RCGR + 0x0144507c, // GCC_UFS_PHY_PHY_AUX_CMD_RCGR +}; + +static const char *const sm6125_rcg_names[] = { + "GCC_USB30_PRIM_MASTER_CMD_RCGR", + "GCC_USB30_PRIM_MOCK_UTMI_CMD_RCGR", + "GCC_USB3_PRIM_PHY_AUX_CMD_RCGR", + "GCC_SDCC1_APPS_CMD_RCGR", + "GCC_SDCC2_APPS_CMD_RCGR", + "GCC_QUPV3_WRAP0_S0_CMD_RCGR", + "GCC_QUPV3_WRAP0_S1_CMD_RCGR", + "GCC_QUPV3_WRAP0_S2_CMD_RCGR", + "GCC_QUPV3_WRAP0_S3_CMD_RCGR", + "GCC_QUPV3_WRAP0_S4_CMD_RCGR", + "GCC_QUPV3_WRAP0_S5_CMD_RCGR", + "GCC_UFS_PHY_AXI_CMD_RCGR", + "GCC_UFS_PHY_ICE_CORE_CMD_RCGR", + "GCC_UFS_PHY_UNIPRO_CORE_CMD_RCGR", + "GCC_UFS_PHY_PHY_AUX_CMD_RCGR", +}; + +static struct msm_clk_data sm6125_gcc_data = { + .resets = sm6125_gcc_resets, + .num_resets = ARRAY_SIZE(sm6125_gcc_resets), + .clks = sm6125_clks, + .num_clks = ARRAY_SIZE(sm6125_clks), + .power_domains = sm6125_gdscs, + .num_power_domains = ARRAY_SIZE(sm6125_gdscs), + + .enable = sm6125_enable, + .set_rate = sm6125_set_rate, + + .dbg_pll_addrs = sm6125_gpll_addrs, + .num_plls = ARRAY_SIZE(sm6125_gpll_addrs), + .dbg_rcg_addrs = sm6125_rcg_addrs, + .num_rcgs = ARRAY_SIZE(sm6125_rcg_addrs), + .dbg_rcg_names = sm6125_rcg_names, +}; + +static const struct udevice_id gcc_sm6125_of_match[] = { + { + .compatible = "qcom,gcc-sm6125", + .data = (ulong)&sm6125_gcc_data, + }, + {} +}; + +U_BOOT_DRIVER(gcc_sm6125) = { + .name = "gcc_sm6125", + .id = UCLASS_NOP, + .of_match = gcc_sm6125_of_match, + .bind = qcom_cc_bind, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 51c87cc3606..1893b6c4181 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -61,11 +61,11 @@ config CLK_RCAR_GEN3 Enable this to support the clocks on Renesas R-Car Gen3 and Gen4 SoCs. config CLK_R8A774A1 - bool "Renesas R8A774A1 clock driver" + bool "Renesas R8A774A1 clock driver" def_bool y if R8A774A1 - depends on CLK_RCAR_GEN3 - help - Enable this to support the clocks on Renesas R8A774A1 SoC. + depends on CLK_RCAR_GEN3 + help + Enable this to support the clocks on Renesas R8A774A1 SoC. config CLK_R8A774B1 bool "Renesas R8A774B1 clock driver" @@ -157,6 +157,12 @@ config CLK_R8A779H0 help Enable this to support the clocks on Renesas R8A779H0 SoC. +config CLK_R8A78000 + bool "Renesas R8A78000 clock driver" + depends on CLK_RENESAS + help + Enable this to support the clocks on Renesas R8A78000 SoC. + config CLK_R9A06G032 bool "Renesas R9A06G032 clock driver" depends on CLK_RENESAS diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index 354035baf2d..fb8d4c1f2f6 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_CLK_R8A779A0) += r8a779a0-cpg-mssr.o obj-$(CONFIG_CLK_R8A779F0) += r8a779f0-cpg-mssr.o obj-$(CONFIG_CLK_R8A779G0) += r8a779g0-cpg-mssr.o obj-$(CONFIG_CLK_R8A779H0) += r8a779h0-cpg-mssr.o +obj-$(CONFIG_CLK_R8A78000) += r8a78000-cpg.o obj-$(CONFIG_CLK_R9A06G032) += r9a06g032-clocks.o obj-$(CONFIG_CLK_RZG2L) += rzg2l-cpg.o obj-$(CONFIG_CLK_R9A07G044) += r9a07g044-cpg.o diff --git a/drivers/clk/renesas/r8a78000-cpg.c b/drivers/clk/renesas/r8a78000-cpg.c new file mode 100644 index 00000000000..e9ca06476f6 --- /dev/null +++ b/drivers/clk/renesas/r8a78000-cpg.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Renesas R-Car Gen5 CPG driver + * + * Copyright (C) 2026 Marek Vasut <[email protected]> + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <linux/clk-provider.h> + +#include <scmi_agent.h> +#include <scmi_agent-uclass.h> +#include <scmi_protocols.h> + +#include <dt-bindings/clock/r8a78000-clock-scmi.h> + +#if IS_ENABLED(CONFIG_CLK_SCMI) +struct gen5_clk_priv { + struct udevice *clk; + u32 basever; +}; + +static struct clk *gen5_clk_get_by_scmi_id(struct clk *clk) +{ + struct gen5_clk_priv *priv = dev_get_priv(clk->dev); + struct udevice *sdev; + struct uclass *uc; + + uclass_id_foreach_dev(UCLASS_CLK, sdev, uc) + if (sdev->seq_ == priv->clk->seq_ + clk->id + 1) + return dev_get_clk_ptr(sdev); + + return NULL; +} + +static ulong gen5_clk_round_rate(struct clk *clk, ulong rate) +{ + struct clk *scmi = gen5_clk_get_by_scmi_id(clk); + + if (!scmi) + return -ENODEV; + + return clk_round_rate(scmi, rate); +} + +static ulong gen5_clk_get_rate(struct clk *clk) +{ + struct clk *scmi = gen5_clk_get_by_scmi_id(clk); + + if (!scmi) + return -ENODEV; + + return clk_get_rate(scmi); +} + +static ulong gen5_clk_set_rate(struct clk *clk, ulong rate) +{ + struct clk *scmi = gen5_clk_get_by_scmi_id(clk); + + if (!scmi) + return -ENODEV; + + return clk_set_rate(scmi, rate); +} + +static int gen5_clk_set_parent(struct clk *clk, struct clk *parent) +{ + struct clk *scmi = gen5_clk_get_by_scmi_id(clk); + + if (!scmi) + return -ENODEV; + + return clk_set_parent(scmi, parent); +} + +static int gen5_clk_enable(struct clk *clk) +{ + struct clk *scmi = gen5_clk_get_by_scmi_id(clk); + + if (!scmi) + return -ENODEV; + + return clk_enable(scmi); +} + +static int gen5_clk_disable(struct clk *clk) +{ + struct clk *scmi = gen5_clk_get_by_scmi_id(clk); + + if (!scmi) + return -ENODEV; + + return clk_disable(scmi); +} + +struct clk_map_in { + u16 dt_id; /* DT binding clock ID */ + u16 fw_id; /* SCMI firmware clock ID */ +}; + +#define GEN5_SCMI_SDK_4_28 0x010a0000 +#define GEN5_SCMI_SDK_4_29 0x010b0000 +#define GEN5_SCMI_SDK_4_30 0x010c0000 +#define GEN5_SCMI_SDK_4_31 0x010d0000 +#define GEN5_SCMI_SDK_4_32 0x010e0000 + +static const struct clk_map_in gen5_clk_map_dt_sdk_4_28[] = { + { SCP_CLOCK_ID_MDLC_UFS0, 202 }, + { SCP_CLOCK_ID_MDLC_UFS1, 203 }, + { SCP_CLOCK_ID_MDLC_SDHI0, 204 }, + { SCP_CLOCK_ID_MDLC_XPCS0, 316 }, + { SCP_CLOCK_ID_MDLC_XPCS1, 317 }, + { SCP_CLOCK_ID_MDLC_XPCS2, 318 }, + { SCP_CLOCK_ID_MDLC_XPCS3, 319 }, + { SCP_CLOCK_ID_MDLC_XPCS4, 320 }, + { SCP_CLOCK_ID_MDLC_XPCS5, 321 }, + { SCP_CLOCK_ID_MDLC_XPCS6, 322 }, + { SCP_CLOCK_ID_MDLC_XPCS7, 323 }, + { SCP_CLOCK_ID_MDLC_RSW3, 324 }, + { SCP_CLOCK_ID_MDLC_RSW3TSN, 325 }, + { SCP_CLOCK_ID_MDLC_RSW3AES, 326 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES0, 327 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES1, 328 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES2, 329 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES3, 330 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES4, 331 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES5, 332 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES6, 333 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES7, 334 }, + { SCP_CLOCK_ID_MDLC_RSW3MFWD, 335 }, + { SCP_CLOCK_ID_MDLC_MPPHY01, 344 }, + { SCP_CLOCK_ID_MDLC_MPPHY11, 345 }, + { SCP_CLOCK_ID_MDLC_MPPHY21, 346 }, + { SCP_CLOCK_ID_MDLC_MPPHY31, 347 }, + { SCP_CLOCK_ID_MDLC_MPPHY02, 348 }, + { SCP_CLOCK_ID_CLK_S0D6_PERE_MAIN, 1691 }, +}; + +static const struct clk_map_in gen5_clk_map_dt_sdk_4_31[] = { + { SCP_CLOCK_ID_MDLC_UFS0, 198 }, + { SCP_CLOCK_ID_MDLC_UFS1, 199 }, + { SCP_CLOCK_ID_MDLC_SDHI0, 200 }, + { SCP_CLOCK_ID_MDLC_XPCS0, 312 }, + { SCP_CLOCK_ID_MDLC_XPCS1, 313 }, + { SCP_CLOCK_ID_MDLC_XPCS2, 314 }, + { SCP_CLOCK_ID_MDLC_XPCS3, 315 }, + { SCP_CLOCK_ID_MDLC_XPCS4, 316 }, + { SCP_CLOCK_ID_MDLC_XPCS5, 317 }, + { SCP_CLOCK_ID_MDLC_XPCS6, 318 }, + { SCP_CLOCK_ID_MDLC_XPCS7, 319 }, + { SCP_CLOCK_ID_MDLC_RSW3, 320 }, + { SCP_CLOCK_ID_MDLC_RSW3TSN, 321 }, + { SCP_CLOCK_ID_MDLC_RSW3AES, 322 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES0, 323 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES1, 324 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES2, 325 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES3, 326 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES4, 327 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES5, 328 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES6, 329 }, + { SCP_CLOCK_ID_MDLC_RSW3TSNTES7, 330 }, + { SCP_CLOCK_ID_MDLC_RSW3MFWD, 331 }, + { SCP_CLOCK_ID_MDLC_MPPHY01, 340 }, + { SCP_CLOCK_ID_MDLC_MPPHY11, 341 }, + { SCP_CLOCK_ID_MDLC_MPPHY21, 342 }, + { SCP_CLOCK_ID_MDLC_MPPHY31, 343 }, + { SCP_CLOCK_ID_MDLC_MPPHY02, 344 }, + { SCP_CLOCK_ID_CLK_S0D6_PERE_MAIN, 1687 }, +}; + +static int gen5_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) +{ + struct gen5_clk_priv *priv = dev_get_priv(clk->dev); + const struct clk_map_in *map; + unsigned int map_size; + int i; + + if (args->args_count != 1) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (priv->basever == GEN5_SCMI_SDK_4_28) { + map = gen5_clk_map_dt_sdk_4_28; + map_size = ARRAY_SIZE(gen5_clk_map_dt_sdk_4_28); + } else if (priv->basever == GEN5_SCMI_SDK_4_31 || + priv->basever == GEN5_SCMI_SDK_4_32) { + map = gen5_clk_map_dt_sdk_4_31; + map_size = ARRAY_SIZE(gen5_clk_map_dt_sdk_4_31); + } else { + printf("Unsupported SCMI base protocol version %x\n", priv->basever); + return -EINVAL; + } + + clk->id = -1; + for (i = 0; i < map_size; i++) { + if (map[i].dt_id != args->args[0]) + continue; + clk->id = map[i].fw_id; + break; + } + + if (clk->id == -1) + return -EINVAL; + + return 0; +} + +static const struct clk_ops gen5_clk_ops = { + .round_rate = gen5_clk_round_rate, + .get_rate = gen5_clk_get_rate, + .set_rate = gen5_clk_set_rate, + .set_parent = gen5_clk_set_parent, + .enable = gen5_clk_enable, + .disable = gen5_clk_disable, + .of_xlate = gen5_clk_of_xlate, +}; + +static int gen5_clk_probe(struct udevice *dev) +{ + struct gen5_clk_priv *priv = dev_get_priv(dev); + struct udevice *agent; + int ret; + + ret = uclass_get_device(UCLASS_SCMI_AGENT, 0, &agent); + if (ret) + return ret; + + if (!agent) + return -ENODEV; + + priv->basever = scmi_impl_version(agent); + + return uclass_get_device_by_driver(UCLASS_CLK, DM_DRIVER_GET(scmi_clock), + &priv->clk); +} +#else +static int gen5_clk_enable(struct clk *clk) +{ + return 0; +} + +static int gen5_clk_disable(struct clk *clk) +{ + return 0; +} + +static int gen5_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) +{ + if (args->args_count != 1) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + clk->id = args->args[0]; + + return 0; +} + +static const struct clk_ops gen5_clk_ops = { + .enable = gen5_clk_enable, + .disable = gen5_clk_disable, + .of_xlate = gen5_clk_of_xlate, +}; +#endif + +static const struct udevice_id r8a78000_mdlc_ids[] = { + { .compatible = "renesas,r8a78000-cpg", }, + { } +}; + +U_BOOT_DRIVER(clk_gen5) = { + .name = "clk_gen5", + .id = UCLASS_CLK, + .of_match = r8a78000_mdlc_ids, + .priv_auto = CONFIG_IS_ENABLED(CLK_SCMI, (sizeof(struct gen5_clk_priv)), (0)), + .ops = &gen5_clk_ops, + .probe = CONFIG_IS_ENABLED(CLK_SCMI, (gen5_clk_probe), (NULL)), + .flags = DM_FLAG_OS_PREPARE | DM_FLAG_VITAL, +}; diff --git a/drivers/clk/renesas/rcar-cpg-lib.c b/drivers/clk/renesas/rcar-cpg-lib.c index 60ab2cb379e..8e992d2c2da 100644 --- a/drivers/clk/renesas/rcar-cpg-lib.c +++ b/drivers/clk/renesas/rcar-cpg-lib.c @@ -30,10 +30,6 @@ #define SDnSRCFC_SHIFT 2 #define STPnHCK_TABLE (CPG_SDCKCR_STPnHCK >> SDnSRCFC_SHIFT) -/* Non-constant mask variant of FIELD_GET/FIELD_PREP */ -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) -#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) - static const struct clk_div_table cpg_sdh_div_table[] = { { 0, 1 }, { 1, 2 }, { STPnHCK_TABLE | 2, 4 }, { STPnHCK_TABLE | 3, 8 }, { STPnHCK_TABLE | 4, 16 }, { 0, 0 }, diff --git a/drivers/clk/rockchip/clk_rk3528.c b/drivers/clk/rockchip/clk_rk3528.c index bcdc0f930d2..cf8c3a62349 100644 --- a/drivers/clk/rockchip/clk_rk3528.c +++ b/drivers/clk/rockchip/clk_rk3528.c @@ -1335,6 +1335,7 @@ static ulong rk3528_clk_get_rate(struct clk *clk) DPLL); break; + case CLK_REF_USB3OTG: case TCLK_EMMC: case TCLK_WDT_NS: rate = OSC_HZ; @@ -1455,6 +1456,7 @@ static ulong rk3528_clk_set_rate(struct clk *clk, ulong rate) priv->ppll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[PPLL], priv->cru, PPLL); break; + case CLK_REF_USB3OTG: case TCLK_EMMC: case TCLK_WDT_NS: return (rate == OSC_HZ) ? 0 : -EINVAL; diff --git a/drivers/clk/rockchip/clk_rk3576.c b/drivers/clk/rockchip/clk_rk3576.c index 1026af27ca1..db8ce25852f 100644 --- a/drivers/clk/rockchip/clk_rk3576.c +++ b/drivers/clk/rockchip/clk_rk3576.c @@ -1549,6 +1549,24 @@ static ulong rk3576_gmac_get_clk(struct rk3576_clk_priv *priv, ulong clk_id) con = readl(&cru->clksel_con[31]); div = (con & CLK_GMAC1_125M_DIV_MASK) >> CLK_GMAC1_125M_DIV_SHIFT; return DIV_TO_RATE(priv->cpll_hz, div); + case REFCLKO25M_GMAC0_OUT: + con = readl(&cru->clksel_con[36]); + div = (con & CLK_REFCLKO25M_GMAC0_DIV_MASK) >> CLK_REFCLKO25M_GMAC0_DIV_SHIFT; + src = (con & CLK_REFCLKO25M_GMAC0_SEL_MASK) >> CLK_REFCLKO25M_GMAC0_SEL_SHIFT; + if (src == CLK_REFCLKO25M_GMAC0_SEL_CPLL) + p_rate = priv->cpll_hz; + else + p_rate = priv->gpll_hz; + return DIV_TO_RATE(p_rate, div); + case REFCLKO25M_GMAC1_OUT: + con = readl(&cru->clksel_con[36]); + div = (con & CLK_REFCLKO25M_GMAC1_DIV_MASK) >> CLK_REFCLKO25M_GMAC1_DIV_SHIFT; + src = (con & CLK_REFCLKO25M_GMAC1_SEL_MASK) >> CLK_REFCLKO25M_GMAC1_SEL_SHIFT; + if (src == CLK_REFCLKO25M_GMAC1_SEL_CPLL) + p_rate = priv->cpll_hz; + else + p_rate = priv->gpll_hz; + return DIV_TO_RATE(p_rate, div); default: return -ENOENT; } @@ -1608,6 +1626,34 @@ static ulong rk3576_gmac_set_clk(struct rk3576_clk_priv *priv, CLK_GMAC1_125M_DIV_MASK, (div - 1) << CLK_GMAC1_125M_DIV_SHIFT); break; + case REFCLKO25M_GMAC0_OUT: + if (!(priv->gpll_hz % rate)) { + src = CLK_REFCLKO25M_GMAC0_SEL_GPLL; + div = priv->gpll_hz / rate; + } else { + src = CLK_REFCLKO25M_GMAC0_SEL_CPLL; + div = priv->cpll_hz / rate; + } + rk_clrsetreg(&cru->clksel_con[36], + CLK_REFCLKO25M_GMAC0_SEL_MASK | + CLK_REFCLKO25M_GMAC0_DIV_MASK, + src << CLK_REFCLKO25M_GMAC0_SEL_SHIFT | + (div - 1) << CLK_REFCLKO25M_GMAC0_DIV_SHIFT); + break; + case REFCLKO25M_GMAC1_OUT: + if (!(priv->gpll_hz % rate)) { + src = CLK_REFCLKO25M_GMAC1_SEL_GPLL; + div = priv->gpll_hz / rate; + } else { + src = CLK_REFCLKO25M_GMAC1_SEL_CPLL; + div = priv->cpll_hz / rate; + } + rk_clrsetreg(&cru->clksel_con[36], + CLK_REFCLKO25M_GMAC1_SEL_MASK | + CLK_REFCLKO25M_GMAC1_DIV_MASK, + src << CLK_REFCLKO25M_GMAC1_SEL_SHIFT | + (div - 1) << CLK_REFCLKO25M_GMAC1_DIV_SHIFT); + break; default: return -ENOENT; } @@ -1987,6 +2033,8 @@ static ulong rk3576_clk_get_rate(struct clk *clk) case HCLK_SDIO: rate = rk3576_mmc_get_clk(priv, clk->id); break; + case CLK_REF_USB3OTG0: + case CLK_REF_USB3OTG1: case TCLK_EMMC: case TCLK_WDT0: rate = OSC_HZ; @@ -2014,6 +2062,8 @@ static ulong rk3576_clk_get_rate(struct clk *clk) case CLK_GMAC1_PTP_REF: case CLK_GMAC0_125M_SRC: case CLK_GMAC1_125M_SRC: + case REFCLKO25M_GMAC0_OUT: + case REFCLKO25M_GMAC1_OUT: rate = rk3576_gmac_get_clk(priv, clk->id); break; case CLK_UART_FRAC_0: @@ -2151,6 +2201,8 @@ static ulong rk3576_clk_set_rate(struct clk *clk, ulong rate) case HCLK_SDIO: ret = rk3576_mmc_set_clk(priv, clk->id, rate); break; + case CLK_REF_USB3OTG0: + case CLK_REF_USB3OTG1: case TCLK_EMMC: case TCLK_WDT0: ret = OSC_HZ; @@ -2193,6 +2245,8 @@ static ulong rk3576_clk_set_rate(struct clk *clk, ulong rate) case CLK_GMAC1_PTP_REF: case CLK_GMAC0_125M_SRC: case CLK_GMAC1_125M_SRC: + case REFCLKO25M_GMAC0_OUT: + case REFCLKO25M_GMAC1_OUT: ret = rk3576_gmac_set_clk(priv, clk->id, rate); break; case CLK_UART_FRAC_0: diff --git a/drivers/clk/sophgo/clk-cv1800b.c b/drivers/clk/sophgo/clk-cv1800b.c index d946ea57a46..248a69321fc 100644 --- a/drivers/clk/sophgo/clk-cv1800b.c +++ b/drivers/clk/sophgo/clk-cv1800b.c @@ -500,9 +500,12 @@ static int cv1800b_register_clk(struct udevice *dev) { struct clk osc; ulong osc_rate; - void *base = devfdt_get_addr_ptr(dev); + void __iomem *base = dev_read_addr_ptr(dev); int i, ret; + if (!base) + return -EINVAL; + ret = clk_get_by_index(dev, 0, &osc); if (ret) { pr_err("Failed to get clock\n"); diff --git a/drivers/clk/spacemit/Kconfig b/drivers/clk/spacemit/Kconfig new file mode 100644 index 00000000000..25a3c1e4a45 --- /dev/null +++ b/drivers/clk/spacemit/Kconfig @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (c) 2025, Junhui Liu <[email protected]> + +config CLK_SPACEMIT + bool "Clock support for SpacemiT SoCs" + depends on CLK || COMPILE_TEST + select REGMAP + select LIB_RATIONAL + help + This enables support clock driver for Spacemit SoC + family. + +if CLK_SPACEMIT + +config CLK_SPACEMIT_K1 + bool "SpacemiT K1 clock support" + select CLK_CCF + help + This enables support clock driver for Spacemit K1 SoC. + It's based on Common Clock Framework. + +endif diff --git a/drivers/clk/spacemit/Makefile b/drivers/clk/spacemit/Makefile new file mode 100644 index 00000000000..824e94d1f74 --- /dev/null +++ b/drivers/clk/spacemit/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright (C) 2025 Junhui Liu <[email protected]> + +obj-$(CONFIG_CLK_SPACEMIT) += clk_ddn.o clk_mix.o clk_pll.o + +obj-$(CONFIG_CLK_SPACEMIT_K1) += clk-k1.o diff --git a/drivers/clk/spacemit/clk-k1.c b/drivers/clk/spacemit/clk-k1.c new file mode 100644 index 00000000000..07adc126ee3 --- /dev/null +++ b/drivers/clk/spacemit/clk-k1.c @@ -0,0 +1,1878 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 SpacemiT Technology Co. Ltd + * Copyright (c) 2024-2025 Haylen Chu <[email protected]> + * Copyright (c) 2025 Junhui Liu <[email protected]> + * Copyright (c) 2025-2026 RISCstar Ltd. + * + * Authors: Haylen Chu <[email protected]> + */ + +#include <dm.h> +#include <dm/device_compat.h> +#include <dm/lists.h> +#include <regmap.h> +#include <linux/clk-provider.h> +#include <soc/spacemit/k1-reset.h> +#include <soc/spacemit/k1-syscon.h> + +#include "clk_common.h" +#include "clk_ddn.h" +#include "clk_mix.h" +#include "clk_pll.h" + +#include <dt-bindings/clock/spacemit,k1-syscon.h> + +#define K1_PLL_ID 100 +#define K1_MPMU_ID 200 +#define K1_APBC_ID 300 +#define K1_APMU_ID 400 + +struct spacemit_ccu_data { + struct clk **clks; + size_t num; + unsigned long offset; +}; + +/* APBS clocks start, APBS region contains and only contains all PLL clocks */ + +/* + * PLL{1,2} must run at fixed frequencies to provide clocks in correct rates for + * peripherals. + */ +static const struct ccu_pll_rate_tbl pll1_rate_tbl[] = { + CCU_PLL_RATE(2457600000UL, 0x0050dd64, 0x330ccccd), +}; + +#if IS_ENABLED(CONFIG_SPL_BUILD) +CCU_PLL_DEFINE(CLK_PLL1, pll1, pll1, "clock-24m", pll1_rate_tbl, + APBS_PLL1_SWCR1, APBS_PLL1_SWCR3, MPMU_POSR, POSR_PLL1_LOCK, + CLK_SET_RATE_GATE); + +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_D4, pll1_d4, pll1_d4, "pll1", APBS_PLL1_SWCR2, + BIT(3), 4, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_D6, pll1_d6, pll1_d6, "pll1", APBS_PLL1_SWCR2, + BIT(5), 6, 1); +CCU_FACTOR_GATE_FLAGS_DEFINE(CLK_PLL1_D8, pll1_d8, pll1_d8, "pll1", + APBS_PLL1_SWCR2, BIT(7), 8, 1, CLK_IS_CRITICAL); +#else +static const struct ccu_pll_rate_tbl pll2_rate_tbl[] = { + CCU_PLL_RATE(3000000000UL, 0x0050dd66, 0x3fe00000), +}; + +static const struct ccu_pll_rate_tbl pll3_rate_tbl[] = { + CCU_PLL_RATE(1600000000UL, 0x0050cd61, 0x43eaaaab), + CCU_PLL_RATE(1800000000UL, 0x0050cd61, 0x4b000000), + CCU_PLL_RATE(2000000000UL, 0x0050dd62, 0x2aeaaaab), + CCU_PLL_RATE(2457600000UL, 0x0050dd64, 0x330ccccd), + CCU_PLL_RATE(3000000000UL, 0x0050dd66, 0x3fe00000), + CCU_PLL_RATE(3200000000UL, 0x0050dd67, 0x43eaaaab), +}; + +CCU_PLL_DEFINE(CLK_PLL1, pll1, pll1, "clock-24m", pll1_rate_tbl, + APBS_PLL1_SWCR1, APBS_PLL1_SWCR3, MPMU_POSR, POSR_PLL1_LOCK, + CLK_SET_RATE_GATE); +CCU_PLL_DEFINE(CLK_PLL2, pll2, pll2, "clock-24m", pll2_rate_tbl, + APBS_PLL2_SWCR1, APBS_PLL2_SWCR3, MPMU_POSR, POSR_PLL2_LOCK, + CLK_SET_RATE_GATE); +CCU_PLL_DEFINE(CLK_PLL3, pll3, pll3, "clock-24m", pll3_rate_tbl, + APBS_PLL3_SWCR1, APBS_PLL3_SWCR3, MPMU_POSR, POSR_PLL3_LOCK, + CLK_SET_RATE_GATE); + +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_D2, pll1_d2, pll1_d2, "pll1", APBS_PLL1_SWCR2, + BIT(1), 2, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_D3, pll1_d3, pll1_d3, "pll1", APBS_PLL1_SWCR2, + BIT(2), 3, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_D4, pll1_d4, pll1_d4, "pll1", APBS_PLL1_SWCR2, + BIT(3), 4, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_D5, pll1_d5, pll1_d5, "pll1", APBS_PLL1_SWCR2, + BIT(4), 5, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_D6, pll1_d6, pll1_d6, "pll1", APBS_PLL1_SWCR2, + BIT(5), 6, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_D7, pll1_d7, pll1_d7, "pll1", APBS_PLL1_SWCR2, + BIT(6), 7, 1); +CCU_FACTOR_GATE_FLAGS_DEFINE(CLK_PLL1_D8, pll1_d8, pll1_d8, "pll1", + APBS_PLL1_SWCR2, BIT(7), 8, 1, CLK_IS_CRITICAL); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_D11, pll1_d11_223p4, pll1_d11_223p4, "pll1", + APBS_PLL1_SWCR2, BIT(15), 11, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_D13, pll1_d13_189, pll1_d13_189, "pll1", + APBS_PLL1_SWCR2, BIT(16), 13, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_D23, pll1_d23_106p8, pll1_d23_106p8, "pll1", + APBS_PLL1_SWCR2, BIT(20), 23, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_D64, pll1_d64_38p4, pll1_d64_38p4, "pll1", + APBS_PLL1_SWCR2, BIT(0), 64, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_D10_AUD, pll1_aud_245p7, pll1_aud_245p7, "pll1", + APBS_PLL1_SWCR2, BIT(10), 10, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_D100_AUD, pll1_aud_24p5, pll1_aud_24p5, "pll1", + APBS_PLL1_SWCR2, BIT(11), 100, 1); + +CCU_FACTOR_GATE_DEFINE(CLK_PLL2_D1, pll2_d1, pll2_d1, "pll2", APBS_PLL2_SWCR2, + BIT(0), 1, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL2_D2, pll2_d2, pll2_d2, "pll2", APBS_PLL2_SWCR2, + BIT(1), 2, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL2_D3, pll2_d3, pll2_d3, "pll2", APBS_PLL2_SWCR2, + BIT(2), 3, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL2_D4, pll2_d4, pll2_d4, "pll2", APBS_PLL2_SWCR2, + BIT(3), 4, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL2_D5, pll2_d5, pll2_d5, "pll2", APBS_PLL2_SWCR2, + BIT(4), 5, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL2_D6, pll2_d6, pll2_d6, "pll2", APBS_PLL2_SWCR2, + BIT(5), 6, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL2_D7, pll2_d7, pll2_d7, "pll2", APBS_PLL2_SWCR2, + BIT(6), 7, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL2_D8, pll2_d8, pll2_d8, "pll2", APBS_PLL2_SWCR2, + BIT(7), 8, 1); + +CCU_FACTOR_GATE_DEFINE(CLK_PLL3_D1, pll3_d1, pll3_d1, "pll3", APBS_PLL3_SWCR2, + BIT(0), 1, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL3_D2, pll3_d2, pll3_d2, "pll3", APBS_PLL3_SWCR2, + BIT(1), 2, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL3_D3, pll3_d3, pll3_d3, "pll3", APBS_PLL3_SWCR2, + BIT(2), 3, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL3_D4, pll3_d4, pll3_d4, "pll3", APBS_PLL3_SWCR2, + BIT(3), 4, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL3_D5, pll3_d5, pll3_d5, "pll3", APBS_PLL3_SWCR2, + BIT(4), 5, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL3_D6, pll3_d6, pll3_d6, "pll3", APBS_PLL3_SWCR2, + BIT(5), 6, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL3_D7, pll3_d7, pll3_d7, "pll3", APBS_PLL3_SWCR2, + BIT(6), 7, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL3_D8, pll3_d8, pll3_d8, "pll3", APBS_PLL3_SWCR2, + BIT(7), 8, 1); + +CCU_FACTOR_DEFINE(CLK_PLL3_20, pll3_20, pll3_20, "pll3_d8", 20, 1); +CCU_FACTOR_DEFINE(CLK_PLL3_40, pll3_40, pll3_40, "pll3_d8", 10, 1); +CCU_FACTOR_DEFINE(CLK_PLL3_80, pll3_80, pll3_80, "pll3_d8", 5, 1); +#endif +/* APBS clocks end */ + +/* MPMU clocks start */ +#if IS_ENABLED(CONFIG_SPL_BUILD) +CCU_GATE_DEFINE(CLK_PLL1_614, pll1_d4_614p4, pll1_d4_614p4, "pll1_d4", + MPMU_ACGR, BIT(15), 0); +CCU_GATE_DEFINE(CLK_PLL1_409P6, pll1_d6_409p6, pll1_d6_409p6, "pll1_d6", + MPMU_ACGR, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PLL1_307P2, pll1_d8_307p2, pll1_d8_307p2, "pll1_d8", + MPMU_ACGR, BIT(13), 0); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_31P5, pll1_d78_31p5, pll1_d78_31p5, + "pll1_d4", MPMU_ACGR, BIT(6), 39, 2); +CCU_DDN_DEFINE(CLK_SLOW_UART2, slow_uart2_48, slow_uart2_48, + "pll1_d4_614p4", MPMU_SUCCR_1, + CCU_DDN_MASK(16, 13), 16, CCU_DDN_MASK(0, 13), 0, 2, 0); +#else +CCU_GATE_DEFINE(CLK_PLL1_307P2, pll1_d8_307p2, pll1_d8_307p2, "pll1_d8", + MPMU_ACGR, BIT(13), 0); + +CCU_FACTOR_DEFINE(CLK_PLL1_76P8, pll1_d32_76p8, pll1_d32_76p8, "pll1_d8_307p2", + 4, 1); + +CCU_FACTOR_DEFINE(CLK_PLL1_61P44, pll1_d40_61p44, pll1_d40_61p44, + "pll1_d8_307p2", 5, 1); + +CCU_FACTOR_DEFINE(CLK_PLL1_153P6, pll1_d16_153p6, pll1_d16_153p6, + "pll1_d8", 2, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_102P4, pll1_d24_102p4, pll1_d24_102p4, + "pll1_d8", MPMU_ACGR, BIT(12), 3, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_51P2, pll1_d48_51p2, pll1_d48_51p2, + "pll1_d8", MPMU_ACGR, BIT(7), 6, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_51P2_AP, pll1_d48_51p2_ap, pll1_d48_51p2_ap, + "pll1_d8", MPMU_ACGR, BIT(11), 6, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_57P6, pll1_m3d128_57p6, pll1_m3d128_57p6, + "pll1_d8", MPMU_ACGR, BIT(8), 16, 3); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_25P6, pll1_d96_25p6, pll1_d96_25p6, + "pll1_d8", MPMU_ACGR, BIT(4), 12, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_12P8, pll1_d192_12p8, pll1_d192_12p8, + "pll1_d8", MPMU_ACGR, BIT(3), 24, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_12P8_WDT, pll1_d192_12p8_wdt, pll1_d192_12p8_wdt, + "pll1_d8", MPMU_ACGR, BIT(19), 24, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_6P4, pll1_d384_6p4, pll1_d384_6p4, + "pll1_d8", MPMU_ACGR, BIT(2), 48, 1); + +CCU_FACTOR_DEFINE(CLK_PLL1_3P2, pll1_d768_3p2, pll1_d768_3p2, + "pll1_d384_6p4", 2, 1); +CCU_FACTOR_DEFINE(CLK_PLL1_1P6, pll1_d1536_1p6, pll1_d1536_1p6, + "pll1_d384_6p4", 4, 1); +CCU_FACTOR_DEFINE(CLK_PLL1_0P8, pll1_d3072_0p8, pll1_d3072_0p8, + "pll1_d384_6p4", 8, 1); + +CCU_GATE_DEFINE(CLK_PLL1_409P6, pll1_d6_409p6, pll1_d6_409p6, "pll1_d6", + MPMU_ACGR, BIT(0), 0); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_204P8, pll1_d12_204p8, pll1_d12_204p8, + "pll1_d6", MPMU_ACGR, BIT(5), 2, 1); + +CCU_GATE_DEFINE(CLK_PLL1_491, pll1_d5_491p52, pll1_d5_491p52, "pll1_d5", + MPMU_ACGR, BIT(21), 0); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_245P76, pll1_d10_245p76, pll1_d10_245p76, + "pll1_d5", MPMU_ACGR, BIT(18), 2, 1); + +CCU_GATE_DEFINE(CLK_PLL1_614, pll1_d4_614p4, pll1_d4_614p4, "pll1_d4", + MPMU_ACGR, BIT(15), 0); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_47P26, pll1_d52_47p26, pll1_d52_47p26, + "pll1_d4", MPMU_ACGR, BIT(10), 13, 1); +CCU_FACTOR_GATE_DEFINE(CLK_PLL1_31P5, pll1_d78_31p5, pll1_d78_31p5, + "pll1_d4", MPMU_ACGR, BIT(6), 39, 2); + +CCU_GATE_DEFINE(CLK_PLL1_819, pll1_d3_819p2, pll1_d3_819p2, "pll1_d3", + MPMU_ACGR, BIT(14), 0); + +CCU_GATE_DEFINE(CLK_PLL1_1228, pll1_d2_1228p8, pll1_d2_1228p8, "pll1_d2", + MPMU_ACGR, BIT(16), 0); + +CCU_GATE_DEFINE(CLK_SLOW_UART, slow_uart, slow_uart, "clock-32k", MPMU_ACGR, + BIT(1), CLK_IGNORE_UNUSED); +CCU_DDN_DEFINE(CLK_SLOW_UART1, slow_uart1_14p74, slow_uart1_14p74, + "pll1_d16_153p6", MPMU_SUCCR, + CCU_DDN_MASK(16, 13), 16, CCU_DDN_MASK(0, 13), 0, 2, 0); +CCU_DDN_DEFINE(CLK_SLOW_UART2, slow_uart2_48, slow_uart2_48, + "pll1_d4_614p4", MPMU_SUCCR_1, + CCU_DDN_MASK(16, 13), 16, CCU_DDN_MASK(0, 13), 0, 2, 0); + +CCU_GATE_DEFINE(CLK_WDT, wdt_clk, wdt_clk, "pll1_d96_25p6", MPMU_WDTPCR, + BIT(1), 0); + +CCU_FACTOR_DEFINE(CLK_I2S_153P6, i2s_153p6, i2s_153p6, "pll1_d8_307p2", 2, 1); + +static const char * const i2s_153p6_base_parents[] = { + "i2s_153p6", + "pll1_d8_307p2", +}; + +CCU_MUX_DEFINE(CLK_I2S_153P6_BASE, i2s_153p6_base, i2s_153p6_base, + i2s_153p6_base_parents, ARRAY_SIZE(i2s_153p6_base_parents), + MPMU_FCCR, 29, 1, 0); + +static const char * const i2s_sysclk_src_parents[] = { + "pll1_d96_25p6", + "i2s_153p6_base" +}; + +CCU_MUX_GATE_DEFINE(CLK_I2S_SYSCLK_SRC, i2s_sysclk_src, i2s_sysclk_src, + i2s_sysclk_src_parents, ARRAY_SIZE(i2s_sysclk_src_parents), + MPMU_ISCCR, 30, 1, BIT(31), 0); + +CCU_DDN_DEFINE(CLK_I2S_SYSCLK, i2s_sysclk, i2s_sysclk, "i2s_sysclk_src", + MPMU_ISCCR, CCU_DDN_MASK(0, 15), 0, CCU_DDN_MASK(15, 12), + 15, 1, 0); + +CCU_FACTOR_DEFINE(CLK_I2S_BCLK_FACTOR, i2s_bclk_factor, i2s_bclk_factor, + "i2s_sysclk", 2, 1); +/* + * Divider of i2s_bclk always implies a 1/2 factor, which is + * described by i2s_bclk_factor. + */ +CCU_DIV_GATE_DEFINE(CLK_I2S_BCLK, i2s_bclk, i2s_bclk, "i2s_bclk_factor", + MPMU_ISCCR, 27, 2, BIT(29), 0); + +static const char * const apb_parents[] = { + "pll1_d96_25p6", + "pll1_d48_51p2", + "pll1_d96_25p6", + "pll1_d24_102p4", +}; + +CCU_MUX_DEFINE(CLK_APB, apb_clk, apb_clk, apb_parents, ARRAY_SIZE(apb_parents), + MPMU_APBCSCR, 0, 2, 0); + +CCU_GATE_DEFINE(CLK_WDT_BUS, wdt_bus_clk, wdt_bus_clk, "apb_clk", MPMU_WDTPCR, + BIT(0), 0); + +CCU_GATE_DEFINE(CLK_RIPC, ripc_clk, ripc_clk, "apb_clk", MPMU_RIPCCR, 0x1, 0); +#endif +/* MPMU clocks end */ + +/* APBC clocks start */ +#if IS_ENABLED(CONFIG_SPL_BUILD) +static const char * const uart_clk_parents[] = { + "clock-dummy", + "clock-dummy", + "slow_uart2_48", +}; + +CCU_MUX_GATE_DEFINE(CLK_UART0, uart0_clk, uart0_clk, uart_clk_parents, + ARRAY_SIZE(uart_clk_parents), APBC_UART1_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); + +static const char * const twsi_parents[] = { + "pll1_d78_31p5", +}; + +CCU_MUX_GATE_DEFINE(CLK_TWSI2, twsi2_clk, twsi2_clk, twsi_parents, + ARRAY_SIZE(twsi_parents), APBC_TWSI2_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); +/* + * APBC_TWSI8_CLK_RST has a quirk that reading always results in zero. + * Combine functional and bus bits together as a gate to avoid sharing the + * write-only register between different clock hardwares. + */ +CCU_GATE_DEFINE(CLK_TWSI8, twsi8_clk, twsi8_clk, "pll1_d78_31p5", + APBC_TWSI8_CLK_RST, BIT(1) | BIT(0), 0); + +#else +static const char * const uart_clk_parents[] = { + "pll1_m3d128_57p6", + "slow_uart1_14p74", + "slow_uart2_48", +}; + +CCU_MUX_GATE_DEFINE(CLK_UART0, uart0_clk, uart0_clk, uart_clk_parents, + ARRAY_SIZE(uart_clk_parents), APBC_UART1_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); + +static const char * const twsi_parents[] = { + "pll1_d78_31p5", + "pll1_d48_51p2", + "pll1_d40_61p44", +}; + +CCU_MUX_GATE_DEFINE(CLK_TWSI2, twsi2_clk, twsi2_clk, twsi_parents, + ARRAY_SIZE(twsi_parents), APBC_TWSI2_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); +/* + * APBC_TWSI8_CLK_RST has a quirk that reading always results in zero. + * Combine functional and bus bits together as a gate to avoid sharing the + * write-only register between different clock hardwares. + */ +CCU_GATE_DEFINE(CLK_TWSI8, twsi8_clk, twsi8_clk, "pll1_d78_31p5", + APBC_TWSI8_CLK_RST, BIT(1) | BIT(0), 0); + +CCU_MUX_GATE_DEFINE(CLK_UART2, uart2_clk, uart2_clk, uart_clk_parents, + ARRAY_SIZE(uart_clk_parents), APBC_UART2_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_UART3, uart3_clk, uart3_clk, uart_clk_parents, + ARRAY_SIZE(uart_clk_parents), APBC_UART3_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_UART4, uart4_clk, uart4_clk, uart_clk_parents, + ARRAY_SIZE(uart_clk_parents), APBC_UART4_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_UART5, uart5_clk, uart5_clk, uart_clk_parents, + ARRAY_SIZE(uart_clk_parents), APBC_UART5_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_UART6, uart6_clk, uart6_clk, uart_clk_parents, + ARRAY_SIZE(uart_clk_parents), APBC_UART6_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_UART7, uart7_clk, uart7_clk, uart_clk_parents, + ARRAY_SIZE(uart_clk_parents), APBC_UART7_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_UART8, uart8_clk, uart8_clk, uart_clk_parents, + ARRAY_SIZE(uart_clk_parents), APBC_UART8_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_UART9, uart9_clk, uart9_clk, uart_clk_parents, + ARRAY_SIZE(uart_clk_parents), APBC_UART9_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); + +CCU_GATE_DEFINE(CLK_GPIO, gpio_clk, gpio_clk, "clock-24m", APBC_GPIO_CLK_RST, + BIT(1) | BIT(0), 0); + +static const char * const pwm_parents[] = { + "pll1_d192_12p8", + "clock-32k", +}; + +CCU_MUX_GATE_DEFINE(CLK_PWM0, pwm0_clk, pwm0_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM0_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM1, pwm1_clk, pwm1_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM1_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM2, pwm2_clk, pwm2_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM2_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM3, pwm3_clk, pwm3_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM3_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM4, pwm4_clk, pwm4_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM4_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM5, pwm5_clk, pwm5_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM5_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM6, pwm6_clk, pwm6_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM6_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM7, pwm7_clk, pwm7_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM7_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM8, pwm8_clk, pwm8_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM8_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM9, pwm9_clk, pwm9_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM9_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM10, pwm10_clk, pwm10_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM10_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM11, pwm11_clk, pwm11_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM11_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM12, pwm12_clk, pwm12_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM12_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM13, pwm13_clk, pwm13_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM13_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM14, pwm14_clk, pwm14_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM14_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM15, pwm15_clk, pwm15_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM15_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM16, pwm16_clk, pwm16_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM16_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM17, pwm17_clk, pwm17_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM17_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM18, pwm18_clk, pwm18_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM18_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_PWM19, pwm19_clk, pwm19_clk, pwm_parents, + ARRAY_SIZE(pwm_parents), APBC_PWM19_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); + +static const char * const ssp_parents[] = { + "pll1_d384_6p4", + "pll1_d192_12p8", + "pll1_d96_25p6", + "pll1_d48_51p2", + "pll1_d768_3p2", + "pll1_d1536_1p6", + "pll1_d3072_0p8", +}; + +CCU_MUX_GATE_DEFINE(CLK_SSP3, ssp3_clk, ssp3_clk, ssp_parents, + ARRAY_SIZE(ssp_parents), APBC_SSP3_CLK_RST, 4, 3, + BIT(1), 0); + +CCU_GATE_DEFINE(CLK_RTC, rtc_clk, rtc_clk, "clock-32k", APBC_RTC_CLK_RST, + BIT(7) | BIT(1) | BIT(0), 0); + +CCU_MUX_GATE_DEFINE(CLK_TWSI0, twsi0_clk, twsi0_clk, twsi_parents, + ARRAY_SIZE(twsi_parents), APBC_TWSI0_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_TWSI1, twsi1_clk, twsi1_clk, twsi_parents, + ARRAY_SIZE(twsi_parents), APBC_TWSI1_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_TWSI4, twsi4_clk, twsi4_clk, twsi_parents, + ARRAY_SIZE(twsi_parents), APBC_TWSI4_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_TWSI5, twsi5_clk, twsi5_clk, twsi_parents, + ARRAY_SIZE(twsi_parents), APBC_TWSI5_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_TWSI6, twsi6_clk, twsi6_clk, twsi_parents, + ARRAY_SIZE(twsi_parents), APBC_TWSI6_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_TWSI7, twsi7_clk, twsi7_clk, twsi_parents, + ARRAY_SIZE(twsi_parents), APBC_TWSI7_CLK_RST, + 4, 3, BIT(1) | BIT(0), 0); + +static const char * const timer_parents[] = { + "pll1_d192_12p8", + "clock-32k", + "pll1_d384_6p4", + "clock-3m", + "clock-1m", +}; + +CCU_MUX_GATE_DEFINE(CLK_TIMERS1, timers1_clk, timers1_clk, timer_parents, + ARRAY_SIZE(timer_parents), APBC_TIMERS1_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); +CCU_MUX_GATE_DEFINE(CLK_TIMERS2, timers2_clk, timers2_clk, timer_parents, + ARRAY_SIZE(timer_parents), APBC_TIMERS2_CLK_RST, 4, 3, + BIT(1) | BIT(0), 0); + +CCU_GATE_DEFINE(CLK_AIB, aib_clk, aib_clk, "clock-24m", APBC_AIB_CLK_RST, + BIT(1) | BIT(0), 0); + +CCU_GATE_DEFINE(CLK_ONEWIRE, onewire_clk, onewire_clk, "clock-24m", + APBC_ONEWIRE_CLK_RST, BIT(1) | BIT(0), 0); + +/* + * When i2s_bclk is selected as the parent clock of sspa, + * the hardware requires bit3 to be set + */ +CCU_GATE_DEFINE(CLK_SSPA0_I2S_BCLK, sspa0_i2s_bclk, sspa0_i2s_bclk, "i2s_bclk", + APBC_SSPA0_CLK_RST, BIT(3), 0); +CCU_GATE_DEFINE(CLK_SSPA1_I2S_BCLK, sspa1_i2s_bclk, sspa1_i2s_bclk, "i2s_bclk", + APBC_SSPA1_CLK_RST, BIT(3), 0); + +static const char * const sspa0_parents[] = { + "pll1_d384_6p4", + "pll1_d192_12p8", + "pll1_d96_25p6", + "pll1_d48_51p2", + "pll1_d768_3p2", + "pll1_d1536_1p6", + "pll1_d3072_0p8", + "sspa0_i2s_bclk", +}; + +CCU_MUX_GATE_DEFINE(CLK_SSPA0, sspa0_clk, sspa0_clk, sspa0_parents, + ARRAY_SIZE(sspa0_parents), APBC_SSPA0_CLK_RST, 4, 3, + BIT(1), 0); + +static const char * const sspa1_parents[] = { + "pll1_d384_6p4", + "pll1_d192_12p8", + "pll1_d96_25p6", + "pll1_d48_51p2", + "pll1_d768_3p2", + "pll1_d1536_1p6", + "pll1_d3072_0p8", + "sspa1_i2s_bclk", +}; + +CCU_MUX_GATE_DEFINE(CLK_SSPA1, sspa1_clk, sspa1_clk, sspa1_parents, + ARRAY_SIZE(sspa1_parents), APBC_SSPA1_CLK_RST, 4, 3, + BIT(1), 0); + +CCU_GATE_DEFINE(CLK_DRO, dro_clk, dro_clk, "apb_clk", APBC_DRO_CLK_RST, + BIT(1) | BIT(0), 0); +CCU_GATE_DEFINE(CLK_IR, ir_clk, ir_clk, "apb_clk", APBC_IR_CLK_RST, + BIT(1) | BIT(0), 0); +CCU_GATE_DEFINE(CLK_TSEN, tsen_clk, tsen_clk, "apb_clk", APBC_TSEN_CLK_RST, + BIT(1) | BIT(0), 0); +CCU_GATE_DEFINE(CLK_IPC_AP2AUD, ipc_ap2aud_clk, ipc_ap2aud_clk, "apb_clk", + APBC_IPC_AP2AUD_CLK_RST, BIT(1) | BIT(0), 0); + +static const char * const can_parents[] = { + "pll3_20", + "pll3_40", + "pll3_80", +}; + +CCU_MUX_GATE_DEFINE(CLK_CAN0, can0_clk, can0_clk, can_parents, + ARRAY_SIZE(can_parents), APBC_CAN0_CLK_RST, 4, 3, + BIT(1), 0); +CCU_GATE_DEFINE(CLK_CAN0_BUS, can0_bus_clk, can0_bus_clk, "clock-24m", + APBC_CAN0_CLK_RST, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_UART0_BUS, uart0_bus_clk, uart0_bus_clk, "apb_clk", + APBC_UART1_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_UART2_BUS, uart2_bus_clk, uart2_bus_clk, "apb_clk", + APBC_UART2_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_UART3_BUS, uart3_bus_clk, uart3_bus_clk, "apb_clk", + APBC_UART3_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_UART4_BUS, uart4_bus_clk, uart4_bus_clk, "apb_clk", + APBC_UART4_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_UART5_BUS, uart5_bus_clk, uart5_bus_clk, "apb_clk", + APBC_UART5_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_UART6_BUS, uart6_bus_clk, uart6_bus_clk, "apb_clk", + APBC_UART6_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_UART7_BUS, uart7_bus_clk, uart7_bus_clk, "apb_clk", + APBC_UART7_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_UART8_BUS, uart8_bus_clk, uart8_bus_clk, "apb_clk", + APBC_UART8_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_UART9_BUS, uart9_bus_clk, uart9_bus_clk, "apb_clk", + APBC_UART9_CLK_RST, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_GPIO_BUS, gpio_bus_clk, gpio_bus_clk, "apb_clk", + APBC_GPIO_CLK_RST, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_PWM0_BUS, pwm0_bus_clk, pwm0_bus_clk, "apb_clk", + APBC_PWM0_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM1_BUS, pwm1_bus_clk, pwm1_bus_clk, "apb_clk", + APBC_PWM1_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM2_BUS, pwm2_bus_clk, pwm2_bus_clk, "apb_clk", + APBC_PWM2_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM3_BUS, pwm3_bus_clk, pwm3_bus_clk, "apb_clk", + APBC_PWM3_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM4_BUS, pwm4_bus_clk, pwm4_bus_clk, "apb_clk", + APBC_PWM4_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM5_BUS, pwm5_bus_clk, pwm5_bus_clk, "apb_clk", + APBC_PWM5_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM6_BUS, pwm6_bus_clk, pwm6_bus_clk, "apb_clk", + APBC_PWM6_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM7_BUS, pwm7_bus_clk, pwm7_bus_clk, "apb_clk", + APBC_PWM7_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM8_BUS, pwm8_bus_clk, pwm8_bus_clk, "apb_clk", + APBC_PWM8_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM9_BUS, pwm9_bus_clk, pwm9_bus_clk, "apb_clk", + APBC_PWM9_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM10_BUS, pwm10_bus_clk, pwm10_bus_clk, "apb_clk", + APBC_PWM10_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM11_BUS, pwm11_bus_clk, pwm11_bus_clk, "apb_clk", + APBC_PWM11_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM12_BUS, pwm12_bus_clk, pwm12_bus_clk, "apb_clk", + APBC_PWM12_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM13_BUS, pwm13_bus_clk, pwm13_bus_clk, "apb_clk", + APBC_PWM13_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM14_BUS, pwm14_bus_clk, pwm14_bus_clk, "apb_clk", + APBC_PWM14_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM15_BUS, pwm15_bus_clk, pwm15_bus_clk, "apb_clk", + APBC_PWM15_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM16_BUS, pwm16_bus_clk, pwm16_bus_clk, "apb_clk", + APBC_PWM16_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM17_BUS, pwm17_bus_clk, pwm17_bus_clk, "apb_clk", + APBC_PWM17_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM18_BUS, pwm18_bus_clk, pwm18_bus_clk, "apb_clk", + APBC_PWM18_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_PWM19_BUS, pwm19_bus_clk, pwm19_bus_clk, "apb_clk", + APBC_PWM19_CLK_RST, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_SSP3_BUS, ssp3_bus_clk, ssp3_bus_clk, "apb_clk", + APBC_SSP3_CLK_RST, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_RTC_BUS, rtc_bus_clk, rtc_bus_clk, "apb_clk", + APBC_RTC_CLK_RST, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_TWSI0_BUS, twsi0_bus_clk, twsi0_bus_clk, "apb_clk", + APBC_TWSI0_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_TWSI1_BUS, twsi1_bus_clk, twsi1_bus_clk, "apb_clk", + APBC_TWSI1_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_TWSI2_BUS, twsi2_bus_clk, twsi2_bus_clk, "apb_clk", + APBC_TWSI2_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_TWSI4_BUS, twsi4_bus_clk, twsi4_bus_clk, "apb_clk", + APBC_TWSI4_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_TWSI5_BUS, twsi5_bus_clk, twsi5_bus_clk, "apb_clk", + APBC_TWSI5_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_TWSI6_BUS, twsi6_bus_clk, twsi6_bus_clk, "apb_clk", + APBC_TWSI6_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_TWSI7_BUS, twsi7_bus_clk, twsi7_bus_clk, "apb_clk", + APBC_TWSI7_CLK_RST, BIT(0), 0); +CCU_FACTOR_DEFINE(CLK_TWSI8_BUS, twsi8_bus_clk, twsi8_bus_clk, "apb_clk", 1, 1); + +CCU_GATE_DEFINE(CLK_TIMERS1_BUS, timers1_bus_clk, timers1_bus_clk, "apb_clk", + APBC_TIMERS1_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_TIMERS2_BUS, timers2_bus_clk, timers2_bus_clk, "apb_clk", + APBC_TIMERS2_CLK_RST, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_AIB_BUS, aib_bus_clk, aib_bus_clk, "apb_clk", + APBC_AIB_CLK_RST, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_ONEWIRE_BUS, onewire_bus_clk, onewire_bus_clk, "apb_clk", + APBC_ONEWIRE_CLK_RST, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_SSPA0_BUS, sspa0_bus_clk, sspa0_bus_clk, "apb_clk", + APBC_SSPA0_CLK_RST, BIT(0), 0); +CCU_GATE_DEFINE(CLK_SSPA1_BUS, sspa1_bus_clk, sspa1_bus_clk, "apb_clk", + APBC_SSPA1_CLK_RST, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_TSEN_BUS, tsen_bus_clk, tsen_bus_clk, "apb_clk", + APBC_TSEN_CLK_RST, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_IPC_AP2AUD_BUS, ipc_ap2aud_bus_clk, ipc_ap2aud_bus_clk, + "apb_clk", APBC_IPC_AP2AUD_CLK_RST, BIT(0), 0); +#endif +/* APBC clocks end */ + +/* APMU clocks start */ +#if IS_ENABLED(CONFIG_SPL_BUILD) +static const char * const pmua_aclk_parents[] = { + "clock-dummy", + "pll1_d8_307p2", +}; + +CCU_MUX_DIV_FC_DEFINE(CLK_PMUA_ACLK, pmua_aclk, pmua_aclk, pmua_aclk_parents, + ARRAY_SIZE(pmua_aclk_parents), + APMU_ACLK_CLK_CTRL, APMU_ACLK_CLK_CTRL, 1, 2, BIT(4), + 0, 1, 0); + +CCU_GATE_DEFINE(CLK_SDH_AXI, sdh_axi_aclk, sdh_axi_aclk, "pmua_aclk", + APMU_SDH0_CLK_RES_CTRL, BIT(3), 0); + +static const char * const sdh01_parents[] = { + "pll1_d6_409p6", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_SDH0, sdh0_clk, sdh0_clk, sdh01_parents, + ARRAY_SIZE(sdh01_parents), + APMU_SDH0_CLK_RES_CTRL, + APMU_SDH0_CLK_RES_CTRL, 8, 3, BIT(11), 5, 3, + BIT(4), 0); + +static const char * const sdh2_parents[] = { + "pll1_d6_409p6", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_SDH2, sdh2_clk, sdh2_clk, sdh2_parents, + ARRAY_SIZE(sdh2_parents), + APMU_SDH2_CLK_RES_CTRL, + APMU_SDH2_CLK_RES_CTRL, 8, 3, BIT(11), 5, 3, + BIT(4), 0); +#else +static const char * const pmua_aclk_parents[] = { + "pll1_d10_245p76", + "pll1_d8_307p2", +}; + +CCU_MUX_DIV_FC_DEFINE(CLK_PMUA_ACLK, pmua_aclk, pmua_aclk, pmua_aclk_parents, + ARRAY_SIZE(pmua_aclk_parents), + APMU_ACLK_CLK_CTRL, APMU_ACLK_CLK_CTRL, 1, 2, BIT(4), + 0, 1, 0); + +static const char * const emmc_parents[] = { + "pll1_d6_409p6", + "pll1_d4_614p4", + "pll1_d52_47p26", + "pll1_d3_819p2", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_EMMC, emmc_clk, emmc_clk, emmc_parents, + ARRAY_SIZE(emmc_parents), + APMU_PMUA_EM_CLK_RES_CTRL, + APMU_PMUA_EM_CLK_RES_CTRL, 8, 3, BIT(11), + 6, 2, BIT(4), 0); +CCU_DIV_GATE_DEFINE(CLK_EMMC_X, emmc_x_clk, emmc_x_clk, "pll1_d2_1228p8", + APMU_PMUA_EM_CLK_RES_CTRL, 12, + 3, BIT(15), 0); + +CCU_GATE_DEFINE(CLK_EMMC_BUS, emmc_bus_clk, emmc_bus_clk, "pmua_aclk", + APMU_PMUA_EM_CLK_RES_CTRL, BIT(3), 0); + +static const char * const cci550_clk_parents[] = { + "pll1_d5_491p52", + "pll1_d4_614p4", + "pll1_d3_819p2", + "pll2_d3", +}; + +CCU_MUX_DIV_FC_DEFINE(CLK_CCI550, cci550_clk, cci550_clk, cci550_clk_parents, + ARRAY_SIZE(cci550_clk_parents), + APMU_CCI550_CLK_CTRL, APMU_CCI550_CLK_CTRL, 8, 3, + BIT(12), 0, 2, CLK_IS_CRITICAL); + +static const char * const cpu_c0_hi_clk_parents[] = { + "pll3_d2", + "pll3_d1", +}; + +CCU_MUX_DEFINE(CLK_CPU_C0_HI, cpu_c0_hi_clk, cpu_c0_hi_clk, + cpu_c0_hi_clk_parents, ARRAY_SIZE(cpu_c0_hi_clk_parents), + APMU_CPU_C0_CLK_CTRL, 13, 1, 0); +static const char * const cpu_c0_clk_parents[] = { + "pll1_d4_614p4", + "pll1_d3_819p2", + "pll1_d6_409p6", + "pll1_d5_491p52", + "pll1_d2_1228p8", + "pll3_d3", + "pll2_d3", + "cpu_c0_hi_clk", +}; + +CCU_MUX_FC_DEFINE(CLK_CPU_C0_CORE, cpu_c0_core_clk, cpu_c0_core_clk, + cpu_c0_clk_parents, ARRAY_SIZE(cpu_c0_clk_parents), + APMU_CPU_C0_CLK_CTRL, APMU_CPU_C0_CLK_CTRL, + BIT(12), 0, 3, CLK_IS_CRITICAL); +CCU_DIV_DEFINE(CLK_CPU_C0_ACE, cpu_c0_ace_clk, cpu_c0_ace_clk, + "cpu_c0_core_clk", APMU_CPU_C0_CLK_CTRL, 6, 3, CLK_IS_CRITICAL); +CCU_DIV_DEFINE(CLK_CPU_C0_TCM, cpu_c0_tcm_clk, cpu_c0_tcm_clk, + "cpu_c0_core_clk", APMU_CPU_C0_CLK_CTRL, 9, 3, CLK_IS_CRITICAL); + +static const char * const cpu_c1_hi_clk_parents[] = { + "pll3_d2", + "pll3_d1", +}; + +CCU_MUX_DEFINE(CLK_CPU_C1_HI, cpu_c1_hi_clk, cpu_c1_hi_clk, + cpu_c1_hi_clk_parents, ARRAY_SIZE(cpu_c1_hi_clk_parents), + APMU_CPU_C1_CLK_CTRL, 13, 1, 0); +static const char * const cpu_c1_clk_parents[] = { + "pll1_d4_614p4", + "pll1_d3_819p2", + "pll1_d6_409p6", + "pll1_d5_491p52", + "pll1_d2_1228p8", + "pll3_d3", + "pll2_d3", + "cpu_c1_hi_clk", +}; + +CCU_MUX_FC_DEFINE(CLK_CPU_C1_CORE, cpu_c1_core_clk, cpu_c1_core_clk, + cpu_c1_clk_parents, ARRAY_SIZE(cpu_c1_clk_parents), + APMU_CPU_C1_CLK_CTRL, APMU_CPU_C1_CLK_CTRL, + BIT(12), 0, 3, CLK_IS_CRITICAL); +CCU_DIV_DEFINE(CLK_CPU_C1_ACE, cpu_c1_ace_clk, cpu_c1_ace_clk, + "cpu_c1_core_clk", APMU_CPU_C1_CLK_CTRL, 6, 3, CLK_IS_CRITICAL); + +static const char * const jpg_parents[] = { + "pll1_d4_614p4", + "pll1_d6_409p6", + "pll1_d5_491p52", + "pll1_d3_819p2", + "pll1_d2_1228p8", + "pll2_d4", + "pll2_d3", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_JPG, jpg_clk, jpg_clk, jpg_parents, + ARRAY_SIZE(jpg_parents), + APMU_JPG_CLK_RES_CTRL, + APMU_JPG_CLK_RES_CTRL, + 5, 3, BIT(15), 2, 3, BIT(1), 0); + +static const char * const ccic2phy_parents[] = { + "pll1_d24_102p4", + "pll1_d48_51p2_ap", +}; + +CCU_MUX_GATE_DEFINE(CLK_CCIC2PHY, ccic2phy_clk, ccic2phy_clk, ccic2phy_parents, + ARRAY_SIZE(ccic2phy_parents), APMU_CSI_CCIC2_CLK_RES_CTRL, + 7, 1, BIT(5), 0); + +static const char * const ccic3phy_parents[] = { + "pll1_d24_102p4", + "pll1_d48_51p2_ap", +}; + +CCU_MUX_GATE_DEFINE(CLK_CCIC3PHY, ccic3phy_clk, ccic3phy_clk, ccic3phy_parents, + ARRAY_SIZE(ccic3phy_parents), APMU_CSI_CCIC2_CLK_RES_CTRL, + 31, 1, BIT(30), 0); + +static const char * const csi_parents[] = { + "pll1_d5_491p52", + "pll1_d6_409p6", + "pll1_d4_614p4", + "pll1_d3_819p2", + "pll2_d2", + "pll2_d3", + "pll2_d4", + "pll1_d2_1228p8", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_CSI, csi_clk, csi_clk, csi_parents, + ARRAY_SIZE(csi_parents), + APMU_CSI_CCIC2_CLK_RES_CTRL, + APMU_CSI_CCIC2_CLK_RES_CTRL, 20, 3, BIT(15), + 16, 3, BIT(4), 0); + +static const char * const camm_parents[] = { + "pll1_d8_307p2", + "pll2_d5", + "pll1_d6_409p6", + "clock-24m", +}; + +CCU_MUX_DIV_GATE_DEFINE(CLK_CAMM0, camm0_clk, camm0_clk, camm_parents, + ARRAY_SIZE(camm_parents), + APMU_CSI_CCIC2_CLK_RES_CTRL, 23, 4, 8, 2, + BIT(28), 0); +CCU_MUX_DIV_GATE_DEFINE(CLK_CAMM1, camm1_clk, camm1_clk, camm_parents, + ARRAY_SIZE(camm_parents), + APMU_CSI_CCIC2_CLK_RES_CTRL, 23, 4, 8, 2, + BIT(6), 0); +CCU_MUX_DIV_GATE_DEFINE(CLK_CAMM2, camm2_clk, camm2_clk, camm_parents, + ARRAY_SIZE(camm_parents), + APMU_CSI_CCIC2_CLK_RES_CTRL, 23, 4, 8, 2, + BIT(3), 0); + +static const char * const isp_cpp_parents[] = { + "pll1_d8_307p2", + "pll1_d6_409p6", +}; + +CCU_MUX_DIV_GATE_DEFINE(CLK_ISP_CPP, isp_cpp_clk, isp_cpp_clk, isp_cpp_parents, + ARRAY_SIZE(isp_cpp_parents), + APMU_ISP_CLK_RES_CTRL, 24, 2, 26, 1, + BIT(28), 0); +static const char * const isp_bus_parents[] = { + "pll1_d6_409p6", + "pll1_d5_491p52", + "pll1_d8_307p2", + "pll1_d10_245p76", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_ISP_BUS, isp_bus_clk, isp_bus_clk, + isp_bus_parents, ARRAY_SIZE(isp_cpp_parents), + APMU_ISP_CLK_RES_CTRL, + APMU_ISP_CLK_RES_CTRL, 18, 3, BIT(23), + 21, 2, BIT(17), 0); +static const char * const isp_parents[] = { + "pll1_d6_409p6", + "pll1_d5_491p52", + "pll1_d4_614p4", + "pll1_d8_307p2", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_ISP, isp_clk, isp_clk, isp_parents, + ARRAY_SIZE(isp_parents), + APMU_ISP_CLK_RES_CTRL, + APMU_ISP_CLK_RES_CTRL, + 4, 3, BIT(7), 8, 2, BIT(1), 0); + +static const char * const dpumclk_parents[] = { + "pll1_d6_409p6", + "pll1_d5_491p52", + "pll1_d4_614p4", + "pll1_d8_307p2", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_DPU_MCLK, dpu_mclk, dpu_mclk, + dpumclk_parents, ARRAY_SIZE(dpumclk_parents), + APMU_LCD_CLK_RES_CTRL2, APMU_LCD_CLK_RES_CTRL1, + 1, 4, BIT(29), 5, 3, BIT(0), 0); + +static const char * const dpuesc_parents[] = { + "pll1_d48_51p2_ap", + "pll1_d52_47p26", + "pll1_d96_25p6", + "pll1_d32_76p8", +}; + +CCU_MUX_GATE_DEFINE(CLK_DPU_ESC, dpu_esc_clk, dpu_esc_clk, dpuesc_parents, + ARRAY_SIZE(dpuesc_parents), APMU_LCD_CLK_RES_CTRL1, 0, 2, + BIT(2), 0); + +static const char * const dpubit_parents[] = { + "pll1_d3_819p2", + "pll2_d2", + "pll2_d3", + "pll1_d2_1228p8", + "pll2_d4", + "pll2_d5", + "pll2_d7", + "pll2_d8", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_DPU_BIT, dpu_bit_clk, dpu_bit_clk, + dpubit_parents, ARRAY_SIZE(dpubit_parents), + APMU_LCD_CLK_RES_CTRL1, + APMU_LCD_CLK_RES_CTRL1, 17, 3, BIT(31), + 20, 3, BIT(16), 0); + +static const char * const dpupx_parents[] = { + "pll1_d6_409p6", + "pll1_d5_491p52", + "pll1_d4_614p4", + "pll1_d8_307p2", + "pll2_d7", + "pll2_d8", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_DPU_PXCLK, dpu_pxclk, dpu_pxclk, + dpupx_parents, ARRAY_SIZE(dpupx_parents), + APMU_LCD_CLK_RES_CTRL2, APMU_LCD_CLK_RES_CTRL1, + 17, 4, BIT(30), 21, 3, BIT(16), 0); + +CCU_GATE_DEFINE(CLK_DPU_HCLK, dpu_hclk, dpu_hclk, "pmua_aclk", + APMU_LCD_CLK_RES_CTRL1, BIT(5), 0); + +static const char * const dpu_spi_parents[] = { + "pll1_d8_307p2", + "pll1_d6_409p6", + "pll1_d10_245p76", + "pll1_d11_223p4", + "pll1_d13_189", + "pll1_d23_106p8", + "pll2_d3", + "pll2_d5", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_DPU_SPI, dpu_spi_clk, dpu_spi_clk, + dpu_spi_parents, ARRAY_SIZE(dpu_spi_parents), + APMU_LCD_SPI_CLK_RES_CTRL, + APMU_LCD_SPI_CLK_RES_CTRL, 8, 3, + BIT(7), 12, 3, BIT(1), 0); +CCU_GATE_DEFINE(CLK_DPU_SPI_HBUS, dpu_spi_hbus_clk, dpu_spi_hbus_clk, + "pmua_aclk", APMU_LCD_SPI_CLK_RES_CTRL, BIT(3), 0); +CCU_GATE_DEFINE(CLK_DPU_SPIBUS, dpu_spi_bus_clk, dpu_spi_bus_clk, + "pmua_aclk", APMU_LCD_SPI_CLK_RES_CTRL, BIT(5), 0); +CCU_GATE_DEFINE(CLK_DPU_SPI_ACLK, dpu_spi_aclk, dpu_spi_aclk, + "pmua_aclk", APMU_LCD_SPI_CLK_RES_CTRL, BIT(6), 0); + +static const char * const v2d_parents[] = { + "pll1_d5_491p52", + "pll1_d6_409p6", + "pll1_d8_307p2", + "pll1_d4_614p4", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_V2D, v2d_clk, v2d_clk, v2d_parents, + ARRAY_SIZE(v2d_parents), + APMU_LCD_CLK_RES_CTRL1, + APMU_LCD_CLK_RES_CTRL1, 9, 3, BIT(28), 12, 2, + BIT(8), 0); + +static const char * const ccic_4x_parents[] = { + "pll1_d5_491p52", + "pll1_d6_409p6", + "pll1_d4_614p4", + "pll1_d3_819p2", + "pll2_d2", + "pll2_d3", + "pll2_d4", + "pll1_d2_1228p8", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_CCIC_4X, ccic_4x_clk, ccic_4x_clk, + ccic_4x_parents, ARRAY_SIZE(ccic_4x_parents), + APMU_CCIC_CLK_RES_CTRL, + APMU_CCIC_CLK_RES_CTRL, 18, 3, + BIT(15), 23, 2, BIT(4), 0); + +static const char * const ccic1phy_parents[] = { + "pll1_d24_102p4", + "pll1_d48_51p2_ap", +}; + +CCU_MUX_GATE_DEFINE(CLK_CCIC1PHY, ccic1phy_clk, ccic1phy_clk, ccic1phy_parents, + ARRAY_SIZE(ccic1phy_parents), APMU_CCIC_CLK_RES_CTRL, 7, 1, + BIT(5), 0); + +CCU_GATE_DEFINE(CLK_SDH_AXI, sdh_axi_aclk, sdh_axi_aclk, "pmua_aclk", + APMU_SDH0_CLK_RES_CTRL, BIT(3), 0); +static const char * const sdh01_parents[] = { + "pll1_d6_409p6", + "pll1_d4_614p4", + "pll2_d8", + "pll2_d5", + "pll1_d11_223p4", + "pll1_d13_189", + "pll1_d23_106p8", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_SDH0, sdh0_clk, sdh0_clk, sdh01_parents, + ARRAY_SIZE(sdh01_parents), + APMU_SDH0_CLK_RES_CTRL, + APMU_SDH0_CLK_RES_CTRL, 8, 3, BIT(11), 5, 3, + BIT(4), 0); +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_SDH1, sdh1_clk, sdh1_clk, sdh01_parents, + ARRAY_SIZE(sdh01_parents), + APMU_SDH1_CLK_RES_CTRL, + APMU_SDH1_CLK_RES_CTRL, 8, 3, BIT(11), 5, 3, + BIT(4), 0); +static const char * const sdh2_parents[] = { + "pll1_d6_409p6", + "pll1_d4_614p4", + "pll2_d8", + "pll1_d3_819p2", + "pll1_d11_223p4", + "pll1_d13_189", + "pll1_d23_106p8", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_SDH2, sdh2_clk, sdh2_clk, sdh2_parents, + ARRAY_SIZE(sdh2_parents), + APMU_SDH2_CLK_RES_CTRL, + APMU_SDH2_CLK_RES_CTRL, 8, 3, BIT(11), 5, 3, + BIT(4), 0); + +CCU_GATE_DEFINE(CLK_USB_AXI, usb_axi_clk, usb_axi_clk, "pmua_aclk", + APMU_USB_CLK_RES_CTRL, BIT(1), 0); +CCU_GATE_DEFINE(CLK_USB_P1, usb_p1_aclk, usb_p1_aclk, "pmua_aclk", + APMU_USB_CLK_RES_CTRL, BIT(5), 0); +CCU_GATE_DEFINE(CLK_USB30, usb30_clk, usb30_clk, "pmua_aclk", + APMU_USB_CLK_RES_CTRL, BIT(8), 0); + +static const char * const qspi_parents[] = { + "pll1_d6_409p6", + "pll2_d8", + "pll1_d8_307p2", + "pll1_d10_245p76", + "pll1_d11_223p4", + "pll1_d23_106p8", + "pll1_d5_491p52", + "pll1_d13_189", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_QSPI, qspi_clk, qspi_clk, qspi_parents, + ARRAY_SIZE(qspi_parents), + APMU_QSPI_CLK_RES_CTRL, + APMU_QSPI_CLK_RES_CTRL, 9, 3, BIT(12), 6, 3, + BIT(4), 0); +CCU_GATE_DEFINE(CLK_QSPI_BUS, qspi_bus_clk, qspi_bus_clk, "pmua_aclk", + APMU_QSPI_CLK_RES_CTRL, BIT(3), 0); +CCU_GATE_DEFINE(CLK_DMA, dma_clk, dma_clk, "pmua_aclk", APMU_DMA_CLK_RES_CTRL, + BIT(3), 0); + +static const char * const aes_parents[] = { + "pll1_d12_204p8", + "pll1_d24_102p4", +}; + +CCU_MUX_GATE_DEFINE(CLK_AES, aes_clk, aes_clk, aes_parents, + ARRAY_SIZE(aes_parents), APMU_AES_CLK_RES_CTRL, 6, 1, + BIT(5), 0); + +static const char * const vpu_parents[] = { + "pll1_d4_614p4", + "pll1_d5_491p52", + "pll1_d3_819p2", + "pll1_d6_409p6", + "pll3_d6", + "pll2_d3", + "pll2_d4", + "pll2_d5", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_VPU, vpu_clk, vpu_clk, vpu_parents, + ARRAY_SIZE(vpu_parents), APMU_VPU_CLK_RES_CTRL, + APMU_VPU_CLK_RES_CTRL, 13, 3, BIT(21), 10, 3, + BIT(3), 0); + +static const char * const gpu_parents[] = { + "pll1_d4_614p4", + "pll1_d5_491p52", + "pll1_d3_819p2", + "pll1_d6_409p6", + "pll3_d6", + "pll2_d3", + "pll2_d4", + "pll2_d5", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_GPU, gpu_clk, gpu_clk, gpu_parents, + ARRAY_SIZE(gpu_parents), APMU_GPU_CLK_RES_CTRL, + APMU_GPU_CLK_RES_CTRL, 12, 3, BIT(15), 18, 3, + BIT(4), 0); + +static const char * const audio_parents[] = { + "pll1_aud_245p7", + "pll1_d8_307p2", + "pll1_d6_409p6", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_AUDIO, audio_clk, audio_clk, audio_parents, + ARRAY_SIZE(audio_parents), + APMU_AUDIO_CLK_RES_CTRL, + APMU_AUDIO_CLK_RES_CTRL, 4, 3, BIT(15), + 7, 3, BIT(12), 0); + +static const char * const hdmi_parents[] = { + "pll1_d6_409p6", + "pll1_d5_491p52", + "pll1_d4_614p4", + "pll1_d8_307p2", +}; + +CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(CLK_HDMI, hdmi_mclk, hdmi_mclk, hdmi_parents, + ARRAY_SIZE(hdmi_parents), + APMU_HDMI_CLK_RES_CTRL, + APMU_HDMI_CLK_RES_CTRL, 1, 4, BIT(29), 5, + 3, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_PCIE0_MASTER, pcie0_master_clk, pcie0_master_clk, + "pmua_aclk", APMU_PCIE_CLK_RES_CTRL_0, BIT(2), 0); +CCU_GATE_DEFINE(CLK_PCIE0_SLAVE, pcie0_slave_clk, pcie0_slave_clk, "pmua_aclk", + APMU_PCIE_CLK_RES_CTRL_0, BIT(1), 0); +CCU_GATE_DEFINE(CLK_PCIE0_DBI, pcie0_dbi_clk, pcie0_dbi_clk, "pmua_aclk", + APMU_PCIE_CLK_RES_CTRL_0, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_PCIE1_MASTER, pcie1_master_clk, pcie1_master_clk, + "pmua_aclk", APMU_PCIE_CLK_RES_CTRL_1, BIT(2), 0); +CCU_GATE_DEFINE(CLK_PCIE1_SLAVE, pcie1_slave_clk, pcie1_slave_clk, "pmua_aclk", + APMU_PCIE_CLK_RES_CTRL_1, BIT(1), 0); +CCU_GATE_DEFINE(CLK_PCIE1_DBI, pcie1_dbi_clk, pcie1_dbi_clk, "pmua_aclk", + APMU_PCIE_CLK_RES_CTRL_1, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_PCIE2_MASTER, pcie2_master_clk, pcie2_master_clk, + "pmua_aclk", APMU_PCIE_CLK_RES_CTRL_2, BIT(2), 0); +CCU_GATE_DEFINE(CLK_PCIE2_SLAVE, pcie2_slave_clk, pcie2_slave_clk, "pmua_aclk", + APMU_PCIE_CLK_RES_CTRL_2, BIT(1), 0); +CCU_GATE_DEFINE(CLK_PCIE2_DBI, pcie2_dbi_clk, pcie2_dbi_clk, "pmua_aclk", + APMU_PCIE_CLK_RES_CTRL_2, BIT(0), 0); + +CCU_GATE_DEFINE(CLK_EMAC0_BUS, emac0_bus_clk, emac0_bus_clk, "pmua_aclk", + APMU_EMAC0_CLK_RES_CTRL, BIT(0), 0); +CCU_GATE_DEFINE(CLK_EMAC0_PTP, emac0_ptp_clk, emac0_ptp_clk, "pll2_d6", + APMU_EMAC0_CLK_RES_CTRL, BIT(15), 0); +CCU_GATE_DEFINE(CLK_EMAC1_BUS, emac1_bus_clk, emac1_bus_clk, "pmua_aclk", + APMU_EMAC1_CLK_RES_CTRL, BIT(0), 0); +CCU_GATE_DEFINE(CLK_EMAC1_PTP, emac1_ptp_clk, emac1_ptp_clk, "pll2_d6", + APMU_EMAC1_CLK_RES_CTRL, BIT(15), 0); + +#endif +/* APMU clocks end */ + +#if IS_ENABLED(CONFIG_SPL_BUILD) +static struct clk *k1_ccu_pll_clks[] = { + &pll1.common.clk, + &pll1_d4.common.clk, + &pll1_d6.common.clk, + &pll1_d8.common.clk, +}; +#else +static struct clk *k1_ccu_pll_clks[] = { + &pll1.common.clk, + &pll2.common.clk, + &pll3.common.clk, + &pll1_d2.common.clk, + &pll1_d3.common.clk, + &pll1_d4.common.clk, + &pll1_d5.common.clk, + &pll1_d6.common.clk, + &pll1_d7.common.clk, + &pll1_d8.common.clk, + &pll1_d11_223p4.common.clk, + &pll1_d13_189.common.clk, + &pll1_d23_106p8.common.clk, + &pll1_d64_38p4.common.clk, + &pll1_aud_245p7.common.clk, + &pll1_aud_24p5.common.clk, + &pll2_d1.common.clk, + &pll2_d2.common.clk, + &pll2_d3.common.clk, + &pll2_d4.common.clk, + &pll2_d5.common.clk, + &pll2_d6.common.clk, + &pll2_d7.common.clk, + &pll2_d8.common.clk, + &pll3_d1.common.clk, + &pll3_d2.common.clk, + &pll3_d3.common.clk, + &pll3_d4.common.clk, + &pll3_d5.common.clk, + &pll3_d6.common.clk, + &pll3_d7.common.clk, + &pll3_d8.common.clk, + &pll3_80.common.clk, + &pll3_40.common.clk, + &pll3_20.common.clk, +}; +#endif + +static const struct spacemit_ccu_data k1_ccu_pll_data = { + .clks = k1_ccu_pll_clks, + .num = ARRAY_SIZE(k1_ccu_pll_clks), + .offset = K1_PLL_ID, +}; + +#if IS_ENABLED(CONFIG_SPL_BUILD) +static struct clk *k1_ccu_mpmu_clks[] = { + &pll1_d4_614p4.common.clk, + &pll1_d6_409p6.common.clk, + &pll1_d8_307p2.common.clk, + &pll1_d78_31p5.common.clk, + &slow_uart2_48.common.clk, +}; +#else +static struct clk *k1_ccu_mpmu_clks[] = { + &pll1_d8_307p2.common.clk, + &pll1_d32_76p8.common.clk, + &pll1_d40_61p44.common.clk, + &pll1_d16_153p6.common.clk, + &pll1_d24_102p4.common.clk, + &pll1_d48_51p2.common.clk, + &pll1_d48_51p2_ap.common.clk, + &pll1_m3d128_57p6.common.clk, + &pll1_d96_25p6.common.clk, + &pll1_d192_12p8.common.clk, + &pll1_d192_12p8_wdt.common.clk, + &pll1_d384_6p4.common.clk, + &pll1_d768_3p2.common.clk, + &pll1_d1536_1p6.common.clk, + &pll1_d3072_0p8.common.clk, + &pll1_d6_409p6.common.clk, + &pll1_d12_204p8.common.clk, + &pll1_d5_491p52.common.clk, + &pll1_d10_245p76.common.clk, + &pll1_d4_614p4.common.clk, + &pll1_d52_47p26.common.clk, + &pll1_d78_31p5.common.clk, + &pll1_d3_819p2.common.clk, + &pll1_d2_1228p8.common.clk, + &slow_uart.common.clk, + &slow_uart1_14p74.common.clk, + &slow_uart2_48.common.clk, + &wdt_clk.common.clk, + &apb_clk.common.clk, + &ripc_clk.common.clk, + &i2s_153p6.common.clk, + &i2s_153p6_base.common.clk, + &i2s_sysclk_src.common.clk, + &i2s_sysclk.common.clk, + &i2s_bclk_factor.common.clk, + &i2s_bclk.common.clk, + &wdt_bus_clk.common.clk, +}; +#endif + +static const struct spacemit_ccu_data k1_ccu_mpmu_data = { + .clks = k1_ccu_mpmu_clks, + .num = ARRAY_SIZE(k1_ccu_mpmu_clks), + .offset = K1_MPMU_ID, +}; + +#if IS_ENABLED(CONFIG_SPL_BUILD) +static struct clk *k1_ccu_apbc_clks[] = { + &uart0_clk.common.clk, + &twsi2_clk.common.clk, + &twsi8_clk.common.clk, +}; +#else +static struct clk *k1_ccu_apbc_clks[] = { + &uart0_clk.common.clk, + &uart2_clk.common.clk, + &uart3_clk.common.clk, + &uart4_clk.common.clk, + &uart5_clk.common.clk, + &uart6_clk.common.clk, + &uart7_clk.common.clk, + &uart8_clk.common.clk, + &uart9_clk.common.clk, + &gpio_clk.common.clk, + &pwm0_clk.common.clk, + &pwm1_clk.common.clk, + &pwm2_clk.common.clk, + &pwm3_clk.common.clk, + &pwm4_clk.common.clk, + &pwm5_clk.common.clk, + &pwm6_clk.common.clk, + &pwm7_clk.common.clk, + &pwm8_clk.common.clk, + &pwm9_clk.common.clk, + &pwm10_clk.common.clk, + &pwm11_clk.common.clk, + &pwm12_clk.common.clk, + &pwm13_clk.common.clk, + &pwm14_clk.common.clk, + &pwm15_clk.common.clk, + &pwm16_clk.common.clk, + &pwm17_clk.common.clk, + &pwm18_clk.common.clk, + &pwm19_clk.common.clk, + &ssp3_clk.common.clk, + &rtc_clk.common.clk, + &twsi0_clk.common.clk, + &twsi1_clk.common.clk, + &twsi2_clk.common.clk, + &twsi4_clk.common.clk, + &twsi5_clk.common.clk, + &twsi6_clk.common.clk, + &twsi7_clk.common.clk, + &twsi8_clk.common.clk, + &timers1_clk.common.clk, + &timers2_clk.common.clk, + &aib_clk.common.clk, + &onewire_clk.common.clk, + &sspa0_clk.common.clk, + &sspa1_clk.common.clk, + &dro_clk.common.clk, + &ir_clk.common.clk, + &tsen_clk.common.clk, + &ipc_ap2aud_clk.common.clk, + &can0_clk.common.clk, + &can0_bus_clk.common.clk, + &uart0_bus_clk.common.clk, + &uart2_bus_clk.common.clk, + &uart3_bus_clk.common.clk, + &uart4_bus_clk.common.clk, + &uart5_bus_clk.common.clk, + &uart6_bus_clk.common.clk, + &uart7_bus_clk.common.clk, + &uart8_bus_clk.common.clk, + &uart9_bus_clk.common.clk, + &gpio_bus_clk.common.clk, + &pwm0_bus_clk.common.clk, + &pwm1_bus_clk.common.clk, + &pwm2_bus_clk.common.clk, + &pwm3_bus_clk.common.clk, + &pwm4_bus_clk.common.clk, + &pwm5_bus_clk.common.clk, + &pwm6_bus_clk.common.clk, + &pwm7_bus_clk.common.clk, + &pwm8_bus_clk.common.clk, + &pwm9_bus_clk.common.clk, + &pwm10_bus_clk.common.clk, + &pwm11_bus_clk.common.clk, + &pwm12_bus_clk.common.clk, + &pwm13_bus_clk.common.clk, + &pwm14_bus_clk.common.clk, + &pwm15_bus_clk.common.clk, + &pwm16_bus_clk.common.clk, + &pwm17_bus_clk.common.clk, + &pwm18_bus_clk.common.clk, + &pwm19_bus_clk.common.clk, + &ssp3_bus_clk.common.clk, + &rtc_bus_clk.common.clk, + &twsi0_bus_clk.common.clk, + &twsi1_bus_clk.common.clk, + &twsi2_bus_clk.common.clk, + &twsi4_bus_clk.common.clk, + &twsi5_bus_clk.common.clk, + &twsi6_bus_clk.common.clk, + &twsi7_bus_clk.common.clk, + &twsi8_bus_clk.common.clk, + &timers1_bus_clk.common.clk, + &timers2_bus_clk.common.clk, + &aib_bus_clk.common.clk, + &onewire_bus_clk.common.clk, + &sspa0_bus_clk.common.clk, + &sspa1_bus_clk.common.clk, + &tsen_bus_clk.common.clk, + &ipc_ap2aud_bus_clk.common.clk, + &sspa0_i2s_bclk.common.clk, + &sspa1_i2s_bclk.common.clk, +}; +#endif + +static const struct spacemit_ccu_data k1_ccu_apbc_data = { + .clks = k1_ccu_apbc_clks, + .num = ARRAY_SIZE(k1_ccu_apbc_clks), + .offset = K1_APBC_ID, +}; + +#if IS_ENABLED(CONFIG_SPL_BUILD) +static struct clk *k1_ccu_apmu_clks[] = { + &pmua_aclk.common.clk, + &sdh_axi_aclk.common.clk, + &sdh0_clk.common.clk, + &sdh2_clk.common.clk, +}; +#else +static struct clk *k1_ccu_apmu_clks[] = { + &cci550_clk.common.clk, + &cpu_c0_hi_clk.common.clk, + &cpu_c0_core_clk.common.clk, + &cpu_c0_ace_clk.common.clk, + &cpu_c0_tcm_clk.common.clk, + &cpu_c1_hi_clk.common.clk, + &cpu_c1_core_clk.common.clk, + &cpu_c1_ace_clk.common.clk, + &ccic_4x_clk.common.clk, + &ccic1phy_clk.common.clk, + &pmua_aclk.common.clk, + &sdh_axi_aclk.common.clk, + &sdh0_clk.common.clk, + &sdh1_clk.common.clk, + &sdh2_clk.common.clk, + &usb_p1_aclk.common.clk, + &usb_axi_clk.common.clk, + &usb30_clk.common.clk, + &qspi_clk.common.clk, + &qspi_bus_clk.common.clk, + &dma_clk.common.clk, + &aes_clk.common.clk, + &vpu_clk.common.clk, + &gpu_clk.common.clk, + &emmc_clk.common.clk, + &emmc_x_clk.common.clk, + &audio_clk.common.clk, + &hdmi_mclk.common.clk, + &pcie0_master_clk.common.clk, + &pcie0_slave_clk.common.clk, + &pcie0_dbi_clk.common.clk, + &pcie1_master_clk.common.clk, + &pcie1_slave_clk.common.clk, + &pcie1_dbi_clk.common.clk, + &pcie2_master_clk.common.clk, + &pcie2_slave_clk.common.clk, + &pcie2_dbi_clk.common.clk, + &emac0_bus_clk.common.clk, + &emac0_ptp_clk.common.clk, + &emac1_bus_clk.common.clk, + &emac1_ptp_clk.common.clk, + &jpg_clk.common.clk, + &ccic2phy_clk.common.clk, + &ccic3phy_clk.common.clk, + &csi_clk.common.clk, + &camm0_clk.common.clk, + &camm1_clk.common.clk, + &camm2_clk.common.clk, + &isp_cpp_clk.common.clk, + &isp_bus_clk.common.clk, + &isp_clk.common.clk, + &dpu_mclk.common.clk, + &dpu_esc_clk.common.clk, + &dpu_bit_clk.common.clk, + &dpu_pxclk.common.clk, + &dpu_hclk.common.clk, + &dpu_spi_clk.common.clk, + &dpu_spi_hbus_clk.common.clk, + &dpu_spi_bus_clk.common.clk, + &dpu_spi_aclk.common.clk, + &v2d_clk.common.clk, + &emmc_bus_clk.common.clk, +}; +#endif + +static int clk_k1_enable(struct clk *clk) +{ + const struct spacemit_ccu_data *data; + struct clk *c; + struct clk *pclk; + int ret, i; + + data = (struct spacemit_ccu_data *)dev_get_driver_data(clk->dev); + for (i = 0; i < data->num; i++) { + if (clk->id == data->clks[i]->id) { + c = data->clks[i]; + break; + } + } + if (i == data->num) + c = clk; + + pclk = clk_get_parent(c); + if (!IS_ERR_OR_NULL(pclk)) { + ret = ccf_clk_enable(pclk); + if (ret) + return ret; + } + ret = ccu_gate_enable(c); + return ret; +} + +static int clk_k1_disable(struct clk *clk) +{ + const struct spacemit_ccu_data *data; + struct clk *c; + struct clk *pclk; + int ret, i; + + data = (struct spacemit_ccu_data *)dev_get_driver_data(clk->dev); + for (i = 0; i < data->num; i++) { + if (clk->id == data->clks[i]->id) { + c = data->clks[i]; + break; + } + } + if (i == data->num) + c = clk; + + pclk = clk_get_parent(c); + if (!IS_ERR_OR_NULL(pclk)) { + ret = ccf_clk_disable(pclk); + if (ret) + return ret; + } + ret = ccu_gate_disable(c); + return ret; +} + +#define K1_CLK_OPS(name) \ +static const struct clk_ops k1_##name##_clk_ops = { \ + .set_rate = ccf_clk_set_rate, \ + .get_rate = ccf_clk_get_rate, \ + .enable = clk_k1_enable, \ + .disable = clk_k1_disable, \ + .set_parent = ccf_clk_set_parent, \ + .of_xlate = k1_##name##_clk_of_xlate, \ +} + +static const struct spacemit_ccu_data k1_ccu_apmu_data = { + .clks = k1_ccu_apmu_clks, + .num = ARRAY_SIZE(k1_ccu_apmu_clks), + .offset = K1_APMU_ID, +}; + +/* + * The K1 clock providers are split across separate syscon devices (PLL, + * MPMU, APMU, APBC) whose clocks parent across device boundaries. U-Boot's + * CCF resolves a parent by name at registration time and silently binds an + * orphan if the parent is not registered yet, so a controller must not + * register its clocks before the controllers owning its parents have probed. + * Force the parent controller to probe by its driver: this is robust against + * device tree node/phandle ordering and needs no helper "clocks" wiring in + * the syscon nodes. + */ +static int k1_clk_force_probe(const struct driver *drv) +{ + struct udevice *dev; + + return uclass_get_device_by_driver(UCLASS_CLK, drv, &dev); +} + +static int k1_clk_register(struct udevice *dev, struct regmap *regmap, + struct regmap *lock_regmap, + const struct spacemit_ccu_data *data) +{ + int i, ret; + + for (i = 0; i < data->num; i++) { + struct clk *clk = data->clks[i]; + struct ccu_common *common; + + if (!clk) + continue; + + common = clk_to_ccu_common(clk); + common->regmap = regmap; + common->lock_regmap = lock_regmap; + + if (common->clk.id < K1_PLL_ID) + clk->id = common->clk.id + data->offset; + else + clk->id = common->clk.id; + + ret = common->init(common); + if (ret) + return ret; + } + + return 0; +} + +static int k1_pll_clk_probe(struct udevice *dev) +{ + struct regmap *base_regmap, *lock_regmap = NULL; + const struct spacemit_ccu_data *data; + int ret; + + clk_register_fixed_rate(NULL, "clock-dummy", 0); + + ret = regmap_init_mem(dev_ofnode(dev), &base_regmap); + if (ret) + return ret; + + /* + * The lock status of PLLs locate in MPMU region, while PLLs themselves + * are in APBS region. Reference to MPMU syscon is required to check PLL + * status. + */ + if (device_is_compatible(dev, "spacemit,k1-pll")) { + struct ofnode_phandle_args mpmu_args; + + ret = dev_read_phandle_with_args(dev, "spacemit,mpmu", NULL, 0, 0, + &mpmu_args); + if (ret) + return ret; + + ret = regmap_init_mem(mpmu_args.node, &lock_regmap); + if (ret) + return ret; + } + + data = (struct spacemit_ccu_data *)dev_get_driver_data(dev); + + ret = k1_clk_register(dev, base_regmap, lock_regmap, data); + if (ret) + return -EPROBE_DEFER; + + return 0; +} + +static int k1_mpmu_clk_probe(struct udevice *dev) +{ + struct regmap *base_regmap, *lock_regmap = NULL; + const struct spacemit_ccu_data *data; + int ret; + + /* MPMU clocks parent off the PLL controller */ + ret = k1_clk_force_probe(DM_DRIVER_GET(k1_pll_clk)); + if (ret) + return ret; + + ret = regmap_init_mem(dev_ofnode(dev), &base_regmap); + if (ret) + return ret; + + data = (struct spacemit_ccu_data *)dev_get_driver_data(dev); + + ret = k1_clk_register(dev, base_regmap, lock_regmap, data); + if (ret) + return -EPROBE_DEFER; + + return 0; +} + +static int k1_apmu_clk_probe(struct udevice *dev) +{ + struct regmap *base_regmap, *lock_regmap = NULL; + const struct spacemit_ccu_data *data; + int ret; + + /* APMU clocks parent off the PLL and MPMU controllers */ + ret = k1_clk_force_probe(DM_DRIVER_GET(k1_pll_clk)); + if (ret) + return ret; + ret = k1_clk_force_probe(DM_DRIVER_GET(k1_mpmu_clk)); + if (ret) + return ret; + + ret = regmap_init_mem(dev_ofnode(dev), &base_regmap); + if (ret) + return ret; + + data = (struct spacemit_ccu_data *)dev_get_driver_data(dev); + + ret = k1_clk_register(dev, base_regmap, lock_regmap, data); + if (ret) + return -EPROBE_DEFER; + + return 0; +} + +static int k1_apbc_clk_probe(struct udevice *dev) +{ + struct regmap *base_regmap, *lock_regmap = NULL; + const struct spacemit_ccu_data *data; + int ret; + + /* APBC clocks parent off the PLL, MPMU and APMU controllers */ + ret = k1_clk_force_probe(DM_DRIVER_GET(k1_pll_clk)); + if (ret) + return ret; + ret = k1_clk_force_probe(DM_DRIVER_GET(k1_mpmu_clk)); + if (ret) + return ret; + ret = k1_clk_force_probe(DM_DRIVER_GET(k1_apmu_clk)); + if (ret) + return ret; + + ret = regmap_init_mem(dev_ofnode(dev), &base_regmap); + if (ret) + return ret; + + data = (struct spacemit_ccu_data *)dev_get_driver_data(dev); + + ret = k1_clk_register(dev, base_regmap, lock_regmap, data); + if (ret) + return -EPROBE_DEFER; + + return 0; +} + +static int k1_pll_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) +{ + if (args->args_count > 1) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args_count) + clk->id = K1_PLL_ID + args->args[0]; + else + clk->id = K1_PLL_ID; + + return 0; +} + +static int k1_mpmu_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) +{ + if (args->args_count > 1) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args_count) + clk->id = K1_MPMU_ID + args->args[0]; + else + clk->id = K1_MPMU_ID; + + return 0; +} + +static int k1_apbc_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) +{ + if (args->args_count > 1) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args_count) + clk->id = K1_APBC_ID + args->args[0]; + else + clk->id = K1_APBC_ID; + + return 0; +} + +static int k1_apmu_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) +{ + if (args->args_count > 1) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (args->args_count) + clk->id = K1_APMU_ID + args->args[0]; + else + clk->id = K1_APMU_ID; + + return 0; +} + +static const struct udevice_id k1_pll_clk_match[] = { + { .compatible = "spacemit,k1-pll", + .data = (ulong)&k1_ccu_pll_data }, + { /* sentinel */ }, +}; + +K1_CLK_OPS(pll); + +U_BOOT_DRIVER(k1_pll_clk) = { + .name = "k1_pll_clk", + .id = UCLASS_CLK, + .of_match = k1_pll_clk_match, + .probe = k1_pll_clk_probe, + .ops = &k1_pll_clk_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +static int k1_mpmu_clk_bind(struct udevice *dev) +{ + return spacemit_k1_reset_bind(dev, SPACEMIT_K1_RESET_MPMU); +} + +static int k1_apbc_clk_bind(struct udevice *dev) +{ + return spacemit_k1_reset_bind(dev, SPACEMIT_K1_RESET_APBC); +} + +static int k1_apmu_clk_bind(struct udevice *dev) +{ + return spacemit_k1_reset_bind(dev, SPACEMIT_K1_RESET_APMU); +} + +static int k1_apbc2_clk_bind(struct udevice *dev) +{ + return spacemit_k1_reset_bind(dev, SPACEMIT_K1_RESET_APBC2); +} + +static const struct udevice_id k1_mpmu_clk_match[] = { + { .compatible = "spacemit,k1-syscon-mpmu", + .data = (ulong)&k1_ccu_mpmu_data }, + { /* sentinel */ }, +}; + +K1_CLK_OPS(mpmu); + +U_BOOT_DRIVER(k1_mpmu_clk) = { + .name = "k1_mpmu_clk", + .id = UCLASS_CLK, + .of_match = k1_mpmu_clk_match, + .bind = k1_mpmu_clk_bind, + .probe = k1_mpmu_clk_probe, + .ops = &k1_mpmu_clk_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +static const struct udevice_id k1_apbc_clk_match[] = { + { .compatible = "spacemit,k1-syscon-apbc", + .data = (ulong)&k1_ccu_apbc_data }, + { /* sentinel */ }, +}; + +K1_CLK_OPS(apbc); + +U_BOOT_DRIVER(k1_apbc_clk) = { + .name = "k1_apbc_clk", + .id = UCLASS_CLK, + .of_match = k1_apbc_clk_match, + .bind = k1_apbc_clk_bind, + .probe = k1_apbc_clk_probe, + .ops = &k1_apbc_clk_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +static const struct udevice_id k1_apmu_clk_match[] = { + { .compatible = "spacemit,k1-syscon-apmu", + .data = (ulong)&k1_ccu_apmu_data }, + { /* sentinel */ }, +}; + +K1_CLK_OPS(apmu); + +U_BOOT_DRIVER(k1_apmu_clk) = { + .name = "k1_apmu_clk", + .id = UCLASS_CLK, + .of_match = k1_apmu_clk_match, + .bind = k1_apmu_clk_bind, + .probe = k1_apmu_clk_probe, + .ops = &k1_apmu_clk_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +static const struct udevice_id k1_apbc2_clk_match[] = { + { .compatible = "spacemit,k1-syscon-apbc2" }, + { /* sentinel */ }, +}; + +U_BOOT_DRIVER(k1_apbc2_clk) = { + .name = "k1_apbc2_clk", + .id = UCLASS_CLK, + .of_match = k1_apbc2_clk_match, + .bind = k1_apbc2_clk_bind, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/spacemit/clk_common.h b/drivers/clk/spacemit/clk_common.h new file mode 100644 index 00000000000..ea5ebf57784 --- /dev/null +++ b/drivers/clk/spacemit/clk_common.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2024 SpacemiT Technology Co. Ltd + * Copyright (c) 2024-2025 Haylen Chu <[email protected]> + * Copyright (c) 2025 Junhui Liu <[email protected]> + * Copyright (c) 2025-2026 RISCstar Ltd. + * + * Authors: Haylen Chu <[email protected]> + */ + +#ifndef _CLK_COMMON_H_ +#define _CLK_COMMON_H_ + +#include <linux/clk-provider.h> + +struct ccu_common; + +typedef int (*ccu_init_fn)(struct ccu_common *common); + +struct ccu_common { + struct regmap *regmap; + struct regmap *lock_regmap; + const char *name; + const char * const *parents; + size_t num_parents; + ccu_init_fn init; + + union { + /* For DDN and MIX */ + struct { + u32 reg_ctrl; + u32 reg_fc; + u32 mask_fc; + }; + + /* For PLL */ + struct { + u32 reg_swcr1; + u32 reg_swcr3; + }; + }; + + struct clk clk; +}; + +#define CCU_COMMON(_id, _name, _parent, _init, _flags) \ + .name = #_name, \ + .parents = (const char *[]) { _parent }, \ + .num_parents = 1, \ + .init = _init, \ + .clk = { .flags = _flags, .id = _id, } \ + +#define CCU_COMMON_PARENTS(_id, _name, _parents, _num_p, _init, _flags) \ + .name = #_name, \ + .parents = _parents, \ + .num_parents = _num_p, \ + .init = _init, \ + .clk = { .flags = _flags, .id = _id, } \ + +static inline struct ccu_common *clk_to_ccu_common(struct clk *clk) +{ + return container_of(clk, struct ccu_common, clk); +} + +#define ccu_read(c, reg) \ + ({ \ + struct ccu_common * const __ccu = (c); \ + u32 tmp; \ + regmap_read(__ccu->regmap, __ccu->reg_##reg, &tmp); \ + tmp; \ + }) +#define ccu_update(c, reg, mask, val) \ + ({ \ + struct ccu_common * const __ccu = (c); \ + regmap_update_bits(__ccu->regmap, __ccu->reg_##reg, \ + mask, val); \ + }) + +#endif /* _CLK_COMMON_H_ */ diff --git a/drivers/clk/spacemit/clk_ddn.c b/drivers/clk/spacemit/clk_ddn.c new file mode 100644 index 00000000000..7b93f30d5c3 --- /dev/null +++ b/drivers/clk/spacemit/clk_ddn.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 SpacemiT Technology Co. Ltd + * Copyright (c) 2024-2025 Haylen Chu <[email protected]> + * Copyright (c) 2025 Junhui Liu <[email protected]> + * Authors: Haylen Chu <[email protected]> + * + * DDN stands for "Divider Denominator Numerator", it's M/N clock with a + * constant x2 factor. This clock hardware follows the equation below, + * + * numerator Fin + * 2 * ------------- = ------- + * denominator Fout + * + * Thus, Fout could be calculated with, + * + * Fin denominator + * Fout = ----- * ------------- + * 2 numerator + */ + +#include <dm/device.h> +#include <regmap.h> +#include <linux/clk-provider.h> +#include <linux/rational.h> + +#include "clk_ddn.h" + +#define UBOOT_DM_SPACEMIT_CLK_DDN "spacemit_clk_ddn" + +static unsigned long ccu_ddn_calc_rate(unsigned long prate, unsigned long num, + unsigned long den, unsigned int pre_div) +{ + return prate * den / pre_div / num; +} + +static unsigned long ccu_ddn_calc_best_rate(struct ccu_ddn *ddn, + unsigned long rate, unsigned long prate, + unsigned long *num, unsigned long *den) +{ + rational_best_approximation(rate, prate / ddn->pre_div, + ddn->den_mask >> ddn->den_shift, + ddn->num_mask >> ddn->num_shift, + den, num); + return ccu_ddn_calc_rate(prate, *num, *den, ddn->pre_div); +} + +static unsigned long ccu_ddn_recalc_rate(struct clk *clk) +{ + struct ccu_ddn *ddn = clk_to_ccu_ddn(clk); + unsigned int val, num, den; + + val = ccu_read(&ddn->common, ctrl); + + num = (val & ddn->num_mask) >> ddn->num_shift; + den = (val & ddn->den_mask) >> ddn->den_shift; + + return ccu_ddn_calc_rate(clk_get_parent_rate(clk), num, den, ddn->pre_div); +} + +static unsigned long ccu_ddn_set_rate(struct clk *clk, unsigned long rate) +{ + struct ccu_ddn *ddn = clk_to_ccu_ddn(clk); + unsigned long num, den; + + ccu_ddn_calc_best_rate(ddn, rate, clk_get_parent_rate(clk), &num, &den); + + ccu_update(&ddn->common, ctrl, + ddn->num_mask | ddn->den_mask, + (num << ddn->num_shift) | (den << ddn->den_shift)); + + return 0; +} + +static const struct clk_ops spacemit_clk_ddn_ops = { + .get_rate = ccu_ddn_recalc_rate, + .set_rate = ccu_ddn_set_rate, +}; + +int spacemit_ddn_init(struct ccu_common *common) +{ + struct clk *clk = &common->clk; + + return clk_register(clk, UBOOT_DM_SPACEMIT_CLK_DDN, + common->name, common->parents[0]); +} + +U_BOOT_DRIVER(spacemit_clk_ddn) = { + .name = UBOOT_DM_SPACEMIT_CLK_DDN, + .id = UCLASS_CLK, + .ops = &spacemit_clk_ddn_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/spacemit/clk_ddn.h b/drivers/clk/spacemit/clk_ddn.h new file mode 100644 index 00000000000..1330ced23b1 --- /dev/null +++ b/drivers/clk/spacemit/clk_ddn.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2024 SpacemiT Technology Co. Ltd + * Copyright (c) 2024-2025 Haylen Chu <[email protected]> + * Copyright (c) 2025 Junhui Liu <[email protected]> + * Copyright (c) 2025-2026 RISCstar Ltd. + * + * Authors: Haylen Chu <[email protected]> + */ + +#ifndef _CLK_DDN_H_ +#define _CLK_DDN_H_ + +#include <linux/clk-provider.h> + +#include "clk_common.h" + +struct ccu_ddn { + struct ccu_common common; + unsigned int num_mask; + unsigned int num_shift; + unsigned int den_mask; + unsigned int den_shift; + unsigned int pre_div; +}; + +#define CCU_DDN_MASK(_num_shift, _num_width) \ + GENMASK((_num_shift) + (_num_width) - 1, _num_shift) + +#define CCU_DDN_DEFINE(_id, _var, _name, _parent, _reg_ctrl, _num_mask, \ + _num_shift, _den_mask, _den_shift, _pre_div, _flags) \ +static struct ccu_ddn _var = { \ + .common = { \ + .reg_ctrl = _reg_ctrl, \ + CCU_COMMON(_id, _name, _parent, spacemit_ddn_init, _flags) \ + }, \ + .num_mask = _num_mask, \ + .num_shift = _num_shift, \ + .den_mask = _den_mask, \ + .den_shift = _den_shift, \ + .pre_div = _pre_div, \ +} + +static inline struct ccu_ddn *clk_to_ccu_ddn(struct clk *clk) +{ + struct ccu_common *common = clk_to_ccu_common(clk); + + return container_of(common, struct ccu_ddn, common); +} + +int spacemit_ddn_init(struct ccu_common *common); + +#endif /* _CLK_DDN_H_ */ diff --git a/drivers/clk/spacemit/clk_mix.c b/drivers/clk/spacemit/clk_mix.c new file mode 100644 index 00000000000..a1158512a92 --- /dev/null +++ b/drivers/clk/spacemit/clk_mix.c @@ -0,0 +1,403 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 SpacemiT Technology Co. Ltd + * Copyright (c) 2024-2025 Haylen Chu <[email protected]> + * Copyright (c) 2025 Junhui Liu <[email protected]> + * Authors: Haylen Chu <[email protected]> + * + * MIX clock type is the combination of mux, factor or divider, and gate + */ + +#include <dm/device.h> +#include <dm/uclass.h> +#include <div64.h> +#include <regmap.h> +#include <linux/clk-provider.h> +#include <linux/kernel.h> + +#include "clk_mix.h" + +#define UBOOT_DM_SPACEMIT_CLK_GATE "spacemit_clk_gate" +#define UBOOT_DM_SPACEMIT_CLK_FACTOR "spacemit_clk_factor" +#define UBOOT_DM_SPACEMIT_CLK_MUX "spacemit_clk_mux" +#define UBOOT_DM_SPACEMIT_CLK_DIV "spacemit_clk_div" +#define UBOOT_DM_SPACEMIT_CLK_FACTOR_GATE "spacemit_clk_factor_gate" +#define UBOOT_DM_SPACEMIT_CLK_MUX_GATE "spacemit_clk_mux_gate" +#define UBOOT_DM_SPACEMIT_CLK_DIV_GATE "spacemit_clk_div_gate" +#define UBOOT_DM_SPACEMIT_CLK_MUX_DIV "spacemit_clk_mux_div" +#define UBOOT_DM_SPACEMIT_CLK_MUX_DIV_GATE "spacemit_clk_mux_div_gate" + +#define MIX_FC_TIMEOUT_US 10000 +#define MIX_FC_DELAY_US 5 + +int ccu_gate_disable(struct clk *clk) +{ + struct ccu_mix *mix = clk_to_ccu_mix(clk); + + ccu_update(&mix->common, ctrl, mix->gate.mask, 0); + + return 0; +} + +int ccu_gate_enable(struct clk *clk) +{ + struct ccu_mix *mix = clk_to_ccu_mix(clk); + struct ccu_gate_config *gate = &mix->gate; + + ccu_update(&mix->common, ctrl, gate->mask, gate->mask); + + return 0; +} + +static unsigned long ccu_factor_recalc_rate(struct clk *clk) +{ + struct ccu_mix *mix = clk_to_ccu_mix(clk); + + return clk_get_parent_rate(clk) * mix->factor.mul / mix->factor.div; +} + +static unsigned long ccu_div_recalc_rate(struct clk *clk) +{ + struct ccu_mix *mix = clk_to_ccu_mix(clk); + struct ccu_div_config *div = &mix->div; + unsigned long val; + + val = ccu_read(&mix->common, ctrl) >> div->shift; + val &= (1 << div->width) - 1; + + return divider_recalc_rate(clk, clk_get_parent_rate(clk), val, NULL, 0, div->width); +} + +/* + * Some clocks require a "FC" (frequency change) bit to be set after changing + * their rates or reparenting. This bit will be automatically cleared by + * hardware in MIX_FC_TIMEOUT_US, which indicates the operation is completed. + */ +static int ccu_mix_trigger_fc(struct clk *clk) +{ + struct ccu_common *common = clk_to_ccu_common(clk); + unsigned int val; + + if (common->reg_fc) + return 0; + + ccu_update(common, fc, common->mask_fc, common->mask_fc); + + return regmap_read_poll_timeout(common->regmap, common->reg_fc, + val, !(val & common->mask_fc), + MIX_FC_DELAY_US, + MIX_FC_TIMEOUT_US); +} + +static unsigned long +ccu_mix_calc_best_rate(struct clk *clk, unsigned long rate, + struct clk **best_parent, + unsigned long *best_parent_rate, + u32 *div_val) +{ + struct ccu_common *common = clk_to_ccu_common(clk); + struct ccu_mix *mix = clk_to_ccu_mix(clk); + unsigned int parent_num = common->num_parents; + struct ccu_div_config *div = &mix->div; + u32 div_max = 1 << div->width; + unsigned long best_rate = 0; + + for (int i = 0; i < parent_num; i++) { + struct udevice *parent_dev; + unsigned long parent_rate; + struct clk *parent; + + if (uclass_get_device_by_name(UCLASS_CLK, common->parents[i], + &parent_dev)) + continue; + parent = dev_get_clk_ptr(parent_dev); + if (!parent) + continue; + + parent_rate = clk_get_rate(parent); + + for (int j = 1; j <= div_max; j++) { + unsigned long tmp = DIV_ROUND_CLOSEST_ULL(parent_rate, j); + + if (abs(tmp - rate) < abs(best_rate - rate)) { + best_rate = tmp; + + if (div_val) + *div_val = j - 1; + + if (best_parent) { + *best_parent = parent; + *best_parent_rate = parent_rate; + } + } + } + } + + return best_rate; +} + +static unsigned long ccu_mix_set_rate(struct clk *clk, unsigned long rate) +{ + struct ccu_mix *mix = clk_to_ccu_mix(clk); + struct ccu_common *common = &mix->common; + struct ccu_div_config *div = &mix->div; + u32 current_div, target_div, mask; + + ccu_mix_calc_best_rate(clk, rate, NULL, NULL, &target_div); + + current_div = ccu_read(common, ctrl) >> div->shift; + current_div &= (1 << div->width) - 1; + + if (current_div == target_div) + return 0; + + mask = GENMASK(div->width + div->shift - 1, div->shift); + + ccu_update(common, ctrl, mask, target_div << div->shift); + + return ccu_mix_trigger_fc(clk); +} + +static u8 ccu_mux_get_parent(struct clk *clk) +{ + struct ccu_mix *mix = clk_to_ccu_mix(clk); + struct ccu_mux_config *mux = &mix->mux; + u8 parent; + + parent = ccu_read(&mix->common, ctrl) >> mux->shift; + parent &= (1 << mux->width) - 1; + + return parent; +} + +static int ccu_mux_set_parent(struct clk *clk, struct clk *parent) +{ + struct ccu_common *common = clk_to_ccu_common(clk); + struct ccu_mix *mix = clk_to_ccu_mix(clk); + struct ccu_mux_config *mux = &mix->mux; + u32 mask; + int i = 0; + + mask = GENMASK(mux->width + mux->shift - 1, mux->shift); + + for (i = 0; i < common->num_parents; i++) { + if (!strcmp(parent->dev->name, common->parents[i])) + break; + } + + if (i == common->num_parents) + return -EINVAL; + + ccu_update(&mix->common, ctrl, mask, i << mux->shift); + + return ccu_mix_trigger_fc(clk); +} + +int spacemit_gate_init(struct ccu_common *common) +{ + struct clk *clk = &common->clk; + + return clk_register(clk, UBOOT_DM_SPACEMIT_CLK_GATE, + common->name, common->parents[0]); +} + +static const struct clk_ops spacemit_clk_gate_ops = { + .disable = ccu_gate_disable, + .enable = ccu_gate_enable, + .get_rate = clk_generic_get_rate, +}; + +U_BOOT_DRIVER(spacemit_clk_gate) = { + .name = UBOOT_DM_SPACEMIT_CLK_GATE, + .id = UCLASS_CLK, + .ops = &spacemit_clk_gate_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +int spacemit_factor_init(struct ccu_common *common) +{ + struct clk *clk = &common->clk; + + return clk_register(clk, UBOOT_DM_SPACEMIT_CLK_FACTOR, + common->name, common->parents[0]); +} + +static const struct clk_ops spacemit_clk_factor_ops = { + .get_rate = ccu_factor_recalc_rate, +}; + +U_BOOT_DRIVER(spacemit_clk_factor) = { + .name = UBOOT_DM_SPACEMIT_CLK_FACTOR, + .id = UCLASS_CLK, + .ops = &spacemit_clk_factor_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +int spacemit_mux_init(struct ccu_common *common) +{ + struct clk *clk = &common->clk; + u8 index; + + index = ccu_mux_get_parent(clk); + if (index >= common->num_parents) + index = 0; + + return clk_register(clk, UBOOT_DM_SPACEMIT_CLK_MUX, + common->name, common->parents[index]); +} + +static const struct clk_ops spacemit_clk_mux_ops = { + .set_parent = ccu_mux_set_parent, + .get_rate = clk_generic_get_rate, +}; + +U_BOOT_DRIVER(spacemit_clk_mux) = { + .name = UBOOT_DM_SPACEMIT_CLK_MUX, + .id = UCLASS_CLK, + .ops = &spacemit_clk_mux_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +int spacemit_div_init(struct ccu_common *common) +{ + struct clk *clk = &common->clk; + + return clk_register(clk, UBOOT_DM_SPACEMIT_CLK_DIV, + common->name, common->parents[0]); +} + +static const struct clk_ops spacemit_clk_div_ops = { + .get_rate = ccu_div_recalc_rate, + .set_rate = ccu_mix_set_rate, +}; + +U_BOOT_DRIVER(spacemit_clk_div) = { + .name = UBOOT_DM_SPACEMIT_CLK_DIV, + .id = UCLASS_CLK, + .ops = &spacemit_clk_div_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +int spacemit_factor_gate_init(struct ccu_common *common) +{ + struct clk *clk = &common->clk; + + return clk_register(clk, UBOOT_DM_SPACEMIT_CLK_FACTOR_GATE, + common->name, common->parents[0]); +} + +static const struct clk_ops spacemit_clk_factor_gate_ops = { + .disable = ccu_gate_disable, + .enable = ccu_gate_enable, + .get_rate = ccu_factor_recalc_rate, +}; + +U_BOOT_DRIVER(spacemit_clk_factor_gate) = { + .name = UBOOT_DM_SPACEMIT_CLK_FACTOR_GATE, + .id = UCLASS_CLK, + .ops = &spacemit_clk_factor_gate_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +int spacemit_mux_gate_init(struct ccu_common *common) +{ + struct clk *clk = &common->clk; + u8 index; + + index = ccu_mux_get_parent(clk); + if (index >= common->num_parents) + index = 0; + + return clk_register(clk, UBOOT_DM_SPACEMIT_CLK_MUX_GATE, + common->name, common->parents[index]); +} + +static const struct clk_ops spacemit_clk_mux_gate_ops = { + .disable = ccu_gate_disable, + .enable = ccu_gate_enable, + .set_parent = ccu_mux_set_parent, + .get_rate = clk_generic_get_rate, +}; + +U_BOOT_DRIVER(spacemit_clk_mux_gate) = { + .name = UBOOT_DM_SPACEMIT_CLK_MUX_GATE, + .id = UCLASS_CLK, + .ops = &spacemit_clk_mux_gate_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +int spacemit_div_gate_init(struct ccu_common *common) +{ + struct clk *clk = &common->clk; + + return clk_register(clk, UBOOT_DM_SPACEMIT_CLK_DIV_GATE, + common->name, common->parents[0]); +} + +static const struct clk_ops spacemit_clk_div_gate_ops = { + .disable = ccu_gate_disable, + .enable = ccu_gate_enable, + .get_rate = ccu_div_recalc_rate, + .set_rate = ccu_mix_set_rate, +}; + +U_BOOT_DRIVER(spacemit_clk_div_gate) = { + .name = UBOOT_DM_SPACEMIT_CLK_DIV_GATE, + .id = UCLASS_CLK, + .ops = &spacemit_clk_div_gate_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +int spacemit_mux_div_init(struct ccu_common *common) +{ + struct clk *clk = &common->clk; + u8 index; + + index = ccu_mux_get_parent(clk); + if (index >= common->num_parents) + index = 0; + + return clk_register(clk, UBOOT_DM_SPACEMIT_CLK_MUX_DIV, + common->name, common->parents[index]); +} + +static const struct clk_ops spacemit_clk_mux_div_ops = { + .set_parent = ccu_mux_set_parent, + .get_rate = ccu_div_recalc_rate, + .set_rate = ccu_mix_set_rate, +}; + +U_BOOT_DRIVER(spacemit_clk_mux_div) = { + .name = UBOOT_DM_SPACEMIT_CLK_MUX_DIV, + .id = UCLASS_CLK, + .ops = &spacemit_clk_mux_div_ops, + .flags = DM_FLAG_PRE_RELOC, +}; + +int spacemit_mux_div_gate_init(struct ccu_common *common) +{ + struct clk *clk = &common->clk; + u8 index; + + index = ccu_mux_get_parent(clk); + if (index >= common->num_parents) + index = 0; + + return clk_register(clk, UBOOT_DM_SPACEMIT_CLK_MUX_DIV_GATE, + common->name, common->parents[index]); +} + +static const struct clk_ops spacemit_clk_mux_div_gate_ops = { + .disable = ccu_gate_disable, + .enable = ccu_gate_enable, + .set_parent = ccu_mux_set_parent, + .get_rate = ccu_div_recalc_rate, + .set_rate = ccu_mix_set_rate, +}; + +U_BOOT_DRIVER(spacemit_clk_mux_div_gate) = { + .name = UBOOT_DM_SPACEMIT_CLK_MUX_DIV_GATE, + .id = UCLASS_CLK, + .ops = &spacemit_clk_mux_div_gate_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/spacemit/clk_mix.h b/drivers/clk/spacemit/clk_mix.h new file mode 100644 index 00000000000..26a12cedd0d --- /dev/null +++ b/drivers/clk/spacemit/clk_mix.h @@ -0,0 +1,224 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2024 SpacemiT Technology Co. Ltd + * Copyright (c) 2024-2025 Haylen Chu <[email protected]> + * Copyright (c) 2025 Junhui Liu <[email protected]> + * Copyright (c) 2025-2026 RISCstar Ltd. + * + * Authors: Haylen Chu <[email protected]> + */ + +#ifndef _CLK_MIX_H_ +#define _CLK_MIX_H_ + +#include <linux/clk-provider.h> + +#include "clk_common.h" + +/** + * struct ccu_gate_config - Gate configuration + * + * @mask: Mask to enable the gate. Some clocks may have more than one bit + * set in this field. + */ +struct ccu_gate_config { + u32 mask; +}; + +struct ccu_factor_config { + u32 div; + u32 mul; +}; + +struct ccu_mux_config { + u8 shift; + u8 width; +}; + +struct ccu_div_config { + u8 shift; + u8 width; +}; + +struct ccu_mix { + struct ccu_factor_config factor; + struct ccu_gate_config gate; + struct ccu_div_config div; + struct ccu_mux_config mux; + struct ccu_common common; +}; + +#define CCU_GATE_INIT(_mask) { .mask = _mask } +#define CCU_FACTOR_INIT(_div, _mul) { .div = _div, .mul = _mul } +#define CCU_MUX_INIT(_shift, _width) { .shift = _shift, .width = _width } +#define CCU_DIV_INIT(_shift, _width) { .shift = _shift, .width = _width } + +#define CCU_GATE_DEFINE(_id, _var, _name, _parent, _reg_ctrl, \ + _mask_gate, _flags) \ +static struct ccu_mix _var = { \ + .gate = CCU_GATE_INIT(_mask_gate), \ + .common = { \ + .reg_ctrl = _reg_ctrl, \ + CCU_COMMON(_id, _name, _parent, spacemit_gate_init, \ + _flags) \ + } \ +} + +#define CCU_FACTOR_DEFINE(_id, _var, _name, _parent, _div, _mul) \ +static struct ccu_mix _var = { \ + .factor = CCU_FACTOR_INIT(_div, _mul), \ + .common = { \ + CCU_COMMON(_id, _name, _parent, spacemit_factor_init, \ + 0) \ + } \ +} + +#define CCU_MUX_DEFINE(_id, _var, _name, _parents, _num_p, _reg_ctrl, \ + _shift, _width, _flags) \ +static struct ccu_mix _var = { \ + .mux = CCU_MUX_INIT(_shift, _width), \ + .common = { \ + .reg_ctrl = _reg_ctrl, \ + CCU_COMMON_PARENTS(_id, _name, _parents, _num_p, \ + spacemit_mux_init, _flags) \ + } \ +} + +#define CCU_DIV_DEFINE(_id, _var, _name, _parent, _reg_ctrl, _shift, \ + _width, _flags) \ +static struct ccu_mix _var = { \ + .div = CCU_DIV_INIT(_shift, _width), \ + .common = { \ + .reg_ctrl = _reg_ctrl, \ + CCU_COMMON(_id, _name, _parent, spacemit_div_init, \ + _flags) \ + } \ +} + +#define CCU_FACTOR_GATE_FLAGS_DEFINE(_id, _var, _name, _parent, \ + _reg_ctrl, _mask_gate, _div, _mul, \ + _flags) \ +static struct ccu_mix _var = { \ + .gate = CCU_GATE_INIT(_mask_gate), \ + .factor = CCU_FACTOR_INIT(_div, _mul), \ + .common = { \ + .reg_ctrl = _reg_ctrl, \ + CCU_COMMON(_id, _name, _parent, \ + spacemit_factor_gate_init, _flags) \ + } \ +} + +#define CCU_FACTOR_GATE_DEFINE(_id, _var, _name, _parent, _reg_ctrl, \ + _mask_gate, _div, _mul) \ + CCU_FACTOR_GATE_FLAGS_DEFINE(_id, _var, _name, _parent, \ + _reg_ctrl, _mask_gate, _div, _mul, \ + 0) + +#define CCU_MUX_GATE_DEFINE(_id, _var, _name, _parents, _num_p, \ + _reg_ctrl, _shift, _width, _mask_gate, \ + _flags) \ +static struct ccu_mix _var = { \ + .gate = CCU_GATE_INIT(_mask_gate), \ + .mux = CCU_MUX_INIT(_shift, _width), \ + .common = { \ + .reg_ctrl = _reg_ctrl, \ + CCU_COMMON_PARENTS(_id, _name, _parents, _num_p, \ + spacemit_mux_gate_init, _flags) \ + } \ +} + +#define CCU_DIV_GATE_DEFINE(_id, _var, _name, _parent, _reg_ctrl, \ + _shift, _width, _mask_gate, _flags) \ +static struct ccu_mix _var = { \ + .gate = CCU_GATE_INIT(_mask_gate), \ + .div = CCU_DIV_INIT(_shift, _width), \ + .common = { \ + .reg_ctrl = _reg_ctrl, \ + CCU_COMMON(_id, _name, _parent, \ + spacemit_div_gate_init, _flags) \ + } \ +} + +#define CCU_MUX_DIV_GATE_DEFINE(_id, _var, _name, _parents, _num_p, \ + _reg_ctrl, _mshift, _mwidth, _muxshift, \ + _muxwidth, _mask_gate, _flags) \ +static struct ccu_mix _var = { \ + .gate = CCU_GATE_INIT(_mask_gate), \ + .div = CCU_DIV_INIT(_mshift, _mwidth), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \ + .common = { \ + .reg_ctrl = _reg_ctrl, \ + CCU_COMMON_PARENTS(_id, _name, _parents, _num_p, \ + spacemit_mux_div_gate_init, _flags) \ + }, \ +} + +#define CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(_id, _var, _name, _parents, \ + _num_p, _reg_ctrl, _reg_fc, \ + _mshift, _mwidth, _mask_fc, \ + _muxshift, _muxwidth, \ + _mask_gate, _flags) \ +static struct ccu_mix _var = { \ + .gate = CCU_GATE_INIT(_mask_gate), \ + .div = CCU_DIV_INIT(_mshift, _mwidth), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \ + .common = { \ + .reg_ctrl = _reg_ctrl, \ + .reg_fc = _reg_fc, \ + .mask_fc = _mask_fc, \ + CCU_COMMON_PARENTS(_id, _name, _parents, _num_p, \ + spacemit_mux_div_gate_init, _flags) \ + }, \ +} + +#define CCU_MUX_DIV_FC_DEFINE(_id, _var, _name, _parents, _num_p, \ + _reg_ctrl, _reg_fc, _mshift, _mwidth, \ + _mask_fc, _muxshift, _muxwidth, _flags) \ +static struct ccu_mix _var = { \ + .div = CCU_DIV_INIT(_mshift, _mwidth), \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \ + .common = { \ + .reg_ctrl = _reg_ctrl, \ + .reg_fc = _reg_fc, \ + .mask_fc = _mask_fc, \ + CCU_COMMON_PARENTS(_id, _name, _parents, _num_p, \ + spacemit_mux_div_init, _flags) \ + }, \ +} + +#define CCU_MUX_FC_DEFINE(_id, _var, _name, _parents, _num_p, \ + _reg_ctrl, _reg_fc, _mask_fc, _muxshift, \ + _muxwidth, _flags) \ +static struct ccu_mix _var = { \ + .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \ + .common = { \ + .reg_ctrl = _reg_ctrl, \ + .reg_fc = _reg_fc, \ + .mask_fc = _mask_fc, \ + CCU_COMMON_PARENTS(_id, _name, _parents, _num_p, \ + spacemit_mux_init, \ + _flags) \ + }, \ +} + +static inline struct ccu_mix *clk_to_ccu_mix(struct clk *clk) +{ + struct ccu_common *common = clk_to_ccu_common(clk); + + return container_of(common, struct ccu_mix, common); +} + +int ccu_gate_enable(struct clk *clk); +int ccu_gate_disable(struct clk *clk); + +int spacemit_gate_init(struct ccu_common *common); +int spacemit_factor_init(struct ccu_common *common); +int spacemit_mux_init(struct ccu_common *common); +int spacemit_div_init(struct ccu_common *common); +int spacemit_factor_gate_init(struct ccu_common *common); +int spacemit_div_gate_init(struct ccu_common *common); +int spacemit_mux_gate_init(struct ccu_common *common); +int spacemit_mux_div_init(struct ccu_common *common); +int spacemit_mux_div_gate_init(struct ccu_common *common); + +#endif /* _CLK_MIX_H_ */ diff --git a/drivers/clk/spacemit/clk_pll.c b/drivers/clk/spacemit/clk_pll.c new file mode 100644 index 00000000000..56da70af58a --- /dev/null +++ b/drivers/clk/spacemit/clk_pll.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 SpacemiT Technology Co. Ltd + * Copyright (c) 2024-2025 Haylen Chu <[email protected]> + * Copyright (c) 2025 Junhui Liu <[email protected]> + * Authors: Haylen Chu <[email protected]> + */ + +#include <dm/device.h> +#include <regmap.h> +#include <linux/bug.h> +#include <linux/clk-provider.h> + +#include "clk_pll.h" + +#define UBOOT_DM_SPACEMIT_CLK_PLL "spacemit_clk_pll" + +#define PLL_TIMEOUT_US 3000 +#define PLL_DELAY_US 5 + +#define PLL_SWCR3_EN ((u32)BIT(31)) +#define PLL_SWCR3_MASK GENMASK(30, 0) + +static const struct ccu_pll_rate_tbl *ccu_pll_lookup_best_rate(struct ccu_pll *pll, + unsigned long rate) +{ + struct ccu_pll_config *config = &pll->config; + const struct ccu_pll_rate_tbl *best_entry; + unsigned long best_delta = ULONG_MAX; + int i; + + for (i = 0; i < config->tbl_num; i++) { + const struct ccu_pll_rate_tbl *entry = &config->rate_tbl[i]; + unsigned long delta = abs(entry->rate - rate); + + if (delta < best_delta) { + best_delta = delta; + best_entry = entry; + } + } + + return best_entry; +} + +static const struct ccu_pll_rate_tbl *ccu_pll_lookup_matched_entry(struct ccu_pll *pll) +{ + struct ccu_pll_config *config = &pll->config; + u32 swcr1, swcr3; + int i; + + swcr1 = ccu_read(&pll->common, swcr1); + swcr3 = ccu_read(&pll->common, swcr3); + swcr3 &= PLL_SWCR3_MASK; + + for (i = 0; i < config->tbl_num; i++) { + const struct ccu_pll_rate_tbl *entry = &config->rate_tbl[i]; + + if (swcr1 == entry->swcr1 && swcr3 == entry->swcr3) + return entry; + } + + return NULL; +} + +static void ccu_pll_update_param(struct ccu_pll *pll, const struct ccu_pll_rate_tbl *entry) +{ + struct ccu_common *common = &pll->common; + + regmap_write(common->regmap, common->reg_swcr1, entry->swcr1); + ccu_update(common, swcr3, PLL_SWCR3_MASK, entry->swcr3); +} + +static int ccu_pll_enable(struct clk *clk) +{ + struct ccu_pll *pll = clk_to_ccu_pll(clk); + struct ccu_common *common = &pll->common; + unsigned int tmp; + + ccu_update(common, swcr3, PLL_SWCR3_EN, PLL_SWCR3_EN); + + /* check lock status */ + return regmap_read_poll_timeout(common->lock_regmap, + pll->config.reg_lock, + tmp, + tmp & pll->config.mask_lock, + PLL_DELAY_US, PLL_TIMEOUT_US); +} + +static int ccu_pll_disable(struct clk *clk) +{ + struct ccu_common *common = clk_to_ccu_common(clk); + + ccu_update(common, swcr3, PLL_SWCR3_EN, 0); + + return 0; +} + +/* + * PLLs must be gated before changing rate, which is ensured by + * flag CLK_SET_RATE_GATE. + */ +static unsigned long ccu_pll_set_rate(struct clk *clk, unsigned long rate) +{ + struct ccu_pll *pll = clk_to_ccu_pll(clk); + const struct ccu_pll_rate_tbl *entry; + + entry = ccu_pll_lookup_best_rate(pll, rate); + ccu_pll_update_param(pll, entry); + + return 0; +} + +static unsigned long ccu_pll_recalc_rate(struct clk *clk) +{ + struct ccu_pll *pll = clk_to_ccu_pll(clk); + const struct ccu_pll_rate_tbl *entry; + + entry = ccu_pll_lookup_matched_entry(pll); + + WARN_ON_ONCE(!entry); + + return entry ? entry->rate : 0; +} + +static const struct clk_ops spacemit_clk_pll_ops = { + .enable = ccu_pll_enable, + .disable = ccu_pll_disable, + .set_rate = ccu_pll_set_rate, + .get_rate = ccu_pll_recalc_rate, +}; + +int spacemit_pll_init(struct ccu_common *common) +{ + struct clk *clk = &common->clk; + struct ccu_pll *pll = clk_to_ccu_pll(clk); + int ret; + + ret = clk_register(clk, UBOOT_DM_SPACEMIT_CLK_PLL, + common->name, common->parents[0]); + if (ret) + return ret; + + if (ccu_pll_lookup_matched_entry(pll)) + return 0; + + ccu_pll_disable(clk); + ccu_pll_update_param(pll, &pll->config.rate_tbl[0]); + + return 0; +} + +U_BOOT_DRIVER(spacemit_clk_pll) = { + .name = UBOOT_DM_SPACEMIT_CLK_PLL, + .id = UCLASS_CLK, + .ops = &spacemit_clk_pll_ops, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/spacemit/clk_pll.h b/drivers/clk/spacemit/clk_pll.h new file mode 100644 index 00000000000..3987cc1141b --- /dev/null +++ b/drivers/clk/spacemit/clk_pll.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2024 SpacemiT Technology Co. Ltd + * Copyright (c) 2024-2025 Haylen Chu <[email protected]> + * Copyright (c) 2025 Junhui Liu <[email protected]> + * Copyright (c) 2025-2026 RISCstar Ltd. + * + * Authors: Haylen Chu <[email protected]> + */ + +#ifndef _CLK_PLL_H_ +#define _CLK_PLL_H_ + +#include <linux/clk-provider.h> + +#include "clk_common.h" + +/** + * struct ccu_pll_rate_tbl - Structure mapping between PLL rate and register + * configuration. + * + * @rate: PLL rate + * @swcr1: Register value of PLLX_SW1_CTRL (PLLx_SWCR1). + * @swcr3: Register value of the PLLx_SW3_CTRL's lowest 31 bits of + * PLLx_SW3_CTRL (PLLx_SWCR3). This highest bit is for enabling + * the PLL and not contained in this field. + */ +struct ccu_pll_rate_tbl { + unsigned long rate; + u32 swcr1; + u32 swcr3; +}; + +#define CCU_PLL_RATE(_rate, _swcr1, _swcr3) \ + { \ + .rate = _rate, \ + .swcr1 = _swcr1, \ + .swcr3 = _swcr3, \ + } + +struct ccu_pll_config { + const struct ccu_pll_rate_tbl *rate_tbl; + u32 tbl_num; + u32 reg_lock; + u32 mask_lock; +}; + +struct ccu_pll { + struct ccu_common common; + struct ccu_pll_config config; +}; + +#define CCU_PLL_CONFIG(_table, _reg_lock, _mask_lock) \ + { \ + .rate_tbl = (_table), \ + .tbl_num = sizeof(_table) / sizeof((_table)[0]), \ + .reg_lock = (_reg_lock), \ + .mask_lock = (_mask_lock), \ + } + +#define CCU_PLL_DEFINE(_id, _var, _name, _parent, _table, _reg_swcr1, \ + _reg_swcr3, _reg_lock, _mask_lock, _flags) \ +static struct ccu_pll _var = { \ + .config = CCU_PLL_CONFIG(_table, _reg_lock, _mask_lock), \ + .common = { \ + .reg_swcr1 = _reg_swcr1, \ + .reg_swcr3 = _reg_swcr3, \ + CCU_COMMON(_id, _name, _parent, spacemit_pll_init, _flags) \ + } \ +} + +static inline struct ccu_pll *clk_to_ccu_pll(struct clk *clk) +{ + struct ccu_common *common = clk_to_ccu_common(clk); + + return container_of(common, struct ccu_pll, common); +} + +int spacemit_pll_init(struct ccu_common *common); + +#endif /* _CLK_PLL_H_ */ diff --git a/drivers/clk/stm32/Kconfig b/drivers/clk/stm32/Kconfig index 4e488136eac..e63385d3051 100644 --- a/drivers/clk/stm32/Kconfig +++ b/drivers/clk/stm32/Kconfig @@ -49,7 +49,7 @@ config CLK_STM32MP21 config CLK_STM32MP25 bool "Enable RCC clock driver for STM32MP25" depends on ARCH_STM32MP && CLK - default y if STM32MP25X + default y if STM32MP23X || STM32MP25X select CLK_STM32_CORE help Enable the STM32 clock (RCC) driver. Enable support for diff --git a/drivers/clk/sunxi/clk_sunxi.c b/drivers/clk/sunxi/clk_sunxi.c index 842a0541bd6..046d5d1605a 100644 --- a/drivers/clk/sunxi/clk_sunxi.c +++ b/drivers/clk/sunxi/clk_sunxi.c @@ -64,7 +64,7 @@ static int sunxi_clk_disable(struct clk *clk) return sunxi_set_gate(clk, false); } -struct clk_ops sunxi_clk_ops = { +static const struct clk_ops sunxi_clk_ops = { .enable = sunxi_clk_enable, .disable = sunxi_clk_disable, }; diff --git a/drivers/clk/ti/clk-ctrl.c b/drivers/clk/ti/clk-ctrl.c index c5c97dc35c4..e3564277982 100644 --- a/drivers/clk/ti/clk-ctrl.c +++ b/drivers/clk/ti/clk-ctrl.c @@ -8,7 +8,11 @@ #include <dm.h> #include <dm/device_compat.h> #include <clk-uclass.h> -#include <asm/arch-am33xx/clock.h> +#include <asm/ti-common/omap_clock.h> +#include <asm/io.h> +#include <linux/iopoll.h> + +#define LDELAY 1000000 struct clk_ti_ctrl_offs { fdt_addr_t start; @@ -33,10 +37,66 @@ static int clk_ti_ctrl_check_offs(struct clk *clk, fdt_addr_t offs) return -EFAULT; } +#define IDLEST_DISABLED (MODULE_CLKCTRL_IDLEST_DISABLED << MODULE_CLKCTRL_IDLEST_SHIFT) +#define IDLEST_TRANSITION (MODULE_CLKCTRL_IDLEST_TRANSITIONING << MODULE_CLKCTRL_IDLEST_SHIFT) +static inline void wait_for_clk_disable(u32 addr) +{ + u32 bound = LDELAY; + int val = 0; + + while ((val & MODULE_CLKCTRL_IDLEST_MASK) != IDLEST_DISABLED) { + val = readl(addr); + + if (--bound == 0) { + printf("Clock disable failed for 0x%x idlest 0x%x\n", + addr, val); + return; + } + } +} + +static int clk_ti_ctrl_disable_clock_module(u32 addr) +{ + clrsetbits_le32(addr, MODULE_CLKCTRL_MODULEMODE_MASK, + MODULE_CLKCTRL_MODULEMODE_SW_DISABLE << + MODULE_CLKCTRL_MODULEMODE_SHIFT); + + wait_for_clk_disable(addr); + + return 0; +} + +static inline void wait_for_clk_enable(u32 addr) +{ + int val = IDLEST_DISABLED; + u32 bound = LDELAY; + + while (((val & MODULE_CLKCTRL_IDLEST_MASK) == IDLEST_DISABLED) || + ((val & MODULE_CLKCTRL_IDLEST_MASK) == IDLEST_TRANSITION)) { + val = readl(addr); + + if (--bound == 0) { + printf("Clock enable failed for 0x%x idlest 0x%x\n", + addr, val); + return; + } + } +} + +static int clk_ti_ctrl_enable_clock_module(u32 addr) +{ + clrsetbits_le32(addr, MODULE_CLKCTRL_MODULEMODE_MASK, + MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN << + MODULE_CLKCTRL_MODULEMODE_SHIFT); + + wait_for_clk_enable(addr); + + return 0; +} + static int clk_ti_ctrl_disable(struct clk *clk) { struct clk_ti_ctrl_priv *priv = dev_get_priv(clk->dev); - u32 *clk_modules[2] = { }; fdt_addr_t offs; int err; @@ -47,16 +107,13 @@ static int clk_ti_ctrl_disable(struct clk *clk) return err; } - clk_modules[0] = (u32 *)(offs); - dev_dbg(clk->dev, "disable module @ %p\n", clk_modules[0]); - do_disable_clocks(NULL, clk_modules, 1); - return 0; + dev_dbg(clk->dev, "disable module @ %x\n", offs); + return clk_ti_ctrl_disable_clock_module(offs); } static int clk_ti_ctrl_enable(struct clk *clk) { struct clk_ti_ctrl_priv *priv = dev_get_priv(clk->dev); - u32 *clk_modules[2] = { }; fdt_addr_t offs; int err; @@ -67,10 +124,8 @@ static int clk_ti_ctrl_enable(struct clk *clk) return err; } - clk_modules[0] = (u32 *)(offs); - dev_dbg(clk->dev, "enable module @ %p\n", clk_modules[0]); - do_enable_clocks(NULL, clk_modules, 1); - return 0; + dev_dbg(clk->dev, "enable module @ %x\n", offs); + return clk_ti_ctrl_enable_clock_module(offs); } static ulong clk_ti_ctrl_get_rate(struct clk *clk) diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 5419bf65b5d..ae0c3466772 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -337,11 +337,19 @@ config SIMPLE_BUS_CORRECT_RANGE config SIMPLE_PM_BUS bool "Support simple-pm-bus driver" - depends on DM && OF_CONTROL && CLK && POWER_DOMAIN + depends on DM && OF_CONTROL && POWER_DOMAIN help Supports the 'simple-pm-bus' driver, which is used for busses that have power domains and/or clocks which need to be enabled before use. +config SPL_SIMPLE_PM_BUS + bool "Support simple-pm-bus driver in SPL" + depends on SPL_DM && SPL_OF_CONTROL && SPL_POWER_DOMAIN + help + Supports the 'simple-pm-bus' driver, which is used for busses that + have power domains and/or clocks which need to be enabled before use, + in SPL. + config OF_TRANSLATE bool "Translate addresses using fdt_translate_address" depends on DM && OF_CONTROL diff --git a/drivers/core/Makefile b/drivers/core/Makefile index a549890c22b..1073c26b2ed 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_$(PHASE_)ACPIGEN) += acpi.o obj-$(CONFIG_$(PHASE_)DEVRES) += devres.o obj-$(CONFIG_$(PHASE_)DM_DEVICE_REMOVE) += device-remove.o obj-$(CONFIG_$(PHASE_)SIMPLE_BUS) += simple-bus.o -obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o +obj-$(CONFIG_$(PHASE_)SIMPLE_PM_BUS) += simple-pm-bus.o obj-$(CONFIG_DM) += dump.o obj-$(CONFIG_$(PHASE_)REGMAP) += regmap.o obj-$(CONFIG_$(PHASE_)SYSCON) += syscon-uclass.o diff --git a/drivers/core/acpi.c b/drivers/core/acpi.c index 4763963914b..284fb70b036 100644 --- a/drivers/core/acpi.c +++ b/drivers/core/acpi.c @@ -87,7 +87,7 @@ int acpi_copy_name(char *out_name, const char *name) int acpi_get_name(const struct udevice *dev, char *out_name) { - struct acpi_ops *aops; + const struct acpi_ops *aops; const char *name; int ret; @@ -154,10 +154,9 @@ static int add_item(struct acpi_ctx *ctx, struct udevice *dev, if (!item->size) return 0; if (type != TYPE_OTHER) { - item->buf = malloc(item->size); + item->buf = memdup(start, item->size); if (!item->buf) return log_msg_ret("mem", -ENOMEM); - memcpy(item->buf, start, item->size); } item_count++; log_debug("* %s: Added type %d, %p, size %x\n", @@ -276,7 +275,7 @@ static int sort_acpi_item_type(struct acpi_ctx *ctx, void *start, acpi_method acpi_get_method(struct udevice *dev, enum method_t method) { - struct acpi_ops *aops; + const struct acpi_ops *aops; aops = device_get_acpi_ops(dev); if (aops) { diff --git a/drivers/core/device.c b/drivers/core/device.c index d365204ba11..6024534ff93 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -1147,6 +1147,8 @@ int device_set_name(struct udevice *dev, const char *name) name = strdup(name); if (!name) return -ENOMEM; + if (dev_get_flags(dev) & DM_FLAG_NAME_ALLOCED) + free((char *)dev->name); dev->name = name; device_set_name_alloced(dev); diff --git a/drivers/core/of_access.c b/drivers/core/of_access.c index b11e36202c1..f910cc9a31b 100644 --- a/drivers/core/of_access.c +++ b/drivers/core/of_access.c @@ -598,6 +598,25 @@ int of_read_u64(const struct device_node *np, const char *propname, u64 *outp) return of_read_u64_index(np, propname, 0, outp); } +int of_read_u64_array(const struct device_node *np, const char *propname, + u64 *out_values, size_t sz) +{ + const __be64 *val; + + log_debug("%s: %s: ", __func__, propname); + val = of_find_property_value_of_size(np, propname, + sz * sizeof(*out_values)); + + if (IS_ERR(val)) + return PTR_ERR(val); + + log_debug("size %zd\n", sz); + while (sz--) + *out_values++ = be64_to_cpup(val++); + + return 0; +} + int of_property_match_string(const struct device_node *np, const char *propname, const char *string) { @@ -845,6 +864,39 @@ int of_count_phandle_with_args(const struct device_node *np, cell_count); } +/** + * of_property_count_elems_of_size - Count the number of elements in a property + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @elem_size: size of the individual element + * + * Search for a property in a device node and count the number of elements of + * size elem_size in it. + * + * Return: The number of elements on sucess, -EINVAL if the property does not + * exist or its length does not match a multiple of elem_size and -ENODATA if + * the property does not have a value. + */ +int of_property_count_elems_of_size(const struct device_node *np, + const char *propname, int elem_size) +{ + const struct property *prop = of_find_property(np, propname, NULL); + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + if (prop->length % elem_size != 0) { + pr_err("size of %s in node %pOF is not a multiple of %d\n", + propname, np, elem_size); + return -EINVAL; + } + + return prop->length / elem_size; +} + static void of_alias_add(struct alias_prop *ap, struct device_node *np, int id, const char *stem, int stem_len) { @@ -1019,7 +1071,7 @@ int of_add_subnode(struct device_node *parent, const char *name, int len, * make sure we don't use a child called "trevor" when we are * searching for "trev". */ - if (!strncmp(child->name, name, len) && strlen(name) == len) { + if (!strncmp(child->name, name, len) && strlen(child->name) == len) { *childp = child; return -EEXIST; } diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 3a36b6fdd03..b5d13c43db1 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -130,8 +130,10 @@ int oftree_new(oftree *treep) if (!fdt) return log_msg_ret("fla", -ENOMEM); ret = fdt_create_empty_tree(fdt, size); - if (ret) + if (ret) { + free(fdt); return log_msg_ret("fla", -EINVAL); + } oftree_list[oftree_count++] = fdt; tree.fdt = fdt; } @@ -664,6 +666,54 @@ int ofnode_read_u32_array(ofnode node, const char *propname, } } +int ofnode_read_u64_array(ofnode node, const char *propname, + u64 *out_values, size_t sz) +{ + assert(ofnode_valid(node)); + log_debug("%s: %s: ", __func__, propname); + + if (ofnode_is_np(node)) { + return of_read_u64_array(ofnode_to_np(node), propname, + out_values, sz); + } else { + int ret; + + ret = fdtdec_get_long_array(ofnode_to_fdt(node), + ofnode_to_offset(node), propname, + out_values, sz); + + /* get the error right, but space is more important in SPL */ + if (!IS_ENABLED(CONFIG_XPL_BUILD)) { + if (ret == -FDT_ERR_NOTFOUND) + return -EINVAL; + else if (ret == -FDT_ERR_BADLAYOUT) + return -EOVERFLOW; + } + return ret; + } +} + +int ofnode_count_elems_of_size(ofnode node, const char *propname, int elem_size) +{ + const char *prop; + int len; + assert(ofnode_valid(node)); + + if (ofnode_is_np(node)) { + return of_property_count_elems_of_size(node.np, propname, elem_size); + } else { + prop = fdt_getprop(ofnode_to_fdt(node), ofnode_to_offset(node), propname, &len); + if (!prop) + return -ENOENT; + if (len % elem_size != 0) { + log_debug("size of %s in node %pOF is not a multiple of %d\n", + propname, &node, elem_size); + return -EINVAL; + } + return len / elem_size; + } +} + #if !CONFIG_IS_ENABLED(DM_INLINE_OFNODE) bool ofnode_is_enabled(ofnode node) { @@ -1750,10 +1800,9 @@ int ofnode_write_prop(ofnode node, const char *propname, const void *value, void *newval; if (copy) { - newval = malloc(len); + newval = memdup(value, len); if (!newval) return log_ret(-ENOMEM); - memcpy(newval, value, len); value = newval; } ret = of_write_prop(ofnode_to_np(node), propname, len, value); diff --git a/drivers/core/read.c b/drivers/core/read.c index c0d7a969db2..ba48862f44b 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -132,12 +132,14 @@ fdt_addr_t dev_read_addr_index(const struct udevice *dev, int index) void *dev_read_addr_index_ptr(const struct udevice *dev, int index) { - fdt_addr_t addr = dev_read_addr_index(dev, index); + fdt_addr_t addr; + fdt_size_t size = 0; + addr = dev_read_addr_size_index(dev, index, &size); if (addr == FDT_ADDR_T_NONE) return NULL; - return map_sysmem(addr, 0); + return map_sysmem(addr, size); } fdt_addr_t dev_read_addr_size_index(const struct udevice *dev, int index, @@ -157,17 +159,19 @@ void *dev_read_addr_size_index_ptr(const struct udevice *dev, int index, if (addr == FDT_ADDR_T_NONE) return NULL; - return map_sysmem(addr, 0); + return map_sysmem(addr, *size); } void *dev_remap_addr_index(const struct udevice *dev, int index) { - fdt_addr_t addr = dev_read_addr_index(dev, index); + fdt_addr_t addr; + fdt_size_t size = 0; + addr = dev_read_addr_size_index(dev, index, &size); if (addr == FDT_ADDR_T_NONE) return NULL; - return map_physmem(addr, 0, MAP_NOCACHE); + return map_physmem(addr, size, MAP_NOCACHE); } fdt_addr_t dev_read_addr_name(const struct udevice *dev, const char *name) @@ -182,12 +186,14 @@ fdt_addr_t dev_read_addr_name(const struct udevice *dev, const char *name) void *dev_read_addr_name_ptr(const struct udevice *dev, const char *name) { - fdt_addr_t addr = dev_read_addr_name(dev, name); + fdt_addr_t addr; + fdt_size_t size = 0; + addr = dev_read_addr_size_name(dev, name, &size); if (addr == FDT_ADDR_T_NONE) return NULL; - return map_sysmem(addr, 0); + return map_sysmem(addr, size); } fdt_addr_t dev_read_addr_size_name(const struct udevice *dev, const char *name, @@ -209,17 +215,19 @@ void *dev_read_addr_size_name_ptr(const struct udevice *dev, const char *name, if (addr == FDT_ADDR_T_NONE) return NULL; - return map_sysmem(addr, 0); + return map_sysmem(addr, *size); } void *dev_remap_addr_name(const struct udevice *dev, const char *name) { - fdt_addr_t addr = dev_read_addr_name(dev, name); + fdt_addr_t addr; + fdt_size_t size = 0; + addr = dev_read_addr_size_name(dev, name, &size); if (addr == FDT_ADDR_T_NONE) return NULL; - return map_physmem(addr, 0, MAP_NOCACHE); + return map_physmem(addr, size, MAP_NOCACHE); } fdt_addr_t dev_read_addr(const struct udevice *dev) @@ -229,12 +237,14 @@ fdt_addr_t dev_read_addr(const struct udevice *dev) void *dev_read_addr_ptr(const struct udevice *dev) { - fdt_addr_t addr = dev_read_addr(dev); + fdt_addr_t addr; + fdt_size_t size = 0; + addr = dev_read_addr_size(dev, &size); if (addr == FDT_ADDR_T_NONE) return NULL; - return map_sysmem(addr, 0); + return map_sysmem(addr, size); } void *dev_remap_addr(const struct udevice *dev) diff --git a/drivers/core/root.c b/drivers/core/root.c index d43645f34dd..2aa16d59b69 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -81,10 +81,9 @@ static int dm_setup_inst(void) /* Now allocate space for the priv/plat data, and copy it in */ size = __priv_data_end - __priv_data_start; - base = calloc(1, size); + base = memdup(__priv_data_start, size); if (!base) return log_msg_ret("priv", -ENOMEM); - memcpy(base, __priv_data_start, size); gd_set_dm_priv_base(base); } @@ -460,7 +459,7 @@ static int root_acpi_get_name(const struct udevice *dev, char *out_name) return acpi_copy_name(out_name, "\\_SB"); } -struct acpi_ops root_acpi_ops = { +static const struct acpi_ops root_acpi_ops = { .get_name = root_acpi_get_name, }; #endif diff --git a/drivers/core/tag.c b/drivers/core/tag.c index a3c5cb7e57c..78b5ee6dc07 100644 --- a/drivers/core/tag.c +++ b/drivers/core/tag.c @@ -46,7 +46,7 @@ int dev_tag_set_ptr(struct udevice *dev, enum dm_tag_t tag, void *ptr) return -EEXIST; } - node = calloc(sizeof(*node), 1); + node = calloc(1, sizeof(*node)); if (!node) return -ENOMEM; @@ -70,7 +70,7 @@ int dev_tag_set_val(struct udevice *dev, enum dm_tag_t tag, ulong val) return -EEXIST; } - node = calloc(sizeof(*node), 1); + node = calloc(1, sizeof(*node)); if (!node) return -ENOMEM; diff --git a/drivers/cpu/armv8_cpu.c b/drivers/cpu/armv8_cpu.c index 4eedfe5e2c5..337661c23a8 100644 --- a/drivers/cpu/armv8_cpu.c +++ b/drivers/cpu/armv8_cpu.c @@ -124,7 +124,7 @@ int armv8_cpu_fill_madt(const struct udevice *dev, struct acpi_ctx *ctx) return 0; } -struct acpi_ops armv8_cpu_acpi_ops = { +static const struct acpi_ops armv8_cpu_acpi_ops = { .fill_ssdt = armv8_cpu_fill_ssdt, .fill_madt = armv8_cpu_fill_madt, }; diff --git a/drivers/cpu/bcm283x_cpu.c b/drivers/cpu/bcm283x_cpu.c index ad638cd8fff..43e74d1811b 100644 --- a/drivers/cpu/bcm283x_cpu.c +++ b/drivers/cpu/bcm283x_cpu.c @@ -193,7 +193,7 @@ static int bcm_cpu_probe(struct udevice *dev) return ret; } -struct acpi_ops bcm283x_cpu_acpi_ops = { +static const struct acpi_ops __maybe_unused bcm283x_cpu_acpi_ops = { .fill_ssdt = armv8_cpu_fill_ssdt, .fill_madt = armv8_cpu_fill_madt, }; diff --git a/drivers/cpu/imx8_cpu.c b/drivers/cpu/imx8_cpu.c index 785c299eca5..7bb7b420176 100644 --- a/drivers/cpu/imx8_cpu.c +++ b/drivers/cpu/imx8_cpu.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright 2019, 2024 NXP + * Copyright 2019, 2024-2026 NXP */ #include <cpu.h> @@ -28,8 +28,18 @@ struct cpu_imx_plat { u32 mpidr; }; +__weak const char *get_cpu_variant_type_name(u32 type) +{ + return NULL; +} + static const char *get_imx_type_str(u32 imxtype) { + const char *name = get_cpu_variant_type_name(imxtype); + + if (name) + return name; + switch (imxtype) { case MXC_CPU_IMX8MM: return "8MMQ"; /* Quad-core version of the imx8mm */ @@ -63,12 +73,18 @@ static const char *get_imx_type_str(u32 imxtype) return "8MNano UltraLite Solo";/* Single-core UltraLite version of the imx8mn */ case MXC_CPU_IMX8MP: return "8MP[8]"; /* Quad-core version of the imx8mp */ + case MXC_CPU_IMX8MPD2: + return "8MP Dual[2]"; /* Dual-core version of the imx8mp, low cost industrial & HMI */ case MXC_CPU_IMX8MPD: return "8MP Dual[3]"; /* Dual-core version of the imx8mp */ case MXC_CPU_IMX8MPL: return "8MP Lite[4]"; /* Quad-core Lite version of the imx8mp */ + case MXC_CPU_IMX8MP5: + return "8MP[5]"; /* Quad-core version of the imx8mp, low cost industrial & HMI */ case MXC_CPU_IMX8MP6: return "8MP[6]"; /* Quad-core version of the imx8mp, NPU fused */ + case MXC_CPU_IMX8MPUL: + return "8MP UltraLite"; /* Quad-core UltraLite version of the imx8mp */ case MXC_CPU_IMX8MQ: return "8MQ"; /* Quad-core version of the imx8mq */ case MXC_CPU_IMX8MQL: @@ -222,7 +238,7 @@ static int cpu_imx_get_desc(const struct udevice *dev, char *buf, int size) ret = snprintf(buf, size, "NXP i.MX%s Rev%s %s at %u MHz", plat->type, plat->rev, plat->name, plat->freq_mhz); - if (IS_ENABLED(CONFIG_IMX_TMU)) { + if (!IS_ENABLED(CONFIG_IMX8)) { /* imx8 does not have segment fuse */ switch (get_cpu_temp_grade(&minc, &maxc)) { case TEMP_AUTOMOTIVE: grade = "Automotive temperature grade"; @@ -231,7 +247,10 @@ static int cpu_imx_get_desc(const struct udevice *dev, char *buf, int size) grade = "Industrial temperature grade"; break; case TEMP_EXTCOMMERCIAL: - grade = "Extended Consumer temperature grade"; + if (IS_ENABLED(CONFIG_ARCH_IMX9)) + grade = "Extended Industrial temperature grade"; + else + grade = "Extended Consumer temperature grade"; break; default: grade = "Consumer temperature grade"; @@ -371,6 +390,7 @@ static int imx_cpu_probe(struct udevice *dev) { struct cpu_imx_plat *plat = dev_get_plat(dev); u32 cpurev; + fdt_addr_t addr; set_core_data(dev); cpurev = get_cpu_rev(); @@ -378,12 +398,14 @@ static int imx_cpu_probe(struct udevice *dev) get_imx_rev_str(plat, cpurev & 0xFFF); plat->type = get_imx_type_str((cpurev & 0x1FF000) >> 12); plat->freq_mhz = imx_get_cpu_rate(dev) / 1000000; - plat->mpidr = dev_read_addr(dev); - if (plat->mpidr == FDT_ADDR_T_NONE) { + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) { printf("%s: Failed to get CPU reg property\n", __func__); return -EINVAL; } + plat->mpidr = (u32)addr; + return 0; } diff --git a/drivers/crypto/aspeed/Kconfig b/drivers/crypto/aspeed/Kconfig index 401225b8528..a4710257f62 100644 --- a/drivers/crypto/aspeed/Kconfig +++ b/drivers/crypto/aspeed/Kconfig @@ -15,11 +15,11 @@ config ASPEED_ACRY bool "ASPEED RSA and ECC Engine" depends on ASPEED_AST2600 help - Select this option to enable a driver for using the RSA/ECC engine in - the ASPEED BMC SoCs. + Select this option to enable a driver for using the RSA/ECC engine in + the ASPEED BMC SoCs. - Enabling this allows the use of RSA/ECC operations in hardware without requiring the - software implementations. It also improves performance and saves code size. + Enabling this allows the use of RSA/ECC operations in hardware without requiring the + software implementations. It also improves performance and saves code size. config ASPEED_CPTRA_SHA bool "Caliptra SHA ACC for Aspeed AST27xx SoCs" diff --git a/drivers/crypto/aspeed/aspeed_acry.c b/drivers/crypto/aspeed/aspeed_acry.c index e3f81ebd5c7..ff01256e150 100644 --- a/drivers/crypto/aspeed/aspeed_acry.c +++ b/drivers/crypto/aspeed/aspeed_acry.c @@ -144,13 +144,13 @@ static int aspeed_acry_probe(struct udevice *dev) return ret; } - acry->base = devfdt_get_addr_index(dev, 0); + acry->base = dev_read_addr_index(dev, 0); if (acry->base == FDT_ADDR_T_NONE) { debug("Failed to get acry base\n"); return acry->base; } - acry->sram_base = devfdt_get_addr_index(dev, 1); + acry->sram_base = dev_read_addr_index(dev, 1); if (acry->sram_base == FDT_ADDR_T_NONE) { debug("Failed to get acry SRAM base\n"); return acry->sram_base; diff --git a/drivers/crypto/aspeed/aspeed_hace.c b/drivers/crypto/aspeed/aspeed_hace.c index 17cc30a7b54..22b5008a296 100644 --- a/drivers/crypto/aspeed/aspeed_hace.c +++ b/drivers/crypto/aspeed/aspeed_hace.c @@ -341,7 +341,7 @@ static int aspeed_hace_probe(struct udevice *dev) return rc; } - hace->base = devfdt_get_addr(dev); + hace->base = dev_read_addr(dev); return rc; } diff --git a/drivers/crypto/aspeed/cptra_ecdsa.c b/drivers/crypto/aspeed/cptra_ecdsa.c index 4b70d89def7..7603ca373ff 100644 --- a/drivers/crypto/aspeed/cptra_ecdsa.c +++ b/drivers/crypto/aspeed/cptra_ecdsa.c @@ -149,7 +149,7 @@ static int cptra_ecdsa_probe(struct udevice *dev) { struct cptra_ecdsa *ce = dev_get_priv(dev); - ce->regs = (void *)devfdt_get_addr(dev); + ce->regs = (void *)dev_read_addr(dev); if (ce->regs == (void *)FDT_ADDR_T_NONE) { debug("cannot map Caliptra mailbox registers\n"); return -EINVAL; diff --git a/drivers/crypto/aspeed/cptra_sha.c b/drivers/crypto/aspeed/cptra_sha.c index 26b97bdd92b..f57778e160d 100644 --- a/drivers/crypto/aspeed/cptra_sha.c +++ b/drivers/crypto/aspeed/cptra_sha.c @@ -219,7 +219,7 @@ static int cptra_sha_probe(struct udevice *dev) { struct cptra_sha *cs = dev_get_priv(dev); - cs->regs = (void *)devfdt_get_addr(dev); + cs->regs = (void *)dev_read_addr(dev); if (cs->regs == (void *)FDT_ADDR_T_NONE) { debug("cannot map Caliptra SHA ACC registers\n"); return -ENODEV; diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig index eb01c6cf700..244a9bd905d 100644 --- a/drivers/crypto/fsl/Kconfig +++ b/drivers/crypto/fsl/Kconfig @@ -20,6 +20,7 @@ config SYS_FSL_MAX_NUM_OF_SEC config CAAM_64BIT bool + depends on FSL_CAAM default y if PHYS_64BIT && !ARCH_IMX8M && !ARCH_IMX8 help Select Crypto driver for 64 bits CAAM version @@ -27,27 +28,27 @@ config CAAM_64BIT config SYS_FSL_HAS_SEC bool help - Enable Freescale Secure Boot and Trusted Architecture + Enable Freescale Secure Boot and Trusted Architecture config SYS_FSL_SEC_COMPAT_2 bool help - Secure boot and trust architecture compatible version 2 + Secure boot and trust architecture compatible version 2 config SYS_FSL_SEC_COMPAT_4 bool help - Secure boot and trust architecture compatible version 4 + Secure boot and trust architecture compatible version 4 config SYS_FSL_SEC_COMPAT_5 bool help - Secure boot and trust architecture compatible version 5 + Secure boot and trust architecture compatible version 5 config SYS_FSL_SEC_COMPAT_6 bool help - Secure boot and trust architecture compatible version 6 + Secure boot and trust architecture compatible version 6 config SYS_FSL_SEC_BE bool "Big-endian access to Freescale Secure Boot" diff --git a/drivers/crypto/tegra/tegra_aes.c b/drivers/crypto/tegra/tegra_aes.c index 7b374c757ba..55a4cec525b 100644 --- a/drivers/crypto/tegra/tegra_aes.c +++ b/drivers/crypto/tegra/tegra_aes.c @@ -518,7 +518,7 @@ static int tegra_aes_probe(struct udevice *dev) return -EINVAL; } - priv->iram_addr = devfdt_get_addr_size_name_ptr(dev, "iram-buffer", &iram_size); + priv->iram_addr = dev_read_addr_size_name_ptr(dev, "iram-buffer", &iram_size); if (!priv->iram_addr) { log_debug("%s: Cannot find iram buffer address, binding failed\n", __func__); return -EINVAL; diff --git a/drivers/ddr/altera/sdram_agilex.c b/drivers/ddr/altera/sdram_agilex.c index b36a765a5de..2d2b72cf766 100644 --- a/drivers/ddr/altera/sdram_agilex.c +++ b/drivers/ddr/altera/sdram_agilex.c @@ -104,7 +104,7 @@ int sdram_mmr_init_full(struct udevice *dev) /* Get bank configuration from devicetree */ ret = fdtdec_decode_ram_size(gd->fdt_blob, NULL, 0, NULL, - (phys_size_t *)&gd->ram_size, &bd); + (phys_size_t *)&gd->ram_size, gd); if (ret) { puts("DDR: Failed to decode memory node\n"); return -ENXIO; @@ -158,7 +158,7 @@ int sdram_mmr_init_full(struct udevice *dev) sdram_set_firewall(&bd); - priv->info.base = bd.bi_dram[0].start; + priv->info.base = gd->dram[0].start; priv->info.size = gd->ram_size; debug("DDR: HMC init success\n"); diff --git a/drivers/ddr/altera/sdram_agilex5.c b/drivers/ddr/altera/sdram_agilex5.c index ee66c72157a..d14e4bc5dcc 100644 --- a/drivers/ddr/altera/sdram_agilex5.c +++ b/drivers/ddr/altera/sdram_agilex5.c @@ -302,7 +302,7 @@ int sdram_mmr_init_full(struct udevice *dev) /* Get bank configuration from devicetree */ ret = fdtdec_decode_ram_size(gd->fdt_blob, NULL, 0, NULL, - (phys_size_t *)&gd->ram_size, gd->bd); + (phys_size_t *)&gd->ram_size, gd); if (ret) { puts("DDR: Failed to decode memory node\n"); ret = -ENXIO; @@ -345,19 +345,19 @@ int sdram_mmr_init_full(struct udevice *dev) for (i = 0; i < config_dram_banks; i++) { remaining_size = hw_size - size_counter; if (remaining_size <= dram_bank_info[i].max_size) { - gd->bd->bi_dram[i].start = dram_bank_info[i].start; - gd->bd->bi_dram[i].size = remaining_size; + gd->dram[i].start = dram_bank_info[i].start; + gd->dram[i].size = remaining_size; debug("Memory bank[%d] Starting address: 0x%llx size: 0x%llx\n", - i, gd->bd->bi_dram[i].start, gd->bd->bi_dram[i].size); + i, gd->dram[i].start, gd->dram[i].size); break; } - gd->bd->bi_dram[i].start = dram_bank_info[i].start; - gd->bd->bi_dram[i].size = dram_bank_info[i].max_size; + gd->dram[i].start = dram_bank_info[i].start; + gd->dram[i].size = dram_bank_info[i].max_size; debug("Memory bank[%d] Starting address: 0x%llx size: 0x%llx\n", - i, gd->bd->bi_dram[i].start, gd->bd->bi_dram[i].size); - size_counter += gd->bd->bi_dram[i].size; + i, gd->dram[i].start, gd->dram[i].size); + size_counter += gd->dram[i].size; } gd->ram_size = hw_size; @@ -408,7 +408,7 @@ int sdram_mmr_init_full(struct udevice *dev) printf("DDR: firewall init success\n"); - priv->info.base = gd->bd->bi_dram[0].start; + priv->info.base = gd->dram[0].start; priv->info.size = gd->ram_size; /* Ending DDR driver initialization success tracking */ diff --git a/drivers/ddr/altera/sdram_agilex7m.c b/drivers/ddr/altera/sdram_agilex7m.c index 9b3cc5c7b86..e4d522202d8 100644 --- a/drivers/ddr/altera/sdram_agilex7m.c +++ b/drivers/ddr/altera/sdram_agilex7m.c @@ -375,7 +375,7 @@ int sdram_mmr_init_full(struct udevice *dev) /* Get bank configuration from devicetree */ ret = fdtdec_decode_ram_size(gd->fdt_blob, NULL, 0, NULL, - (phys_size_t *)&gd->ram_size, &bd); + (phys_size_t *)&gd->ram_size, gd); if (ret) { printf("%s: Failed to decode memory node\n", memory_type_in_use(dev)); @@ -484,7 +484,7 @@ int sdram_mmr_init_full(struct udevice *dev) printf("%s: firewall init success\n", (is_ddr_in_use(dev) ? io96b_ctrl->ddr_type : "HBM")); - priv->info.base = bd.bi_dram[0].start; + priv->info.base = gd->dram[0].start; priv->info.size = gd->ram_size; /* Ending DDR driver initialization success tracking */ diff --git a/drivers/ddr/altera/sdram_arria10.c b/drivers/ddr/altera/sdram_arria10.c index c281f711fdf..9cc809b8001 100644 --- a/drivers/ddr/altera/sdram_arria10.c +++ b/drivers/ddr/altera/sdram_arria10.c @@ -674,9 +674,9 @@ static void sdram_size_check(void) debug("DDR: Running SDRAM size sanity check\n"); - ram_check = get_ram_size((long *)gd->bd->bi_dram[0].start, - gd->bd->bi_dram[0].size); - if (ram_check != gd->bd->bi_dram[0].size) { + ram_check = get_ram_size((long *)gd->dram[0].start, + gd->dram[0].size); + if (ram_check != gd->dram[0].size) { puts("DDR: SDRAM size check failed!\n"); hang(); } @@ -719,14 +719,14 @@ int ddr_calibration_sequence(void) /* setup the dram info within bd */ dram_init_banksize(); - if (gd->ram_size != gd->bd->bi_dram[0].size) { + if (gd->ram_size != gd->dram[0].size) { printf("DDR: Warning: DRAM size from device tree (%ld MiB)\n", - gd->bd->bi_dram[0].size >> 20); + gd->dram[0].size >> 20); printf(" mismatch with hardware (%ld MiB).\n", gd->ram_size >> 20); } - if (gd->bd->bi_dram[0].size > gd->ram_size) { + if (gd->dram[0].size > gd->ram_size) { printf("DDR: Error: DRAM size from device tree is greater\n"); printf(" than hardware size.\n"); hang(); diff --git a/drivers/ddr/altera/sdram_n5x.c b/drivers/ddr/altera/sdram_n5x.c index 17ec6afa82b..900d4f59989 100644 --- a/drivers/ddr/altera/sdram_n5x.c +++ b/drivers/ddr/altera/sdram_n5x.c @@ -2279,7 +2279,7 @@ int sdram_mmr_init_full(struct udevice *dev) /* Get bank configuration from devicetree */ ret = fdtdec_decode_ram_size(gd->fdt_blob, NULL, 0, NULL, - (phys_size_t *)&gd->ram_size, &bd); + (phys_size_t *)&gd->ram_size, gd); if (ret) { debug("%s: Failed to decode memory node\n", __func__); return -1; @@ -2287,7 +2287,7 @@ int sdram_mmr_init_full(struct udevice *dev) printf("DDR: %lld MiB\n", gd->ram_size >> 20); - priv->info.base = bd.bi_dram[0].start; + priv->info.base = gd->dram[0].start; priv->info.size = gd->ram_size; sdram_size_check(&bd); diff --git a/drivers/ddr/altera/sdram_s10.c b/drivers/ddr/altera/sdram_s10.c index 4ac4c79e0ac..6664090f86a 100644 --- a/drivers/ddr/altera/sdram_s10.c +++ b/drivers/ddr/altera/sdram_s10.c @@ -285,7 +285,7 @@ int sdram_mmr_init_full(struct udevice *dev) /* Get bank configuration from devicetree */ ret = fdtdec_decode_ram_size(gd->fdt_blob, NULL, 0, NULL, - (phys_size_t *)&gd->ram_size, &bd); + (phys_size_t *)&gd->ram_size, gd); if (ret) { puts("DDR: Failed to decode memory node\n"); return -1; @@ -328,7 +328,7 @@ int sdram_mmr_init_full(struct udevice *dev) sdram_size_check(&bd); - priv->info.base = bd.bi_dram[0].start; + priv->info.base = gd->dram[0].start; priv->info.size = gd->ram_size; debug("DDR: HMC init success\n"); diff --git a/drivers/ddr/altera/sdram_soc64.c b/drivers/ddr/altera/sdram_soc64.c index 8ee7049b164..93df3d1812a 100644 --- a/drivers/ddr/altera/sdram_soc64.c +++ b/drivers/ddr/altera/sdram_soc64.c @@ -150,8 +150,8 @@ void sdram_init_ecc_bits(struct bd_info *bd) icache_enable(); - start_addr = bd->bi_dram[0].start; - size = bd->bi_dram[0].size; + start_addr = gd->dram[0].start; + size = gd->dram[0].size; /* Initialize small block for page table */ memset((void *)start_addr, 0, PGTABLE_SIZE + PGTABLE_OFF); @@ -174,8 +174,8 @@ void sdram_init_ecc_bits(struct bd_info *bd) if (bank >= CONFIG_NR_DRAM_BANKS) break; - start_addr = bd->bi_dram[bank].start; - size = bd->bi_dram[bank].size; + start_addr = gd->dram[bank].start; + size = gd->dram[bank].size; } dcache_disable(); @@ -198,12 +198,12 @@ void sdram_size_check(struct bd_info *bd) phys_addr_t start = 0; phys_size_t remaining_size; - start = bd->bi_dram[bank].start; - remaining_size = bd->bi_dram[bank].size; + start = gd->dram[bank].start; + remaining_size = gd->dram[bank].size; debug("Checking bank %d: start=0x%llx, size=0x%llx\n", bank, start, remaining_size); - while (ram_check < bd->bi_dram[bank].size) { + while (ram_check < gd->dram[bank].size) { phys_size_t size, test_size, detected_size; size = min((phys_addr_t)SZ_1G, (phys_addr_t)remaining_size); @@ -232,7 +232,7 @@ void sdram_size_check(struct bd_info *bd) } ram_check += detected_size; - remaining_size = bd->bi_dram[bank].size - ram_check; + remaining_size = gd->dram[bank].size - ram_check; } total_ram_check += ram_check; @@ -292,10 +292,10 @@ static void sdram_set_firewall_non_f2sdram(struct bd_info *bd) u32 lower, upper; for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { - if (!bd->bi_dram[i].size) + if (!gd->dram[i].size) continue; - value = bd->bi_dram[i].start; + value = gd->dram[i].start; /* Keep first 1MB of SDRAM memory region as secure region when * using ATF flow, where the ATF code is located. @@ -322,7 +322,7 @@ static void sdram_set_firewall_non_f2sdram(struct bd_info *bd) (i * 4 * sizeof(u32))); /* Setting non-secure MPU limit and limit extended */ - value = bd->bi_dram[i].start + bd->bi_dram[i].size - 1; + value = gd->dram[i].start + gd->dram[i].size - 1; lower = lower_32_bits(value); upper = upper_32_bits(value); @@ -354,10 +354,10 @@ static void sdram_set_firewall_f2sdram(struct bd_info *bd) phys_size_t value; for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { - if (!bd->bi_dram[i].size) + if (!gd->dram[i].size) continue; - value = bd->bi_dram[i].start; + value = gd->dram[i].start; /* Keep first 1MB of SDRAM memory region as secure region when * using ATF flow, where the ATF code is located. @@ -376,7 +376,7 @@ static void sdram_set_firewall_f2sdram(struct bd_info *bd) (i * 4 * sizeof(u32))); /* Setting limit and limit extended */ - value = bd->bi_dram[i].start + bd->bi_dram[i].size - 1; + value = gd->dram[i].start + gd->dram[i].size - 1; lower = lower_32_bits(value); upper = upper_32_bits(value); diff --git a/drivers/ddr/fsl/Kconfig b/drivers/ddr/fsl/Kconfig index 7f8f3570dd8..b11fa79ca59 100644 --- a/drivers/ddr/fsl/Kconfig +++ b/drivers/ddr/fsl/Kconfig @@ -21,12 +21,12 @@ if SYS_FSL_DDR || SYS_FSL_MMDC config SYS_FSL_DDR_BE bool help - Access DDR registers in big-endian + Access DDR registers in big-endian config SYS_FSL_DDR_LE bool help - Access DDR registers in little-endian + Access DDR registers in little-endian config FSL_DDR_BIST bool diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c index d59e94779ff..2b879c63b5f 100644 --- a/drivers/ddr/fsl/main.c +++ b/drivers/ddr/fsl/main.c @@ -221,7 +221,7 @@ void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, unsigned int i2c_address = 0; if (ctrl_num >= CONFIG_SYS_NUM_DDR_CTLRS) { - printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + printf("%s unexpected ctrl_num = %u\n", __func__, ctrl_num); return; } diff --git a/drivers/ddr/fsl/mpc85xx_ddr_gen1.c b/drivers/ddr/fsl/mpc85xx_ddr_gen1.c index a8520754006..e43dc869fc5 100644 --- a/drivers/ddr/fsl/mpc85xx_ddr_gen1.c +++ b/drivers/ddr/fsl/mpc85xx_ddr_gen1.c @@ -21,7 +21,7 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, (struct ccsr_ddr __iomem *)CFG_SYS_FSL_DDR_ADDR; if (ctrl_num != 0) { - printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + printf("%s unexpected ctrl_num = %u\n", __func__, ctrl_num); return; } diff --git a/drivers/ddr/fsl/mpc85xx_ddr_gen2.c b/drivers/ddr/fsl/mpc85xx_ddr_gen2.c index 00b4b376dd4..3a8ad6cc86b 100644 --- a/drivers/ddr/fsl/mpc85xx_ddr_gen2.c +++ b/drivers/ddr/fsl/mpc85xx_ddr_gen2.c @@ -26,7 +26,7 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, #endif if (ctrl_num) { - printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + printf("%s unexpected ctrl_num = %u\n", __func__, ctrl_num); return; } diff --git a/drivers/ddr/fsl/mpc85xx_ddr_gen3.c b/drivers/ddr/fsl/mpc85xx_ddr_gen3.c index b0a61fa2b41..ee9811481ab 100644 --- a/drivers/ddr/fsl/mpc85xx_ddr_gen3.c +++ b/drivers/ddr/fsl/mpc85xx_ddr_gen3.c @@ -71,7 +71,7 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, break; #endif default: - printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num); + printf("%s unexpected ctrl_num = %u\n", __func__, ctrl_num); return; } diff --git a/drivers/ddr/imx/imx9/Kconfig b/drivers/ddr/imx/imx9/Kconfig index 0a45340ffb6..7b3dbf53dff 100644 --- a/drivers/ddr/imx/imx9/Kconfig +++ b/drivers/ddr/imx/imx9/Kconfig @@ -24,9 +24,16 @@ config IMX9_DRAM_INLINE_ECC config SAVED_DRAM_TIMING_BASE hex "Define the base address for saved dram timing" + default 0x2051C000 help after DRAM is trained, need to save the dram related timming info into memory for low power use. - default 0x2051C000 + +config QB_SAVED_STATE_BASE + hex "Define the base address for saved QuickBoot state" + default 0x8fe00000 + help + Once DRAM is trained, the resulted training info is + saved into memory in order to be reachable from U-Boot. endmenu diff --git a/drivers/ddr/imx/phy/helper.c b/drivers/ddr/imx/phy/helper.c index b0dfc3a0b4f..147ec9ab061 100644 --- a/drivers/ddr/imx/phy/helper.c +++ b/drivers/ddr/imx/phy/helper.c @@ -38,6 +38,8 @@ binman_sym_declare(ulong, ddr_2d_dmem_fw, image_pos); binman_sym_declare(ulong, ddr_2d_dmem_fw, size); #endif +binman_sym_declare(ulong, u_boot_spl, image_pos); + /* We need PHY iMEM PHY is 32KB padded */ void ddr_load_train_firmware(enum fw_type type) { @@ -49,6 +51,7 @@ void ddr_load_train_firmware(enum fw_type type) unsigned long dmem_start; unsigned long imem_len = IMEM_LEN, dmem_len = DMEM_LEN; static enum fw_type last_type = -1; + unsigned long spl_start = 0; /* If FW doesn't change, we can save the loading. */ if (last_type == type) @@ -67,6 +70,9 @@ void ddr_load_train_firmware(enum fw_type type) dmem_start = imem_start + imem_len; if (BINMAN_SYMS_OK) { + if (IS_ENABLED(CONFIG_IMX8MQ)) + spl_start = binman_sym(ulong, u_boot_spl, image_pos); + switch (type) { case FW_1D_IMAGE: imem_start = binman_sym(ulong, ddr_1d_imem_fw, image_pos); @@ -83,6 +89,13 @@ void ddr_load_train_firmware(enum fw_type type) #endif break; } + + if (IS_ENABLED(CONFIG_IMX8MQ)) { + imem_start -= spl_start; + imem_start += CONFIG_SPL_TEXT_BASE; + dmem_start -= spl_start; + dmem_start += CONFIG_SPL_TEXT_BASE; + } } pr_from32 = imem_start; diff --git a/drivers/dfu/Kconfig b/drivers/dfu/Kconfig index 962bda40ad2..eeae2fd65ad 100644 --- a/drivers/dfu/Kconfig +++ b/drivers/dfu/Kconfig @@ -11,7 +11,7 @@ config DFU_OVER_USB config DFU_OVER_TFTP bool - depends on NET + depends on NET_LEGACY config DFU_WRITE_ALT bool diff --git a/drivers/dma/ti/Kconfig b/drivers/dma/ti/Kconfig index d904982c800..8c9b377e8a3 100644 --- a/drivers/dma/ti/Kconfig +++ b/drivers/dma/ti/Kconfig @@ -3,14 +3,14 @@ if ARCH_K3 config TI_K3_NAVSS_UDMA - bool "Texas Instruments UDMA" - depends on ARCH_K3 - select DEVRES - select DMA - select TI_K3_NAVSS_RINGACC - select TI_K3_PSIL - help - Support for UDMA used in K3 devices. + bool "Texas Instruments UDMA" + depends on ARCH_K3 + select DEVRES + select DMA + select TI_K3_NAVSS_RINGACC + select TI_K3_PSIL + help + Support for UDMA used in K3 devices. endif config TI_K3_PSIL diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index 576c3ef8a45..90212fcf9ef 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -27,7 +27,7 @@ config USB_FUNCTION_FASTBOOT This enables the USB part of the fastboot gadget. config UDP_FUNCTION_FASTBOOT - depends on NET + depends on NET_LEGACY select FASTBOOT bool "Enable fastboot protocol over UDP" help @@ -41,7 +41,7 @@ config UDP_FUNCTION_FASTBOOT_PORT The fastboot protocol requires a UDP port number. config TCP_FUNCTION_FASTBOOT - depends on NET + depends on NET_LEGACY select FASTBOOT bool "Enable fastboot protocol over TCP" help diff --git a/drivers/fastboot/fb_common.c b/drivers/fastboot/fb_common.c index dac5528f809..9c52e004588 100644 --- a/drivers/fastboot/fb_common.c +++ b/drivers/fastboot/fb_common.c @@ -191,13 +191,13 @@ void fastboot_handle_boot(int command, bool success) switch (command) { case FASTBOOT_COMMAND_BOOT: fastboot_boot(); -#if CONFIG_IS_ENABLED(NET) +#if CONFIG_IS_ENABLED(NET_LEGACY) net_set_state(NETLOOP_SUCCESS); #endif break; case FASTBOOT_COMMAND_CONTINUE: -#if CONFIG_IS_ENABLED(NET) +#if CONFIG_IS_ENABLED(NET_LEGACY) net_set_state(NETLOOP_SUCCESS); #endif break; diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index 11d9c8e8460..9bc782ccd02 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -263,7 +263,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, /* Write new kernel size to boot image header */ hdr->kernel_size = download_bytes; res = blk_dwrite(dev_desc, info.start, hdr_sectors, (void *)hdr); - if (res == 0) { + if (res != hdr_sectors) { pr_err("cannot writeback boot image header\n"); fastboot_fail("cannot write back boot image header", response); return -1; @@ -275,7 +275,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, sectors_per_page; res = blk_dwrite(dev_desc, kernel_sector_start, kernel_sectors, download_buffer); - if (res == 0) { + if (res != kernel_sectors) { pr_err("cannot write new kernel\n"); fastboot_fail("cannot write new kernel", response); return -1; @@ -287,7 +287,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, sectors_per_page; res = blk_dwrite(dev_desc, ramdisk_sector_start, ramdisk_sectors, ramdisk_buffer); - if (res == 0) { + if (res != ramdisk_sectors) { pr_err("cannot write back original ramdisk\n"); fastboot_fail("cannot write back original ramdisk", response); return -1; diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 220de731950..f524f741e54 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -14,7 +14,7 @@ config ARM_PSCI_FW select FIRMWARE config TI_SCI_PROTOCOL - tristate "TI System Control Interface (TISCI) Message Protocol" + bool "TI System Control Interface (TISCI) Message Protocol" depends on K3_SEC_PROXY select DEVRES select FIRMWARE diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index fb583580ebe..6052a31b5b4 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -3,10 +3,11 @@ * Xilinx Zynq MPSoC Firmware driver * * Copyright (C) 2018-2019 Xilinx, Inc. - * Copyright (C) 2022 - 2025, Advanced Micro Devices, Inc. + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. */ #include <asm/arch/hardware.h> +#include <asm/arch/sys_proto.h> #include <asm/io.h> #include <cpu_func.h> #include <dm.h> @@ -16,6 +17,7 @@ #include <zynqmp_firmware.h> #include <asm/cache.h> #include <asm/ptrace.h> +#include <asm/system.h> #include <linux/bitfield.h> #if defined(CONFIG_ZYNQMP_IPI) @@ -197,6 +199,58 @@ int zynqmp_pm_ufs_cal_reg(u32 *value) *value = readl(PMXC_EFUSE_CACHE_BASE_ADDRESS + PMXC_UFS_CAL_1_OFFSET); return 0; } +#endif /* CONFIG_ARCH_VERSAL2 */ + +#if defined(CONFIG_ARCH_VERSAL) || defined(CONFIG_ARCH_VERSAL2) +u32 zynqmp_pm_get_pmc_global_pggs_reg(u32 reg_addr) +{ + int ret; + u32 value = 0; + u32 ret_payload[PAYLOAD_ARG_CNT]; + + if (reg_addr == PMC_GLOBAL_PGGS3_REG) { + value = 0; + } else if (reg_addr == PMC_GLOBAL_PGGS4_REG) { + value = 1; + } else { + printf("%s: not supported pggs register 0x%x\n", + __func__, reg_addr); + return 0; + } + + ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_READ_PGGS); + if (ret) { + ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_READ_REG); + if (ret) { + printf("%s: IOCTL_READ_REG is not supported : %d\n" + , __func__, ret); + return 0; + } + + /* find node ID from the pggs3 offset */ + value = PM_REG_PGGS3 + value; + + ret = xilinx_pm_request(PM_IOCTL, value, + IOCTL_READ_REG, 0, 0, 0, 0, + ret_payload); + if (ret) { + printf("%s: node 0x%x get pggs register failed\n", + __func__, value); + return 0; + } + } else { + ret = xilinx_pm_request(PM_IOCTL, PMC_GLOBAL_PGGS3_REG_NODE, + IOCTL_READ_PGGS, value, 0, 0, 0, + ret_payload); + if (ret) { + printf("%s: node 0x%x get pggs register failed\n", + __func__, PMC_GLOBAL_PGGS3_REG_NODE); + return 0; + } + } + + return ret_payload[1]; +} #endif int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 value) @@ -274,6 +328,93 @@ u32 zynqmp_pm_get_pmc_multi_boot_reg(void) } #endif +#if defined(CONFIG_ARCH_VERSAL) +u32 versal_pmc_multi_boot(void) +{ + /* At EL3 the SMC path to firmware is unavailable, read directly */ + if (current_el() == 3) + return versal_multi_boot_reg(); + + return zynqmp_pm_get_pmc_multi_boot_reg() & PMC_MULTI_BOOT_MASK; +} + +u8 versal_get_bootmode(void) +{ + u32 reg; + + /* At EL3 the SMC path to firmware is unavailable, read directly */ + if (current_el() == 3) + reg = versal_bootmode_reg(); + else + reg = zynqmp_pm_get_bootmode_reg(); + + if (reg >> BOOT_MODE_ALT_SHIFT) + reg >>= BOOT_MODE_ALT_SHIFT; + + return reg & BOOT_MODES_MASK; +} +#endif + +#if defined(CONFIG_ARCH_VERSAL_NET) +u8 versal_net_get_bootmode(void) +{ + u32 reg; + + /* At EL3 the SMC path to firmware is unavailable, read directly */ + if (current_el() == 3) + reg = versal_net_bootmode_reg(); + else + reg = zynqmp_pm_get_bootmode_reg(); + + if (reg >> BOOT_MODE_ALT_SHIFT) + reg >>= BOOT_MODE_ALT_SHIFT; + + return reg & BOOT_MODES_MASK; +} +#endif + +#if defined(CONFIG_ARCH_ZYNQMP) +int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value) +{ + /* At EL3 or in SPL the firmware (SMC) path is unavailable */ + if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3) + return zynqmp_mmio_rawwrite(address, mask, value); + + return xilinx_pm_request(PM_MMIO_WRITE, address, mask, value, + 0, 0, 0, NULL); +} + +int zynqmp_mmio_read(const u32 address, u32 *value) +{ + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + if (!value) + return -EINVAL; + + /* At EL3 or in SPL the firmware (SMC) path is unavailable */ + if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3) + return zynqmp_mmio_rawread(address, value); + + ret = xilinx_pm_request(PM_MMIO_READ, address, 0, 0, 0, 0, 0, + ret_payload); + *value = ret_payload[1]; + + return ret; +} +#endif + +#if defined(CONFIG_ARCH_VERSAL2) +u32 versal2_pmc_multi_boot(void) +{ + /* At EL3 the SMC path to firmware is unavailable, read directly */ + if (current_el() == 3) + return versal2_multi_boot_reg(); + + return zynqmp_pm_get_pmc_multi_boot_reg() & PMC_MULTI_BOOT_MASK; +} +#endif + int zynqmp_pm_feature(const u32 api_id) { int ret; diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index 010bf99fbc6..832bfb55711 100644 --- a/drivers/firmware/scmi/sandbox-scmi_agent.c +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -1341,7 +1341,7 @@ static const struct udevice_id sandbox_scmi_test_ids[] = { { } }; -struct scmi_agent_ops sandbox_scmi_test_ops = { +static const struct scmi_agent_ops sandbox_scmi_test_ops = { .of_get_channel = sandbox_scmi_of_get_channel, .process_msg = sandbox_scmi_test_process_msg, }; diff --git a/drivers/fpga/altera.c b/drivers/fpga/altera.c index 822183c5785..69d7111a5f1 100644 --- a/drivers/fpga/altera.c +++ b/drivers/fpga/altera.c @@ -12,8 +12,7 @@ /* * Altera FPGA support */ -#if IS_ENABLED(CONFIG_ARCH_SOCFPGA_AGILEX) || \ - IS_ENABLED(CONFIG_ARCH_SOCFPGA_STRATIX10) +#if IS_ENABLED(CONFIG_FPGA_INTEL_SDM_MAILBOX) #include <asm/arch/misc.h> #endif #include <errno.h> @@ -48,8 +47,7 @@ static const struct altera_fpga { #endif }; -#if IS_ENABLED(CONFIG_ARCH_SOCFPGA_AGILEX) || \ - IS_ENABLED(CONFIG_ARCH_SOCFPGA_STRATIX10) +#if IS_ENABLED(CONFIG_FPGA_INTEL_SDM_MAILBOX) int fpga_is_partial_data(int devnum, size_t img_len) { /* diff --git a/drivers/fpga/spartan2.c b/drivers/fpga/spartan2.c index 792e4033428..e3715bf2b24 100644 --- a/drivers/fpga/spartan2.c +++ b/drivers/fpga/spartan2.c @@ -52,7 +52,7 @@ static int spartan2_load(xilinx_desc *desc, const void *buf, size_t bsize, default: printf ("%s: Unsupported interface type, %d\n", - __FUNCTION__, desc->iface); + __func__, desc->iface); } return ret_val; @@ -75,7 +75,7 @@ static int spartan2_dump(xilinx_desc *desc, const void *buf, size_t bsize) default: printf ("%s: Unsupported interface type, %d\n", - __FUNCTION__, desc->iface); + __func__, desc->iface); } return ret_val; @@ -234,7 +234,7 @@ static int spartan2_sp_load(xilinx_desc *desc, const void *buf, size_t bsize) #endif } else { - printf ("%s: NULL Interface function table!\n", __FUNCTION__); + printf("%s: NULL Interface function table!\n", __func__); } return ret_val; @@ -279,7 +279,7 @@ static int spartan2_sp_dump(xilinx_desc *desc, const void *buf, size_t bsize) /* XXX - checksum the data? */ } else { - printf ("%s: NULL Interface function table!\n", __FUNCTION__); + printf("%s: NULL Interface function table!\n", __func__); } return ret_val; @@ -423,7 +423,7 @@ static int spartan2_ss_load(xilinx_desc *desc, const void *buf, size_t bsize) #endif } else { - printf ("%s: NULL Interface function table!\n", __FUNCTION__); + printf("%s: NULL Interface function table!\n", __func__); } return ret_val; @@ -434,7 +434,7 @@ static int spartan2_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize) /* Readback is only available through the Slave Parallel and */ /* boundary-scan interfaces. */ printf ("%s: Slave Serial Dumping is unavailable\n", - __FUNCTION__); + __func__); return FPGA_FAIL; } diff --git a/drivers/fpga/spartan3.c b/drivers/fpga/spartan3.c index 98405589134..6221041e092 100644 --- a/drivers/fpga/spartan3.c +++ b/drivers/fpga/spartan3.c @@ -57,7 +57,7 @@ static int spartan3_load(xilinx_desc *desc, const void *buf, size_t bsize, default: printf ("%s: Unsupported interface type, %d\n", - __FUNCTION__, desc->iface); + __func__, desc->iface); } return ret_val; @@ -80,7 +80,7 @@ static int spartan3_dump(xilinx_desc *desc, const void *buf, size_t bsize) default: printf ("%s: Unsupported interface type, %d\n", - __FUNCTION__, desc->iface); + __func__, desc->iface); } return ret_val; @@ -241,7 +241,7 @@ static int spartan3_sp_load(xilinx_desc *desc, const void *buf, size_t bsize) #endif } else { - printf ("%s: NULL Interface function table!\n", __FUNCTION__); + printf("%s: NULL Interface function table!\n", __func__); } return ret_val; @@ -286,7 +286,7 @@ static int spartan3_sp_dump(xilinx_desc *desc, const void *buf, size_t bsize) /* XXX - checksum the data? */ } else { - printf ("%s: NULL Interface function table!\n", __FUNCTION__); + printf("%s: NULL Interface function table!\n", __func__); } return ret_val; @@ -442,7 +442,7 @@ static int spartan3_ss_load(xilinx_desc *desc, const void *buf, size_t bsize) #endif } else { - printf ("%s: NULL Interface function table!\n", __FUNCTION__); + printf("%s: NULL Interface function table!\n", __func__); } return ret_val; @@ -453,7 +453,7 @@ static int spartan3_ss_dump(xilinx_desc *desc, const void *buf, size_t bsize) /* Readback is only available through the Slave Parallel and */ /* boundary-scan interfaces. */ printf ("%s: Slave Serial Dumping is unavailable\n", - __FUNCTION__); + __func__); return FPGA_FAIL; } diff --git a/drivers/fpga/versalpl.c b/drivers/fpga/versalpl.c index 630d1ecfea3..3cb56cc0dc9 100644 --- a/drivers/fpga/versalpl.c +++ b/drivers/fpga/versalpl.c @@ -17,7 +17,7 @@ static ulong versal_align_dma_buffer(ulong *buf, u32 len) if ((ulong)buf != ALIGN((ulong)buf, ARCH_DMA_MINALIGN)) { new_buf = (ulong *)ALIGN((ulong)buf, ARCH_DMA_MINALIGN); - memcpy(new_buf, buf, len); + memmove(new_buf, buf, len); buf = new_buf; } diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c index 25b348648ef..b6966c7d2cb 100644 --- a/drivers/fpga/xilinx.c +++ b/drivers/fpga/xilinx.c @@ -11,6 +11,7 @@ * Xilinx FPGA support */ +#include <env.h> #include <fpga.h> #include <log.h> #include <virtex2.h> @@ -92,7 +93,11 @@ int fpga_loadbitstream(int devnum, char *fpgadata, size_t size, __func__); printf("%s: Bitstream ID %s, current device ID %d/%s\n", __func__, dataptr, devnum, xdesc->name); - return FPGA_FAIL; + if (!CONFIG_IS_ENABLED(ENV_SUPPORT) || + env_get_yesno("fpga_skip_idcheck") != 1) + return FPGA_FAIL; + + printf("%s: Skipping ID check\n", __func__); } } else { printf("%s: Please fill correct device ID to xilinx_desc\n", @@ -144,8 +149,8 @@ int fpga_loadbitstream(int devnum, char *fpgadata, size_t size, int xilinx_load(xilinx_desc *desc, const void *buf, size_t bsize, bitstream_type bstype, int flags) { - if (!xilinx_validate (desc, (char *)__FUNCTION__)) { - printf ("%s: Invalid device descriptor\n", __FUNCTION__); + if (!xilinx_validate(desc, (char *)__func__)) { + printf("%s: Invalid device descriptor\n", __func__); return FPGA_FAIL; } @@ -195,8 +200,8 @@ int xilinx_loads(xilinx_desc *desc, const void *buf, size_t bsize, int xilinx_dump(xilinx_desc *desc, const void *buf, size_t bsize) { - if (!xilinx_validate (desc, (char *)__FUNCTION__)) { - printf ("%s: Invalid device descriptor\n", __FUNCTION__); + if (!xilinx_validate(desc, (char *)__func__)) { + printf("%s: Invalid device descriptor\n", __func__); return FPGA_FAIL; } @@ -212,7 +217,7 @@ int xilinx_info(xilinx_desc *desc) { int ret_val = FPGA_FAIL; - if (xilinx_validate (desc, (char *)__FUNCTION__)) { + if (xilinx_validate(desc, (char *)__func__)) { printf ("Family: \t"); switch (desc->family) { case xilinx_spartan2: @@ -288,7 +293,7 @@ int xilinx_info(xilinx_desc *desc) ret_val = FPGA_SUCCESS; } else { - printf ("%s: Invalid device descriptor\n", __FUNCTION__); + printf("%s: Invalid device descriptor\n", __func__); } return ret_val; diff --git a/drivers/gpio/74x164_gpio.c b/drivers/gpio/74x164_gpio.c index 331428ccdb9..de2926894ec 100644 --- a/drivers/gpio/74x164_gpio.c +++ b/drivers/gpio/74x164_gpio.c @@ -10,17 +10,13 @@ #include <errno.h> #include <dm.h> -#include <fdtdec.h> #include <malloc.h> -#include <asm/global_data.h> #include <asm/gpio.h> #include <asm/io.h> #include <dm/device_compat.h> #include <dt-bindings/gpio/gpio.h> #include <spi.h> -DECLARE_GLOBAL_DATA_PTR; - /* * struct gen_74x164_chip - Data for 74Hx164 * @@ -127,11 +123,9 @@ static int gen_74x164_probe(struct udevice *dev) { struct gen_74x164_priv *priv = dev_get_priv(dev); struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + const u8 *defaults; char *str, name[32]; int ret; - const void *fdt = gd->fdt_blob; - int node = dev_of_offset(dev); - snprintf(name, sizeof(name), "%s_", dev->name); str = strdup(name); if (!str) @@ -141,16 +135,17 @@ static int gen_74x164_probe(struct udevice *dev) * See Linux kernel: * Documentation/devicetree/bindings/gpio/gpio-74x164.txt */ - priv->nregs = fdtdec_get_int(fdt, node, "registers-number", 1); + priv->nregs = dev_read_u32_default(dev, "registers-number", 1); priv->buffer = calloc(priv->nregs, sizeof(u8)); if (!priv->buffer) { ret = -ENOMEM; goto free_str; } - ret = fdtdec_get_byte_array(fdt, node, "registers-default", - priv->buffer, priv->nregs); - if (ret) + defaults = dev_read_u8_array_ptr(dev, "registers-default", priv->nregs); + if (defaults) + memcpy(priv->buffer, defaults, priv->nregs); + else dev_dbg(dev, "No registers-default property\n"); ret = gpio_request_by_name(dev, "oe-gpios", 0, &priv->oe, diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 0b5466b39b8..a11f3043670 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -294,9 +294,9 @@ config MAX7320_GPIO bool "MAX7320 I2C GPIO Expander driver" depends on DM_GPIO && DM_I2C help - Support for MAX7320 I2C 8/16-bit GPIO expander. - original maxim device has 8 push/pull outputs, - some clones offers 16bit. + Support for MAX7320 I2C 8/16-bit GPIO expander. + original maxim device has 8 push/pull outputs, + some clones offers 16bit. config MAX77663_GPIO bool "MAX77663 GPIO cell of PMIC driver" @@ -309,27 +309,27 @@ config MAX77663_GPIO config MCP230XX_GPIO bool "MCP230XX GPIO driver" - depends on DM + depends on DM && DM_I2C && DM_SPI help - Support for Microchip's MCP230XX I2C connected GPIO devices. + Support for Microchip's MCP230XX I2C and SPI connected GPIO devices. The following chips are supported: - - MCP23008 - - MCP23017 - - MCP23018 - - MCP23S08 - - MCP23S17 - - MCP23S18 + - MCP23008 + - MCP23017 + - MCP23018 + - MCP23S08 + - MCP23S17 + - MCP23S18 config MSCC_SGPIO bool "Microsemi Serial GPIO driver" depends on DM_GPIO && SOC_VCOREIII help Support for the VCoreIII SoC serial GPIO device. By using a - serial interface, the SIO controller significantly extends - the number of available GPIOs with a minimum number of - additional pins on the device. The primary purpose of the - SIO controller is to connect control signals from SFP - modules and to act as an LED controller. + serial interface, the SIO controller significantly extends + the number of available GPIOs with a minimum number of + additional pins on the device. The primary purpose of the + SIO controller is to connect control signals from SFP + modules and to act as an LED controller. config MSM_GPIO bool "Qualcomm GPIO driver" @@ -404,8 +404,8 @@ config PCF8575_GPIO bool "PCF8575 I2C GPIO Expander driver" depends on DM_GPIO && DM_I2C help - Support for PCF8575 I2C 16-bit GPIO expander. Most of these - chips are from NXP and TI. + Support for PCF8575 I2C 16-bit GPIO expander. Most of these + chips are from NXP and TI. config RCAR_GPIO bool "Renesas R-Car GPIO driver" @@ -449,6 +449,14 @@ config SANDBOX_GPIO_COUNT of 'anonymous' GPIOs that do not belong to any device or bank. Select a suitable value depending on your needs. +config SPACEMIT_GPIO + bool "Spacemit K1 GPIO driver" + depends on DM_GPIO && TARGET_SPACEMIT_K1 + help + Support the GPIO device in Spacemit SoCs. The GPIOs are arranged + into a number of banks (different for each SoC type) each with 32 + GPIOs. + config SUNXI_GPIO bool "Allwinner GPIO driver" depends on ARCH_SUNXI @@ -459,9 +467,9 @@ config SUNXI_GPIO config SUNXI_NEW_PINCTRL bool depends on SUNXI_GPIO - ---help--- - The Allwinner D1 and other new SoCs use a different register map - for the GPIO block, which we need to know about in the SPL. + help + The Allwinner D1 and other new SoCs use a different register map + for the GPIO block, which we need to know about in the SPL. config XILINX_GPIO bool "Xilinx GPIO driver" @@ -728,15 +736,15 @@ config SLG7XL45106_I2C_GPO bool "slg7xl45106 i2c gpo expander" depends on DM_GPIO && ARCH_ZYNQMP help - Support for slg7xl45106 i2c gpo expander. It is an i2c based - 8-bit gpo expander, all gpo lines are controlled by writing - value into data register. + Support for slg7xl45106 i2c gpo expander. It is an i2c based + 8-bit gpo expander, all gpo lines are controlled by writing + value into data register. config GPIO_SCMI bool "SCMI GPIO pinctrl driver" depends on DM_GPIO && PINCTRL_SCMI help - Support pinctrl GPIO over the SCMI interface. + Support pinctrl GPIO over the SCMI interface. config ADP5585_GPIO bool "ADP5585 GPIO driver" @@ -756,10 +764,11 @@ config SPL_ADP5585_GPIO depends on SPL_DM_GPIO && SPL_I2C help Support ADP5585 GPIO expander in SPL. + config MPFS_GPIO bool "Enable Polarfire SoC GPIO driver" depends on DM_GPIO help - Enable to support the GPIO driver on Polarfire SoC + Enable to support the GPIO driver on Polarfire SoC endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 863557e45ce..020e23c7252 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o obj-$(CONFIG_MSM_GPIO) += msm_gpio.o obj-$(CONFIG_$(PHASE_)PCF8575_GPIO) += pcf8575_gpio.o obj-$(CONFIG_$(PHASE_)QCOM_PMIC_GPIO) += qcom_pmic_gpio.o qcom_spmi_gpio.o +obj-$(CONFIG_$(PHASE_)SPACEMIT_GPIO) += spacemit_gpio.o obj-$(CONFIG_MT7620_GPIO) += mt7620_gpio.o obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o diff --git a/drivers/gpio/gpio-aspeed-g7.c b/drivers/gpio/gpio-aspeed-g7.c index 4607468ca05..ae330173f38 100644 --- a/drivers/gpio/gpio-aspeed-g7.c +++ b/drivers/gpio/gpio-aspeed-g7.c @@ -131,7 +131,7 @@ static int aspeed_gpio_probe(struct udevice *dev) uc_priv->bank_name = dev->name; ofnode_read_u32(dev_ofnode(dev), "ngpios", &uc_priv->gpio_count); - priv->regs = devfdt_get_addr_ptr(dev); + priv->regs = dev_read_addr_ptr(dev); return 0; } diff --git a/drivers/gpio/gpio-aspeed-sgpio.c b/drivers/gpio/gpio-aspeed-sgpio.c index 4bbdec756f3..d6144d5706b 100644 --- a/drivers/gpio/gpio-aspeed-sgpio.c +++ b/drivers/gpio/gpio-aspeed-sgpio.c @@ -223,9 +223,9 @@ static int aspeed_sgpio_probe(struct udevice *dev) ulong apb_freq; int ret; - priv->base = devfdt_get_addr_ptr(dev); - if (IS_ERR(priv->base)) - return PTR_ERR(priv->base); + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -EINVAL; priv->pdata = (const struct aspeed_sgpio_pdata *)dev_get_driver_data(dev); if (!priv->pdata) diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c index c5608f4a9df..54a786c4dc0 100644 --- a/drivers/gpio/gpio-aspeed.c +++ b/drivers/gpio/gpio-aspeed.c @@ -275,7 +275,7 @@ static int aspeed_gpio_probe(struct udevice *dev) uc_priv->bank_name = dev->name; ofnode_read_u32(dev_ofnode(dev), "ngpios", &uc_priv->gpio_count); - priv->regs = devfdt_get_addr_ptr(dev); + priv->regs = dev_read_addr_ptr(dev); return 0; } diff --git a/drivers/gpio/gpio-fxl6408.c b/drivers/gpio/gpio-fxl6408.c index c8d2dff5f7b..180799139b3 100644 --- a/drivers/gpio/gpio-fxl6408.c +++ b/drivers/gpio/gpio-fxl6408.c @@ -273,7 +273,7 @@ static int fxl6408_probe(struct udevice *dev) u32 val32; addr = dev_read_addr(dev); - if (addr == 0) + if (addr == FDT_ADDR_T_NONE) return -EINVAL; info->addr = addr; diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 7651d5360d6..4d40738e5aa 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -877,8 +877,19 @@ static int get_function(struct udevice *dev, int offset, bool skip_unused, return -ENODEV; if (offset < 0 || offset >= uc_priv->gpio_count) return -EINVAL; - if (namep) + if (namep) { *namep = uc_priv->name[offset]; + /* Fall back to DT "gpio-line-names" for unrequested pins. */ + if (CONFIG_IS_ENABLED(DM_GPIO_LOOKUP_LINE_NAME) && + (!*namep || !**namep)) { + const char *dt_name = NULL; + + if (!dev_read_string_index(dev, "gpio-line-names", + offset, &dt_name) && + dt_name && *dt_name) + *namep = dt_name; + } + } if (skip_unused && !gpio_is_claimed(uc_priv, offset)) return GPIOF_UNUSED; if (ops->get_function) { diff --git a/drivers/gpio/imx_rgpio2p.c b/drivers/gpio/imx_rgpio2p.c index 7cf178f8a48..ba3c5fcf25b 100644 --- a/drivers/gpio/imx_rgpio2p.c +++ b/drivers/gpio/imx_rgpio2p.c @@ -194,11 +194,11 @@ static int imx_rgpio2p_bind(struct udevice *dev) dual_base = true; if (dual_base) { - addr = devfdt_get_addr_index(dev, 1); + addr = dev_read_addr_index(dev, 1); if (addr == FDT_ADDR_T_NONE) return -EINVAL; } else { - addr = devfdt_get_addr_index(dev, 0); + addr = dev_read_addr_index(dev, 0); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/gpio/mpc8xxx_gpio.c b/drivers/gpio/mpc8xxx_gpio.c index 709d04017d1..40646407369 100644 --- a/drivers/gpio/mpc8xxx_gpio.c +++ b/drivers/gpio/mpc8xxx_gpio.c @@ -171,6 +171,58 @@ static int mpc8xxx_gpio_get_function(struct udevice *dev, uint gpio) return dir ? GPIOF_OUTPUT : GPIOF_INPUT; } +static int mpc8xxx_gpio_set_flags(struct udevice *dev, uint gpio, + ulong flags) +{ + u32 mask = gpio_mask(gpio); + int ret; + + /* The QorIQ GPIO pad supports open-drain only; open-source has + * no silicon counterpart, so reject it rather than silently + * pretending. + */ + if (flags & GPIOD_OPEN_SOURCE) + return -EOPNOTSUPP; + + /* GPODR is per-pin and meaningful in both directions (it stays + * latched when the pin is re-purposed), so apply it before the + * direction change. + */ + if (flags & GPIOD_OPEN_DRAIN) + mpc8xxx_gpio_open_drain_on(dev, mask); + else + mpc8xxx_gpio_open_drain_off(dev, mask); + + if (flags & GPIOD_IS_OUT) { + ret = mpc8xxx_gpio_direction_output(dev, gpio, + !!(flags & GPIOD_IS_OUT_ACTIVE)); + } else if (flags & GPIOD_IS_IN) { + ret = mpc8xxx_gpio_direction_input(dev, gpio); + } else { + ret = 0; + } + + return ret; +} + +static int mpc8xxx_gpio_get_flags(struct udevice *dev, uint gpio, + ulong *flagsp) +{ + u32 mask = gpio_mask(gpio); + ulong flags = 0; + + if (mpc8xxx_gpio_get_dir(dev, mask)) + flags |= GPIOD_IS_OUT; + else + flags |= GPIOD_IS_IN; + + if (mpc8xxx_gpio_open_drain_val(dev, mask)) + flags |= GPIOD_OPEN_DRAIN; + + *flagsp = flags; + return 0; +} + #if CONFIG_IS_ENABLED(OF_CONTROL) static int mpc8xxx_gpio_of_to_plat(struct udevice *dev) { @@ -255,6 +307,8 @@ static const struct dm_gpio_ops gpio_mpc8xxx_ops = { .get_value = mpc8xxx_gpio_get_value, .set_value = mpc8xxx_gpio_set_value, .get_function = mpc8xxx_gpio_get_function, + .set_flags = mpc8xxx_gpio_set_flags, + .get_flags = mpc8xxx_gpio_get_flags, }; static const struct udevice_id mpc8xxx_gpio_ids[] = { diff --git a/drivers/gpio/nx_gpio.c b/drivers/gpio/nx_gpio.c index 5abbb34daea..1c3d27eb1cc 100644 --- a/drivers/gpio/nx_gpio.c +++ b/drivers/gpio/nx_gpio.c @@ -213,9 +213,10 @@ static int nx_gpio_of_to_plat(struct udevice *dev) { struct nx_gpio_plat *plat = dev_get_plat(dev); - plat->regs = map_physmem(devfdt_get_addr(dev), - sizeof(struct nx_gpio_regs), - MAP_NOCACHE); + plat->regs = dev_remap_addr(dev); + if (!plat->regs) + return -EINVAL; + plat->gpio_count = dev_read_s32_default(dev, "nexell,gpio-bank-width", 32); plat->bank_name = dev_read_string(dev, "gpio-bank-name"); diff --git a/drivers/gpio/pca953x_gpio.c b/drivers/gpio/pca953x_gpio.c index 523ca8473a8..965a5fcf30b 100644 --- a/drivers/gpio/pca953x_gpio.c +++ b/drivers/gpio/pca953x_gpio.c @@ -312,7 +312,7 @@ static int pca953x_probe(struct udevice *dev) u8 val[MAX_BANK]; addr = dev_read_addr(dev); - if (addr == 0) + if (addr == FDT_ADDR_T_NONE) return -ENODEV; info->addr = addr; diff --git a/drivers/gpio/qcom_pmic_gpio.c b/drivers/gpio/qcom_pmic_gpio.c index 4458c55cd3d..ad4a70dd49b 100644 --- a/drivers/gpio/qcom_pmic_gpio.c +++ b/drivers/gpio/qcom_pmic_gpio.c @@ -344,7 +344,6 @@ static int qcom_gpio_probe(struct udevice *dev) static const struct udevice_id qcom_gpio_ids[] = { { .compatible = "qcom,pm8916-gpio" }, { .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */ - { .compatible = "qcom,pm8998-gpio" }, { .compatible = "qcom,pms405-gpio" }, { .compatible = "qcom,pm6125-gpio" }, { .compatible = "qcom,pm8150-gpio" }, @@ -410,7 +409,7 @@ static int qcom_pmic_pinctrl_generic_pinmux_set_mux(struct udevice *dev, unsigne return 0; } -struct pinctrl_ops qcom_pmic_pinctrl_ops = { +static const struct pinctrl_ops qcom_pmic_pinctrl_ops = { .get_pins_count = qcom_pmic_pinctrl_get_pins_count, .get_pin_name = qcom_pmic_pinctrl_get_pin_name, .set_state = pinctrl_generic_set_state, diff --git a/drivers/gpio/qcom_spmi_gpio.c b/drivers/gpio/qcom_spmi_gpio.c index 1a7c7c48dfc..3efee206007 100644 --- a/drivers/gpio/qcom_spmi_gpio.c +++ b/drivers/gpio/qcom_spmi_gpio.c @@ -747,10 +747,12 @@ static const struct udevice_id qcom_spmi_pmic_gpio_ids[] = { { .compatible = "qcom,pm6350-gpio" }, { .compatible = "qcom,pm660l-gpio" }, { .compatible = "qcom,pm7325-gpio" }, + { .compatible = "qcom,pm7550-gpio" }, { .compatible = "qcom,pm8550-gpio" }, { .compatible = "qcom,pm8550b-gpio" }, { .compatible = "qcom,pm8550ve-gpio" }, { .compatible = "qcom,pm8550vs-gpio" }, + { .compatible = "qcom,pm8998-gpio" }, { .compatible = "qcom,pmk8550-gpio" }, { .compatible = "qcom,pmr735d-gpio" }, { } @@ -1019,7 +1021,7 @@ static int qcom_spmi_pmic_pinctrl_pinmux_set_mux(struct udevice *dev, unsigned i return spmi_pmic_gpio_write(plat, pad, PMIC_GPIO_REG_EN_CTL, val); } -struct pinctrl_ops qcom_spmi_pmic_pinctrl_ops = { +static const struct pinctrl_ops qcom_spmi_pmic_pinctrl_ops = { .get_pins_count = qcom_spmi_pmic_pinctrl_get_pins_count, .get_pin_name = qcom_spmi_pmic_pinctrl_get_pin_name, .set_state = pinctrl_generic_set_state, diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c index e8f50d815d7..76aff0ed5aa 100644 --- a/drivers/gpio/sandbox.c +++ b/drivers/gpio/sandbox.c @@ -306,7 +306,7 @@ static int sb_gpio_get_name(const struct udevice *dev, char *out_name) return acpi_copy_name(out_name, "GPIO"); } -struct acpi_ops gpio_sandbox_acpi_ops = { +static const struct acpi_ops gpio_sandbox_acpi_ops = { .get_name = sb_gpio_get_name, }; #endif /* ACPIGEN */ @@ -568,7 +568,7 @@ static struct pinctrl_ops sandbox_pinctrl_gpio_ops = { }; #if CONFIG_IS_ENABLED(ACPIGEN) -struct acpi_ops pinctrl_sandbox_acpi_ops = { +static const struct acpi_ops pinctrl_sandbox_acpi_ops = { .get_name = sb_pinctrl_get_name, }; #endif diff --git a/drivers/gpio/spacemit_gpio.c b/drivers/gpio/spacemit_gpio.c new file mode 100644 index 00000000000..de71880df15 --- /dev/null +++ b/drivers/gpio/spacemit_gpio.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025-2026 RISCstar Ltd. + */ + +#include <asm/gpio.h> +#include <clk.h> +#include <dm/device.h> +#include <dm/device_compat.h> +#include <dm/pinctrl.h> +#include <dm/read.h> +#include <dm/uclass.h> +#include <linux/bitops.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <log.h> + +#define GPIO_BANK_SIZE 32 +#define GPIO_TO_BANK(pin) ((pin) / GPIO_BANK_SIZE) +#define GPIO_TO_BIT(pin) ((pin) % GPIO_BANK_SIZE) + +static inline int gpio_to_reg_offset(unsigned int pin) +{ + unsigned int bank = GPIO_TO_BANK(pin); + + if (bank == 0) + return 0; + else if (bank == 1) + return 4; + else if (bank == 2) + return 8; + else if (bank == 3) + return 0x100; + log_warning("Use default GPIO bank for an invalid GPIO[%d].\n", pin); + return 0; +} + +#define REG_PLR(pin) (0x00 + gpio_to_reg_offset(pin)) +#define REG_PDR(pin) (0x0c + gpio_to_reg_offset(pin)) +#define REG_PSR(pin) (0x18 + gpio_to_reg_offset(pin)) +#define REG_PCR(pin) (0x24 + gpio_to_reg_offset(pin)) +#define REG_SDR(pin) (0x54 + gpio_to_reg_offset(pin)) +#define REG_CDR(pin) (0x60 + gpio_to_reg_offset(pin)) + +struct spacemit_gpio_data { + u16 gpio_base; + u16 gpio_count; + u8 num_banks; +}; + +struct spacemit_gpio_priv { + void __iomem *regs; +}; + +static int spacemit_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, + struct ofnode_phandle_args *args) +{ + struct spacemit_gpio_data *data; + u32 bank, offset, flags; + + data = (struct spacemit_gpio_data *)dev_get_driver_data(dev); + if (args->args_count < 3) { + dev_err(dev, "Invalid args count: %d, expected 3\n", + args->args_count); + return -EINVAL; + } + bank = args->args[0]; + offset = args->args[1]; + flags = args->args[2]; + + if (bank >= data->num_banks) { + dev_err(dev, "Invalid gpio bank: %u (max %u)\n", + bank, data->num_banks - 1); + return -EINVAL; + } + if (offset >= GPIO_BANK_SIZE) { + dev_err(dev, "Invalid offset: %u (max 31)\n", offset); + return -EINVAL; + } + desc->offset = bank * GPIO_BANK_SIZE + offset; + desc->flags = gpio_flags_xlate(flags); + return 0; +} + +static int spacemit_gpio_get_value(struct udevice *dev, unsigned int offset) +{ + struct spacemit_gpio_priv *priv = dev_get_priv(dev); + void __iomem *addr; + u32 value, mask; + + addr = priv->regs + REG_PLR(offset); + value = readl(addr); + mask = 1 << GPIO_TO_BIT(offset); + return !!(value & mask); +} + +static int spacemit_gpio_get_function(struct udevice *dev, unsigned int offset) +{ + struct spacemit_gpio_priv *priv = dev_get_priv(dev); + void __iomem *addr; + u32 value, mask; + + addr = priv->regs + REG_PDR(offset); + value = readl(addr); + mask = 1 << GPIO_TO_BIT(offset); + if (value & mask) + return GPIOF_OUTPUT; + return GPIOF_INPUT; +} + +static int spacemit_gpio_get_flags(struct udevice *dev, unsigned int offset, + ulong *flagsp) +{ + ulong flags = 0; + u32 dir; + + dir = spacemit_gpio_get_function(dev, offset); + if (dir) { + flags |= GPIOD_IS_OUT; + if (spacemit_gpio_get_value(dev, offset)) + flags |= GPIOD_IS_OUT_ACTIVE; + } else { + flags |= GPIOD_IS_IN; + } + *flagsp = flags; + return 0; +} + +static int spacemit_gpio_set_flags(struct udevice *dev, unsigned int offset, + ulong flags) +{ + struct spacemit_gpio_priv *priv = dev_get_priv(dev); + void __iomem *addr; + int value; + + value = (flags & GPIOD_IS_OUT_ACTIVE) ? 1 : 0; + if (flags & GPIOD_IS_IN) { + addr = priv->regs + REG_CDR(offset); + writel(1 << GPIO_TO_BIT(offset), addr); + } + if (flags & GPIOD_IS_OUT) { + if (value) { + addr = priv->regs + REG_PSR(offset); + writel(1 << GPIO_TO_BIT(offset), addr); + } else { + addr = priv->regs + REG_PCR(offset); + writel(1 << GPIO_TO_BIT(offset), addr); + } + addr = priv->regs + REG_SDR(offset); + writel(1 << GPIO_TO_BIT(offset), addr); + } + return 0; +} + +static int spacemit_gpio_request(struct udevice *dev, unsigned int offset, + const char *label) +{ + const struct pinctrl_ops *ops; + struct udevice *pctldev; + int ret; + + ret = uclass_first_device_err(UCLASS_PINCTRL, &pctldev); + if (ret) + return ret; + + ops = pinctrl_get_ops(pctldev); + if (!ops->gpio_request_enable) + return -ENOSYS; + + return ops->gpio_request_enable(pctldev, offset); +} + +static int spacemit_gpio_rfree(struct udevice *dev, unsigned int offset) +{ + const struct pinctrl_ops *ops; + struct udevice *pctldev; + int ret; + + ret = uclass_first_device_err(UCLASS_PINCTRL, &pctldev); + if (ret) + return ret; + + ops = pinctrl_get_ops(pctldev); + if (!ops->gpio_disable_free) + return -ENOSYS; + + return ops->gpio_disable_free(pctldev, offset); +} + +static const struct dm_gpio_ops spacemit_gpio_ops = { + .request = spacemit_gpio_request, + .rfree = spacemit_gpio_rfree, + .xlate = spacemit_gpio_xlate, + .get_value = spacemit_gpio_get_value, + .get_function = spacemit_gpio_get_function, + .get_flags = spacemit_gpio_get_flags, + .set_flags = spacemit_gpio_set_flags, +}; + +static int spacemit_gpio_probe(struct udevice *dev) +{ + struct spacemit_gpio_priv *priv; + struct spacemit_gpio_data *data; + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct clk_bulk clks; + int ret; + + data = (struct spacemit_gpio_data *)dev_get_driver_data(dev); + priv = dev_get_priv(dev); + priv->regs = dev_read_addr_ptr(dev); + if (!priv->regs) { + dev_err(dev, "Fail to get base address\n"); + return -EINVAL; + } + uc_priv->bank_name = "GPIO"; + uc_priv->gpio_count = data->gpio_count; + uc_priv->gpio_base = data->gpio_base; + + ret = clk_get_bulk(dev, &clks); + if (ret) { + dev_err(dev, "Fail to get bulk clks\n"); + return ret; + } + ret = clk_enable_bulk(&clks); + if (ret) { + dev_err(dev, "Fail to enable bulk clks\n"); + goto out; + } + return 0; +out: + clk_release_bulk(&clks); + return ret; +} + +static const struct spacemit_gpio_data k1_gpio_data = { + .num_banks = 4, + .gpio_count = 128, + .gpio_base = 0, +}; + +static const struct udevice_id spacemit_gpio_ids[] = { + { .compatible = "spacemit,k1-gpio", .data = (uintptr_t)&k1_gpio_data, }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(k1_gpio) = { + .name = "spacemit_k1_gpio", + .id = UCLASS_GPIO, + .of_match = spacemit_gpio_ids, + .ops = &spacemit_gpio_ops, + .priv_auto = sizeof(struct spacemit_gpio_priv), + .probe = spacemit_gpio_probe, +}; diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 55465dc1d46..0e8b2408376 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -98,7 +98,7 @@ config SYS_I2C_EARLY_INIT board_early_init_f. config I2C_CROS_EC_TUNNEL - tristate "Chrome OS EC tunnel I2C bus" + bool "Chrome OS EC tunnel I2C bus" depends on CROS_EC help This provides an I2C bus that will tunnel i2c commands through to @@ -110,16 +110,16 @@ config I2C_CROS_EC_TUNNEL config I2C_CROS_EC_LDO bool "Provide access to LDOs on the Chrome OS EC" depends on CROS_EC - ---help--- - On many Chromebooks the main PMIC is inaccessible to the AP. This is - often dealt with by using an I2C pass-through interface provided by - the EC. On some unfortunate models (e.g. Spring) the pass-through - is not available, and an LDO message is available instead. This - option enables a driver which provides very basic access to those - regulators, via the EC. We implement this as an I2C bus which - emulates just the TPS65090 messages we know about. This is done to - avoid duplicating the logic in the TPS65090 regulator driver for - enabling/disabling an LDO. + help + On many Chromebooks the main PMIC is inaccessible to the AP. This is + often dealt with by using an I2C pass-through interface provided by + the EC. On some unfortunate models (e.g. Spring) the pass-through + is not available, and an LDO message is available instead. This + option enables a driver which provides very basic access to those + regulators, via the EC. We implement this as an I2C bus which + emulates just the TPS65090 messages we know about. This is done to + avoid duplicating the logic in the TPS65090 regulator driver for + enabling/disabling an LDO. config I2C_SET_DEFAULT_BUS_NUM bool "Set default I2C bus number" @@ -180,9 +180,9 @@ config SYS_I2C_IPROC Say yes here to to enable the Broadco I2C driver. config SYS_I2C_FSL - bool "Freescale I2C bus driver" - depends on M68K || PPC - help + bool "Freescale I2C bus driver" + depends on M68K || PPC + help Add support for Freescale I2C busses as used on MPC8240, MPC8245, and MPC85xx processors. @@ -213,14 +213,14 @@ config SYS_FSL_I2C4_OFFSET endif config SYS_I2C_CADENCE - tristate "Cadence I2C Controller" + bool "Cadence I2C Controller" depends on DM_I2C help Say yes here to select Cadence I2C Host Controller. This controller is e.g. used by Xilinx Zynq. config SYS_I2C_CA - tristate "Cortina-Access I2C Controller" + bool "Cortina-Access I2C Controller" depends on DM_I2C && CORTINA_PLATFORM help Add support for the Cortina Access I2C host controller. @@ -249,14 +249,14 @@ config SYS_I2C_DW_PCI controller. config SYS_I2C_AST2600 - bool "AST2600 I2C Controller" - depends on DM_I2C && ARCH_ASPEED - help - Say yes here to select AST2600 I2C Host Controller. The driver - support AST2600 I2C new mode register. This I2C controller supports: - _Standard-mode (up to 100 kHz) - _Fast-mode (up to 400 kHz) - _Fast-mode Plus (up to 1 MHz) + bool "AST2600 I2C Controller" + depends on DM_I2C && ARCH_ASPEED + help + Say yes here to select AST2600 I2C Host Controller. The driver + support AST2600 I2C new mode register. This I2C controller supports: + _Standard-mode (up to 100 kHz) + _Fast-mode (up to 400 kHz) + _Fast-mode Plus (up to 1 MHz) config SYS_I2C_ASPEED bool "Aspeed I2C Controller" @@ -333,50 +333,50 @@ if SYS_I2C_MXC && (SYS_I2C_LEGACY || SPL_SYS_I2C_LEGACY) config SYS_I2C_MXC_I2C1 bool "NXP MXC I2C1" help - Add support for NXP MXC I2C Controller 1. - Required for SoCs which have I2C MXC controller 1 eg LS1088A, LS2080A + Add support for NXP MXC I2C Controller 1. + Required for SoCs which have I2C MXC controller 1 eg LS1088A, LS2080A config SYS_I2C_MXC_I2C2 bool "NXP MXC I2C2" help - Add support for NXP MXC I2C Controller 2. - Required for SoCs which have I2C MXC controller 2 eg LS1088A, LS2080A + Add support for NXP MXC I2C Controller 2. + Required for SoCs which have I2C MXC controller 2 eg LS1088A, LS2080A config SYS_I2C_MXC_I2C3 bool "NXP MXC I2C3" help - Add support for NXP MXC I2C Controller 3. - Required for SoCs which have I2C MXC controller 3 eg LS1088A, LS2080A + Add support for NXP MXC I2C Controller 3. + Required for SoCs which have I2C MXC controller 3 eg LS1088A, LS2080A config SYS_I2C_MXC_I2C4 bool "NXP MXC I2C4" help - Add support for NXP MXC I2C Controller 4. - Required for SoCs which have I2C MXC controller 4 eg LS1088A, LS2080A + Add support for NXP MXC I2C Controller 4. + Required for SoCs which have I2C MXC controller 4 eg LS1088A, LS2080A config SYS_I2C_MXC_I2C5 bool "NXP MXC I2C5" help - Add support for NXP MXC I2C Controller 5. - Required for SoCs which have I2C MXC controller 5 eg LX2160A + Add support for NXP MXC I2C Controller 5. + Required for SoCs which have I2C MXC controller 5 eg LX2160A config SYS_I2C_MXC_I2C6 bool "NXP MXC I2C6" help - Add support for NXP MXC I2C Controller 6. - Required for SoCs which have I2C MXC controller 6 eg LX2160A + Add support for NXP MXC I2C Controller 6. + Required for SoCs which have I2C MXC controller 6 eg LX2160A config SYS_I2C_MXC_I2C7 bool "NXP MXC I2C7" help - Add support for NXP MXC I2C Controller 7. - Required for SoCs which have I2C MXC controller 7 eg LX2160A + Add support for NXP MXC I2C Controller 7. + Required for SoCs which have I2C MXC controller 7 eg LX2160A config SYS_I2C_MXC_I2C8 bool "NXP MXC I2C8" help - Add support for NXP MXC I2C Controller 8. - Required for SoCs which have I2C MXC controller 8 eg LX2160A + Add support for NXP MXC I2C Controller 8. + Required for SoCs which have I2C MXC controller 8 eg LX2160A endif if SYS_I2C_MXC_I2C1 @@ -385,13 +385,13 @@ config SYS_MXC_I2C1_SPEED default 40000000 if TARGET_LS2080A_EMU default 100000 help - MXC I2C Channel 1 speed + MXC I2C Channel 1 speed config SYS_MXC_I2C1_SLAVE hex "I2C1 Slave" default 0x0 help - MXC I2C1 Slave + MXC I2C1 Slave endif if SYS_I2C_MXC_I2C2 @@ -400,13 +400,13 @@ config SYS_MXC_I2C2_SPEED default 40000000 if TARGET_LS2080A_EMU default 100000 help - MXC I2C Channel 2 speed + MXC I2C Channel 2 speed config SYS_MXC_I2C2_SLAVE hex "I2C2 Slave" default 0x0 help - MXC I2C2 Slave + MXC I2C2 Slave endif if SYS_I2C_MXC_I2C3 @@ -414,13 +414,13 @@ config SYS_MXC_I2C3_SPEED int "I2C Channel 3 speed" default 100000 help - MXC I2C Channel 3 speed + MXC I2C Channel 3 speed config SYS_MXC_I2C3_SLAVE hex "I2C3 Slave" default 0x0 help - MXC I2C3 Slave + MXC I2C3 Slave endif if SYS_I2C_MXC_I2C4 @@ -428,13 +428,13 @@ config SYS_MXC_I2C4_SPEED int "I2C Channel 4 speed" default 100000 help - MXC I2C Channel 4 speed + MXC I2C Channel 4 speed config SYS_MXC_I2C4_SLAVE hex "I2C4 Slave" default 0x0 help - MXC I2C4 Slave + MXC I2C4 Slave endif if SYS_I2C_MXC_I2C5 @@ -442,13 +442,13 @@ config SYS_MXC_I2C5_SPEED int "I2C Channel 5 speed" default 100000 help - MXC I2C Channel 5 speed + MXC I2C Channel 5 speed config SYS_MXC_I2C5_SLAVE hex "I2C5 Slave" default 0x0 help - MXC I2C5 Slave + MXC I2C5 Slave endif if SYS_I2C_MXC_I2C6 @@ -456,13 +456,13 @@ config SYS_MXC_I2C6_SPEED int "I2C Channel 6 speed" default 100000 help - MXC I2C Channel 6 speed + MXC I2C Channel 6 speed config SYS_MXC_I2C6_SLAVE hex "I2C6 Slave" default 0x0 help - MXC I2C6 Slave + MXC I2C6 Slave endif if SYS_I2C_MXC_I2C7 @@ -470,13 +470,13 @@ config SYS_MXC_I2C7_SPEED int "I2C Channel 7 speed" default 100000 help - MXC I2C Channel 7 speed + MXC I2C Channel 7 speed config SYS_MXC_I2C7_SLAVE hex "I2C7 Slave" default 0x0 help - MXC I2C7 Slave + MXC I2C7 Slave endif if SYS_I2C_MXC_I2C8 @@ -484,13 +484,13 @@ config SYS_MXC_I2C8_SPEED int "I2C Channel 8 speed" default 100000 help - MXC I2C Channel 8 speed + MXC I2C Channel 8 speed config SYS_MXC_I2C8_SLAVE hex "I2C8 Slave" default 0x0 help - MXC I2C8 Slave + MXC I2C8 Slave endif config SYS_I2C_NEXELL @@ -624,26 +624,6 @@ config SH_I2C_CLOCK default 104000000 endif -config SYS_I2C_SOFT - bool "Legacy software I2C interface" - depends on !COMPILE_TEST - help - Enable the legacy software defined I2C interface - -config SYS_I2C_SOFT_SPEED - int "Software I2C bus speed" - depends on SYS_I2C_SOFT - default 100000 - help - Speed of the software I2C bus - -config SYS_I2C_SOFT_SLAVE - hex "Software I2C slave address" - depends on SYS_I2C_SOFT - default 0xfe - help - Slave address of the software I2C bus - config SYS_I2C_OCTEON bool "Octeon II/III/TX/TX2 I2C driver" depends on (ARCH_OCTEON || ARCH_OCTEONTX || ARCH_OCTEONTX2) && DM_I2C @@ -688,19 +668,19 @@ config SYS_I2C_STM32F7 help Enable this option to add support for STM32 I2C controller introduced with STM32F7/H7 SoCs. This I2C controller supports : - _ Slave and master modes - _ Multimaster capability - _ Standard-mode (up to 100 kHz) - _ Fast-mode (up to 400 kHz) - _ Fast-mode Plus (up to 1 MHz) - _ 7-bit and 10-bit addressing mode - _ Multiple 7-bit slave addresses (2 addresses, 1 with configurable mask) - _ All 7-bit addresses acknowledge mode - _ General call - _ Programmable setup and hold times - _ Easy to use event management - _ Optional clock stretching - _ Software reset + _ Slave and master modes + _ Multimaster capability + _ Standard-mode (up to 100 kHz) + _ Fast-mode (up to 400 kHz) + _ Fast-mode Plus (up to 1 MHz) + _ 7-bit and 10-bit addressing mode + _ Multiple 7-bit slave addresses (2 addresses, 1 with configurable mask) + _ All 7-bit addresses acknowledge mode + _ General call + _ Programmable setup and hold times + _ Easy to use event management + _ Optional clock stretching + _ Software reset config SYS_I2C_SUN6I_P2WI bool "Allwinner sun6i P2WI controller" @@ -800,7 +780,7 @@ config SYS_I2C_BUS_MAX int "Max I2C busses" depends on ARCH_OMAP2PLUS || ARCH_SOCFPGA default 3 if OMAP34XX || AM33XX || AM43XX - default 4 if ARCH_SOCFPGA + default 4 if ARCH_SOCFPGA || OMAP44XX default 5 if OMAP54XX help Define the maximum number of available I2C buses. @@ -812,10 +792,17 @@ config SYS_I2C_XILINX_XIIC Support for Xilinx AXI I2C controller. config SYS_I2C_IHS - bool "gdsys IHS I2C driver" - depends on DM_I2C - help - Support for gdsys IHS I2C driver on FPGA bus. + bool "gdsys IHS I2C driver" + depends on DM_I2C + help + Support for gdsys IHS I2C driver on FPGA bus. + +config SYS_I2C_SPACEMIT_K1 + bool "Spacemit K1 I2C driver" + depends on DM_I2C + help + Support for Spacemit I2C controller. It's based on + Driver Model. source "drivers/i2c/muxes/Kconfig" diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 5fe30d0df4f..0e3a0f9fb5f 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -47,7 +47,7 @@ obj-$(CONFIG_SYS_I2C_RZ_RIIC) += rz_riic.o obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o exynos_hs_i2c.o obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o -obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o +obj-$(CONFIG_SYS_I2C_SPACEMIT_K1) += k1_i2c.o obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o obj-$(CONFIG_SYS_I2C_SUN6I_P2WI) += sun6i_p2wi.o obj-$(CONFIG_SYS_I2C_SUN8I_RSB) += sun8i_rsb.o diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index 8ad716f410e..8d290acefda 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -740,13 +740,47 @@ static int designware_i2c_probe_chip(struct udevice *bus, uint chip_addr, { struct dw_i2c *i2c = dev_get_priv(bus); struct i2c_regs *i2c_base = i2c->regs; - u32 tmp; - int ret; + u32 start_time, ic_status; + int ret = 0; - /* Try to read the first location of the chip */ - ret = __dw_i2c_read(i2c_base, chip_addr, 0, 1, (uchar *)&tmp, 1); + ret = i2c_wait_for_bb(i2c_base); if (ret) - __dw_i2c_init(i2c_base, 0, 0); + return ret; + + dw_i2c_enable(i2c_base, false); + writel(chip_addr, &i2c_base->ic_tar); + dw_i2c_enable(i2c_base, true); + + writel(IC_STOP, &i2c_base->ic_cmd_data); + + start_time = get_timer(0); + while (1) { + ic_status = readl(&i2c_base->ic_status); + + if ((ic_status & IC_STATUS_TFE) && !(ic_status & IC_STATUS_MA)) + break; + + if (readl(&i2c_base->ic_raw_intr_stat) & IC_TX_ABRT) { + readl(&i2c_base->ic_clr_tx_abrt); + ret = -EREMOTEIO; + break; + } + + if (get_timer(start_time) > I2C_BYTE_TO) { + ret = -ETIMEDOUT; + break; + } + } + + start_time = get_timer(0); + while (1) { + if ((readl(&i2c_base->ic_raw_intr_stat) & IC_STOP_DET)) { + readl(&i2c_base->ic_clr_stop_det); + break; + } else if (get_timer(start_time) > I2C_STOPDET_TO) { + break; + } + } return ret; } diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c index c21c412231c..db2706fdb6e 100644 --- a/drivers/i2c/designware_i2c_pci.c +++ b/drivers/i2c/designware_i2c_pci.c @@ -168,7 +168,7 @@ static int dw_i2c_acpi_fill_ssdt(const struct udevice *dev, return 0; } -struct acpi_ops dw_i2c_acpi_ops = { +static const struct acpi_ops dw_i2c_acpi_ops = { .fill_ssdt = dw_i2c_acpi_fill_ssdt, }; diff --git a/drivers/i2c/imx_lpi2c.c b/drivers/i2c/imx_lpi2c.c index a309fd6f07c..e2b4fd334ec 100644 --- a/drivers/i2c/imx_lpi2c.c +++ b/drivers/i2c/imx_lpi2c.c @@ -239,7 +239,6 @@ static int bus_i2c_stop(struct udevice *bus) start_time = get_timer(0); while (1) { status = readl(®s->msr); - result = imx_lpci2c_check_clear_error(regs); /* stop detect flag */ if (status & LPI2C_MSR_SDF_MASK) { /* clear stop flag */ @@ -250,10 +249,13 @@ static int bus_i2c_stop(struct udevice *bus) if (get_timer(start_time) > LPI2C_NACK_TOUT_MS) { debug("stop timeout\n"); + result = imx_lpci2c_check_clear_error(regs); return -ETIMEDOUT; } } + result = imx_lpci2c_check_clear_error(regs); + return result; } diff --git a/drivers/i2c/k1_i2c.c b/drivers/i2c/k1_i2c.c new file mode 100644 index 00000000000..a08ff15803d --- /dev/null +++ b/drivers/i2c/k1_i2c.c @@ -0,0 +1,523 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023-2026 Spacemit, Inc + * Copyright (C) 2025-2026 RISCstar Ltd. + */ + +#include <asm/io.h> +#include <clk.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <i2c.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <reset.h> +#include "k1_i2c.h" + +#define ICR_OFFSET 0x00 +#define ISR_OFFSET 0x04 +#define ISAR_OFFSET 0x08 +#define IDBR_OFFSET 0x0c +#define ILCR_OFFSET 0x10 +#define IWCR_OFFSET 0x14 +#define IRCR_OFFSET 0x18 +#define IBMR_OFFSET 0x1c +#define WFIFO_OFFSET 0x20 +#define WFIFO_WPTR_OFFSET 0x24 +#define WFIFO_RPTR_OFFSET 0x28 +#define RFIFO_OFFSET 0x2c +#define RFIFO_WPTR_OFFSET 0x30 +#define RFIFO_RPTR_OFFSET 0x34 + +/* All transfers are described by this data structure */ +struct k1_i2c_msg { + u8 condition; + u8 acknack; + u8 direction; + u8 data; +}; + +struct k1_i2c { + u32 icr; + u32 isr; + u32 isar; + u32 idbr; + u32 ilcr; + u32 iwcr; + u32 irst_cyc; + u32 ibmr; +}; + +struct k1_i2c_priv { + int id; + void __iomem *base; + struct clk clk; + u32 clk_rate; +}; + +/* + * i2c_reset: - reset the host controller + * + */ +static void i2c_reset(void __iomem *base) +{ + u32 icr_mode; + u32 val; + + /* Save bus mode (standard or fast speed) for later use */ + icr_mode = readl(base + ICR_OFFSET) & ICR_MODE_MASK; + /* disable unit */ + val = readl(base + ICR_OFFSET); + writel(val & ~ICR_IUE, base + ICR_OFFSET); + udelay(10); + /* reset the unit */ + val = readl(base + ICR_OFFSET); + val |= ICR_UR; + writel(val, base + ICR_OFFSET); + udelay(100); + /* disable unit */ + val = readl(base + ICR_OFFSET); + writel(val & ~ICR_IUE, base + ICR_OFFSET); + + /* set slave address */ + writel(0x00, base + ISR_OFFSET); + /* set control reg values */ + writel(I2C_ICR_INIT | icr_mode, base + ICR_OFFSET); + writel(I2C_ISR_INIT, base + ISR_OFFSET); /* set clear interrupt bits */ + val = readl(base + ICR_OFFSET); + val |= ICR_IUE; + writel(val, base + ICR_OFFSET); /* enable unit */ + udelay(100); +} + +static inline bool is_isr_set_or_clr(unsigned long isr, unsigned long set_mask, + unsigned long clr_mask) +{ + return ((isr & set_mask) == set_mask) && ((isr & clr_mask) == 0); +} + +/* + * i2c_isr_set_cleared: - wait until certain bits of the I2C status register + * are set and cleared + * + * @return: 0 on success or -ETIMEDOUT. + */ +static int i2c_isr_set_cleared(void __iomem *base, unsigned long set_mask, + unsigned long clr_mask) +{ + int cnt = 1000, delay = 10, isr, ret; + + ret = read_poll_timeout(readl, isr, + is_isr_set_or_clr(isr, set_mask, clr_mask), + delay, delay * cnt, base + ISR_OFFSET); + return ret; +} + +/* + * i2c_transfer: - Transfer one byte over the i2c bus + * + * This function can transfer a byte over the i2c bus in both directions. + * It is used by the public API functions. + * + * @return: 0: transfer successful or error code + */ +static int i2c_transfer(void __iomem *base, struct k1_i2c_msg *msg) +{ + int ret; + u32 val; + + if (!msg) + goto transfer_error_msg_empty; + + switch (msg->direction) { + case I2C_WRITE: + /* check if bus is not busy */ + if (i2c_isr_set_cleared(base, 0, ISR_IBB)) + goto transfer_error_bus_busy; + + /* start transmission */ + val = readl(base + ICR_OFFSET); + val &= ~ICR_START; + writel(val, base + ICR_OFFSET); + val = readl(base + ICR_OFFSET); + val &= ~ICR_STOP; + writel(val, base + ICR_OFFSET); + writel(msg->data, base + IDBR_OFFSET); + if (msg->condition == I2C_COND_START) { + val = readl(base + ICR_OFFSET); + val |= ICR_START; + writel(val, base + ICR_OFFSET); + } + if (msg->condition == I2C_COND_STOP) { + val = readl(base + ICR_OFFSET); + val |= ICR_STOP; + writel(val, base + ICR_OFFSET); + } + if (msg->acknack == I2C_ACKNAK_SENDNAK) { + val = readl(base + ICR_OFFSET); + val |= ICR_ACKNAK; + writel(val, base + ICR_OFFSET); + } + if (msg->acknack == I2C_ACKNAK_SENDACK) { + val = readl(base + ICR_OFFSET); + val &= ~ICR_ACKNAK; + writel(val, base + ICR_OFFSET); + } + val = readl(base + ICR_OFFSET); + val &= ~ICR_ALDIE; + writel(val, base + ICR_OFFSET); + val = readl(base + ICR_OFFSET); + val |= ICR_TB; + writel(val, base + ICR_OFFSET); + + /* transmit register empty? */ + if (i2c_isr_set_cleared(base, ISR_ITE, 0)) + goto transfer_error_transmit_timeout; + + /* clear 'transmit empty' state */ + val = readl(base + ISR_OFFSET); + val |= ISR_ITE; + writel(val, base + ISR_OFFSET); + + /* wait for ACK from slave */ + if (msg->acknack == I2C_ACKNAK_WAITACK) + if (i2c_isr_set_cleared(base, 0, ISR_ACKNAK)) + goto transfer_error_ack_missing; + break; + + case I2C_READ: + /* check if bus is not busy */ + if (i2c_isr_set_cleared(base, 0, ISR_IBB)) + goto transfer_error_bus_busy; + + /* start receive */ + val = readl(base + ICR_OFFSET); + val &= ~ICR_START; + writel(val, base + ICR_OFFSET); + val = readl(base + ICR_OFFSET); + val &= ~ICR_STOP; + writel(val, base + ICR_OFFSET); + if (msg->condition == I2C_COND_START) { + val = readl(base + ICR_OFFSET); + val |= ICR_START; + writel(val, base + ICR_OFFSET); + } + if (msg->condition == I2C_COND_STOP) { + val = readl(base + ICR_OFFSET); + val |= ICR_STOP; + writel(val, base + ICR_OFFSET); + } + if (msg->acknack == I2C_ACKNAK_SENDNAK) { + val = readl(base + ICR_OFFSET); + val |= ICR_ACKNAK; + writel(val, base + ICR_OFFSET); + } + if (msg->acknack == I2C_ACKNAK_SENDACK) { + val = readl(base + ICR_OFFSET); + val &= ~ICR_ACKNAK; + writel(val, base + ICR_OFFSET); + } + val = readl(base + ICR_OFFSET); + val &= ~ICR_ALDIE; + writel(val, base + ICR_OFFSET); + val = readl(base + ICR_OFFSET); + val |= ICR_TB; + writel(val, base + ICR_OFFSET); + + /* receive register full? */ + if (i2c_isr_set_cleared(base, ISR_IRF, 0)) + goto transfer_error_receive_timeout; + + msg->data = readl(base + IDBR_OFFSET); + + /* clear 'receive empty' state */ + val = readl(base + ISR_OFFSET); + val |= ISR_IRF; + writel(val, base + ISR_OFFSET); + break; + default: + goto transfer_error_illegal_param; + } + + return 0; + +transfer_error_msg_empty: + debug("%s: error: 'msg' is empty\n", __func__); + ret = -EINVAL; + goto i2c_transfer_finish; + +transfer_error_transmit_timeout: + debug("%s: error: transmit timeout\n", __func__); + ret = -ETIMEDOUT; + goto i2c_transfer_finish; + +transfer_error_ack_missing: + debug("%s: error: ACK missing\n", __func__); + ret = -EREMOTEIO; + goto i2c_transfer_finish; + +transfer_error_receive_timeout: + debug("%s: error: receive timeout\n", __func__); + ret = -ETIMEDOUT; + goto i2c_transfer_finish; + +transfer_error_illegal_param: + debug("%s: error: illegal parameters\n", __func__); + ret = -EINVAL; + goto i2c_transfer_finish; + +transfer_error_bus_busy: + debug("%s: error: bus is busy\n", __func__); + ret = -EIO; + goto i2c_transfer_finish; + +i2c_transfer_finish: + debug("%s: ISR: 0x%04x\n", __func__, readl(base + ISR_OFFSET)); + i2c_reset(base); + return ret; +} + +static int __i2c_read(void __iomem *base, uchar chip, u8 *addr, int alen, + uchar *buffer, int len) +{ + struct k1_i2c_msg msg; + int ret; + + debug("%s(chip=0x%02x, addr=0x%02x, alen=0x%02x, len=0x%02x)\n", + __func__, chip, *addr, alen, len); + + if (len == 0) { + pr_err("reading zero byte is invalid\n"); + return -EINVAL; + } + + i2c_reset(base); + + /* dummy chip address write */ + debug("%s: dummy chip address write\n", __func__); + msg.condition = I2C_COND_START; + msg.acknack = I2C_ACKNAK_WAITACK; + msg.direction = I2C_WRITE; + msg.data = (chip << 1); + msg.data &= 0xFE; + ret = i2c_transfer(base, &msg); + if (ret) + return ret; + + /* + * send memory address bytes; + * alen defines how much bytes we have to send. + */ + while (--alen >= 0) { + debug("%s: send address byte %02x (alen=%d)\n", + __func__, *addr, alen); + msg.condition = I2C_COND_NORMAL; + msg.acknack = I2C_ACKNAK_WAITACK; + msg.direction = I2C_WRITE; + msg.data = addr[alen]; + ret = i2c_transfer(base, &msg); + if (ret) + return ret; + } + + /* start read sequence */ + debug("%s: start read sequence\n", __func__); + msg.condition = I2C_COND_START; + msg.acknack = I2C_ACKNAK_WAITACK; + msg.direction = I2C_WRITE; + msg.data = (chip << 1); + msg.data |= 0x01; + ret = i2c_transfer(base, &msg); + if (ret) + return ret; + + /* read bytes; send NACK at last byte */ + while (len--) { + if (len == 0) { + msg.condition = I2C_COND_STOP; + msg.acknack = I2C_ACKNAK_SENDNAK; + } else { + msg.condition = I2C_COND_NORMAL; + msg.acknack = I2C_ACKNAK_SENDACK; + } + + msg.direction = I2C_READ; + msg.data = 0x00; + ret = i2c_transfer(base, &msg); + if (ret) + return ret; + + *buffer = msg.data; + debug("%s: reading byte (%p)=0x%02x\n", + __func__, buffer, *buffer); + buffer++; + } + + i2c_reset(base); + + return 0; +} + +static int __i2c_write(struct k1_i2c *base, uchar chip, u8 *addr, int alen, + uchar *buffer, int len) +{ + struct k1_i2c_msg msg; + int ret; + + debug("%s(chip=0x%02x, addr=0x%02x, alen=0x%02x, len=0x%02x)\n", + __func__, chip, *addr, alen, len); + + i2c_reset(base); + + /* chip address write */ + debug("%s: chip address write\n", __func__); + msg.condition = I2C_COND_START; + msg.acknack = I2C_ACKNAK_WAITACK; + msg.direction = I2C_WRITE; + msg.data = (chip << 1); + msg.data &= 0xFE; + ret = i2c_transfer(base, &msg); + if (ret) + return ret; + + /* + * send memory address bytes; + * alen defines how much bytes we have to send. + */ + while (--alen >= 0) { + debug("%s: send address byte %02x (alen=%d)\n", + __func__, *addr, alen); + msg.condition = I2C_COND_NORMAL; + msg.acknack = I2C_ACKNAK_WAITACK; + msg.direction = I2C_WRITE; + msg.data = addr[alen]; + ret = i2c_transfer(base, &msg); + if (ret) + return ret; + } + + /* write bytes; send NACK at last byte */ + while (len--) { + debug("%s: writing byte (%p)=0x%02x\n", + __func__, buffer, *buffer); + + if (len == 0) + msg.condition = I2C_COND_STOP; + else + msg.condition = I2C_COND_NORMAL; + + msg.acknack = I2C_ACKNAK_WAITACK; + msg.direction = I2C_WRITE; + msg.data = *(buffer++); + + ret = i2c_transfer(base, &msg); + if (ret) + return ret; + } + + i2c_reset(base); + + return 0; +} + +static int k1_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) +{ + struct k1_i2c_priv *i2c = dev_get_priv(bus); + struct i2c_msg *dmsg, *omsg, dummy; + + memset(&dummy, 0, sizeof(struct i2c_msg)); + + /* + * We expect either two messages (one with an offset and one with the + * actual data) or one message (just data or offset/data combined) + */ + if (nmsgs > 2 || nmsgs == 0) { + debug("%s: Only one or two messages are supported.", __func__); + return -EINVAL; + } + + omsg = nmsgs == 1 ? &dummy : msg; + dmsg = nmsgs == 1 ? msg : msg + 1; + + if (dmsg->flags & I2C_M_RD) + return __i2c_read(i2c->base, dmsg->addr, omsg->buf, + omsg->len, dmsg->buf, dmsg->len); + else + return __i2c_write(i2c->base, dmsg->addr, omsg->buf, + omsg->len, dmsg->buf, dmsg->len); +} + +static int k1_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) +{ + struct k1_i2c_priv *priv = dev_get_priv(bus); + void __iomem *base = priv->base; + u32 val; + + if (speed > I2C_SPEED_STANDARD_RATE) + val = ICR_FM; + else + val = ICR_SM; + clrsetbits_le32(base + ICR_OFFSET, ICR_MODE_MASK, val); + + return 0; +} + +static int k1_i2c_probe(struct udevice *bus) +{ + struct k1_i2c_priv *priv = dev_get_priv(bus); + struct reset_ctl reset; + int ret; + + priv->id = dev_seq(bus); + + /* + * The upstream K1 dts intentionally omits the 'resets' property + * on i2c nodes — the apbc clock-enable path performs the + * controller reset internally as part of clock gating. Treat the + * reset lookup as optional so we work on the kernel-mainline DT. + */ + ret = reset_get_by_index(bus, 0, &reset); + if (!ret) { + reset_assert(&reset); + udelay(10); + reset_deassert(&reset); + udelay(10); + } else if (ret != -ENOENT && ret != -ENODATA) { + dev_err(bus, "%s: reset lookup failed (%d)\n", __func__, ret); + return ret; + } + + ret = clk_get_by_index(bus, 0, &priv->clk); + if (ret) + return ret; + + ret = clk_enable(&priv->clk); + if (ret && ret != -ENOSYS && ret != -EOPNOTSUPP) { + debug("%s: failed to enable clock\n", __func__); + return ret; + } + priv->clk_rate = clk_get_rate(&priv->clk); + + priv->base = (void *)devfdt_get_addr_ptr(bus); + k1_i2c_set_bus_speed(bus, priv->clk_rate); + return 0; +} + +static const struct dm_i2c_ops k1_i2c_ops = { + .xfer = k1_i2c_xfer, + .set_bus_speed = k1_i2c_set_bus_speed, +}; + +static const struct udevice_id k1_i2c_ids[] = { + { .compatible = "spacemit,k1-i2c" }, + { } +}; + +U_BOOT_DRIVER(i2c_spacemit) = { + .name = "i2c_spacemit", + .id = UCLASS_I2C, + .of_match = k1_i2c_ids, + .probe = k1_i2c_probe, + .priv_auto = sizeof(struct k1_i2c_priv), + .ops = &k1_i2c_ops, +}; diff --git a/drivers/i2c/k1_i2c.h b/drivers/i2c/k1_i2c.h new file mode 100644 index 00000000000..856947aa43b --- /dev/null +++ b/drivers/i2c/k1_i2c.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2023-2026 Spacemit Ltd. + * Copyright (C) 2025-2026 RISCstar Ltd. + */ + +#ifndef __SPACEMIT_I2C_H +#define __SPACEMIT_I2C_H + +/* Shall the current transfer have a start/stop condition? */ +#define I2C_COND_NORMAL 0 +#define I2C_COND_START 1 +#define I2C_COND_STOP 2 + +/* Shall the current transfer be ack/nacked or being waited for it? */ +#define I2C_ACKNAK_WAITACK 1 +#define I2C_ACKNAK_SENDACK 2 +#define I2C_ACKNAK_SENDNAK 4 + +/* Specify who shall transfer the data (master or slave) */ +#define I2C_READ 0 +#define I2C_WRITE 1 + +#if (CONFIG_SYS_I2C_SPEED == 400000) +#define I2C_ICR_INIT (ICR_FM | ICR_BEIE | ICR_IRFIE | ICR_ITEIE | \ + ICR_GCD | ICR_SCLE) +#else +#define I2C_ICR_INIT (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | \ + ICR_SCLE) +#endif + +/* ----- Control register bits ---------------------------------------- */ + +#define ICR_START 0x1 /* start bit */ +#define ICR_STOP 0x2 /* stop bit */ +#define ICR_ACKNAK 0x4 /* send ACK(0) or NAK(1) */ +#define ICR_TB 0x8 /* transfer byte bit */ +#define ICR_MA BIT(12) /* master abort */ +#define ICR_SCLE BIT(13) /* master clock enable, mona SCLEA */ +#define ICR_IUE BIT(14) /* unit enable */ +#define ICR_GCD BIT(21) /* general call disable */ +#define ICR_ITEIE BIT(19) /* enable tx interrupts */ +#define ICR_IRFIE BIT(20) /* enable rx interrupts, mona: DRFIE */ +#define ICR_BEIE BIT(22) /* enable bus error ints */ +#define ICR_SSDIE BIT(24) /* slave STOP detected int enable */ +#define ICR_ALDIE BIT(18) /* enable arbitration interrupt */ +#define ICR_SADIE BIT(23) /* slave address detected int enable */ +#define ICR_UR BIT(10) /* unit reset */ +#define ICR_SM (0x0) /* Standard Mode */ +#define ICR_FM BIT(8) /* Fast Mode */ +#define ICR_MODE_MASK (0x300) /* Mode mask */ + +/* ----- Status register bits ----------------------------------------- */ + +#define ISR_RWM BIT(13) /* read/write mode */ +#define ISR_ACKNAK BIT(14) /* ack/nak status */ +#define ISR_UB BIT(15) /* unit busy */ +#define ISR_IBB BIT(16) /* bus busy */ +#define ISR_SSD BIT(24) /* slave stop detected */ +#define ISR_ALD BIT(18) /* arbitration loss detected */ +#define ISR_ITE BIT(19) /* tx buffer empty */ +#define ISR_IRF BIT(20) /* rx buffer full */ +#define ISR_GCAD BIT(21) /* general call address detected */ +#define ISR_SAD BIT(23) /* slave address detected */ +#define ISR_BED BIT(22) /* bus error no ACK/NAK */ + +#define I2C_ISR_INIT 0x1FDE000 + +#endif diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index 3b1220b2105..89a4b82458a 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -26,14 +26,14 @@ config I2C_ARB_GPIO_CHALLENGE a GPIO. config I2C_MUX_PCA9541 - tristate "NXP PCA9541 I2C Master Selector" + bool "NXP PCA9541 I2C Master Selector" depends on I2C_MUX help If you say yes here you get support for the NXP PCA9541 I2C Master Selector. config I2C_MUX_PCA954x - tristate "TI PCA954x I2C Mux/switches" + bool "TI PCA954x I2C Mux/switches" depends on I2C_MUX help If you say yes here you get support for the TI PCA954x I2C mux/switch @@ -49,7 +49,7 @@ config I2C_MUX_PCA954x MAX7356, MAX7357, MAX7358, MAX7367, MAX7368 and MAX7369 config I2C_MUX_GPIO - tristate "GPIO-based I2C multiplexer" + bool "GPIO-based I2C multiplexer" depends on I2C_MUX && DM_GPIO select DEVRES help diff --git a/drivers/i2c/nx_i2c.c b/drivers/i2c/nx_i2c.c index 706b7adefe8..5800e79ab70 100644 --- a/drivers/i2c/nx_i2c.c +++ b/drivers/i2c/nx_i2c.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0+ + #include <errno.h> #include <dm.h> #include <i2c.h> @@ -230,12 +232,13 @@ static void i2c_process_node(struct udevice *dev) static int nx_i2c_probe(struct udevice *dev) { struct nx_i2c_bus *bus = dev_get_priv(dev); - fdt_addr_t addr; + void __iomem *addr; /* get regs = i2c base address */ - addr = devfdt_get_addr(dev); - if (addr == FDT_ADDR_T_NONE) + addr = dev_read_addr_ptr(dev); + if (!addr) return -EINVAL; + bus->regs = (struct nx_i2c_regs *)addr; bus->bus_num = dev_seq(dev); diff --git a/drivers/i2c/soft_i2c.c b/drivers/i2c/soft_i2c.c index 4102375e5b7..e69de29bb2d 100644 --- a/drivers/i2c/soft_i2c.c +++ b/drivers/i2c/soft_i2c.c @@ -1,418 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * (C) Copyright 2009 - * Heiko Schocher, DENX Software Engineering, [email protected]. - * Changes for multibus/multiadapter I2C support. - * - * (C) Copyright 2001, 2002 - * Wolfgang Denk, DENX Software Engineering, [email protected]. - * - * This has been changed substantially by Gerald Van Baren, Custom IDEAS, - * [email protected]. It was heavily influenced by LiMon, written by - * Neil Russell. - * - * NOTE: This driver should be converted to driver model before June 2017. - * Please see doc/driver-model/i2c-howto.rst for instructions. - */ - -#include <config.h> -#if defined(CONFIG_AT91FAMILY) -#include <asm/io.h> -#include <asm/arch/hardware.h> -#include <asm/arch/at91_pio.h> -#ifdef CONFIG_ATMEL_LEGACY -#include <asm/arch/gpio.h> -#endif -#endif -#include <i2c.h> -#include <linux/delay.h> - -#if defined(CONFIG_SOFT_I2C_GPIO_SCL) -# include <asm/gpio.h> - -# ifndef I2C_GPIO_SYNC -# define I2C_GPIO_SYNC -# endif - -# ifndef I2C_INIT -# define I2C_INIT \ - do { \ - gpio_request(CONFIG_SOFT_I2C_GPIO_SCL, "soft_i2c"); \ - gpio_request(CONFIG_SOFT_I2C_GPIO_SDA, "soft_i2c"); \ - } while (0) -# endif - -# ifndef I2C_ACTIVE -# define I2C_ACTIVE do { } while (0) -# endif - -# ifndef I2C_TRISTATE -# define I2C_TRISTATE do { } while (0) -# endif - -# ifndef I2C_READ -# define I2C_READ gpio_get_value(CONFIG_SOFT_I2C_GPIO_SDA) -# endif - -# ifndef I2C_SDA -# define I2C_SDA(bit) \ - do { \ - if (bit) \ - gpio_direction_input(CONFIG_SOFT_I2C_GPIO_SDA); \ - else \ - gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SDA, 0); \ - I2C_GPIO_SYNC; \ - } while (0) -# endif - -# ifndef I2C_SCL -# define I2C_SCL(bit) \ - do { \ - gpio_direction_output(CONFIG_SOFT_I2C_GPIO_SCL, bit); \ - I2C_GPIO_SYNC; \ - } while (0) -# endif - -# ifndef I2C_DELAY -# define I2C_DELAY udelay(5) /* 1/4 I2C clock duration */ -# endif - -#endif - -/* #define DEBUG_I2C */ - -#ifndef I2C_SOFT_DECLARATIONS -# define I2C_SOFT_DECLARATIONS -#endif - -/*----------------------------------------------------------------------- - * Definitions - */ -#define RETRIES 0 - -#define I2C_ACK 0 /* PD_SDA level to ack a byte */ -#define I2C_NOACK 1 /* PD_SDA level to noack a byte */ - -#ifdef DEBUG_I2C -#define PRINTD(fmt,args...) do { \ - printf (fmt ,##args); \ - } while (0) -#else -#define PRINTD(fmt,args...) -#endif - -/*----------------------------------------------------------------------- - * Local functions - */ -static void send_reset (void); -static void send_start (void); -static void send_stop (void); -static void send_ack (int); -static int write_byte (uchar byte); -static uchar read_byte (int); - -/*----------------------------------------------------------------------- - * Send a reset sequence consisting of 9 clocks with the data signal high - * to clock any confused device back into an idle state. Also send a - * <stop> at the end of the sequence for belts & suspenders. - */ -static void send_reset(void) -{ - I2C_SOFT_DECLARATIONS /* intentional without ';' */ - int j; - - I2C_SCL(1); - I2C_SDA(1); -#ifdef I2C_INIT - I2C_INIT; -#endif - I2C_TRISTATE; - for(j = 0; j < 9; j++) { - I2C_SCL(0); - I2C_DELAY; - I2C_DELAY; - I2C_SCL(1); - I2C_DELAY; - I2C_DELAY; - } - send_stop(); - I2C_TRISTATE; -} - -/*----------------------------------------------------------------------- - * START: High -> Low on SDA while SCL is High - */ -static void send_start(void) -{ - I2C_SOFT_DECLARATIONS /* intentional without ';' */ - - I2C_DELAY; - I2C_SDA(1); - I2C_ACTIVE; - I2C_DELAY; - I2C_SCL(1); - I2C_DELAY; - I2C_SDA(0); - I2C_DELAY; -} - -/*----------------------------------------------------------------------- - * STOP: Low -> High on SDA while SCL is High - */ -static void send_stop(void) -{ - I2C_SOFT_DECLARATIONS /* intentional without ';' */ - - I2C_SCL(0); - I2C_DELAY; - I2C_SDA(0); - I2C_ACTIVE; - I2C_DELAY; - I2C_SCL(1); - I2C_DELAY; - I2C_SDA(1); - I2C_DELAY; - I2C_TRISTATE; -} - -/*----------------------------------------------------------------------- - * ack should be I2C_ACK or I2C_NOACK - */ -static void send_ack(int ack) -{ - I2C_SOFT_DECLARATIONS /* intentional without ';' */ - - I2C_SCL(0); - I2C_DELAY; - I2C_ACTIVE; - I2C_SDA(ack); - I2C_DELAY; - I2C_SCL(1); - I2C_DELAY; - I2C_DELAY; - I2C_SCL(0); - I2C_DELAY; -} - -/*----------------------------------------------------------------------- - * Send 8 bits and look for an acknowledgement. - */ -static int write_byte(uchar data) -{ - I2C_SOFT_DECLARATIONS /* intentional without ';' */ - int j; - int nack; - - I2C_ACTIVE; - for(j = 0; j < 8; j++) { - I2C_SCL(0); - I2C_DELAY; - I2C_SDA(data & 0x80); - I2C_DELAY; - I2C_SCL(1); - I2C_DELAY; - I2C_DELAY; - - data <<= 1; - } - - /* - * Look for an <ACK>(negative logic) and return it. - */ - I2C_SCL(0); - I2C_DELAY; - I2C_SDA(1); - I2C_TRISTATE; - I2C_DELAY; - I2C_SCL(1); - I2C_DELAY; - I2C_DELAY; - nack = I2C_READ; - I2C_SCL(0); - I2C_DELAY; - I2C_ACTIVE; - - return(nack); /* not a nack is an ack */ -} - -/*----------------------------------------------------------------------- - * if ack == I2C_ACK, ACK the byte so can continue reading, else - * send I2C_NOACK to end the read. - */ -static uchar read_byte(int ack) -{ - I2C_SOFT_DECLARATIONS /* intentional without ';' */ - int data; - int j; - - /* - * Read 8 bits, MSB first. - */ - I2C_TRISTATE; - I2C_SDA(1); - data = 0; - for(j = 0; j < 8; j++) { - I2C_SCL(0); - I2C_DELAY; - I2C_SCL(1); - I2C_DELAY; - data <<= 1; - data |= I2C_READ; - I2C_DELAY; - } - send_ack(ack); - - return(data); -} - -/*----------------------------------------------------------------------- - * Initialization - */ -static void soft_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr) -{ - /* - * WARNING: Do NOT save speed in a static variable: if the - * I2C routines are called before RAM is initialized (to read - * the DIMM SPD, for instance), RAM won't be usable and your - * system will crash. - */ - send_reset (); -} - -/*----------------------------------------------------------------------- - * Probe to see if a chip is present. Also good for checking for the - * completion of EEPROM writes since the chip stops responding until - * the write completes (typically 10mSec). - */ -static int soft_i2c_probe(struct i2c_adapter *adap, uint8_t addr) -{ - int rc; - - /* - * perform 1 byte write transaction with just address byte - * (fake write) - */ - send_start(); - rc = write_byte ((addr << 1) | 0); - send_stop(); - - return (rc ? 1 : 0); -} - -/*----------------------------------------------------------------------- - * Read bytes - */ -static int soft_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr, - int alen, uchar *buffer, int len) -{ - int shift; - PRINTD("i2c_read: chip %02X addr %02X alen %d buffer %p len %d\n", - chip, addr, alen, buffer, len); - -#ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW - /* - * EEPROM chips that implement "address overflow" are ones - * like Catalyst 24WC04/08/16 which has 9/10/11 bits of - * address and the extra bits end up in the "chip address" - * bit slots. This makes a 24WC08 (1Kbyte) chip look like - * four 256 byte chips. - * - * Note that we consider the length of the address field to - * still be one byte because the extra address bits are - * hidden in the chip address. - */ - chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); - - PRINTD("i2c_read: fix addr_overflow: chip %02X addr %02X\n", - chip, addr); -#endif - - /* - * Do the addressing portion of a write cycle to set the - * chip's address pointer. If the address length is zero, - * don't do the normal write cycle to set the address pointer, - * there is no address pointer in this chip. - */ - send_start(); - if(alen > 0) { - if(write_byte(chip << 1)) { /* write cycle */ - send_stop(); - PRINTD("i2c_read, no chip responded %02X\n", chip); - return(1); - } - shift = (alen-1) * 8; - while(alen-- > 0) { - if(write_byte(addr >> shift)) { - PRINTD("i2c_read, address not <ACK>ed\n"); - return(1); - } - shift -= 8; - } - - /* Some I2C chips need a stop/start sequence here, - * other chips don't work with a full stop and need - * only a start. Default behaviour is to send the - * stop/start sequence. - */ -#ifdef CONFIG_SOFT_I2C_READ_REPEATED_START - send_start(); -#else - send_stop(); - send_start(); -#endif - } - /* - * Send the chip address again, this time for a read cycle. - * Then read the data. On the last byte, we do a NACK instead - * of an ACK(len == 0) to terminate the read. - */ - write_byte((chip << 1) | 1); /* read cycle */ - while(len-- > 0) { - *buffer++ = read_byte(len == 0); - } - send_stop(); - return(0); -} - -/*----------------------------------------------------------------------- - * Write bytes - */ -static int soft_i2c_write(struct i2c_adapter *adap, uchar chip, uint addr, - int alen, uchar *buffer, int len) -{ - int shift, failures = 0; - - PRINTD("i2c_write: chip %02X addr %02X alen %d buffer %p len %d\n", - chip, addr, alen, buffer, len); - - send_start(); - if(write_byte(chip << 1)) { /* write cycle */ - send_stop(); - PRINTD("i2c_write, no chip responded %02X\n", chip); - return(1); - } - shift = (alen-1) * 8; - while(alen-- > 0) { - if(write_byte(addr >> shift)) { - PRINTD("i2c_write, address not <ACK>ed\n"); - return(1); - } - shift -= 8; - } - - while(len-- > 0) { - if(write_byte(*buffer++)) { - failures++; - } - } - send_stop(); - return(failures); -} - -/* - * Register soft i2c adapters - */ -U_BOOT_I2C_ADAP_COMPLETE(soft00, soft_i2c_init, soft_i2c_probe, - soft_i2c_read, soft_i2c_write, NULL, - CONFIG_SYS_I2C_SOFT_SPEED, CONFIG_SYS_I2C_SOFT_SLAVE, - 0) diff --git a/drivers/i3c/Kconfig b/drivers/i3c/Kconfig index 48341f9b873..41a4177b3ae 100644 --- a/drivers/i3c/Kconfig +++ b/drivers/i3c/Kconfig @@ -1,5 +1,5 @@ menuconfig I3C - tristate "I3C support" + bool "I3C support" select I2C select DEVRES help diff --git a/drivers/i3c/master/Kconfig b/drivers/i3c/master/Kconfig index 79776f60ae4..63467ef9cc2 100644 --- a/drivers/i3c/master/Kconfig +++ b/drivers/i3c/master/Kconfig @@ -1,5 +1,5 @@ config DW_I3C_MASTER - tristate "Synopsys DesignWare I3C master driver" + bool "Synopsys DesignWare I3C master driver" depends on I3C help Support for Synopsys DesignWare MIPI I3C Controller. diff --git a/drivers/iommu/apple_dart.c b/drivers/iommu/apple_dart.c index bfd4ad20105..ebef28d0b9d 100644 --- a/drivers/iommu/apple_dart.c +++ b/drivers/iommu/apple_dart.c @@ -6,6 +6,7 @@ #include <cpu_func.h> #include <dm.h> #include <iommu.h> +#include <linux/sizes.h> #include <lmb.h> #include <memalign.h> #include <asm/io.h> diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index de95a1debdc..04ebc24e8cf 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -133,7 +133,7 @@ config LED_GPIO config SPL_LED_GPIO bool "LED support for GPIO-connected LEDs in SPL" - depends on SPL_LED && SPL_DM_GPIO + depends on SPL_LED && SPL_DM_GPIO help This option is an SPL-variant of the LED_GPIO option. See the help of LED_GPIO for details. diff --git a/drivers/led/led_sw_blink.c b/drivers/led/led_sw_blink.c index ee1546d02d4..4190fde8f0f 100644 --- a/drivers/led/led_sw_blink.c +++ b/drivers/led/led_sw_blink.c @@ -114,9 +114,11 @@ bool led_sw_on_state_change(struct udevice *dev, enum led_state_t state) case LEDST_ON: ops->set_state(dev, LEDST_OFF); sw_blink->state = LED_SW_BLINK_ST_OFF; + break; default: ops->set_state(dev, LEDST_ON); sw_blink->state = LED_SW_BLINK_ST_ON; + break; } return true; diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index f45e611c966..1d9e284cfd1 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -32,6 +32,8 @@ config MPFS_MBOX bool "Enable MPFS system controller support" depends on DM_MAILBOX && ARCH_RV64I select DEVRES + depends on SYSCON + depends on REGMAP help Enable support for the mailboxes that provide a communication channel with the system controller integrated on PolarFire SoC. diff --git a/drivers/mailbox/apple-mbox.c b/drivers/mailbox/apple-mbox.c index 2ee49734f40..39a7edc0285 100644 --- a/drivers/mailbox/apple-mbox.c +++ b/drivers/mailbox/apple-mbox.c @@ -59,7 +59,7 @@ static int apple_mbox_recv(struct mbox_chan *chan, void *data) return 0; } -struct mbox_ops apple_mbox_ops = { +static const struct mbox_ops apple_mbox_ops = { .of_xlate = apple_mbox_of_xlate, .send = apple_mbox_send, .recv = apple_mbox_recv, diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c index c7eaa3de96f..fd0fce21d78 100644 --- a/drivers/mailbox/imx-mailbox.c +++ b/drivers/mailbox/imx-mailbox.c @@ -387,7 +387,7 @@ int imx_mu_of_xlate(struct mbox_chan *chan, struct ofnode_phandle_args *args) return plat->dcfg->of_xlate(chan, args); } -struct mbox_ops imx_mu_ops = { +static const struct mbox_ops imx_mu_ops = { .of_xlate = imx_mu_of_xlate, .request = imx_mu_chan_request, .rfree = imx_mu_chan_free, diff --git a/drivers/mailbox/k3-sec-proxy.c b/drivers/mailbox/k3-sec-proxy.c index 6f5ad37919f..6eebfcd3601 100644 --- a/drivers/mailbox/k3-sec-proxy.c +++ b/drivers/mailbox/k3-sec-proxy.c @@ -293,7 +293,7 @@ static int k3_sec_proxy_recv(struct mbox_chan *chan, void *data) return 0; } -struct mbox_ops k3_sec_proxy_mbox_ops = { +static const struct mbox_ops k3_sec_proxy_mbox_ops = { .of_xlate = k3_sec_proxy_of_xlate, .request = k3_sec_proxy_request, .rfree = k3_sec_proxy_free, diff --git a/drivers/mailbox/mpfs-mbox.c b/drivers/mailbox/mpfs-mbox.c index 55238847ecd..b1ce377525e 100644 --- a/drivers/mailbox/mpfs-mbox.c +++ b/drivers/mailbox/mpfs-mbox.c @@ -13,19 +13,21 @@ #include <dm/device-internal.h> #include <dm/device.h> #include <dm/device_compat.h> -#include <dm/devres.h> #include <dm/ofnode.h> #include <linux/bitops.h> #include <linux/compat.h> -#include <linux/io.h> -#include <linux/ioport.h> +#include <linux/err.h> +#include <linux/errno.h> #include <log.h> #include <mailbox-uclass.h> -#include <malloc.h> #include <mpfs-mailbox.h> +#include <regmap.h> +#include <syscon.h> #define SERVICES_CR_OFFSET 0x50u #define SERVICES_SR_OFFSET 0x54u +#define MESSAGE_INT_OFFSET 0x18cu +#define MAILBOX_REG_OFFSET 0x800u #define SERVICE_CR_REQ_MASK 0x1u #define SERVICE_SR_BUSY_MASK 0x2u @@ -35,17 +37,18 @@ struct mpfs_mbox { struct udevice *dev; - void __iomem *ctrl_base; void __iomem *mbox_base; - struct mbox_chan *chan; + void __iomem *int_reg; + struct regmap *control_scb; + struct regmap *sysreg_scb; }; static bool mpfs_mbox_busy(struct mbox_chan *chan) { struct mpfs_mbox *mbox = dev_get_priv(chan->dev); - uint16_t status; + u32 status; - status = readl(mbox->ctrl_base + SERVICES_SR_OFFSET); + regmap_read(mbox->control_scb, SERVICES_SR_OFFSET, &status); return status & SERVICE_SR_BUSY_MASK; } @@ -80,14 +83,15 @@ static int mpfs_mbox_send(struct mbox_chan *chan, const void *data) cmd_shifted = msg->cmd_opcode << SERVICE_CR_COMMAND_SHIFT; cmd_shifted |= SERVICE_CR_REQ_MASK; - writel(cmd_shifted, mbox->ctrl_base + SERVICES_CR_OFFSET); + + regmap_write(mbox->control_scb, SERVICES_CR_OFFSET, cmd_shifted); do { - value = readl(mbox->ctrl_base + SERVICES_CR_OFFSET); + regmap_read(mbox->control_scb, SERVICES_CR_OFFSET, &value); } while (SERVICE_CR_REQ_MASK == (value & SERVICE_CR_REQ_MASK)); do { - value = readl(mbox->ctrl_base + SERVICES_SR_OFFSET); + regmap_read(mbox->control_scb, SERVICES_SR_OFFSET, &value); } while (SERVICE_SR_BUSY_MASK == (value & SERVICE_SR_BUSY_MASK)); msg->response->resp_status = (value >> SERVICE_SR_STATUS_SHIFT); @@ -118,6 +122,11 @@ static int mpfs_mbox_recv(struct mbox_chan *chan, void *data) for (idx = 0; idx < response->resp_size; idx++) *((u8 *)(response->resp_msg) + idx) = readb(mbox->mbox_base + msg->resp_offset + idx); + if (mbox->sysreg_scb) + regmap_write(mbox->sysreg_scb, MESSAGE_INT_OFFSET, 0); + else + writel_relaxed(0, mbox->int_reg); + return 0; } @@ -126,42 +135,71 @@ static const struct mbox_ops mpfs_mbox_ops = { .recv = mpfs_mbox_recv, }; -static int mpfs_mbox_probe(struct udevice *dev) +/* + * Use global compatible lookup instead of phandles, as U-Boot may run + * with a reduced or firmware-provided device tree where mailbox syscon + * phandle properties are not guaranteed to be present. + */ +static int mpfs_mbox_syscon_probe(struct udevice *dev, struct mpfs_mbox *mbox) { - struct mpfs_mbox *mbox; - struct resource regs; ofnode node; - int ret; - node = dev_ofnode(dev); + node = ofnode_by_compatible(ofnode_null(), "microchip,mpfs-control-scb"); + if (!ofnode_valid(node)) + return -ENODEV; - mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL); - if (!mbox) - return -ENOMEM; + mbox->control_scb = syscon_node_to_regmap(node); + if (IS_ERR(mbox->control_scb)) + return PTR_ERR(mbox->control_scb); - ret = ofnode_read_resource(node, 0, ®s); - if (ret) { - dev_err(dev, "No reg property for controller base\n"); - return ret; - }; + node = ofnode_by_compatible(ofnode_null(), "microchip,mpfs-sysreg-scb"); + if (!ofnode_valid(node)) + return -ENODEV; - mbox->ctrl_base = devm_ioremap(dev, regs.start, regs.start - regs.end); + mbox->sysreg_scb = syscon_node_to_regmap(node); + if (IS_ERR(mbox->sysreg_scb)) + return PTR_ERR(mbox->sysreg_scb); - ret = ofnode_read_resource(node, 2, ®s); - if (ret) { - dev_err(dev, "No reg property for mailbox base\n"); + mbox->mbox_base = dev_read_addr_ptr(dev); + if (!mbox->mbox_base) + return -EINVAL; + + return 0; +} + +static int mpfs_mbox_legacy_probe(struct udevice *dev, struct mpfs_mbox *mbox) +{ + int ret; + + ret = regmap_init_mem_index(dev_ofnode(dev), &mbox->control_scb, 0); + if (ret) return ret; - }; - mbox->mbox_base = devm_ioremap(dev, regs.start, regs.start - regs.end); + mbox->mbox_base = dev_read_addr_index_ptr(dev, 2); + if (!mbox->mbox_base) + mbox->mbox_base = dev_read_addr_index_ptr(dev, 0) + MAILBOX_REG_OFFSET; - mbox->dev = dev; - dev_set_priv(dev, mbox); - mbox->chan->con_priv = mbox; + mbox->int_reg = dev_read_addr_index_ptr(dev, 1); + if (!mbox->int_reg) + return -EINVAL; return 0; } +static int mpfs_mbox_probe(struct udevice *dev) +{ + struct mpfs_mbox *mbox = dev_get_priv(dev); + int ret; + + mbox->dev = dev; + + ret = mpfs_mbox_syscon_probe(dev, mbox); + if (!ret) + return 0; + + return mpfs_mbox_legacy_probe(dev, mbox); +} + static const struct udevice_id mpfs_mbox_ids[] = { {.compatible = "microchip,mpfs-mailbox"}, { } @@ -174,4 +212,4 @@ U_BOOT_DRIVER(mpfs_mbox) = { .probe = mpfs_mbox_probe, .priv_auto = sizeof(struct mpfs_mbox), .ops = &mpfs_mbox_ops, -}; +};
\ No newline at end of file diff --git a/drivers/mailbox/renesas-mfis.c b/drivers/mailbox/renesas-mfis.c index 1e9e8285974..19b801e56a6 100644 --- a/drivers/mailbox/renesas-mfis.c +++ b/drivers/mailbox/renesas-mfis.c @@ -29,7 +29,7 @@ static int mfis_send(struct mbox_chan *chan, const void *data) return 0; } -struct mbox_ops mfis_mbox_ops = { +static const struct mbox_ops mfis_mbox_ops = { .send = mfis_send, }; diff --git a/drivers/mailbox/sandbox-mbox.c b/drivers/mailbox/sandbox-mbox.c index 87e06e492fe..d6ac758c4d8 100644 --- a/drivers/mailbox/sandbox-mbox.c +++ b/drivers/mailbox/sandbox-mbox.c @@ -86,7 +86,7 @@ static const struct udevice_id sandbox_mbox_ids[] = { { } }; -struct mbox_ops sandbox_mbox_mbox_ops = { +static const struct mbox_ops sandbox_mbox_mbox_ops = { .request = sandbox_mbox_request, .rfree = sandbox_mbox_free, .send = sandbox_mbox_send, diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c index dda108735fc..49f7795b3cd 100644 --- a/drivers/mailbox/stm32-ipcc.c +++ b/drivers/mailbox/stm32-ipcc.c @@ -147,7 +147,7 @@ static const struct udevice_id stm32_ipcc_ids[] = { { } }; -struct mbox_ops stm32_ipcc_mbox_ops = { +static const struct mbox_ops stm32_ipcc_mbox_ops = { .request = stm32_ipcc_request, .rfree = stm32_ipcc_free, .send = stm32_ipcc_send, diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index 591d9d9c656..5f029fd3e70 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -44,18 +44,18 @@ config STM32_OMM This driver manages the muxing between the 2 OSPI busses and the 2 output ports. There are 4 possible muxing configurations: - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2 - output is on port 2 + output is on port 2 - OSPI1 and OSPI2 are multiplexed over the same output port 1 - swapped mode (no multiplexing), OSPI1 output is on port 2, - OSPI2 output is on port 1 + OSPI2 output is on port 1 - OSPI1 and OSPI2 are multiplexed over the same output port 2 It also manages : - - the split of the memory area shared between the 2 OSPI instances. - - chip select selection override. - - the time between 2 transactions in multiplexed mode. + - the split of the memory area shared between the 2 OSPI instances. + - chip select selection override. + - the time between 2 transactions in multiplexed mode. config TI_AEMIF - tristate "Texas Instruments AEMIF driver" + bool "Texas Instruments AEMIF driver" depends on ARCH_KEYSTONE || ARCH_DAVINCI help This driver is for the AEMIF module available in Texas Instruments @@ -71,9 +71,9 @@ config TI_GPMC depends on MEMORY && CLK && OF_CONTROL help This driver is for the General Purpose Memory Controller (GPMC) - present on Texas Instruments SoCs (e.g. OMAP2+). GPMC allows - interfacing to a variety of asynchronous as well as synchronous - memory drives like NOR, NAND, OneNAND, SRAM. + present on Texas Instruments SoCs (e.g. OMAP2+). GPMC allows + interfacing to a variety of asynchronous as well as synchronous + memory drives like NOR, NAND, OneNAND, SRAM. if TI_GPMC config TI_GPMC_DEBUG diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ae53b02f27c..79f4db9849c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1,4 +1,4 @@ config MFD_ATMEL_SMC - bool "Atmel Static Memory Controller driver" - help - Say yes here to support Atmel Static Memory Controller driver. + bool "Atmel Static Memory Controller driver" + help + Say yes here to support Atmel Static Memory Controller driver. diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index ea785793d18..44415f24ae1 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -71,9 +71,9 @@ config ATSHA204A select BITREVERSE depends on MISC help - Enable support for I2C connected Atmel's ATSHA204A - CryptoAuthentication module found for example on the Turris Omnia - board. + Enable support for I2C connected Atmel's ATSHA204A + CryptoAuthentication module found for example on the Turris Omnia + board. config GATEWORKS_SC bool "Gateworks System Controller Support" @@ -94,7 +94,7 @@ config QCOM_GENI etc. config ROCKCHIP_EFUSE - bool "Rockchip e-fuse support" + bool "Rockchip e-fuse support" depends on MISC help Enable (read-only) access for the e-fuse block found in Rockchip @@ -505,7 +505,7 @@ config TURRIS_OMNIA_MCU board power off. config USB_HUB_USB251XB - tristate "USB251XB Hub Controller Configuration Driver" + bool "USB251XB Hub Controller Configuration Driver" depends on I2C help This option enables support for configuration via SMBus of the @@ -647,6 +647,7 @@ config IHS_FPGA gdsys devices, which supply the majority of the functionality offered by the devices. This driver supports both CON and CPU variants of the devices, depending on the device tree entry. + config ESM_K3 bool "Enable K3 ESM driver" depends on ARCH_K3 diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index fabe4964a33..e163224b8e3 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -258,7 +258,7 @@ static int send_command_proto3(struct cros_ec_dev *cdev, const void *dout, int dout_len, uint8_t **dinp, int din_len) { - struct dm_cros_ec_ops *ops; + const struct dm_cros_ec_ops *ops; int out_bytes, in_bytes; int rv; @@ -287,7 +287,7 @@ static int send_command(struct cros_ec_dev *dev, uint cmd, int cmd_version, const void *dout, int dout_len, uint8_t **dinp, int din_len) { - struct dm_cros_ec_ops *ops; + const struct dm_cros_ec_ops *ops; int ret = -1; /* Handle protocol version 3 support */ @@ -487,7 +487,7 @@ int cros_ec_read_build_info(struct udevice *dev, char **strp) } int cros_ec_read_current_image(struct udevice *dev, - enum ec_current_image *image) + enum ec_image *image) { struct ec_response_get_version *r; @@ -756,9 +756,8 @@ int cros_ec_flash_protect(struct udevice *dev, uint32_t set_mask, static int cros_ec_check_version(struct udevice *dev) { struct cros_ec_dev *cdev = dev_get_uclass_priv(dev); + const struct dm_cros_ec_ops *ops; struct ec_params_hello req; - - struct dm_cros_ec_ops *ops; int ret; ops = dm_cros_ec_get_ops(dev); @@ -1638,7 +1637,7 @@ int cros_ec_vstore_write(struct udevice *dev, int slot, const uint8_t *data, int cros_ec_get_switches(struct udevice *dev) { - struct dm_cros_ec_ops *ops; + const struct dm_cros_ec_ops *ops; int ret; ops = dm_cros_ec_get_ops(dev); diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 432b1fbb0c4..9fedca4e6b6 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -100,7 +100,7 @@ struct ec_state { struct fdt_cros_ec ec_config; uint8_t *flash_data; int flash_data_len; - enum ec_current_image current_image; + enum ec_image current_image; int matrix_count; struct ec_keymatrix_entry *matrix; /* the key matrix info */ uint8_t keyscan[KEYBOARD_COLS]; @@ -726,7 +726,7 @@ int cros_ec_probe(struct udevice *dev) return cros_ec_register(dev); } -struct dm_cros_ec_ops cros_ec_ops = { +static const struct dm_cros_ec_ops cros_ec_ops = { .packet = cros_ec_sandbox_packet, .get_switches = cros_ec_sandbox_get_switches, }; diff --git a/drivers/misc/i2c_eeprom_emul.c b/drivers/misc/i2c_eeprom_emul.c index 3ad2e047ee3..40f34ad03a4 100644 --- a/drivers/misc/i2c_eeprom_emul.c +++ b/drivers/misc/i2c_eeprom_emul.c @@ -144,7 +144,7 @@ static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg, return 0; } -struct dm_i2c_ops sandbox_i2c_emul_ops = { +static const struct dm_i2c_ops sandbox_i2c_emul_ops = { .xfer = sandbox_i2c_eeprom_xfer, }; diff --git a/drivers/misc/imx_ele/ele_api.c b/drivers/misc/imx_ele/ele_api.c index 8ee0a7733ca..355fd86ed8c 100644 --- a/drivers/misc/imx_ele/ele_api.c +++ b/drivers/misc/imx_ele/ele_api.c @@ -795,6 +795,38 @@ int ele_generate_dek_blob(u32 key_id, u32 src_paddr, u32 dst_paddr, u32 max_outp return ret; } +int ele_v2x_get_state(struct v2x_get_state *state, u32 *response) +{ + struct udevice *dev = gd->arch.ele_dev; + int size = sizeof(struct ele_msg); + struct ele_msg msg = {}; + int ret; + + if (!dev) { + printf("ele dev is not initialized\n"); + return -ENODEV; + } + + msg.version = ELE_VERSION; + msg.tag = ELE_CMD_TAG; + msg.size = 1; + msg.command = ELE_V2X_GET_STATE_REQ; + + ret = misc_call(dev, false, &msg, size, &msg, size); + if (ret) + printf("Error: %s: ret %d, response 0x%x\n", + __func__, ret, msg.data[0]); + + if (response) + *response = msg.data[0]; + + state->v2x_state = msg.data[1] & 0xFF; + state->v2x_power_state = (msg.data[1] & 0xFF00) >> 8; + state->v2x_err_code = msg.data[2]; + + return ret; +} + int ele_volt_change_start_req(void) { struct udevice *dev = gd->arch.ele_dev; diff --git a/drivers/misc/imx_ele/ele_mu.c b/drivers/misc/imx_ele/ele_mu.c index cdb85b999db..65a4779c041 100644 --- a/drivers/misc/imx_ele/ele_mu.c +++ b/drivers/misc/imx_ele/ele_mu.c @@ -209,7 +209,7 @@ static int imx8ulp_mu_probe(struct udevice *dev) debug("%s(dev=%p) (priv=%p)\n", __func__, dev, priv); - addr = devfdt_get_addr(dev); + addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/misc/k3_avs.c b/drivers/misc/k3_avs.c index 0774e0a4c9e..a885c99c547 100644 --- a/drivers/misc/k3_avs.c +++ b/drivers/misc/k3_avs.c @@ -300,7 +300,7 @@ static void k3_avs_program_tshut(struct k3_avs_privdata *priv) void __iomem *cfg2_base; void __iomem *fuse_base; - cfg2_base = (void __iomem *)devfdt_get_addr_index(priv->dev, 1); + cfg2_base = (void __iomem *)dev_read_addr_index(priv->dev, 1); if (IS_ERR(cfg2_base)) { dev_err(priv->dev, "cfg base is not defined\n"); return; @@ -319,7 +319,7 @@ static void k3_avs_program_tshut(struct k3_avs_privdata *priv) */ if (device_is_compatible(priv->dev, "ti,j721e-vtm")) { - fuse_base = (void __iomem *)devfdt_get_addr_index(priv->dev, 2); + fuse_base = (void __iomem *)dev_read_addr_index(priv->dev, 2); if (IS_ERR(fuse_base)) { dev_err(priv->dev, "fuse-base is not defined for J721E Soc\n"); return; diff --git a/drivers/misc/qfw.c b/drivers/misc/qfw.c index 0e002ac25f4..8a11637ca7f 100644 --- a/drivers/misc/qfw.c +++ b/drivers/misc/qfw.c @@ -152,7 +152,7 @@ UCLASS_DRIVER(qfw) = { .per_device_auto = sizeof(struct qfw_dev), }; -struct bootdev_ops qfw_bootdev_ops = { +static const struct bootdev_ops qfw_bootdev_ops = { .get_bootflow = qfw_get_bootflow, }; diff --git a/drivers/misc/qfw_acpi.c b/drivers/misc/qfw_acpi.c index 721f42ecbc3..afa3b820395 100644 --- a/drivers/misc/qfw_acpi.c +++ b/drivers/misc/qfw_acpi.c @@ -265,6 +265,7 @@ out: struct acpi_rsdp *rsdp = ctx->rsdp; rsdp->length = sizeof(*rsdp); + rsdp->ext_checksum = 0; rsdp->ext_checksum = table_compute_checksum((u8 *)rsdp, sizeof(*rsdp)); gd_set_acpi_start(acpi_get_rsdp_addr()); diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 22bd3a972bd..f9f7aa5cf97 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -332,7 +332,7 @@ config MMC_MESON_GX bool "Meson GX EMMC controller support" depends on ARCH_MESON help - Support for EMMC host controller on Meson GX ARM SoCs platform (S905) + Support for EMMC host controller on Meson GX ARM SoCs platform (S905) config MMC_OWL bool "Actions OWL Multimedia Card Interface support" @@ -415,7 +415,7 @@ config MMC_OMAP36XX_PINS config HSMMC2_8BIT bool "Enable 8-bit interface for eMMC (interface #2)" - depends on MMC_OMAP_HS && (OMAP54XX || DRA7XX || AM33XX || \ + depends on MMC_OMAP_HS && (OMAP44XX || OMAP54XX || DRA7XX || AM33XX || \ AM43XX || ARCH_KEYSTONE) config SH_MMCIF @@ -576,7 +576,7 @@ config MMC_SDHCI_ATMEL specification. config MMC_SDHCI_BCM2835 - tristate "SDHCI support for the BCM2835 SD/MMC Controller" + bool "SDHCI support for the BCM2835 SD/MMC Controller" depends on ARCH_BCM283X depends on MMC_SDHCI select MMC_SDHCI_IO_ACCESSORS @@ -589,7 +589,7 @@ config MMC_SDHCI_BCM2835 If unsure, say N. config MMC_SDHCI_BCMSTB - tristate "SDHCI support for the BCMSTB SD/MMC Controller" + bool "SDHCI support for the BCMSTB SD/MMC Controller" depends on MMC_SDHCI && (ARCH_BCMSTB || ARCH_BCM283X) help This selects the Broadcom set-top box SD/MMC controller. @@ -659,8 +659,8 @@ config MMC_SDHCI_MSM depends on MMC_SDHCI && ARCH_SNAPDRAGON help Enables support for SDHCI 2.0 controller present on some Qualcomm - Snapdragon devices. This device is compatible with eMMC v4.5 and - SD 3.0 specifications. Both SD and eMMC devices are supported. + Snapdragon devices. This device is compatible with eMMC v4.5 and + SD 3.0 specifications. Both SD and eMMC devices are supported. Card-detect gpios are not supported. config MMC_SDHCI_MV @@ -852,12 +852,13 @@ config FTSDC010_SDIO bool "Support ftsdc010 sdio" depends on FTSDC010 help - This can enable ftsdc010 sdio function. + This can enable ftsdc010 sdio function. config MMC_MTK bool "MediaTek SD/MMC Card Interface support" depends on ARCH_MEDIATEK || ARCH_MTMIPS || ARCH_AIROHA depends on OF_CONTROL + imply LMB_LIMIT_DMA_BELOW_RAM_TOP help This selects the MediaTek(R) Secure digital and Multimedia card Interface. If you have a machine with a integrated SD/MMC card reader, say Y here. @@ -924,7 +925,7 @@ config ESDHCI_QUIRK_BROKEN_TIMEOUT_VALUE config FSL_ESDHC_IMX bool "Freescale/NXP i.MX eSDHC controller support" - depends on MACH_IMX + depends on MACH_IMX || M68K help This selects support for the i.MX eSDHC (Enhanced Secure Digital Host Controller) found on numerous Freescale/NXP SoCs. diff --git a/drivers/mmc/bcm2835_sdhci.c b/drivers/mmc/bcm2835_sdhci.c index 655d9902dfa..efa4d14f5da 100644 --- a/drivers/mmc/bcm2835_sdhci.c +++ b/drivers/mmc/bcm2835_sdhci.c @@ -219,6 +219,10 @@ static int bcm2835_sdhci_probe(struct udevice *dev) host->mmc = &plat->mmc; host->mmc->dev = dev; + ret = mmc_of_parse(dev, &plat->cfg); + if (ret) + return ret; + ret = sdhci_setup_cfg(&plat->cfg, host, emmc_freq, MIN_FREQ); if (ret) { debug("%s: Failed to setup SDHCI (err=%d)\n", __func__, ret); diff --git a/drivers/mmc/bcmstb_sdhci.c b/drivers/mmc/bcmstb_sdhci.c index 7bddbebb162..f27b84a6ee4 100644 --- a/drivers/mmc/bcmstb_sdhci.c +++ b/drivers/mmc/bcmstb_sdhci.c @@ -56,7 +56,7 @@ struct sdhci_brcmstb_dev_priv { static int sdhci_brcmstb_init_2712(struct udevice *dev) { - struct sdhci_host *host = dev_get_priv(dev); + struct sdhci_bcmstb_plat *plat = dev_get_plat(dev); void *cfg_regs; u32 reg; @@ -65,8 +65,8 @@ static int sdhci_brcmstb_init_2712(struct udevice *dev) if (!cfg_regs) return -ENOENT; - if ((host->mmc->host_caps & MMC_CAP_NONREMOVABLE) || - (host->mmc->host_caps & MMC_CAP_NEEDS_POLL)) { + if ((plat->cfg.host_caps & MMC_CAP_NONREMOVABLE) || + (plat->cfg.host_caps & MMC_CAP_NEEDS_POLL)) { /* Force presence */ reg = readl(cfg_regs + SDIO_CFG_CTRL); reg &= ~SDIO_CFG_CTRL_SDCD_N_TEST_LEV; diff --git a/drivers/mmc/cv1800b_sdhci.c b/drivers/mmc/cv1800b_sdhci.c index 036e798f374..b756649f90f 100644 --- a/drivers/mmc/cv1800b_sdhci.c +++ b/drivers/mmc/cv1800b_sdhci.c @@ -85,7 +85,7 @@ static int cv1800b_sdhci_probe(struct udevice *dev) int ret; host->name = dev->name; - host->ioaddr = devfdt_get_addr_ptr(dev); + host->ioaddr = dev_read_addr_ptr(dev); upriv->mmc = &plat->mmc; host->mmc = &plat->mmc; @@ -94,6 +94,9 @@ static int cv1800b_sdhci_probe(struct udevice *dev) host->ops = &cv1800b_sdhci_sd_ops; host->max_clk = MMC_MAX_CLOCK; + if (dev_read_bool(dev, "no-1-8-v")) + host->quirks |= SDHCI_QUIRK_NO_1_8_V; + ret = mmc_of_parse(dev, &plat->cfg); if (ret) return ret; diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index d9c05b223d5..c2424d7875c 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -645,9 +645,11 @@ static int dwmci_set_ios(struct mmc *mmc) int ret; if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) - ret = regulator_set_value(mmc->vqmmc_supply, 1800000); + ret = regulator_set_value_clamp(mmc->vqmmc_supply, + 1700000, 1800000, 1950000); else - ret = regulator_set_value(mmc->vqmmc_supply, 3300000); + ret = regulator_set_value_clamp(mmc->vqmmc_supply, + 2700000, 3300000, 3600000); if (ret && ret != -ENOSYS) return ret; } diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 87125493c0d..e718a17f94c 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -36,7 +36,6 @@ #include <dm/pinctrl.h> #include <dt-structs.h> #include <mapmem.h> -#include <dm/ofnode.h> #include <linux/iopoll.h> #include <linux/dma-mapping.h> @@ -1393,7 +1392,6 @@ static int fsl_esdhc_of_to_plat(struct udevice *dev) struct udevice *vqmmc_dev; int ret; - ofnode node = dev_ofnode(dev); fdt_addr_t addr; unsigned int val; @@ -1407,15 +1405,15 @@ static int fsl_esdhc_of_to_plat(struct udevice *dev) priv->dev = dev; priv->mode = -1; - val = ofnode_read_u32_default(node, "fsl,tuning-step", 1); + val = dev_read_u32_default(dev, "fsl,tuning-step", 1); priv->tuning_step = val; - val = ofnode_read_u32_default(node, "fsl,tuning-start-tap", - ESDHC_TUNING_START_TAP_DEFAULT); + val = dev_read_u32_default(dev, "fsl,tuning-start-tap", + ESDHC_TUNING_START_TAP_DEFAULT); priv->tuning_start_tap = val; - val = ofnode_read_u32_default(node, "fsl,strobe-dll-delay-target", - ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT); + val = dev_read_u32_default(dev, "fsl,strobe-dll-delay-target", + ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_DEFAULT); priv->strobe_dll_delay_target = val; - val = ofnode_read_u32_default(node, "fsl,signal-voltage-switch-extra-delay-ms", 0); + val = dev_read_u32_default(dev, "fsl,signal-voltage-switch-extra-delay-ms", 0); priv->signal_voltage_switch_extra_delay_ms = val; if (dev_read_bool(dev, "broken-cd")) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index f0e38efb262..2e565560656 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -2721,10 +2721,11 @@ static int mmc_startup(struct mmc *mmc) #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 voltage switch was skipped during ACMD41 but the card is + * already at 1.8V (retained from a previous session, e.g. warm + * reboot), re-configure the host to match. */ - if (mmc_sd_card_using_v18(mmc)) { + if (!(mmc->ocr & OCR_S18R) && 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. diff --git a/drivers/mmc/mmc_bootdev.c b/drivers/mmc/mmc_bootdev.c index 5a1688b75d0..b382521fdeb 100644 --- a/drivers/mmc/mmc_bootdev.c +++ b/drivers/mmc/mmc_bootdev.c @@ -19,7 +19,7 @@ static int mmc_bootdev_bind(struct udevice *dev) return 0; } -struct bootdev_ops mmc_bootdev_ops = { +static const struct bootdev_ops mmc_bootdev_ops = { }; static const struct udevice_id mmc_bootdev_ids[] = { diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c index 66f3cf2de4f..7bdb02142a2 100644 --- a/drivers/mmc/msm_sdhci.c +++ b/drivers/mmc/msm_sdhci.c @@ -64,15 +64,13 @@ static int msm_sdc_clk_init(struct udevice *dev) { struct msm_sdhc *prv = dev_get_priv(dev); const struct msm_sdhc_variant_info *var_info; - ofnode node = dev_ofnode(dev); ulong clk_rate; int ret, i = 0, n_clks; const char *clk_name; var_info = (void *)dev_get_driver_data(dev); - ret = ofnode_read_u32(node, "clock-frequency", (uint *)(&clk_rate)); - if (ret) + if (dev_read_u32(dev, "max-frequency", (uint *)(&clk_rate))) clk_rate = 201500000; ret = clk_get_bulk(dev, &prv->clks); @@ -88,7 +86,7 @@ static int msm_sdc_clk_init(struct udevice *dev) } /* If clock-names is unspecified, then the first clock is the core clock */ - if (!ofnode_get_property(node, "clock-names", &n_clks)) { + if (!dev_read_prop(dev, "clock-names", &n_clks)) { if (!clk_set_rate(&prv->clks.clks[0], clk_rate)) { log_warning("Couldn't set core clock rate: %d\n", ret); return -EINVAL; @@ -97,7 +95,7 @@ static int msm_sdc_clk_init(struct udevice *dev) /* Find the index of the "core" clock */ while (i < n_clks) { - ofnode_read_string_index(node, "clock-names", i, &clk_name); + dev_read_string_index(dev, "clock-names", i, &clk_name); if (!strcmp(clk_name, "core")) break; i++; diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c index 7a4bdee7496..51c9c0a3fad 100644 --- a/drivers/mmc/mtk-sd.c +++ b/drivers/mmc/mtk-sd.c @@ -539,7 +539,7 @@ static bool msdc_cmd_is_ready(struct msdc_host *host) return false; } - if (host->last_resp_type == MMC_RSP_R1b && host->last_data_write) { + if (host->last_resp_type == MMC_RSP_R1b || host->last_data_write) { ret = readl_poll_timeout(&host->base->msdc_ps, reg, reg & MSDC_PS_DAT0, 1000000); @@ -1983,10 +1983,12 @@ static const struct msdc_compatible mt8189_compat = { .clk_div_bits = 12, .pad_tune0 = true, .async_fifo = true, + .async_fifo_crcsts = true, .data_tune = true, .busy_check = true, .stop_clk_fix = true, .enhance_rx = true, + .use_dma_mode = true, }; static const struct udevice_id msdc_ids[] = { diff --git a/drivers/mmc/mvebu_mmc.c b/drivers/mmc/mvebu_mmc.c index 5af1953cd14..89d511c1a6f 100644 --- a/drivers/mmc/mvebu_mmc.c +++ b/drivers/mmc/mvebu_mmc.c @@ -375,8 +375,8 @@ static void mvebu_window_setup(const struct mmc *mmc) break; } - size = gd->bd->bi_dram[i].size; - base = gd->bd->bi_dram[i].start; + size = gd->dram[i].size; + base = gd->dram[i].start; if (size && attrib) { mvebu_mmc_write(mmc, WINDOW_CTRL(i), MVCPU_WIN_CTRL_DATA(size, diff --git a/drivers/mmc/octeontx_hsmmc.c b/drivers/mmc/octeontx_hsmmc.c index bb4fb29424b..b4942f99a52 100644 --- a/drivers/mmc/octeontx_hsmmc.c +++ b/drivers/mmc/octeontx_hsmmc.c @@ -3514,7 +3514,7 @@ static u32 xlate_voltage(u32 voltage) */ static bool octeontx_mmc_get_valid(struct udevice *dev) { - const char *stat = ofnode_read_string(dev_ofnode(dev), "status"); + const char *stat = dev_read_string(dev, "status"); if (!stat || !strncmp(stat, "ok", 2)) return true; @@ -3536,16 +3536,13 @@ static int octeontx_mmc_get_config(struct udevice *dev) uint low, high; char env_name[32]; int err; - ofnode node = dev_ofnode(dev); int bus_width = 1; ulong new_max_freq; debug("%s(%s)", __func__, dev->name); slot->cfg.name = dev->name; - slot->cfg.f_max = ofnode_read_s32_default(dev_ofnode(dev), - "max-frequency", - 26000000); + slot->cfg.f_max = dev_read_s32_default(dev, "max-frequency", 26000000); snprintf(env_name, sizeof(env_name), "mmc_max_frequency%d", slot->bus_id); @@ -3562,26 +3559,21 @@ static int octeontx_mmc_get_config(struct udevice *dev) if (IS_ENABLED(CONFIG_ARCH_OCTEONTX2)) { slot->hs400_tuning_block = - ofnode_read_s32_default(dev_ofnode(dev), - "marvell,hs400-tuning-block", - -1); + dev_read_s32_default(dev, "marvell,hs400-tuning-block", -1); debug("%s(%s): mmc HS400 tuning block: %d\n", __func__, dev->name, slot->hs400_tuning_block); slot->hs200_tap_adj = - ofnode_read_s32_default(dev_ofnode(dev), - "marvell,hs200-tap-adjust", 0); + dev_read_s32_default(dev, "marvell,hs200-tap-adjust", 0); debug("%s(%s): hs200-tap-adjust: %d\n", __func__, dev->name, slot->hs200_tap_adj); slot->hs400_tap_adj = - ofnode_read_s32_default(dev_ofnode(dev), - "marvell,hs400-tap-adjust", 0); + dev_read_s32_default(dev, "marvell,hs400-tap-adjust", 0); debug("%s(%s): hs400-tap-adjust: %d\n", __func__, dev->name, slot->hs400_tap_adj); } - err = ofnode_read_u32_array(dev_ofnode(dev), "voltage-ranges", - voltages, 2); + err = dev_read_u32_array(dev, "voltage-ranges", voltages, 2); if (err) { slot->cfg.voltages = MMC_VDD_32_33 | MMC_VDD_33_34; } else { @@ -3601,12 +3593,12 @@ static int octeontx_mmc_get_config(struct udevice *dev) } while (low <= high); } debug("%s: config voltages: 0x%x\n", __func__, slot->cfg.voltages); - slot->slew = ofnode_read_s32_default(node, "cavium,clk-slew", -1); - slot->drive = ofnode_read_s32_default(node, "cavium,drv-strength", -1); + slot->slew = dev_read_s32_default(dev, "cavium,clk-slew", -1); + slot->drive = dev_read_s32_default(dev, "cavium,drv-strength", -1); gpio_request_by_name(dev, "cd-gpios", 0, &slot->cd_gpio, GPIOD_IS_IN); - slot->cd_inverted = ofnode_read_bool(node, "cd-inverted"); + slot->cd_inverted = dev_read_bool(dev, "cd-inverted"); gpio_request_by_name(dev, "wp-gpios", 0, &slot->wp_gpio, GPIOD_IS_IN); - slot->wp_inverted = ofnode_read_bool(node, "wp-inverted"); + slot->wp_inverted = dev_read_bool(dev, "wp-inverted"); if (slot->cfg.voltages & MMC_VDD_165_195) { slot->is_1_8v = true; slot->is_3_3v = false; @@ -3617,7 +3609,7 @@ static int octeontx_mmc_get_config(struct udevice *dev) slot->is_3_3v = true; } - bus_width = ofnode_read_u32_default(node, "bus-width", 1); + bus_width = dev_read_u32_default(dev, "bus-width", 1); /* Note fall-through */ switch (bus_width) { case 8: @@ -3628,63 +3620,63 @@ static int octeontx_mmc_get_config(struct udevice *dev) slot->cfg.host_caps |= MMC_MODE_1BIT; break; } - if (ofnode_read_bool(node, "no-1-8-v")) { + if (dev_read_bool(dev, "no-1-8-v")) { slot->is_3_3v = true; slot->is_1_8v = false; if (!(slot->cfg.voltages & (MMC_VDD_32_33 | MMC_VDD_33_34))) pr_warn("%s(%s): voltages indicate 3.3v but 3.3v not supported\n", __func__, dev->name); } - if (ofnode_read_bool(node, "mmc-ddr-3-3v")) { + if (dev_read_bool(dev, "mmc-ddr-3-3v")) { slot->is_3_3v = true; slot->is_1_8v = false; if (!(slot->cfg.voltages & (MMC_VDD_32_33 | MMC_VDD_33_34))) pr_warn("%s(%s): voltages indicate 3.3v but 3.3v not supported\n", __func__, dev->name); } - if (ofnode_read_bool(node, "cap-sd-highspeed") || - ofnode_read_bool(node, "cap-mmc-highspeed") || - ofnode_read_bool(node, "sd-uhs-sdr25")) + if (dev_read_bool(dev, "cap-sd-highspeed") || + dev_read_bool(dev, "cap-mmc-highspeed") || + dev_read_bool(dev, "sd-uhs-sdr25")) slot->cfg.host_caps |= MMC_MODE_HS; if (slot->cfg.f_max >= 50000000 && slot->cfg.host_caps & MMC_MODE_HS) slot->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; - if (ofnode_read_bool(node, "sd-uhs-sdr50")) + if (dev_read_bool(dev, "sd-uhs-sdr50")) slot->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; - if (ofnode_read_bool(node, "sd-uhs-ddr50")) + if (dev_read_bool(dev, "sd-uhs-ddr50")) slot->cfg.host_caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_DDR_52MHz; if (IS_ENABLED(CONFIG_ARCH_OCTEONTX2)) { if (!slot->is_asim && !slot->is_emul) { - if (ofnode_read_bool(node, "mmc-hs200-1_8v")) + if (dev_read_bool(dev, "mmc-hs200-1_8v")) slot->cfg.host_caps |= MMC_MODE_HS200 | MMC_MODE_HS_52MHz; - if (ofnode_read_bool(node, "mmc-hs400-1_8v")) + if (dev_read_bool(dev, "mmc-hs400-1_8v")) slot->cfg.host_caps |= MMC_MODE_HS400 | MMC_MODE_HS_52MHz | MMC_MODE_HS200 | MMC_MODE_DDR_52MHz; slot->cmd_out_hs200_delay = - ofnode_read_u32_default(node, + dev_read_u32_default(dev, "marvell,cmd-out-hs200-dly", MMC_DEFAULT_HS200_CMD_OUT_DLY); debug("%s(%s): HS200 cmd out delay: %d\n", __func__, dev->name, slot->cmd_out_hs200_delay); slot->data_out_hs200_delay = - ofnode_read_u32_default(node, + dev_read_u32_default(dev, "marvell,data-out-hs200-dly", MMC_DEFAULT_HS200_DATA_OUT_DLY); debug("%s(%s): HS200 data out delay: %d\n", __func__, dev->name, slot->data_out_hs200_delay); slot->cmd_out_hs400_delay = - ofnode_read_u32_default(node, + dev_read_u32_default(dev, "marvell,cmd-out-hs400-dly", MMC_DEFAULT_HS400_CMD_OUT_DLY); debug("%s(%s): HS400 cmd out delay: %d\n", __func__, dev->name, slot->cmd_out_hs400_delay); slot->data_out_hs400_delay = - ofnode_read_u32_default(node, + dev_read_u32_default(dev, "marvell,data-out-hs400-dly", MMC_DEFAULT_HS400_DATA_OUT_DLY); debug("%s(%s): HS400 data out delay: %d\n", @@ -3692,12 +3684,10 @@ static int octeontx_mmc_get_config(struct udevice *dev) } } - slot->disable_ddr = ofnode_read_bool(node, "marvell,disable-ddr"); - slot->non_removable = ofnode_read_bool(node, "non-removable"); - slot->cmd_clk_skew = ofnode_read_u32_default(node, - "cavium,cmd-clk-skew", 0); - slot->dat_clk_skew = ofnode_read_u32_default(node, - "cavium,dat-clk-skew", 0); + slot->disable_ddr = dev_read_bool(dev, "marvell,disable-ddr"); + slot->non_removable = dev_read_bool(dev, "non-removable"); + slot->cmd_clk_skew = dev_read_u32_default(dev, "cavium,cmd-clk-skew", 0); + slot->dat_clk_skew = dev_read_u32_default(dev, "cavium,dat-clk-skew", 0); debug("%s(%s): host caps: 0x%x\n", __func__, dev->name, slot->cfg.host_caps); return 0; @@ -3843,7 +3833,6 @@ static int octeontx_mmc_host_probe(struct udevice *dev) pr_err("%s: No device tree information found\n", __func__); return -1; } - host->node = dev_ofnode(dev); host->last_slotid = -1; #if !defined(CONFIG_ARCH_OCTEON) if (otx_is_platform(PLATFORM_ASIM)) @@ -3851,9 +3840,7 @@ static int octeontx_mmc_host_probe(struct udevice *dev) if (otx_is_platform(PLATFORM_EMULATOR)) host->is_emul = true; #endif - host->dma_wait_delay = - ofnode_read_u32_default(dev_ofnode(dev), - "marvell,dma-wait-delay", 1); + host->dma_wait_delay = dev_read_u32_default(dev, "marvell,dma-wait-delay", 1); /* Force reset of eMMC */ writeq(0, host->base_addr + MIO_EMM_CFG()); debug("%s: Clearing MIO_EMM_CFG\n", __func__); @@ -3922,13 +3909,12 @@ static int octeontx_mmc_host_child_pre_probe(struct udevice *dev) struct octeontx_mmc_host *host = dev_get_priv(dev_get_parent(dev)); struct octeontx_mmc_slot *slot; struct mmc_uclass_priv *upriv; - ofnode node = dev_ofnode(dev); u32 bus_id; char name[16]; int err; debug("%s(%s) Pre-Probe\n", __func__, dev->name); - if (ofnode_read_u32(node, "reg", &bus_id)) { + if (dev_read_u32(dev, "reg", &bus_id)) { pr_err("%s(%s): Error: \"reg\" not found in device tree\n", __func__, dev->name); return -1; diff --git a/drivers/mmc/octeontx_hsmmc.h b/drivers/mmc/octeontx_hsmmc.h index 9849121f174..c374ce18838 100644 --- a/drivers/mmc/octeontx_hsmmc.h +++ b/drivers/mmc/octeontx_hsmmc.h @@ -123,7 +123,6 @@ struct octeontx_mmc_host { union mio_emm_cfg emm_cfg; u64 timing_taps; struct mmc *last_mmc; /** Last mmc used */ - ofnode node; int cur_slotid; int last_slotid; int max_width; diff --git a/drivers/mmc/pci_mmc.c b/drivers/mmc/pci_mmc.c index d446c55f72b..82e393fd9d6 100644 --- a/drivers/mmc/pci_mmc.c +++ b/drivers/mmc/pci_mmc.c @@ -137,11 +137,11 @@ static int pci_mmc_acpi_fill_ssdt(const struct udevice *dev, return 0; } -struct acpi_ops pci_mmc_acpi_ops = { #ifdef CONFIG_ACPIGEN +static const struct acpi_ops pci_mmc_acpi_ops = { .fill_ssdt = pci_mmc_acpi_fill_ssdt, -#endif }; +#endif static const struct udevice_id pci_mmc_match[] = { { .compatible = "intel,apl-sd", .data = TYPE_SD }, diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 648dfa4b5ef..71a6d8ea2f5 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -215,7 +215,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd, u32 mask, flags, mode = 0; unsigned int time = 0; int mmc_dev = mmc_get_blk_desc(mmc)->devnum; - ulong start = get_timer(0); + ulong start; host->start_addr = 0; /* Timeout unit - ms */ @@ -551,7 +551,7 @@ void sdhci_set_uhs_timing(struct sdhci_host *host) void sdhci_set_voltage(struct sdhci_host *host) { - if (IS_ENABLED(CONFIG_MMC_IO_VOLTAGE)) { + if (CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)) { struct mmc *mmc = (struct mmc *)host->mmc; u32 ctrl; diff --git a/drivers/mmc/xenon_sdhci.c b/drivers/mmc/xenon_sdhci.c index 0e4902fab77..6aa73792f96 100644 --- a/drivers/mmc/xenon_sdhci.c +++ b/drivers/mmc/xenon_sdhci.c @@ -537,10 +537,9 @@ static int xenon_sdhci_of_to_plat(struct udevice *dev) host->ioaddr = dev_read_addr_ptr(dev); if (device_is_compatible(dev, "marvell,armada-3700-sdhci")) - priv->pad_ctrl_reg = devfdt_get_addr_index_ptr(dev, 1); + priv->pad_ctrl_reg = dev_read_addr_index_ptr(dev, 1); - name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "marvell,pad-type", - NULL); + name = ofnode_get_property(dev_ofnode(dev), "marvell,pad-type", NULL); if (name) { if (0 == strncmp(name, "sd", 2)) { priv->pad_type = SOC_PAD_SD; diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 21b8b21f6b2..38d6dd142dd 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -205,16 +205,16 @@ config HBMC_AM654 bool "HyperBus controller driver for AM65x SoC" depends on MULTIPLEXER && (MUX_MMIO || SPL_MUX_MMIO) help - This is the driver for HyperBus controller on TI's AM65x and - other SoCs + This is the driver for HyperBus controller on TI's AM65x and + other SoCs config STM32_FLASH bool "STM32 MCU Flash driver" depends on ARCH_STM32 select USE_SYS_MAX_FLASH_BANKS help - This is the driver of embedded flash for some STMicroelectronics - STM32 MCU. + This is the driver of embedded flash for some STMicroelectronics + STM32 MCU. config SYS_MAX_FLASH_SECT int "Maximum number of sectors on a flash chip" @@ -236,17 +236,17 @@ config SYS_MAX_FLASH_BANKS depends on USE_SYS_MAX_FLASH_BANKS default 1 help - Max number of Flash memory banks using by the MTD framework, in the - flash CFI driver and in some other driver to define the flash_info - struct declaration. + Max number of Flash memory banks using by the MTD framework, in the + flash CFI driver and in some other driver to define the flash_info + struct declaration. config SYS_MAX_FLASH_BANKS_DETECT bool "Detection of flash banks number in CFI driver" depends on CFI_FLASH && FLASH_CFI_DRIVER help - This enables detection of number of flash banks in CFI driver, - to reduce the effective number of flash bank, between 0 and - CONFIG_SYS_MAX_FLASH_BANKS + This enables detection of number of flash banks in CFI driver, + to reduce the effective number of flash bank, between 0 and + CONFIG_SYS_MAX_FLASH_BANKS source "drivers/mtd/nand/Kconfig" diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 78ae04bdcba..5ffec9502b6 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -1,5 +1,5 @@ config MTD_NAND_CORE - tristate + bool source "drivers/mtd/nand/raw/Kconfig" diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 2999e6b1710..b5dfad7380f 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -310,47 +310,47 @@ choice prompt "ECC scheme" default NAND_OMAP_ECCSCHEME_BCH8_CODE_HW help - On OMAP platforms, this CONFIG specifies NAND ECC scheme. - It can take following values: - OMAP_ECC_HAM1_CODE_SW + On OMAP platforms, this CONFIG specifies NAND ECC scheme. + It can take following values: + OMAP_ECC_HAM1_CODE_SW 1-bit Hamming code using software lib. (for legacy devices only) - OMAP_ECC_HAM1_CODE_HW + OMAP_ECC_HAM1_CODE_HW 1-bit Hamming code using GPMC hardware. (for legacy devices only) - OMAP_ECC_BCH4_CODE_HW_DETECTION_SW + OMAP_ECC_BCH4_CODE_HW_DETECTION_SW 4-bit BCH code (unsupported) - OMAP_ECC_BCH4_CODE_HW + OMAP_ECC_BCH4_CODE_HW 4-bit BCH code (unsupported) - OMAP_ECC_BCH8_CODE_HW_DETECTION_SW + OMAP_ECC_BCH8_CODE_HW_DETECTION_SW 8-bit BCH code with - ecc calculation using GPMC hardware engine, - error detection using software library. - requires CONFIG_BCH to enable software BCH library (For legacy device which do not have ELM h/w engine) - OMAP_ECC_BCH8_CODE_HW + OMAP_ECC_BCH8_CODE_HW 8-bit BCH code with - ecc calculation using GPMC hardware engine, - error detection using ELM hardware engine. - OMAP_ECC_BCH16_CODE_HW + OMAP_ECC_BCH16_CODE_HW 16-bit BCH code with - ecc calculation using GPMC hardware engine, - error detection using ELM hardware engine. - How to select ECC scheme on OMAP and AMxx platforms ? - ----------------------------------------------------- - Though higher ECC schemes have more capability to detect and correct - bit-flips, but still selection of ECC scheme is dependent on following - - hardware engines present in SoC. + How to select ECC scheme on OMAP and AMxx platforms ? + ----------------------------------------------------- + Though higher ECC schemes have more capability to detect and correct + bit-flips, but still selection of ECC scheme is dependent on following + - hardware engines present in SoC. Some legacy OMAP SoC do not have ELM h/w engine thus such SoC cannot support BCHx_HW ECC schemes. - - size of OOB/Spare region + - size of OOB/Spare region With higher ECC schemes, more OOB/Spare area is required to store ECC. So choice of ECC scheme is limited by NAND oobsize. - In general following expression can help: + In general following expression can help: NAND_OOBSIZE >= 2 + (NAND_PAGESIZE / 512) * ECC_BYTES - where + where NAND_OOBSIZE = number of bytes available in OOB/spare area per NAND page. NAND_PAGESIZE = bytes in main-area of NAND page. diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c index 7324dc72e0a..ef01d48acc0 100644 --- a/drivers/mtd/nand/raw/pxa3xx_nand.c +++ b/drivers/mtd/nand/raw/pxa3xx_nand.c @@ -184,6 +184,7 @@ struct pxa3xx_nand_host { struct pxa3xx_nand_info { struct nand_hw_control controller; struct pxa3xx_nand_platform_data *pdata; + struct udevice *dev; struct clk *clk; void __iomem *mmio_base; @@ -585,8 +586,7 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len) ts = get_timer(0); while (!(nand_readl(info, NDSR) & NDSR_RDDREQ)) { if (get_timer(ts) > TIMEOUT_DRAIN_FIFO) { - dev_err(info->controller.active->mtd.dev, - "Timeout on RDDREQ while draining the FIFO\n"); + dev_err(info->dev, "Timeout on RDDREQ while draining the FIFO\n"); return; } } @@ -638,8 +638,7 @@ static void handle_data_pio(struct pxa3xx_nand_info *info) DIV_ROUND_UP(info->step_spare_size, 4)); break; default: - dev_err(info->controller.active->mtd.dev, - "%s: invalid state %d\n", __func__, info->state); + dev_err(info->dev, "%s: invalid state %d\n", __func__, info->state); BUG(); } @@ -1557,8 +1556,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info, ecc->size = 512; if (ecc_stepsize != 512 || !(nfc_layouts[i].strength)) { - dev_err(info->controller.active->mtd.dev, - "ECC strength %d at page size %d is not supported\n", + dev_err(info->dev, "ECC strength %d at page size %d is not supported\n", strength, page_size); return -ENODEV; } @@ -1799,6 +1797,7 @@ static int pxa3xx_nand_probe(struct udevice *dev) if (ret) return ret; + info->dev = dev; pdata = info->pdata; ret = alloc_nand_resource(dev, info); diff --git a/drivers/mtd/nand/raw/rockchip_nfc.c b/drivers/mtd/nand/raw/rockchip_nfc.c index f730e15d041..ea8e67d1a23 100644 --- a/drivers/mtd/nand/raw/rockchip_nfc.c +++ b/drivers/mtd/nand/raw/rockchip_nfc.c @@ -861,6 +861,15 @@ static int rk_nfc_ecc_init(struct rk_nfc *nfc, struct nand_chip *chip) ecc->steps = mtd->writesize / ecc->size; ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * chip->ecc.size), 8); + rknand->metadata_size = NFC_SYS_DATA_SIZE * ecc->steps; + + if (rknand->metadata_size < NFC_SYS_DATA_SIZE + 2) { + dev_err(nfc->dev, + "driver needs at least %d bytes of meta data\n", + NFC_SYS_DATA_SIZE + 2); + return -EIO; + } + if (ecc->bytes * ecc->steps > mtd->oobsize - rknand->metadata_size) return -EINVAL; @@ -974,15 +983,6 @@ static int rk_nfc_nand_chip_init(ofnode node, struct rk_nfc *nfc, int devnum) ret = ofnode_read_u32(node, "rockchip,boot-ecc-strength", &tmp); rknand->boot_ecc = ret ? ecc->strength : tmp; - rknand->metadata_size = NFC_SYS_DATA_SIZE * ecc->steps; - - if (rknand->metadata_size < NFC_SYS_DATA_SIZE + 2) { - dev_err(dev, - "driver needs at least %d bytes of meta data\n", - NFC_SYS_DATA_SIZE + 2); - return -EIO; - } - if (!nfc->page_buf) { nfc->page_buf = kzalloc(NFC_MAX_PAGE_SIZE, GFP_KERNEL); if (!nfc->page_buf) { diff --git a/drivers/mtd/nand/raw/sunxi_nand.c b/drivers/mtd/nand/raw/sunxi_nand.c index ef27a4b7a36..49748fddf80 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.c +++ b/drivers/mtd/nand/raw/sunxi_nand.c @@ -114,6 +114,7 @@ struct sunxi_nand_hw_ecc { * @clk_rate: clk_rate required for this NAND chip * @timing_cfg TIMING_CFG register value for this NAND chip * @selected: current active CS + * @user_data_bytes array of user data lengths for all ECC steps * @nsels: number of CS lines required by the NAND chip * @sels: array of CS lines descriptions */ @@ -128,6 +129,7 @@ struct sunxi_nand_chip { u32 addr[2]; int cmd_cycles; u8 cmd[2]; + u8 *user_data_bytes; int nsels; struct sunxi_nand_chip_sel sels[0]; }; @@ -744,20 +746,76 @@ static void sunxi_nfc_set_user_data_len(struct sunxi_nfc *nfc, writel(val, nfc->regs + NFC_REG_USER_DATA_LEN(nfc, step)); } +static u8 sunxi_nfc_user_data_sz(const struct sunxi_nand_chip *sunxi_nand, int step) +{ + if (!sunxi_nand->user_data_bytes) + return USER_DATA_SZ; + + return sunxi_nand->user_data_bytes[step]; +} + +static void sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct nand_chip *nand, u8 *oob, + int step, bool bbm, int page, + unsigned int user_data_sz) +{ + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + u32 user_data; + + if (!nfc->caps->reg_user_data_len) { + /* + * For A10, the user data for step n is in the nth + * REG_USER_DATA + */ + user_data = readl(nfc->regs + NFC_REG_USER_DATA(nfc, step)); + sunxi_nfc_user_data_to_buf(user_data, oob); + + } else { + /* + * For H6 NAND controller, the user data for all steps is + * contained in 32 user data registers, but not at a specific + * offset for each step, they are just concatenated. + */ + unsigned int user_data_off = 0; + unsigned int reg_off; + u8 *ptr = oob; + unsigned int i; + + for (i = 0; i < step; i++) + user_data_off += sunxi_nfc_user_data_sz(sunxi_nand, i); + + user_data_off /= 4; + for (i = 0; i < user_data_sz / 4; i++, ptr += 4) { + reg_off = NFC_REG_USER_DATA(nfc, user_data_off + i); + user_data = readl(nfc->regs + reg_off); + sunxi_nfc_user_data_to_buf(user_data, ptr); + } + } + + /* De-randomize the Bad Block Marker. */ + if (bbm && nand->options & NAND_NEED_SCRAMBLING) + sunxi_nfc_randomize_bbm(&nand->mtd, page, oob); +} + static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, u8 *data, int data_off, u8 *oob, int oob_off, int *cur_off, unsigned int *max_bitflips, - bool bbm, int page) + int step, int page) { struct nand_chip *nand = mtd_to_nand(mtd); struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); + unsigned int user_data_sz = sunxi_nfc_user_data_sz(sunxi_nand, step); struct nand_ecc_ctrl *ecc = &nand->ecc; int raw_mode = 0; u32 status; u32 pattern_found; + bool bbm = !step; int ret; + /* From the controller point of view, we are at step 0 */ + const int nfc_step = 0; if (*cur_off != data_off) nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); @@ -771,8 +829,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, if (ret) return ret; - sunxi_nfc_reset_user_data_len(nfc); - sunxi_nfc_set_user_data_len(nfc, 4, 0); + sunxi_nfc_set_user_data_len(nfc, user_data_sz, nfc_step); sunxi_nfc_randomizer_enable(mtd); writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP, @@ -783,31 +840,31 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, if (ret) return ret; - *cur_off = oob_off + ecc->bytes + 4; + *cur_off = oob_off + ecc->bytes + user_data_sz; pattern_found = readl(nfc->regs + nfc->caps->reg_pat_found); pattern_found = field_get(NFC_ECC_PAT_FOUND_MSK(nfc), pattern_found); - if (pattern_found & NFC_ECC_PAT_FOUND(0)) { + if (pattern_found & NFC_ECC_PAT_FOUND(nfc_step)) { u8 pattern = 0xff; if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID(nfc)) & 0x1))) pattern = 0x0; memset(data, pattern, ecc->size); - memset(oob, pattern, ecc->bytes + 4); + memset(oob, pattern, ecc->bytes + user_data_sz); return 1; } - ret = NFC_ECC_ERR_CNT(0, readl(nfc->regs + NFC_REG_ECC_ERR_CNT(nfc, 0))); + ret = NFC_ECC_ERR_CNT(nfc_step, readl(nfc->regs + NFC_REG_ECC_ERR_CNT(nfc, nfc_step))); memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size); nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); - sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4, true, page); + sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + user_data_sz, true, page); status = readl(nfc->regs + NFC_REG_ECC_ST); - if (status & NFC_ECC_ERR(0)) { + if (status & NFC_ECC_ERR(nfc_step)) { /* * Re-read the data with the randomizer disabled to identify * bitflips in erased pages. @@ -816,26 +873,21 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, nand->cmdfunc(mtd, NAND_CMD_RNDOUT, data_off, -1); nand->read_buf(mtd, data, ecc->size); nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1); - nand->read_buf(mtd, oob, ecc->bytes + 4); + nand->read_buf(mtd, oob, ecc->bytes + user_data_sz); } ret = nand_check_erased_ecc_chunk(data, ecc->size, - oob, ecc->bytes + 4, + oob, ecc->bytes + user_data_sz, NULL, 0, ecc->strength); if (ret >= 0) raw_mode = 1; } else { /* - * The engine protects 4 bytes of OOB data per chunk. + * The engine protects user_data_sz bytes of OOB data per chunk. * Retrieve the corrected OOB bytes. */ - sunxi_nfc_user_data_to_buf(readl(nfc->regs + - NFC_REG_USER_DATA(nfc, 0)), - oob); - - /* De-randomize the Bad Block Marker. */ - if (bbm && nand->options & NAND_NEED_SCRAMBLING) - sunxi_nfc_randomize_bbm(mtd, page, oob); + sunxi_nfc_hw_ecc_get_prot_oob_bytes(nand, oob, nfc_step, + bbm, page, user_data_sz); } if (ret < 0) { @@ -848,13 +900,30 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, return raw_mode; } +/* + * Returns the offset of the OOB for each step. + * (it includes the user data before the ECC data.) + */ +static int sunxi_get_oob_offset(struct sunxi_nand_chip *sunxi_nand, + struct nand_ecc_ctrl *ecc, int step) +{ + int ecc_off = step * ecc->bytes; + int i; + + for (i = 0; i < step; i++) + ecc_off += sunxi_nfc_user_data_sz(sunxi_nand, i); + + return ecc_off; +} + static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info *mtd, u8 *oob, int *cur_off, bool randomize, int page) { struct nand_chip *nand = mtd_to_nand(mtd); struct nand_ecc_ctrl *ecc = &nand->ecc; - int offset = ((ecc->bytes + 4) * ecc->steps); + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); + int offset = sunxi_get_oob_offset(sunxi_nand, ecc, ecc->steps); int len = mtd->oobsize - offset; if (len <= 0) @@ -881,13 +950,18 @@ static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf) static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd, const u8 *data, int data_off, const u8 *oob, int oob_off, - int *cur_off, bool bbm, + int *cur_off, int step, int page) { struct nand_chip *nand = mtd_to_nand(mtd); struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); + unsigned int user_data_sz = sunxi_nfc_user_data_sz(sunxi_nand, step); struct nand_ecc_ctrl *ecc = &nand->ecc; + bool bbm = !step; int ret; + /* From the controller point of view, we are at step 0 */ + const int nfc_step = 0; if (data_off != *cur_off) nand->cmdfunc(mtd, NAND_CMD_RNDIN, data_off, -1); @@ -896,15 +970,20 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd, /* Fill OOB data in */ if ((nand->options & NAND_NEED_SCRAMBLING) && bbm) { - u8 user_data[4]; + u8 *user_data; - memcpy(user_data, oob, 4); + user_data = kzalloc(user_data_sz, GFP_KERNEL); + if (!user_data) + return -ENOMEM; + + memcpy(user_data, oob, user_data_sz); sunxi_nfc_randomize_bbm(mtd, page, user_data); writel(sunxi_nfc_buf_to_user_data(user_data), - nfc->regs + NFC_REG_USER_DATA(nfc, 0)); + nfc->regs + NFC_REG_USER_DATA(nfc, nfc_step)); + kfree(user_data); } else { writel(sunxi_nfc_buf_to_user_data(oob), - nfc->regs + NFC_REG_USER_DATA(nfc, 0)); + nfc->regs + NFC_REG_USER_DATA(nfc, nfc_step)); } if (data_off + ecc->size != oob_off) @@ -914,8 +993,7 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd, if (ret) return ret; - sunxi_nfc_reset_user_data_len(nfc); - sunxi_nfc_set_user_data_len(nfc, 4, 0); + sunxi_nfc_set_user_data_len(nfc, user_data_sz, nfc_step); sunxi_nfc_randomizer_enable(mtd); writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | @@ -927,7 +1005,7 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd, if (ret) return ret; - *cur_off = oob_off + ecc->bytes + 4; + *cur_off = oob_off + ecc->bytes + user_data_sz; return 0; } @@ -938,7 +1016,8 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct mtd_info *mtd, { struct nand_chip *nand = mtd_to_nand(mtd); struct nand_ecc_ctrl *ecc = &nand->ecc; - int offset = ((ecc->bytes + 4) * ecc->steps); + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); + int offset = sunxi_get_oob_offset(sunxi_nand, ecc, ecc->steps); int len = mtd->oobsize - offset; if (len <= 0) @@ -957,6 +1036,8 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip); + struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); struct nand_ecc_ctrl *ecc = &chip->ecc; unsigned int max_bitflips = 0; int ret, i, cur_off = 0; @@ -964,16 +1045,17 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd, sunxi_nfc_hw_ecc_enable(mtd); + sunxi_nfc_reset_user_data_len(nfc); for (i = 0; i < ecc->steps; i++) { int data_off = i * ecc->size; - int oob_off = i * (ecc->bytes + 4); + int oob_off = sunxi_get_oob_offset(sunxi_nand, ecc, i); u8 *data = buf + data_off; u8 *oob = chip->oob_poi + oob_off; ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob, oob_off + mtd->writesize, &cur_off, &max_bitflips, - !i, page); + i, page); if (ret < 0) return ret; else if (ret) @@ -994,23 +1076,26 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info *mtd, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi, int page) { + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip); + struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); struct nand_ecc_ctrl *ecc = &chip->ecc; int ret, i, cur_off = 0; unsigned int max_bitflips = 0; sunxi_nfc_hw_ecc_enable(mtd); + sunxi_nfc_reset_user_data_len(nfc); chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); for (i = data_offs / ecc->size; i < DIV_ROUND_UP(data_offs + readlen, ecc->size); i++) { int data_off = i * ecc->size; - int oob_off = i * (ecc->bytes + 4); + int oob_off = sunxi_get_oob_offset(sunxi_nand, ecc, i); u8 *data = bufpoi + data_off; u8 *oob = chip->oob_poi + oob_off; ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob, oob_off + mtd->writesize, - &cur_off, &max_bitflips, !i, page); + &cur_off, &max_bitflips, i, page); if (ret < 0) return ret; } @@ -1025,20 +1110,23 @@ static int sunxi_nfc_hw_ecc_write_page(struct mtd_info *mtd, const uint8_t *buf, int oob_required, int page) { + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip); + struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); struct nand_ecc_ctrl *ecc = &chip->ecc; int ret, i, cur_off = 0; sunxi_nfc_hw_ecc_enable(mtd); + sunxi_nfc_reset_user_data_len(nfc); for (i = 0; i < ecc->steps; i++) { int data_off = i * ecc->size; - int oob_off = i * (ecc->bytes + 4); + int oob_off = sunxi_get_oob_offset(sunxi_nand, ecc, i); const u8 *data = buf + data_off; const u8 *oob = chip->oob_poi + oob_off; ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob, oob_off + mtd->writesize, - &cur_off, !i, page); + &cur_off, i, page); if (ret) return ret; } @@ -1058,21 +1146,24 @@ static int sunxi_nfc_hw_ecc_write_subpage(struct mtd_info *mtd, const u8 *buf, int oob_required, int page) { + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip); + struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); struct nand_ecc_ctrl *ecc = &chip->ecc; int ret, i, cur_off = 0; sunxi_nfc_hw_ecc_enable(mtd); + sunxi_nfc_reset_user_data_len(nfc); for (i = data_offs / ecc->size; i < DIV_ROUND_UP(data_offs + data_len, ecc->size); i++) { int data_off = i * ecc->size; - int oob_off = i * (ecc->bytes + 4); + int oob_off = sunxi_get_oob_offset(sunxi_nand, ecc, i); const u8 *data = buf + data_off; const u8 *oob = chip->oob_poi + oob_off; ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob, oob_off + mtd->writesize, - &cur_off, !i, page); + &cur_off, i, page); if (ret) return ret; } @@ -1087,18 +1178,23 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd, uint8_t *buf, int oob_required, int page) { + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip); + struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); struct nand_ecc_ctrl *ecc = &chip->ecc; unsigned int max_bitflips = 0; int ret, i, cur_off = 0; bool raw_mode = false; + /* With hw_syndrome, user data length is fixed */ + unsigned int user_data_sz = sunxi_nfc_user_data_sz(sunxi_nand, 0); sunxi_nfc_hw_ecc_enable(mtd); + sunxi_nfc_reset_user_data_len(nfc); for (i = 0; i < ecc->steps; i++) { - int data_off = i * (ecc->size + ecc->bytes + 4); + int data_off = i * (ecc->size + ecc->bytes + user_data_sz); int oob_off = data_off + ecc->size; u8 *data = buf + (i * ecc->size); - u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4)); + u8 *oob = chip->oob_poi + (i * (ecc->bytes + user_data_sz)); ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob, oob_off, &cur_off, @@ -1123,16 +1219,19 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd, const uint8_t *buf, int oob_required, int page) { + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip); struct nand_ecc_ctrl *ecc = &chip->ecc; int ret, i, cur_off = 0; + /* With hw_syndrome, user data length is fixed */ + unsigned int user_data_sz = sunxi_nfc_user_data_sz(sunxi_nand, 0); sunxi_nfc_hw_ecc_enable(mtd); for (i = 0; i < ecc->steps; i++) { - int data_off = i * (ecc->size + ecc->bytes + 4); + int data_off = i * (ecc->size + ecc->bytes + user_data_sz); int oob_off = data_off + ecc->size; const u8 *data = buf + (i * ecc->size); - const u8 *oob = chip->oob_poi + (i * (ecc->bytes + 4)); + const u8 *oob = chip->oob_poi + (i * (ecc->bytes + user_data_sz)); ret = sunxi_nfc_hw_ecc_write_chunk(mtd, data, data_off, oob, oob_off, &cur_off, @@ -1334,6 +1433,34 @@ static int sunxi_nand_chip_init_timings(struct sunxi_nfc *nfc, return sunxi_nand_chip_set_timings(nfc, chip, timings); } +static int sunxi_nfc_maximize_user_data(struct nand_chip *nand, uint32_t oobsize, + int ecc_bytes, int nsectors) +{ + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); + struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller); + const struct sunxi_nfc_caps *c = nfc->caps; + int remaining_bytes = oobsize - (ecc_bytes * nsectors); + int i, step; + + sunxi_nand->user_data_bytes = devm_kzalloc(nfc->dev, nsectors, + GFP_KERNEL); + if (!sunxi_nand->user_data_bytes) + return -ENOMEM; + + for (step = 0; (step < nsectors) && (remaining_bytes > 0); step++) { + for (i = 0; i < c->nuser_data_tab; i++) { + if (c->user_data_len_tab[i] > remaining_bytes) + break; + sunxi_nand->user_data_bytes[step] = c->user_data_len_tab[i]; + } + remaining_bytes -= sunxi_nand->user_data_bytes[step]; + if (sunxi_nand->user_data_bytes[step] == 0) + break; + } + + return 0; +} + static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc) { @@ -1342,6 +1469,7 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); struct sunxi_nand_hw_ecc *data; struct nand_ecclayout *layout; + unsigned int total_user_data_sz = 0; int nsectors; int ret; int i; @@ -1390,7 +1518,15 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, layout = &data->layout; nsectors = mtd->writesize / ecc->size; - if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) { + /* Use the remaining OOB space for user data */ + if (nfc->caps->reg_user_data_len) + sunxi_nfc_maximize_user_data(nand, mtd->oobsize, ecc->bytes, + nsectors); + + for (i = 0; i < nsectors; i++) + total_user_data_sz += sunxi_nfc_user_data_sz(sunxi_nand, i); + + if (mtd->oobsize < ecc->bytes * nsectors + total_user_data_sz) { ret = -EINVAL; goto err; } @@ -1404,6 +1540,8 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, err: kfree(data); + devm_kfree(nfc->dev, sunxi_nand->user_data_bytes); + sunxi_nand->user_data_bytes = NULL; return ret; } @@ -1418,7 +1556,10 @@ static void sunxi_nand_hw_common_ecc_ctrl_cleanup(struct nand_ecc_ctrl *ecc) static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc) { + struct nand_chip *nand = mtd_to_nand(mtd); + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct nand_ecclayout *layout; + unsigned int total_user_data_sz = 0; int nsectors; int i, j; int ret; @@ -1440,14 +1581,14 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, layout->oobfree[i - 1].offset + layout->oobfree[i - 1].length + ecc->bytes; - layout->oobfree[i].length = 4; + layout->oobfree[i].length = sunxi_nfc_user_data_sz(sunxi_nand, i); } else { /* * The first 2 bytes are used for BB markers, hence we - * only have 2 bytes available in the first user data - * section. + * only have user_data_len(0) - 2 bytes available in the + * first user data section. */ - layout->oobfree[i].length = 2; + layout->oobfree[i].length = sunxi_nfc_user_data_sz(sunxi_nand, i) - 2; layout->oobfree[i].offset = 2; } @@ -1457,13 +1598,16 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, layout->oobfree[i].length + j; } - if (mtd->oobsize > (ecc->bytes + 4) * nsectors) { + for (i = 0; i < nsectors; i++) + total_user_data_sz += sunxi_nfc_user_data_sz(sunxi_nand, i); + + if (mtd->oobsize > ecc->bytes * nsectors + total_user_data_sz) { layout->oobfree[nsectors].offset = layout->oobfree[nsectors - 1].offset + layout->oobfree[nsectors - 1].length + ecc->bytes; layout->oobfree[nsectors].length = mtd->oobsize - - ((ecc->bytes + 4) * nsectors); + (ecc->bytes * nsectors + total_user_data_sz); } return 0; @@ -1472,6 +1616,8 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc) { + struct nand_chip *nand = mtd_to_nand(mtd); + struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand); struct nand_ecclayout *layout; int nsectors; int i; @@ -1481,7 +1627,13 @@ static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd, if (ret) return ret; - ecc->prepad = 4; + for (i = 0; i < nsectors; i++) + if (sunxi_nfc_user_data_sz(sunxi_nand, i) != + sunxi_nfc_user_data_sz(sunxi_nand, 0)) { + dev_err(mtd->dev, "Variable user data length not upported with NAND_ECC_HW_SYNDROME\n"); + return -EOPNOTSUPP; + } + ecc->prepad = sunxi_nfc_user_data_sz(sunxi_nand, 0); ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page; ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page; @@ -1596,21 +1748,20 @@ static int sunxi_nand_chip_init(struct udevice *dev, struct sunxi_nfc *nfc, if (ret) { dev_err(dev, "could not retrieve reg property: %d\n", ret); - kfree(chip); - return ret; + goto err_free; } if (tmp > NFC_MAX_CS) { dev_err(dev, "invalid reg value: %u (max CS = 7)\n", tmp); - kfree(chip); - return -EINVAL; + ret = -EINVAL; + goto err_free; } if (test_and_set_bit(tmp, &nfc->assigned_cs)) { dev_err(dev, "CS %d already assigned\n", tmp); - kfree(chip); - return -EINVAL; + ret = -EINVAL; + goto err_free; } chip->sels[i].cs = tmp; @@ -1636,15 +1787,13 @@ static int sunxi_nand_chip_init(struct udevice *dev, struct sunxi_nfc *nfc, dev_err(dev, "could not retrieve timings for ONFI mode 0: %d\n", ret); - kfree(chip); - return ret; + goto err_free; } ret = sunxi_nand_chip_set_timings(nfc, chip, timings); if (ret) { dev_err(dev, "could not configure chip timings: %d\n", ret); - kfree(chip); - return ret; + goto err_free; } nand = &chip->nand; @@ -1665,10 +1814,8 @@ static int sunxi_nand_chip_init(struct udevice *dev, struct sunxi_nfc *nfc, mtd = nand_to_mtd(nand); ret = nand_scan_ident(mtd, nsels, NULL); - if (ret) { - kfree(chip); - return ret; - } + if (ret) + goto err_free; if (nand->bbt_options & NAND_BBT_USE_FLASH) nand->bbt_options |= NAND_BBT_NO_OOB; @@ -1681,34 +1828,35 @@ static int sunxi_nand_chip_init(struct udevice *dev, struct sunxi_nfc *nfc, ret = sunxi_nand_chip_init_timings(nfc, chip); if (ret) { dev_err(dev, "could not configure chip timings: %d\n", ret); - kfree(chip); - return ret; + goto err_free; } ret = sunxi_nand_ecc_init(mtd, &nand->ecc); if (ret) { dev_err(dev, "ECC init failed: %d\n", ret); - kfree(chip); - return ret; + goto err_free; } ret = nand_scan_tail(mtd); if (ret) { dev_err(dev, "nand_scan_tail failed: %d\n", ret); - kfree(chip); - return ret; + goto err_free; } ret = nand_register(devnum, mtd); if (ret) { dev_err(dev, "failed to register mtd device: %d\n", ret); - kfree(chip); - return ret; + goto err_free; } list_add_tail(&chip->node, &nfc->chips); return 0; + +err_free: + kfree(chip); + + return ret; } static int sunxi_nand_chips_init(struct udevice *dev, struct sunxi_nfc *nfc) @@ -1736,6 +1884,7 @@ static void sunxi_nand_chips_cleanup(struct sunxi_nfc *nfc) nand_release(&chip->mtd); sunxi_nand_ecc_cleanup(&chip->nand.ecc); list_del(&chip->node); + devm_kfree(nfc->dev, chip->user_data_bytes); kfree(chip); } } diff --git a/drivers/mtd/nand/raw/sunxi_nand.h b/drivers/mtd/nand/raw/sunxi_nand.h index 6ee3ea14ee1..1b2c514852d 100644 --- a/drivers/mtd/nand/raw/sunxi_nand.h +++ b/drivers/mtd/nand/raw/sunxi_nand.h @@ -24,10 +24,7 @@ #define SUNXI_NAND_H #include <linux/bitops.h> - -/* non compile-time field get/prep */ -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) -#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) +#include <linux/bitfield.h> #define NFC_REG_CTL 0x0000 #define NFC_REG_ST 0x0004 @@ -181,6 +178,9 @@ #define NFC_MAX_CS 7 +/* On A10, the user data length register is 4 bytes */ +#define USER_DATA_SZ 4 + /* * NAND Controller capabilities structure: stores NAND controller capabilities * for distinction between compatible strings. diff --git a/drivers/mtd/nand/raw/sunxi_nand_spl.c b/drivers/mtd/nand/raw/sunxi_nand_spl.c index 67f7d22ed2c..cf351de4e8d 100644 --- a/drivers/mtd/nand/raw/sunxi_nand_spl.c +++ b/drivers/mtd/nand/raw/sunxi_nand_spl.c @@ -28,6 +28,7 @@ struct nfc_config { bool randomize; bool valid; const struct sunxi_nfc_caps *caps; + u8 *user_data_bytes; }; /* minimal "boot0" style NAND support for Allwinner A20 */ @@ -223,22 +224,6 @@ static int nand_change_column(u16 column) return 0; } -/* - * On H6/H616 the user_data length has to be set in specific registers - * before writing. - */ -static void sunxi_nfc_reset_user_data_len(const struct nfc_config *nfc) -{ - int loop_step = NFC_REG_USER_DATA_LEN_CAPACITY; - - /* not all SoCs have this register */ - if (!NFC_REG_USER_DATA_LEN(nfc, 0)) - return; - - for (int i = 0; i < nfc->caps->max_ecc_steps; i += loop_step) - writel_nfc(0, NFC_REG_USER_DATA_LEN(nfc, i)); -} - static void sunxi_nfc_set_user_data_len(const struct nfc_config *nfc, int len, int step) { @@ -269,13 +254,19 @@ static void sunxi_nfc_set_user_data_len(const struct nfc_config *nfc, writel_nfc(val, NFC_REG_USER_DATA_LEN(nfc, step)); } +/* + * Values in this table are obtained by doing: + * DIV_ROUND_UP(info->ecc_strength * 14, 8) + * So it's the number of bytes needed for ECC one step + * (not counting the user data length) + */ #if defined(CONFIG_MACH_SUN50I_H616) || defined(CONFIG_MACH_SUN50I_H6) static const int ecc_bytes[] = { - 32, 46, 54, 60, 74, 82, 88, 96, 102, 110, 116, 124, 130, 138, 144 + 28, 42, 50, 56, 70, 78, 84, 92, 98, 106, 112, 120, 126, 134, 140 }; #else static const int ecc_bytes[] = { - 32, 46, 54, 60, 74, 88, 102, 110, 116 + 28, 42, 50, 56, 70, 84, 98, 106, 112 }; #endif @@ -288,6 +279,14 @@ static void nand_readlcpy(u32 *dest, u32 * __iomem src, size_t len) *dest++ = readl(src++); } +static u8 nand_user_data_sz(const struct nfc_config *conf, int step) +{ + if (!conf->user_data_bytes) + return USER_DATA_SZ; + + return conf->user_data_bytes[step]; +} + static int nand_read_page(const struct nfc_config *conf, u32 offs, void *dest, int len) { @@ -295,8 +294,11 @@ static int nand_read_page(const struct nfc_config *conf, u32 offs, u16 rand_seed = 0; int oob_chunk_sz = ecc_bytes[conf->ecc_strength]; int page = offs / conf->page_size; + int oob_off = conf->page_size; u32 ecc_st, pattern_found; int i; + /* From the controller point of view, we are at step 0 */ + const int nfc_step = 0; if (offs % conf->page_size || len % conf->ecc_size || len > conf->page_size || len < 0) @@ -309,9 +311,9 @@ static int nand_read_page(const struct nfc_config *conf, u32 offs, /* Retrieve data from SRAM (PIO) */ for (i = 0; i < nsectors; i++) { int data_off = i * conf->ecc_size; - int oob_off = conf->page_size + (i * oob_chunk_sz); u8 *data = dest + data_off; u32 ecc512_bit = 0; + unsigned int user_data_sz = nand_user_data_sz(conf, i); if (conf->caps->has_ecc_block_512 && conf->ecc_size == 512) ecc512_bit = NFC_ECC_BLOCK_512; @@ -337,8 +339,7 @@ static int nand_read_page(const struct nfc_config *conf, u32 offs, */ nand_change_column(oob_off); - sunxi_nfc_reset_user_data_len(conf); - sunxi_nfc_set_user_data_len(conf, 4, 0); + sunxi_nfc_set_user_data_len(conf, user_data_sz, nfc_step); nand_exec_cmd(NFC_DATA_TRANS | NFC_ECC_OP); /* Get the ECC status */ @@ -356,7 +357,7 @@ static int nand_read_page(const struct nfc_config *conf, u32 offs, pattern_found = readl_nfc(conf->caps->reg_pat_found); pattern_found = field_get(NFC_ECC_PAT_FOUND_MSK(conf), pattern_found); - if (pattern_found & NFC_ECC_PAT_FOUND(0)) + if (pattern_found & NFC_ECC_PAT_FOUND(nfc_step)) return 1; } @@ -364,13 +365,61 @@ static int nand_read_page(const struct nfc_config *conf, u32 offs, nand_readlcpy((u32 *)data, (void *)(uintptr_t)SUNXI_NFC_BASE + NFC_RAM0_BASE, conf->ecc_size); - /* Stop the ECC engine */ writel_nfc(readl_nfc(NFC_REG_ECC_CTL) & ~NFC_ECC_EN, NFC_REG_ECC_CTL); if (data_off + conf->ecc_size >= len) break; + + oob_off += oob_chunk_sz + user_data_sz; + } + + return 0; +} + +static int nand_min_user_data_sz(struct nfc_config *conf, int nsectors) +{ + const struct sunxi_nfc_caps *c = conf->caps; + int min_user_data_sz = 0; + int i; + + if (!c->reg_user_data_len) { + for (i = 0; i < nsectors; i++) + min_user_data_sz += nand_user_data_sz(conf, i); + } else { + for (i = 0; i < c->nuser_data_tab; i++) + /* We want at least enough size for the BBM */ + if (c->user_data_len_tab[i] >= 2) + break; + min_user_data_sz = c->user_data_len_tab[i]; + } + + return min_user_data_sz; +} + +static int nand_maximize_user_data(struct nfc_config *conf, uint32_t oobsize, + int ecc_len, int nsectors) +{ + const struct sunxi_nfc_caps *c = conf->caps; + int remaining_bytes = oobsize - (ecc_len * nsectors); + int i, step; + + kfree(conf->user_data_bytes); + + conf->user_data_bytes = kzalloc(nsectors, GFP_KERNEL); + if (!conf->user_data_bytes) + return -ENOMEM; + + for (step = 0; (step < nsectors) && (remaining_bytes > 0); step++) { + for (i = 0; i < c->nuser_data_tab; i++) { + if (c->user_data_len_tab[i] > remaining_bytes) + break; + conf->user_data_bytes[step] = c->user_data_len_tab[i]; + } + remaining_bytes -= conf->user_data_bytes[step]; + if (conf->user_data_bytes[step] == 0) + break; } return 0; @@ -380,7 +429,8 @@ static int nand_max_ecc_strength(struct nfc_config *conf) { int max_oobsize, max_ecc_bytes; int nsectors = conf->page_size / conf->ecc_size; - int i; + unsigned int total_user_data_sz = 0; + int ecc_idx, i; /* * ECC strength is limited by the size of the OOB area which is @@ -405,15 +455,38 @@ static int nand_max_ecc_strength(struct nfc_config *conf) max_ecc_bytes = max_oobsize / nsectors; - for (i = 0; i < ARRAY_SIZE(ecc_bytes); i++) { - if (ecc_bytes[i] > max_ecc_bytes) + /* + * nand_min_user_data_sz() will return the total_user_data_sz in case + * of a fixed user data length, or the minimal usable user data size + * in case of variable data length (with at least enough space for the + * BBM. + */ + total_user_data_sz = nand_min_user_data_sz(conf, nsectors); + + for (ecc_idx = 0; ecc_idx < ARRAY_SIZE(ecc_bytes); ecc_idx++) { + if (ecc_bytes[ecc_idx] + total_user_data_sz > max_ecc_bytes) break; } - if (!i) + if (!ecc_idx) return -EINVAL; - return i - 1; + ecc_idx--; + + /* + * The rationale for variable data length is to prioritize maximum ECC + * strength, and then use the remaining space for user data. + */ + if (conf->caps->reg_user_data_len) { + nand_maximize_user_data(conf, max_oobsize, + ecc_bytes[ecc_idx], nsectors); + + total_user_data_sz = 0; + for (i = 0; i < nsectors; i++) + total_user_data_sz += nand_user_data_sz(conf, i); + } + + return ecc_idx; } static int nand_detect_ecc_config(struct nfc_config *conf, u32 offs, diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index de78a6cb707..4ff58380b59 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -94,39 +94,39 @@ config SPI_FLASH_SFDP_SUPPORT bool "SFDP table parsing support for SPI NOR flashes" depends on !SPI_FLASH_BAR help - Enable support for parsing and auto discovery of parameters for - SPI NOR flashes using Serial Flash Discoverable Parameters (SFDP) - tables as per JESD216 standard. + Enable support for parsing and auto discovery of parameters for + SPI NOR flashes using Serial Flash Discoverable Parameters (SFDP) + tables as per JESD216 standard. config SPI_FLASH_SMART_HWCAPS bool "Smart hardware capability detection based on SPI MEM supports_op() hook" default y help - Enable support for smart hardware capability detection based on SPI - MEM supports_op() hook that lets controllers express whether they - can support a type of operation in a much more refined way compared - to using flags like SPI_RX_DUAL, SPI_TX_QUAD, etc. + Enable support for smart hardware capability detection based on SPI + MEM supports_op() hook that lets controllers express whether they + can support a type of operation in a much more refined way compared + to using flags like SPI_RX_DUAL, SPI_TX_QUAD, etc. config SPI_NOR_BOOT_SOFT_RESET_EXT_INVERT bool "Command extension type is INVERT for Software Reset on boot" help - Because of SFDP information can not be get before boot. - So define command extension type is INVERT when Software Reset on boot only. + Because of SFDP information can not be get before boot. + So define command extension type is INVERT when Software Reset on boot only. config SPI_FLASH_SOFT_RESET bool "Software Reset support for SPI NOR flashes" help - Enable support for xSPI Software Reset. It will be used to switch from - Octal DTR mode to legacy mode on shutdown and boot (if enabled). + Enable support for xSPI Software Reset. It will be used to switch from + Octal DTR mode to legacy mode on shutdown and boot (if enabled). config SPI_FLASH_SOFT_RESET_ON_BOOT bool "Perform a Software Reset on boot on flashes that boot in stateful mode" depends on SPI_FLASH_SOFT_RESET help - Perform a Software Reset on boot to allow detecting flashes that are - handed to us in Octal DTR mode. Do not enable this config on flashes - that are not supposed to be handed to U-Boot in Octal DTR mode, even - if they _do_ support the Soft Reset sequence. + Perform a Software Reset on boot to allow detecting flashes that are + handed to us in Octal DTR mode. Do not enable this config on flashes + that are not supposed to be handed to U-Boot in Octal DTR mode, even + if they _do_ support the Soft Reset sequence. config SPI_FLASH_BAR bool "SPI flash Bank/Extended address register support" @@ -139,18 +139,18 @@ config SPI_FLASH_LOCK bool "Enable the Locking feature" default y help - Enable the SPI flash lock support. By default this is set to y. - If you intend not to use the lock support you should say n here. + Enable the SPI flash lock support. By default this is set to y. + If you intend not to use the lock support you should say n here. config SPI_FLASH_UNLOCK_ALL bool "Unlock the entire SPI flash on u-boot startup" default y help - Some flashes tend to power up with the software write protection - bits set. If this option is set, the whole flash will be unlocked. + Some flashes tend to power up with the software write protection + bits set. If this option is set, the whole flash will be unlocked. - For legacy reasons, this option default to y. But if you intend to - actually use the software protection bits you should say n here. + For legacy reasons, this option default to y. But if you intend to + actually use the software protection bits you should say n here. config SPI_FLASH_ATMEL bool "Atmel SPI flash support" @@ -201,9 +201,9 @@ config SPI_FLASH_S28HX_T bool "Cypress SEMPER Octal (S28) chip support" depends on SPI_FLASH_SPANSION help - Add support for the Cypress S28HL-T and S28HS-T chip. This is a separate - config because the fixup hooks for this flash add extra size overhead. - Boards that don't use the flash can disable this to save space. + Add support for the Cypress S28HL-T and S28HS-T chip. This is a separate + config because the fixup hooks for this flash add extra size overhead. + Boards that don't use the flash can disable this to save space. config SPI_FLASH_STMICRO bool "STMicro SPI flash support" @@ -214,9 +214,9 @@ config SPI_FLASH_MT35XU bool "Micron MT35XU chip support" depends on SPI_FLASH_STMICRO help - Add support for the Micron MT35XU chip. This is a separate config - because the fixup hooks for this flash add extra size overhead. Boards - that don't use the flash can disable this to save space. + Add support for the Micron MT35XU chip. This is a separate config + because the fixup hooks for this flash add extra size overhead. Boards + that don't use the flash can disable this to save space. config SPI_FLASH_SST bool "SST SPI flash support" @@ -282,7 +282,7 @@ config SPI_FLASH_MTD bool "SPI Flash MTD support" depends on SPI_FLASH && MTD help - Enable the MTD support for spi flash layer, this adapter is for + Enable the MTD support for spi flash layer, this adapter is for translating mtd_read/mtd_write commands into spi_flash_read/write commands. It is not intended to use it within sf_cmd or the SPI flash subsystem. Such an adapter is needed for subsystems like @@ -294,7 +294,7 @@ config SPL_SPI_FLASH_MTD bool "SPI flash MTD support for SPL" depends on SPI_FLASH && SPL help - Enable the MTD support for the SPI flash layer in SPL. + Enable the MTD support for the SPI flash layer in SPL. If unsure, say N diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 44e67cd913a..9a96be11e6d 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -8,14 +8,13 @@ spi-nor-y := sf_probe.o spi-nor-ids.o ifdef CONFIG_XPL_BUILD obj-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o +endif + ifeq ($(CONFIG_$(PHASE_)SPI_FLASH_TINY),y) spi-nor-y += spi-nor-tiny.o else spi-nor-y += spi-nor-core.o endif -else -spi-nor-y += spi-nor-core.o -endif obj-$(CONFIG_SPI_FLASH) += spi-nor.o obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o diff --git a/drivers/mtd/spi/sf_bootdev.c b/drivers/mtd/spi/sf_bootdev.c index 017a74a3016..6ace4ee0aed 100644 --- a/drivers/mtd/spi/sf_bootdev.c +++ b/drivers/mtd/spi/sf_bootdev.c @@ -57,7 +57,7 @@ static int sf_bootdev_bind(struct udevice *dev) return 0; } -struct bootdev_ops sf_bootdev_ops = { +static const struct bootdev_ops sf_bootdev_ops = { .get_bootflow = sf_get_bootflow, }; diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 7100b64bf22..dee03662d45 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -229,9 +229,11 @@ static int spi_flash_std_remove(struct udevice *dev) spi_mem_dirmap_destroy(flash->dirmap.rdesc); } - ret = spi_nor_remove(flash); - if (ret) - return ret; + if (CONFIG_IS_ENABLED(SPI_FLASH_SOFT_RESET)) { + ret = spi_nor_remove(flash); + if (ret) + return ret; + } if (CONFIG_IS_ENABLED(SPI_FLASH_MTD)) spi_flash_mtd_unregister(flash); diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index c0fa98424aa..31a2ba49a87 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -231,6 +231,10 @@ const struct flash_info spi_nor_ids[] = { SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) }, + { + INFO("gd55lb02gf", 0xc8601c, 0, 64 * 1024, 4096, + SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) + }, #endif #ifdef CONFIG_SPI_FLASH_ISSI /* ISSI */ /* ISSI */ diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig index ba77c034736..e523a4c4707 100644 --- a/drivers/mtd/ubi/Kconfig +++ b/drivers/mtd/ubi/Kconfig @@ -82,8 +82,8 @@ config MTD_UBI_BEB_LIMIT config MTD_UBI_FASTMAP bool "UBI Fastmap (Experimental feature)" help - Important: this feature is experimental so far and the on-flash - format for fastmap may change in the next kernel versions + Important: this feature is experimental so far and the on-flash + format for fastmap may change in the next kernel versions Fastmap is a mechanism which allows attaching an UBI device in nearly constant time. Instead of scanning the whole MTD device it diff --git a/drivers/mux/Kconfig b/drivers/mux/Kconfig index de74e5d5e4e..383dac532c1 100644 --- a/drivers/mux/Kconfig +++ b/drivers/mux/Kconfig @@ -5,17 +5,17 @@ config MULTIPLEXER depends on DM select DEVRES help - The mux framework is a minimalistic subsystem that handles multiplexer - controllers. It provides the same API as Linux and mux drivers should - be portable with a minimum effort. + The mux framework is a minimalistic subsystem that handles multiplexer + controllers. It provides the same API as Linux and mux drivers should + be portable with a minimum effort. if MULTIPLEXER config SPL_MUX_MMIO bool "MMIO register bitfield-controlled Multiplexer" - depends on MULTIPLEXER && SYSCON - help - MMIO register bitfield-controlled Multiplexer controller. + depends on MULTIPLEXER && SYSCON + help + MMIO register bitfield-controlled Multiplexer controller. The driver builds multiplexer controllers for bitfields in a syscon register. For N bit wide bitfields, there will be 2^N possible diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ed07e286676..4399c6c7a99 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -184,10 +184,10 @@ config CALXEDA_XGMAC config DWC_ETH_XGMAC bool select PHYLIB - help - This driver supports the Synopsys Designware Ethernet XGMAC (10G - Ethernet MAC) IP block. The IP supports many options for bus type, - clocking/reset structure, and feature list. + help + This driver supports the Synopsys Designware Ethernet XGMAC (10G + Ethernet MAC) IP block. The IP supports many options for bus type, + clocking/reset structure, and feature list. config DWC_ETH_XGMAC_SOCFPGA bool "Synopsys DWC Ethernet XGMAC device support for SOCFPGA" @@ -229,8 +229,8 @@ config DWC_ETH_QOS_ADI bool "Synopsys DWC Ethernet QOS device support for ADI SC59x-64 parts" depends on DWC_ETH_QOS && ARCH_SC5XX help - The Synopsis Designware Ethernet QoS IP block with the specific - configuration used in the ADI ADSP-SC59X 64 bit SoCs + The Synopsis Designware Ethernet QoS IP block with the specific + configuration used in the ADI ADSP-SC59X 64 bit SoCs config DWC_ETH_QOS_IMX bool "Synopsys DWC Ethernet QOS device support for IMX" @@ -246,6 +246,20 @@ config DWC_ETH_QOS_INTEL The Synopsys Designware Ethernet QOS IP block with the specific configuration used in the Intel Elkhart-Lake soc. +config DWC_ETH_QOS_MTK + bool "Synopsys DWC Ethernet QOS device support for MediaTek SoCs" + depends on DWC_ETH_QOS && ARCH_MEDIATEK + help + The Synopsys Designware Ethernet QOS IP block with the specific + configuration used in MediaTek SoCs. + +config DWC_ETH_QOS_QCOM + bool "Synopsys DWC Ethernet QOS device support for Qcom SoCs" + depends on DWC_ETH_QOS + help + The Synopsys Designware Ethernet QOS IP block with specific + configuration used in Qcom QCS404 SoC. + config DWC_ETH_QOS_ROCKCHIP bool "Synopsys DWC Ethernet QOS device support for Rockchip SoCs" depends on DWC_ETH_QOS && ARCH_ROCKCHIP @@ -254,6 +268,13 @@ config DWC_ETH_QOS_ROCKCHIP The Synopsys Designware Ethernet QOS IP block with specific configuration used in Rockchip SoCs. +config DWC_ETH_QOS_STARFIVE + bool "Synopsys DWC Ethernet QOS device support for STARFIVE" + depends on DWC_ETH_QOS + help + The Synopsys Designware Ethernet QOS IP block with specific + configuration used in STARFIVE JH7110 soc. + config DWC_ETH_QOS_STM32 bool "Synopsys DWC Ethernet QOS device support for STM32" depends on DWC_ETH_QOS && ARCH_STM32MP @@ -271,20 +292,6 @@ config DWC_ETH_QOS_TEGRA186 The Synopsys Designware Ethernet QOS IP block with specific configuration used in NVIDIA's Tegra186 chip. -config DWC_ETH_QOS_QCOM - bool "Synopsys DWC Ethernet QOS device support for Qcom SoCs" - depends on DWC_ETH_QOS - help - The Synopsys Designware Ethernet QOS IP block with specific - configuration used in Qcom QCS404 SoC. - -config DWC_ETH_QOS_STARFIVE - bool "Synopsys DWC Ethernet QOS device support for STARFIVE" - depends on DWC_ETH_QOS - help - The Synopsys Designware Ethernet QOS IP block with specific - configuration used in STARFIVE JH7110 soc. - config E1000 bool "Intel PRO/1000 Gigabit Ethernet support" depends on PCI @@ -339,7 +346,7 @@ config ESSEDMA config ETH_SANDBOX depends on SANDBOX - depends on NET || NET_LWIP + depends on NET default y bool "Sandbox: Mocked Ethernet driver" help @@ -350,7 +357,7 @@ config ETH_SANDBOX config ETH_SANDBOX_RAW depends on SANDBOX - depends on NET + depends on NET_LEGACY default y bool "Sandbox: Bridge to Linux Raw Sockets" help @@ -460,9 +467,9 @@ config FSL_FM_10GEC_REGULAR_NOTATION help On SoCs T4240, T2080, LS1043A, etc, the notation between 10GEC and MAC as below: - 10GEC1->MAC9, 10GEC2->MAC10, 10GEC3->MAC1, 10GEC4->MAC2 + 10GEC1->MAC9, 10GEC2->MAC10, 10GEC3->MAC1, 10GEC4->MAC2 While on SoCs T1024, etc, the notation between 10GEC and MAC as below: - 10GEC1->MAC1, 10GEC2->MAC2 + 10GEC1->MAC1, 10GEC2->MAC2 so we introduce CONFIG_FSL_FM_10GEC_REGULAR_NOTATION to identify the new SoCs on which 10GEC enumeration is consistent with MAC enumeration. @@ -476,7 +483,7 @@ config FTMAC100 config FTGMAC100 bool "Ftgmac100 Ethernet Support" select PHYLIB - depends on NET + depends on NET_LEGACY help This driver supports the Faraday's FTGMAC100 Gigabit SoC Ethernet controller that can be found on Aspeed SoCs (which @@ -529,7 +536,7 @@ config KSZ9477 config LITEETH bool "LiteX LiteEth Ethernet MAC" help - Driver for the LiteEth Ethernet MAC from LiteX. + Driver for the LiteEth Ethernet MAC from LiteX. config MV88E6XXX bool "Marvell MV88E6xxx Ethernet switch DSA driver" @@ -701,12 +708,12 @@ config SJA1105 family. These are 5-port devices and are managed over an SPI interface. Probing is handled based on OF bindings. The driver supports the following revisions: - - SJA1105E (Gen. 1, No TT-Ethernet) - - SJA1105T (Gen. 1, TT-Ethernet) - - SJA1105P (Gen. 2, No SGMII, No TT-Ethernet) - - SJA1105Q (Gen. 2, No SGMII, TT-Ethernet) - - SJA1105R (Gen. 2, SGMII, No TT-Ethernet) - - SJA1105S (Gen. 2, SGMII, TT-Ethernet) + - SJA1105E (Gen. 1, No TT-Ethernet) + - SJA1105T (Gen. 1, TT-Ethernet) + - SJA1105P (Gen. 2, No SGMII, No TT-Ethernet) + - SJA1105Q (Gen. 2, No SGMII, TT-Ethernet) + - SJA1105R (Gen. 2, SGMII, No TT-Ethernet) + - SJA1105S (Gen. 2, SGMII, TT-Ethernet) config SMC911X bool "SMSC LAN911x and LAN921x controller driver" @@ -740,11 +747,11 @@ config SUN4I_EMAC This driver supports the Allwinner based SUN4I Ethernet MAC. config SUN8I_EMAC - bool "Allwinner Sun8i Ethernet MAC support" - select PHYLIB + bool "Allwinner Sun8i Ethernet MAC support" + select PHYLIB select PHY_GIGE - help - This driver supports the Allwinner based SUN8I/SUN50I Ethernet MAC. + help + This driver supports the Allwinner based SUN8I/SUN50I Ethernet MAC. It can be found in H3/A64/A83T based SoCs and compatible with both External and Internal PHYs. @@ -905,7 +912,7 @@ config FEC1_PHY help Define to the hardcoded PHY address which corresponds to the given FEC; i. e. - #define CONFIG_FEC1_PHY 4 + #define CONFIG_FEC1_PHY 4 means that the PHY with address 4 is connected to FEC1 When set to -1, means to probe for first available. @@ -929,7 +936,7 @@ config FEC2_PHY help Define to the hardcoded PHY address which corresponds to the given FEC; i. e. - #define CONFIG_FEC1_PHY 4 + #define CONFIG_FEC1_PHY 4 means that the PHY with address 4 is connected to FEC1 When set to -1, means to probe for first available. @@ -1018,8 +1025,8 @@ config FSL_ENETC config FSL_ENETC_NETC_BLK_CTRL bool "NXP ENETC NETC blocks control driver" depends on FSL_ENETC - depends on IMX95 || IMX94 - default y if IMX95 || IMX94 + depends on IMX95 || IMX94 || IMX952 + default y if IMX95 || IMX94 || IMX952 help This driver configures Integrated Endpoint Register Block (IERB) and Privileged Register Block (PRB) of NETC. For i.MX platforms, it also @@ -1034,7 +1041,7 @@ config MDIO_GPIO_BITBANG bool "GPIO bitbanging MDIO driver" depends on DM_MDIO && DM_GPIO help - Driver for bitbanging MDIO + Driver for bitbanging MDIO config MDIO_MUX_I2CREG bool "MDIO MUX accessed as a register over I2C" @@ -1080,8 +1087,8 @@ config MDIO_MSCC_MIIM depends on DM_MDIO select REGMAP help - This driver supports MDIO interface found in Microsemi and Microchip - network switches. + This driver supports MDIO interface found in Microsemi and Microchip + network switches. config MDIO_MUX_MMIOREG bool "MDIO MUX accessed as a MMIO register access" diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 5e90183d090..761f7f0f451 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_AG7XXX) += ag7xxx.o -obj-y += airoha/ obj-$(CONFIG_AIROHA_ETH) += airoha_eth.o obj-$(CONFIG_ALTERA_TSE) += altera_tse.o obj-$(CONFIG_ASPEED_MDIO) += aspeed_mdio.o @@ -22,12 +21,13 @@ obj-$(CONFIG_DWC_ETH_QOS) += dwc_eth_qos.o obj-$(CONFIG_DWC_ETH_QOS_ADI) += dwc_eth_qos_adi.o obj-$(CONFIG_DWC_ETH_QOS_IMX) += dwc_eth_qos_imx.o obj-$(CONFIG_DWC_ETH_QOS_INTEL) += dwc_eth_qos_intel.o -obj-$(CONFIG_DWC_ETH_QOS_ROCKCHIP) += dwc_eth_qos_rockchip.o +obj-$(CONFIG_DWC_ETH_QOS_MTK) += dwc_eth_qos_mtk.o obj-$(CONFIG_DWC_ETH_QOS_QCOM) += dwc_eth_qos_qcom.o -obj-$(CONFIG_DWC_ETH_XGMAC) += dwc_eth_xgmac.o -obj-$(CONFIG_DWC_ETH_XGMAC_SOCFPGA) += dwc_eth_xgmac_socfpga.o +obj-$(CONFIG_DWC_ETH_QOS_ROCKCHIP) += dwc_eth_qos_rockchip.o obj-$(CONFIG_DWC_ETH_QOS_STARFIVE) += dwc_eth_qos_starfive.o obj-$(CONFIG_DWC_ETH_QOS_STM32) += dwc_eth_qos_stm32.o +obj-$(CONFIG_DWC_ETH_XGMAC) += dwc_eth_xgmac.o +obj-$(CONFIG_DWC_ETH_XGMAC_SOCFPGA) += dwc_eth_xgmac_socfpga.o obj-$(CONFIG_E1000) += e1000.o obj-$(CONFIG_E1000_SPI) += e1000_spi.o obj-$(CONFIG_EEPRO100) += eepro100.o @@ -62,9 +62,9 @@ obj-$(CONFIG_KSZ9477) += ksz9477.o obj-$(CONFIG_LITEETH) += liteeth.o obj-$(CONFIG_MACB) += macb.o obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o +obj-$(CONFIG_MDIO_GPIO_BITBANG) += mdio_gpio.o obj-$(CONFIG_MDIO_IPQ4019) += mdio-ipq4019.o obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.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 @@ -109,6 +109,7 @@ obj-$(CONFIG_XILINX_AXIEMAC) += xilinx_axi_emac.o obj-$(CONFIG_XILINX_AXIMRMAC) += xilinx_axi_mrmac.o obj-$(CONFIG_XILINX_EMACLITE) += xilinx_emaclite.o obj-$(CONFIG_ZYNQ_GEM) += zynq_gem.o +obj-y += airoha/ obj-y += mscc_eswitch/ obj-y += phy/ obj-y += qe/ diff --git a/drivers/net/airoha_eth.c b/drivers/net/airoha_eth.c index 84ee9b2ad76..e5d39b95cc5 100644 --- a/drivers/net/airoha_eth.c +++ b/drivers/net/airoha_eth.c @@ -845,11 +845,45 @@ static int airoha_alloc_gdm_port(struct udevice *dev, ofnode node) (ulong)eth, node, &gdm_dev); } +static struct udevice *airoha_switch_mdio_init(struct udevice *dev) +{ + struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev); + ofnode switch_node, mdio_node; + struct udevice *mdio_dev; + int ret; + + if (!CONFIG_IS_ENABLED(MDIO_MT7531_MMIO)) + return NULL; + + switch_node = ofnode_by_compatible(ofnode_null(), + data->switch_compatible); + if (!ofnode_valid(switch_node)) { + debug("Warning: missing airoha switch node\n"); + return ERR_PTR(-EINVAL); + } + + mdio_node = ofnode_find_subnode(switch_node, "mdio"); + if (!ofnode_valid(mdio_node)) { + debug("Warning: missing airoha switch mdio subnode\n"); + return ERR_PTR(-EINVAL); + } + + ret = device_bind_driver_to_node(dev, "mt7531-mdio-mmio", "mt7531-mdio", + mdio_node, &mdio_dev); + if (ret) { + debug("Warning: failed to bind airoha switch mdio\n"); + return ERR_PTR(ret); + } + + return mdio_dev; +} + 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; + struct udevice *mdio_dev; ofnode node; int i, ret; @@ -908,10 +942,10 @@ static int airoha_eth_probe(struct udevice *dev) if (ret) return ret; - if (eth->switch_mdio_dev) { - if (!device_probe(eth->switch_mdio_dev)) - debug("Warning: failed to probe airoha switch mdio\n"); - } + /* Airoha switch mdio PHYs maybe used by several GDM devices */ + mdio_dev = airoha_switch_mdio_init(dev); + if (!IS_ERR_OR_NULL(mdio_dev)) + eth->switch_mdio_dev = mdio_dev; ofnode_for_each_subnode(node, dev_ofnode(dev)) { if (!ofnode_device_is_compatible(node, "airoha,eth-mac")) @@ -957,6 +991,16 @@ static int airoha_eth_port_probe(struct udevice *dev) #else return -EINVAL; #endif + } else { + /* + * GDM1 device connected to airoha switch. Probe airoha switch + * mdio to be able set/query states of corresponding LAN ports. + */ + ret = device_probe(eth->switch_mdio_dev); + if (ret) { + debug("Warning: failed to probe airoha switch mdio\n"); + eth->switch_mdio_dev = NULL; + } } return 0; @@ -1202,38 +1246,12 @@ static int arht_eth_write_hwaddr(struct udevice *dev) static int airoha_eth_bind(struct udevice *dev) { - struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev); - struct airoha_eth *eth = dev_get_priv(dev); - ofnode switch_node, mdio_node; - int ret; - /* * Force Probe as we set the Main ETH driver as misc * to register multiple eth port for each GDM */ dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND); - if (!CONFIG_IS_ENABLED(MDIO_MT7531_MMIO)) - return 0; - - switch_node = ofnode_by_compatible(ofnode_null(), - data->switch_compatible); - if (!ofnode_valid(switch_node)) { - debug("Warning: missing switch node\n"); - return 0; - } - - mdio_node = ofnode_find_subnode(switch_node, "mdio"); - if (!ofnode_valid(mdio_node)) { - debug("Warning: missing mdio node\n"); - return 0; - } - - ret = device_bind_driver_to_node(dev, "mt7531-mdio-mmio", "mt7531-mdio", - mdio_node, ð->switch_mdio_dev); - if (ret) - debug("Warning: failed to bind mdio controller\n"); - return 0; } diff --git a/drivers/net/calxedaxgmac.c b/drivers/net/calxedaxgmac.c index 92990fa6d47..df0ed820e06 100644 --- a/drivers/net/calxedaxgmac.c +++ b/drivers/net/calxedaxgmac.c @@ -555,7 +555,7 @@ static int xgmac_ofdata_to_platdata(struct udevice *dev) return -ENOMEM; dev_set_priv(dev, priv); - pdata->iobase = devfdt_get_addr(dev); + pdata->iobase = dev_read_addr(dev); if (pdata->iobase == FDT_ADDR_T_NONE) { printf("%s: Cannot find XGMAC base address\n", __func__); return -EINVAL; diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c index 8fa549280aa..2a21eceac57 100644 --- a/drivers/net/dc2114x.c +++ b/drivers/net/dc2114x.c @@ -653,7 +653,7 @@ static int dc2114x_of_to_plat(struct udevice *dev) struct eth_pdata *plat = dev_get_plat(dev); struct dc2114x_priv *priv = dev_get_priv(dev); - plat->iobase = (phys_addr_t)map_physmem((phys_addr_t)devfdt_get_addr(dev), 0, MAP_NOCACHE); + plat->iobase = (phys_addr_t)dev_remap_addr(dev); priv->iobase = (void *)plat->iobase; return 0; diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 0f31d646845..b7e6299c307 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -1659,6 +1659,12 @@ static const struct udevice_id eqos_ids[] = { .data = (ulong)&eqos_adi_config }, #endif +#if IS_ENABLED(CONFIG_DWC_ETH_QOS_MTK) + { + .compatible = "mediatek,mt8189-gmac", + .data = (ulong)&eqos_mtk_config + }, +#endif { } }; diff --git a/drivers/net/dwc_eth_qos.h b/drivers/net/dwc_eth_qos.h index ba16f1a37cb..978b848b46e 100644 --- a/drivers/net/dwc_eth_qos.h +++ b/drivers/net/dwc_eth_qos.h @@ -97,6 +97,7 @@ struct eqos_mac_regs { #define EQOS_MAC_MDIO_ADDRESS_PA_MASK GENMASK(25, 21) #define EQOS_MAC_MDIO_ADDRESS_RDA_MASK GENMASK(20, 16) #define EQOS_MAC_MDIO_ADDRESS_CR_MASK GENMASK(11, 8) +#define EQOS_MAC_MDIO_ADDRESS_CR_60_100 0 #define EQOS_MAC_MDIO_ADDRESS_CR_100_150 1 #define EQOS_MAC_MDIO_ADDRESS_CR_20_35 2 #define EQOS_MAC_MDIO_ADDRESS_CR_150_250 4 @@ -316,3 +317,4 @@ extern struct eqos_config eqos_stm32mp15_config; extern struct eqos_config eqos_stm32mp25_config; extern struct eqos_config eqos_jh7110_config; extern struct eqos_config eqos_adi_config; +extern struct eqos_config eqos_mtk_config; diff --git a/drivers/net/dwc_eth_qos_mtk.c b/drivers/net/dwc_eth_qos_mtk.c new file mode 100644 index 00000000000..43e1085dfe5 --- /dev/null +++ b/drivers/net/dwc_eth_qos_mtk.c @@ -0,0 +1,442 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2026 BayLibre, SAS. + * Author: Julien Stephan <[email protected]> + */ + +#include <dm.h> +#include <dm/device_compat.h> +#include <linux/bitfield.h> +#include <net.h> +#include <phy.h> +#include <regmap.h> +#include <syscon.h> + +#include "dwc_eth_qos.h" + +/* + * Peri Configuration register is SoC specific, + * so add a SoC specific prefix. + */ +#define MT8189_PERI_ETH_CTRL0 0x270 +#define MT8189_PERI_ETH_CTRL1 0x274 +#define MT8189_PERI_ETH_CTRL2 0x278 + +#define EQOS_MTK_RMII_CLK_SRC_INTERNAL BIT(28) +#define EQOS_MTK_RMII_CLK_SRC_RXC BIT(27) +#define EQOS_MTK_ETH_INTF_SEL GENMASK(26, 24) +#define EQOS_MTK_PHY_INTF_MII 0 +#define EQOS_MTK_PHY_INTF_RGMII 1 +#define EQOS_MTK_PHY_INTF_RMII 4 +#define EQOS_MTK_RGMII_TXC_PHASE_CTRL BIT(22) +#define EQOS_MTK_EXT_PHY_MODE BIT(21) +#define EQOS_MTK_TXC_OUT_OP BIT(20) +#define EQOS_MTK_DLY_GTXC_INV BIT(12) +#define EQOS_MTK_DLY_GTXC_STAGE_FINE GENMASK(11, 6) +#define EQOS_MTK_DLY_GTXC_ENABLE BIT(5) +#define EQOS_MTK_DLY_GTXC_STAGES GENMASK(4, 0) + +#define EQOS_MTK_DLY_RXC_INV BIT(25) +#define EQOS_MTK_DLY_RXC_ENABLE BIT(18) +#define EQOS_MTK_DLY_RXC_STAGES GENMASK(17, 13) +#define EQOS_MTK_DLY_TXC_INV BIT(12) +#define EQOS_MTK_DLY_TXC_ENABLE BIT(5) +#define EQOS_MTK_DLY_TXC_STAGES GENMASK(4, 0) + +#define EQOS_MTK_DLY_RMII_RXC_INV BIT(25) +#define EQOS_MTK_DLY_RMII_RXC_ENABLE BIT(18) +#define EQOS_MTK_DLY_RMII_RXC_STAGES GENMASK(17, 13) +#define EQOS_MTK_DLY_RMII_TXC_INV BIT(12) +#define EQOS_MTK_DLY_RMII_TXC_ENABLE BIT(5) +#define EQOS_MTK_DLY_RMII_TXC_STAGES GENMASK(4, 0) + +#define DELAY_MAX_PS 9800 +#define DELAY_PS_PER_STAGE 290 + +struct eqos_mtk_priv { + struct regmap *peri_regmap; + bool rmii_clk_from_mac; + bool rmii_rxc; + u32 tx_delay_stage; + u32 rx_delay_stage; + bool tx_inv; + bool rx_inv; +}; + +static int mtk_clk_init(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + + ret = clk_get_by_name(dev, "mac_main", &eqos->clk_tx); + if (ret) { + dev_err(dev, "clk_get_by_name(mac_main) failed: %d", ret); + return ret; + } + + ret = clk_get_by_name(dev, "ptp_ref", &eqos->clk_ptp_ref); + if (ret) { + dev_err(dev, "clk_get_by_name(ptp_ref) failed: %d", ret); + return ret; + } + + return 0; +} + +static int mtk_set_delay(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct eqos_mtk_priv *mtk_pdata = pdata->priv_pdata; + u32 gtxc_delay_val = 0, delay_val = 0, rmii_delay_val = 0; + + switch (pdata->phy_interface) { + case PHY_INTERFACE_MODE_MII: + delay_val |= FIELD_PREP(EQOS_MTK_DLY_TXC_ENABLE, + !!mtk_pdata->tx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_TXC_STAGES, mtk_pdata->tx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_TXC_INV, mtk_pdata->tx_inv); + + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_ENABLE, + !!mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_STAGES, mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_INV, mtk_pdata->rx_inv); + break; + case PHY_INTERFACE_MODE_RMII: + if (mtk_pdata->rmii_clk_from_mac) { + /* case 1: mac provides the rmii reference clock, + * and the clock output to TXC pin. + * The egress timing can be adjusted by RMII_TXC delay macro circuit. + * The ingress timing can be adjusted by RMII_RXC delay macro circuit. + */ + rmii_delay_val |= FIELD_PREP(EQOS_MTK_DLY_RMII_TXC_ENABLE, + !!mtk_pdata->tx_delay_stage); + rmii_delay_val |= FIELD_PREP(EQOS_MTK_DLY_RMII_TXC_STAGES, + mtk_pdata->tx_delay_stage); + rmii_delay_val |= FIELD_PREP(EQOS_MTK_DLY_RMII_TXC_INV, + mtk_pdata->tx_inv); + + rmii_delay_val |= FIELD_PREP(EQOS_MTK_DLY_RMII_RXC_ENABLE, + !!mtk_pdata->rx_delay_stage); + rmii_delay_val |= FIELD_PREP(EQOS_MTK_DLY_RMII_RXC_STAGES, + mtk_pdata->rx_delay_stage); + rmii_delay_val |= FIELD_PREP(EQOS_MTK_DLY_RMII_RXC_INV, + mtk_pdata->rx_inv); + } else { + /* case 2: the rmii reference clock is from external phy, + * and the property "rmii_rxc" indicates which pin(TXC/RXC) + * the reference clk is connected to. The reference clock is a + * received signal, so rx_delay_stage/rx_inv are used to indicate + * the reference clock timing adjustment + */ + if (mtk_pdata->rmii_rxc) { + /* the rmii reference clock from outside is connected + * to RXC pin, the reference clock will be adjusted + * by RXC delay macro circuit. + */ + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_ENABLE, + !!mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_STAGES, + mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_INV, + mtk_pdata->rx_inv); + } else { + /* the rmii reference clock from outside is connected + * to TXC pin, the reference clock will be adjusted + * by TXC delay macro circuit. + */ + delay_val |= FIELD_PREP(EQOS_MTK_DLY_TXC_ENABLE, + !!mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_TXC_STAGES, + mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_TXC_INV, + mtk_pdata->rx_inv); + } + } + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_ID: + gtxc_delay_val |= FIELD_PREP(EQOS_MTK_DLY_GTXC_ENABLE, + !!mtk_pdata->tx_delay_stage); + gtxc_delay_val |= FIELD_PREP(EQOS_MTK_DLY_GTXC_STAGES, + mtk_pdata->tx_delay_stage); + gtxc_delay_val |= FIELD_PREP(EQOS_MTK_DLY_GTXC_INV, mtk_pdata->tx_inv); + gtxc_delay_val |= EQOS_MTK_DLY_GTXC_STAGE_FINE; + + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_ENABLE, + !!mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_STAGES, mtk_pdata->rx_delay_stage); + delay_val |= FIELD_PREP(EQOS_MTK_DLY_RXC_INV, mtk_pdata->rx_inv); + + break; + default: + dev_err(dev, "phy interface not supported\n"); + return -EINVAL; + } + + regmap_update_bits(mtk_pdata->peri_regmap, + MT8189_PERI_ETH_CTRL0, + EQOS_MTK_RGMII_TXC_PHASE_CTRL | + EQOS_MTK_DLY_GTXC_ENABLE | + EQOS_MTK_DLY_GTXC_INV | + EQOS_MTK_DLY_GTXC_STAGE_FINE | + EQOS_MTK_DLY_GTXC_STAGES, + gtxc_delay_val); + regmap_write(mtk_pdata->peri_regmap, MT8189_PERI_ETH_CTRL1, delay_val); + regmap_write(mtk_pdata->peri_regmap, MT8189_PERI_ETH_CTRL2, rmii_delay_val); + + return 0; +} + +static int mtk_set_interface(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct eqos_mtk_priv *mtk_pdata = pdata->priv_pdata; + int rmii_clk_from_mac = mtk_pdata->rmii_clk_from_mac ? EQOS_MTK_RMII_CLK_SRC_INTERNAL : 0; + int rmii_rxc = mtk_pdata->rmii_rxc ? EQOS_MTK_RMII_CLK_SRC_RXC : 0; + u32 intf_val = 0; + + /* select phy interface in top control domain */ + switch (pdata->phy_interface) { + case PHY_INTERFACE_MODE_MII: + intf_val |= FIELD_PREP(EQOS_MTK_ETH_INTF_SEL, EQOS_MTK_PHY_INTF_MII); + break; + case PHY_INTERFACE_MODE_RMII: + intf_val |= (rmii_rxc | rmii_clk_from_mac); + intf_val |= FIELD_PREP(EQOS_MTK_ETH_INTF_SEL, EQOS_MTK_PHY_INTF_RMII); + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_ID: + intf_val |= FIELD_PREP(EQOS_MTK_ETH_INTF_SEL, EQOS_MTK_PHY_INTF_RGMII); + break; + default: + dev_err(dev, "phy interface not supported\n"); + return -EINVAL; + } + + /* only support external PHY */ + intf_val |= EQOS_MTK_EXT_PHY_MODE; + + intf_val |= EQOS_MTK_TXC_OUT_OP; + + regmap_write(mtk_pdata->peri_regmap, MT8189_PERI_ETH_CTRL0, intf_val); + + return 0; +} + +static int mtk_config_dt(struct udevice *dev) +{ struct eth_pdata *pdata = dev_get_plat(dev); + struct eqos_mtk_priv *mtk_pdata = pdata->priv_pdata; + struct ofnode_phandle_args args; + u32 tx_delay_ps = 0, rx_delay_ps = 0; + int ret; + + if (!dev_read_u32(dev, "mediatek,tx-delay-ps", &tx_delay_ps)) { + if (tx_delay_ps > DELAY_MAX_PS) { + dev_err(dev, "Invalid TX clock delay: %dps\n", tx_delay_ps); + return -EINVAL; + } + } + + if (!dev_read_u32(dev, "mediatek,rx-delay-ps", &rx_delay_ps)) { + if (rx_delay_ps > DELAY_MAX_PS) { + dev_err(dev, "Invalid RX clock delay: %dps\n", rx_delay_ps); + return -EINVAL; + } + } + + mtk_pdata->tx_delay_stage = tx_delay_ps / DELAY_PS_PER_STAGE; + mtk_pdata->rx_delay_stage = rx_delay_ps / DELAY_PS_PER_STAGE; + + mtk_pdata->tx_inv = dev_read_bool(dev, "mediatek,txc-inverse"); + mtk_pdata->rx_inv = dev_read_bool(dev, "mediatek,rxc-inverse"); + mtk_pdata->rmii_clk_from_mac = dev_read_bool(dev, "mediatek,rmii-clk-from-mac"); + mtk_pdata->rmii_rxc = dev_read_bool(dev, "mediatek,rmii-rxc"); + + ret = dev_read_phandle_with_args(dev, "mediatek,pericfg", NULL, 0, 0, &args); + if (ret) { + dev_err(dev, "Failed to get mediatek,pericfg property: %d\n", ret); + return ret; + } + + mtk_pdata->peri_regmap = syscon_node_to_regmap(args.node); + if (IS_ERR(mtk_pdata->peri_regmap)) { + dev_err(dev, "fail to get regmap: %d\n", (int)PTR_ERR(mtk_pdata->peri_regmap)); + return PTR_ERR(mtk_pdata->peri_regmap); + } + + return 0; +} + +static int eqos_probe_resources_mtk(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_plat(dev); + struct eqos_mtk_priv *mtk_pdata; + int ret; + + debug("%s(dev=%p):\n", __func__, dev); + + ret = eqos_get_base_addr_dt(dev); + if (ret) { + dev_err(dev, "eqos_get_base_addr_dt failed: %d\n", ret); + return ret; + } + + mtk_pdata = calloc(1, sizeof(struct eqos_mtk_priv)); + if (!mtk_pdata) + return -ENOMEM; + + pdata->priv_pdata = mtk_pdata; + + ret = mtk_config_dt(dev); + if (ret) { + dev_err(dev, "mtk config dt failed: %d\n", ret); + goto err; + } + + ret = mtk_clk_init(dev); + if (ret) + goto err; + + pdata->phy_interface = eqos->config->interface(dev); + if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) { + dev_err(dev, "Invalid PHY interface\n"); + ret = -EINVAL; + goto err; + } + + ret = mtk_set_interface(dev); + if (ret) + goto err; + + ret = mtk_set_delay(dev); + if (ret) + goto err; + + debug("%s: OK\n", __func__); + return 0; +err: + free(mtk_pdata); + return ret; +} + +static int eqos_remove_resources_mtk(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct eqos_mtk_priv *mtk_pdata = pdata->priv_pdata; + + debug("%s(dev=%p):\n", __func__, dev); + + free(mtk_pdata); + + debug("%s: OK\n", __func__); + return 0; +} + +static int eqos_stop_clks_mtk(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + + debug("%s(dev=%p):\n", __func__, dev); + + clk_disable(&eqos->clk_ptp_ref); + clk_disable(&eqos->clk_tx); + + debug("%s: OK\n", __func__); + return 0; +} + +static int eqos_start_clks_mtk(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + int ret; + + debug("%s(dev=%p):\n", __func__, dev); + + ret = clk_enable(&eqos->clk_tx); + if (ret < 0) { + dev_err(dev, "clk_enable(mac_main) failed: %d", ret); + goto err; + } + + ret = clk_enable(&eqos->clk_ptp_ref); + if (ret < 0) { + dev_err(dev, "clk_enable(ptp_ref) failed: %d", ret); + goto err_disable_clk_mac_main; + } + + debug("%s: OK\n", __func__); + return 0; + +err_disable_clk_mac_main: + clk_disable(&eqos->clk_tx); +err: + debug("%s: FAILED: %d\n", __func__, ret); + return ret; +} + +static int eqos_fix_mac_speed_mtk(struct udevice *dev) +{ + struct eqos_priv *eqos = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_plat(dev); + struct eqos_mtk_priv *mtk_pdata = pdata->priv_pdata; + + debug("%s(dev=%p):\n", __func__, dev); + + switch (pdata->phy_interface) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_ID: + if (eqos->phy->speed == SPEED_1000) + regmap_update_bits(mtk_pdata->peri_regmap, + MT8189_PERI_ETH_CTRL0, + EQOS_MTK_RGMII_TXC_PHASE_CTRL | + EQOS_MTK_DLY_GTXC_ENABLE | + EQOS_MTK_DLY_GTXC_INV | + EQOS_MTK_DLY_GTXC_STAGE_FINE | + EQOS_MTK_DLY_GTXC_STAGES, + EQOS_MTK_RGMII_TXC_PHASE_CTRL); + else + mtk_set_delay(dev); + break; + default: + debug("%s: dev=%p no need to adjust mac delay\n", __func__, dev); + break; + } + + debug("%s: OK\n", __func__); + return 0; +} + +static struct eqos_ops eqos_mtk_ops = { + .eqos_inval_desc = eqos_inval_desc_generic, + .eqos_flush_desc = eqos_flush_desc_generic, + .eqos_inval_buffer = eqos_inval_buffer_generic, + .eqos_flush_buffer = eqos_flush_buffer_generic, + .eqos_probe_resources = eqos_probe_resources_mtk, + .eqos_remove_resources = eqos_remove_resources_mtk, + .eqos_stop_resets = eqos_null_ops, + .eqos_start_resets = eqos_null_ops, + .eqos_stop_clks = eqos_stop_clks_mtk, + .eqos_start_clks = eqos_start_clks_mtk, + .eqos_calibrate_pads = eqos_null_ops, + .eqos_disable_calibration = eqos_null_ops, + .eqos_set_tx_clk_speed = eqos_fix_mac_speed_mtk, + .eqos_get_enetaddr = eqos_null_ops, +}; + +struct eqos_config eqos_mtk_config = { + .reg_access_always_ok = false, + .mdio_wait = 10000, + .swr_wait = 10, + .config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB, + .config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_60_100, + .axi_bus_width = EQOS_AXI_WIDTH_64, + .interface = dev_read_phy_mode, + .ops = &eqos_mtk_ops +}; diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index dc7e6f1929f..87b2b3426c8 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -686,7 +686,7 @@ static int ethoc_of_to_plat(struct udevice *dev) fdt_addr_t addr; pdata->eth_pdata.iobase = dev_read_addr(dev); - addr = devfdt_get_addr_index(dev, 1); + addr = dev_read_addr_index(dev, 1); if (addr != FDT_ADDR_T_NONE) pdata->packet_base = addr; return 0; diff --git a/drivers/net/fsl_enetc.c b/drivers/net/fsl_enetc.c index a4ba27904bc..f393af40e27 100644 --- a/drivers/net/fsl_enetc.c +++ b/drivers/net/fsl_enetc.c @@ -8,6 +8,7 @@ #include <clk.h> #include <cpu_func.h> #include <dm.h> +#include <dm/device_compat.h> #include <errno.h> #include <fdt_support.h> #include <malloc.h> @@ -17,17 +18,25 @@ #include <asm/io.h> #include <pci.h> #include <miiphy.h> +#include <linux/bitfield.h> #include <linux/bug.h> #include <linux/delay.h> #include <linux/build_bug.h> +#include <linux/bitfield.h> +#include <power/regulator.h> +#include "fsl_enetc.h" #ifdef CONFIG_ARCH_IMX9 #include <asm/mach-imx/sys_proto.h> #include <cpu_func.h> +#include "fsl_enetc_xpcs_phy.c" +#else +static inline int xpcs_phy_usxgmii_pma_config(struct udevice *dev) +{ + return 0; +} #endif -#include "fsl_enetc.h" - #define ENETC_DRIVER_NAME "enetc_eth" /* @@ -66,10 +75,36 @@ static int enetc_is_ls1028a(struct udevice *dev) pplat->vendor == PCI_VENDOR_ID_FREESCALE; } +static int enetc_dev_id_imx(struct udevice *dev) +{ + if (IS_ENABLED(CONFIG_IMX952)) { + int bus_devfn; + u32 reg[5]; + int error; + + error = dev_read_u32_array(dev, "reg", reg, ARRAY_SIZE(reg)); + if (error) + return error; + + bus_devfn = (reg[0] >> 8) & 0xffff; + + switch (bus_devfn) { + case 0: + return 0; + case 0x100: + return 1; + default: + return -EINVAL; + } + } + + return PCI_DEV(pci_get_devfn(dev)) >> 3; +} + static int enetc_dev_id(struct udevice *dev) { if (enetc_is_imx95(dev)) - return PCI_DEV(pci_get_devfn(dev)) >> 3; + return enetc_dev_id_imx(dev); if (enetc_is_ls1028a(dev)) return PCI_FUNC(pci_get_devfn(dev)); @@ -388,7 +423,7 @@ static int enetc_init_sgmii(struct udevice *dev) /* set up MAC for RGMII */ static void enetc_init_rgmii(struct udevice *dev, struct phy_device *phydev) { - u32 old_val, val, dpx = 0; + u32 old_val, val = 0; old_val = val = enetc_read_mac_port(dev, ENETC_PM_IF_MODE); @@ -408,15 +443,14 @@ static void enetc_init_rgmii(struct udevice *dev, struct phy_device *phydev) val |= ENETC_PM_IFM_SSP_10; } - if (enetc_is_imx95(dev)) - dpx = ENETC_PM_IFM_FULL_DPX_IMX; + if (enetc_is_imx95(dev)) + val = u32_replace_bits(val, + phydev->duplex == DUPLEX_FULL ? 0 : 1, + ENETC_PM_IFM_FULL_DPX_IMX); else if (enetc_is_ls1028a(dev)) - dpx = ENETC_PM_IFM_FULL_DPX_LS; - - if (phydev->duplex == DUPLEX_FULL) - val |= dpx; - else - val &= ~dpx; + val = u32_replace_bits(val, + phydev->duplex == DUPLEX_FULL ? 1 : 0, + ENETC_PM_IFM_FULL_DPX_LS); if (val == old_val) return; @@ -454,19 +488,23 @@ static void enetc_setup_mac_iface(struct udevice *dev, /* set up serdes for SXGMII */ static int enetc_init_sxgmii(struct udevice *dev) { - struct enetc_priv *priv = dev_get_priv(dev); - if (!enetc_has_imdio(dev)) return 0; - /* Dev ability - SXGMII */ - enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL, - ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SXGMII); + if (enetc_is_imx95(dev)) { + xpcs_phy_usxgmii_pma_config(dev); + } else { + struct enetc_priv *priv = dev_get_priv(dev); - /* Restart PCS AN */ - enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL, - ENETC_PCS_CR, - ENETC_PCS_CR_RST | ENETC_PCS_CR_RESET_AN); + /* Dev ability - SXGMII */ + enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL, + ENETC_PCS_DEV_ABILITY, ENETC_PCS_DEV_ABILITY_SXGMII); + + /* Restart PCS AN */ + enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, ENETC_PCS_DEVAD_REPL, + ENETC_PCS_CR, + ENETC_PCS_CR_RST | ENETC_PCS_CR_RESET_AN); + } return 0; } @@ -523,6 +561,10 @@ static int enetc_config_phy(struct udevice *dev) return -ENODEV; supported = PHY_GBIT_FEATURES | SUPPORTED_2500baseX_Full; + + if (enetc_is_imx95(dev)) + supported |= PHY_10G_FEATURES; + priv->phy->supported &= supported; priv->phy->advertising &= supported; @@ -537,12 +579,31 @@ static int enetc_probe(struct udevice *dev) { struct enetc_priv *priv = dev_get_priv(dev); int res; + struct udevice *supply = NULL; if (ofnode_valid(dev_ofnode(dev)) && !ofnode_is_enabled(dev_ofnode(dev))) { enetc_dbg(dev, "interface disabled\n"); return -ENODEV; } + if (CONFIG_IS_ENABLED(DM_REGULATOR)) { + res = device_get_supply_regulator(dev, "serdes-supply", + &supply); + if (res && res != -ENOENT) { + printf("%s: device_get_supply_regulator failed: %d\n", + __func__, res); + return res; + } + + if (supply) { + res = regulator_set_enable_if_allowed(supply, true); + if (res) { + printf("%s: Error enabling phy supply\n", dev->name); + return res; + } + } + } + priv->enetc_txbd = memalign(ENETC_BD_ALIGN, sizeof(struct enetc_tx_bd) * ENETC_BD_CNT); priv->enetc_rxbd = memalign(ENETC_BD_ALIGN, diff --git a/drivers/net/fsl_enetc.h b/drivers/net/fsl_enetc.h index 804df853bf5..6d868e82f8c 100644 --- a/drivers/net/fsl_enetc.h +++ b/drivers/net/fsl_enetc.h @@ -205,6 +205,7 @@ struct enetc_data { /* PCS / internal SoC PHY ID, it defaults to 0 on all interfaces */ #define ENETC_PCS_PHY_ADDR 0 +#define ENETC_NON_PCS_PHY_ADDR 16 /* PCS registers */ #define ENETC_PCS_CR 0x00 diff --git a/drivers/net/fsl_enetc_netc_blk_ctrl.c b/drivers/net/fsl_enetc_netc_blk_ctrl.c index 8577bb75632..0c87d80ea5c 100644 --- a/drivers/net/fsl_enetc_netc_blk_ctrl.c +++ b/drivers/net/fsl_enetc_netc_blk_ctrl.c @@ -35,6 +35,7 @@ #define MII_PROT_RGMII 0x2 #define MII_PROT_SERIAL 0x3 #define MII_PROT(port, prot) (((prot) & 0xf) << ((port) << 2)) +#define MII_PROT_GET(reg, port) (((reg) >> ((port) << 2)) & 0xf) #define IMX95_CFG_LINK_PCS_PROT(a) (0x8 + (a) * 4) #define PCS_PROT_1G_SGMII BIT(0) @@ -97,6 +98,9 @@ #define IMX94_TIMER1_ID 1 #define IMX94_TIMER2_ID 2 +#define IMX952_ENETC0_BUS_DEVFN 0x0 +#define IMX952_ENETC1_BUS_DEVFN 0x100 + /* Flags for different platforms */ #define NETC_HAS_NETCMIX BIT(0) @@ -567,6 +571,69 @@ static int netc_prb_check_error(struct netc_blk_ctrl *priv) return 0; } +static int imx952_netcmix_init(struct udevice *dev) +{ + struct netc_blk_ctrl *priv = dev_get_priv(dev); + ofnode child, gchild; + phy_interface_t interface; + int bus_devfn, mii_proto; + u32 val; + + /* Default setting */ + val = MII_PROT(0, MII_PROT_RGMII) | MII_PROT(1, MII_PROT_RGMII); + + /* Update the link MII protocol through parsing phy-mode */ + 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")) + continue; + + bus_devfn = netc_of_pci_get_bus_devfn(gchild); + if (bus_devfn < 0) + return -EINVAL; + + interface = ofnode_read_phy_mode(gchild); + if (interface == -1) + continue; + + mii_proto = netc_get_link_mii_protocol(interface); + if (mii_proto < 0) + return -EINVAL; + + switch (bus_devfn) { + case IMX952_ENETC0_BUS_DEVFN: + val &= ~CFG_LINK_MII_PORT_0; + val |= FIELD_PREP(CFG_LINK_MII_PORT_0, mii_proto); + break; + case IMX952_ENETC1_BUS_DEVFN: + val &= ~CFG_LINK_MII_PORT_1; + val |= FIELD_PREP(CFG_LINK_MII_PORT_1, mii_proto); + break; + default: + return -EINVAL; + } + } + } + + if (MII_PROT_GET(val, 1) == MII_PROT_SERIAL) { + /* Configure Link I/O variant */ + netc_reg_write(priv->netcmix, IMX95_CFG_LINK_IO_VAR, + IO_VAR(1, IO_VAR_16FF_16G_SERDES)); + /* Configure Link 2 PCS protocol */ + netc_reg_write(priv->netcmix, IMX95_CFG_LINK_PCS_PROT(1), + PCS_PROT_2500M_SGMII); + } + netc_reg_write(priv->netcmix, IMX95_CFG_LINK_MII_PROT, val); + + return 0; +} + static const struct netc_devinfo imx95_devinfo = { .netcmix_init = imx95_netcmix_init, .ierb_init = imx95_ierb_init, @@ -578,9 +645,14 @@ static const struct netc_devinfo imx94_devinfo = { .xpcs_port_init = imx94_netc_xpcs_port_init, }; +static const struct netc_devinfo imx952_devinfo = { + .netcmix_init = imx952_netcmix_init, +}; + static const struct udevice_id netc_blk_ctrl_match[] = { { .compatible = "nxp,imx95-netc-blk-ctrl", .data = (ulong)&imx95_devinfo }, { .compatible = "nxp,imx94-netc-blk-ctrl", .data = (ulong)&imx94_devinfo }, + { .compatible = "nxp,imx952-netc-blk-ctrl", .data = (ulong)&imx952_devinfo }, {}, }; diff --git a/drivers/net/fsl_enetc_xpcs_phy.c b/drivers/net/fsl_enetc_xpcs_phy.c new file mode 100644 index 00000000000..4039690223d --- /dev/null +++ b/drivers/net/fsl_enetc_xpcs_phy.c @@ -0,0 +1,970 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2024 NXP + */ + +#define XPCS_PHY_GLOBAL 0x0 +#define XPCS_PHY_MPLLA 0x1 +#define XPCS_PHY_MPLLB 0x2 +#define XPCS_PHY_LANE 0x3 +#define XPCS_PHY_MAC_ADAPTER 0x1f + +#define XPCS_PHY_REG(x) (((x) & 0x1fffe) >> 1) + +/* MAC ADAPTER */ +#define MAC_ADAPTER_LOCK_PHY 0x200 +#define MAC_ADAPTER_LOCK_MPLLA 0x204 +#define MAC_ADAPTER_LOCK_MPLLB 0x208 +#define MAC_ADAPTER_LOCK_ROM 0x20c +#define MAC_ADAPTER_LOCK_RAM 0x210 +#define MAC_ADAPTER_LOCK_EVENT 0x214 + +#define MAC_ADAPTER_LOCK_LOCK BIT(7) + +/* PMA */ +#define PMA_RX_LSTS 0x10040 +#define PMA_RX_LSTS_RX_VALID_0 BIT(12) +#define PMA_MP_12G_16G_25G_TX_GENCTRL0 0x10060 +#define PMA_TX_GENCTRL0_TX_RST_0 BIT(8) +#define PMA_TX_GENCTRL0_TX_DT_EN_0 BIT(12) +#define PMA_MP_12G_16G_25G_TX_GENCTRL1 0x10062 +#define PMA_TX_GENCTRL1_VBOOST_EN_0 BIT(4) +#define PMA_TX_GENCTRL1_VBOOST_LVL_MASK GENMASK(10, 8) +#define PMA_TX_GENCTRL1_VBOOST_LVL(x) (((x) << 8) & GENMASK(10, 8)) +#define PMA_TX_GENCTRL1_TX_CLK_RDY_0 BIT(12) +#define PMA_MP_12G_16G_TX_GENCTRL2 0x10064 +#define PMA_TX_GENCTRL2_TX_REQ_0 BIT(0) +#define PMA_TX_GENCTRL2_TX0_WIDTH_MASK GENMASK(9, 8) +#define PMA_TX_GENCTRL2_TX0_WIDTH(x) (((x) << 8) & GENMASK(9, 8)) +#define PMA_MP_12G_16G_25G_TX_BOOST_CTRL 0x10066 +#define PMA_TX_BOOST_CTRL_TX0_IBOOST_MASK GENMASK(3, 0) +#define PMA_TX_BOOST_CTRL_TX0_IBOOST(x) ((x) & GENMASK(3, 0)) +#define PMA_MP_12G_16G_25G_TX_RATE_CTRL 0x10068 +#define PMA_TX_RATE_CTRL_TX0_RATE_MASK GENMASK(2, 0) +#define PMA_TX_RATE_CTRL_TX0_RATE(x) ((x) & GENMASK(2, 0)) +#define PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL 0x1006A +#define PMA_POWER_STATE_CTRL_TX0_PSTATE_MASK GENMASK(1, 0) +#define PMA_POWER_STATE_CTRL_TX0_PSTATE(x) ((x) & GENMASK(1, 0)) +#define PMA_POWER_STATE_CTRL_TX_DISABLE_0 BIT(8) +#define PMA_MP_12G_16G_25G_TX_EQ_CTRL0 0x1006C +#define PMA_TX_EQ_CTRL0_TX_EQ_PRE_MASK GENMASK(5, 0) +#define PMA_TX_EQ_CTRL0_TX_EQ_PRE(x) ((x) & GENMASK(5, 0)) +#define PMA_TX_EQ_CTRL0_TX_EQ_MAIN_MASK GENMASK(13, 8) +#define PMA_TX_EQ_CTRL0_TX_EQ_MAIN(x) (((x) << 8) & GENMASK(13, 8)) +#define PMA_MP_12G_16G_25G_TX_EQ_CTRL1 0x1006E +#define PMA_TX_EQ_CTRL1_TX_EQ_POST_MASK GENMASK(5, 0) +#define PMA_TX_EQ_CTRL1_TX_EQ_POST(x) ((x) & GENMASK(5, 0)) +#define PMA_MP_16G_25G_TX_MISC_CTRL0 0x1007C +#define PMA_TX_MISC_CTRL0_TX0_MISC_MASK GENMASK(7, 0) +#define PMA_TX_MISC_CTRL0_TX0_MISC(x) ((x) & GENMASK(7, 0)) +#define PMA_MP_12G_16G_25G_RX_GENCTRL0 0x100A0 +#define PMA_RX_GENCTRL0_RX_DT_EN_0 BIT(8) +#define PMA_MP_12G_16G_25G_RX_GENCTRL1 0x100A2 +#define PMA_RX_GENCTRL1_RX_RST_0 BIT(4) +#define PMA_RX_GENCTRL1_RX_TERM_ACDC_0 BIT(8) +#define PMA_RX_GENCTRL1_RX_DIV16P5_CLK_EN_0 BIT(12) +#define PMA_MP_12G_16G_RX_GENCTRL2 0x100A4 +#define PMA_RX_GENCTRL2_RX_REQ_0 BIT(0) +#define PMA_RX_GENCTRL2_RX0_WIDTH_MASK GENMASK(9, 8) +#define PMA_RX_GENCTRL2_RX0_WIDTH(x) (((x) << 8) & GENMASK(9, 8)) +#define PMA_MP_12G_16G_RX_GENCTRL3 0x100A6 +#define PMA_RX_GENCTRL3_LOS_TRSHLD_0_MASK GENMASK(2, 0) +#define PMA_RX_GENCTRL3_LOS_TRSHLD_0(x) ((x) & GENMASK(2, 0)) +#define PMA_RX_GENCTRL3_LOS_LFPS_EN_0 BIT(12) +#define PMA_MP_12G_16G_25G_RX_RATE_CTRL 0x100A8 +#define PMA_RX_RATE_CTRL_RX0_RATE_MASK GENMASK(1, 0) +#define PMA_RX_RATE_CTRL_RX0_RATE(x) ((x) & GENMASK(1, 0)) +#define PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL 0x100AA +#define PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK GENMASK(1, 0) +#define PMA_RX_POWER_STATE_CTRL_RX0_PSTATE(x) ((x) & GENMASK(1, 0)) +#define PMA_RX_POWER_STATE_CTRL_RX_DISABLE_0 BIT(8) +#define PMA_MP_12G_16G_25G_RX_CDR_CTRL 0x100AC +#define PMA_RX_CDR_CTRL_CDR_SSC_EN_0 BIT(4) +#define PMA_MP_12G_16G_25G_RX_ATTN_CTRL 0x100AE +#define PMA_RX_ATTN_CTRL_RX0_EQ_ATT_LVL_MASK GENMASK(2, 0) +#define PMA_RX_ATTN_CTRL_RX0_EQ_ATT_LVL(x) ((x) & GENMASK(2, 0)) +#define PMA_MP_16G_25G_RX_EQ_CTRL0 0x100B0 +#define PMA_RX_EQ_CTRL0_CTLE_BOOST_0_MASK GENMASK(4, 0) +#define PMA_RX_EQ_CTRL0_CTLE_BOOST_0(x) ((x) & GENMASK(4, 0)) +#define PMA_RX_EQ_CTRL0_CTLE_POLE_0_MASK GENMASK(6, 5) +#define PMA_RX_EQ_CTRL0_CTLE_POLE_0(x) (((x) << 5) & GENMASK(6, 5)) +#define PMA_RX_EQ_CTRL0_VGA2_GAIN_0_MASK GENMASK(10, 8) +#define PMA_RX_EQ_CTRL0_VGA2_GAIN_0(x) (((x) << 8) & GENMASK(10, 8)) +#define PMA_RX_EQ_CTRL0_VGA1_GAIN_0_MASK GENMASK(14, 12) +#define PMA_RX_EQ_CTRL0_VGA1_GAIN_0(x) (((x) << 12) & GENMASK(14, 12)) +#define PMA_MP_12G_16G_25G_RX_EQ_CTRL4 0x100B8 +#define PMA_RX_EQ_CTRL4_CONT_ADAPT_0 BIT(0) +#define PMA_RX_EQ_CTRL4_RX_AD_REQ BIT(12) +#define PMA_MP_16G_25G_RX_EQ_CTRL5 0x100BA +#define PMA_RX_EQ_CTRL5_RX_ADPT_SEL_0 BIT(0) +#define PMA_RX_EQ_CTRL5_RX0_ADPT_MODE_MASK GENMASK(5, 4) +#define PMA_RX_EQ_CTRL5_RX0_ADPT_MODE(x) (((x) << 4) & GENMASK(5, 4)) +#define PMA_MP_12G_16G_25G_DFE_TAP_CTRL0 0x100BC +#define PMA_DFE_TAP_CTRL0_DFE_TAP1_0_MASK GENMASK(7, 0) +#define PMA_DFE_TAP_CTRL0_DFE_TAP1_0(x) ((x) & GENMASK(7, 0)) +#define PMA_MP_16G_RX_CDR_CTRL1 0x100C8 +#define PMA_RX_CDR_CTRL1_VCO_TEMP_COMP_EN_0 BIT(0) +#define PMA_RX_CDR_CTRL1_VCO_STEP_CTRL_0 BIT(4) +#define PMA_RX_CDR_CTRL1_VCO_FRQBAND_0_MASK GENMASK(9, 8) +#define PMA_RX_CDR_CTRL1_VCO_FRQBAND_0(x) (((x) << 8) & GENMASK(9, 8)) +#define PMA_MP_16G_25G_RX_PPM_CTRL0 0x100CA +#define PMA_RX_PPM_CTRL0_RX0_CDR_PPM_MAX_MASK GENMASK(4, 0) +#define PMA_RX_PPM_CTRL0_RX0_CDR_PPM_MAX(x) ((x) & GENMASK(4, 0)) +#define PMA_MP_16G_25G_RX_GENCTRL4 0x100D0 +#define PMA_RX_GENCTRL4_RX_DFE_BYP_0 BIT(8) +#define PMA_MP_16G_25G_RX_MISC_CTRL0 0x100D2 +#define PMA_RX_MISC_CTRL0_RX0_MISC_MASK GENMASK(7, 0) +#define PMA_RX_MISC_CTRL0_RX0_MISC(x) ((x) & GENMASK(7, 0)) +#define PMA_MP_16G_25G_RX_IQ_CTRL0 0x100D6 +#define PMA_RX_IQ_CTRL0_RX0_MARGIN_IQ_MASK GENMASK(6, 0) +#define PMA_RX_IQ_CTRL0_RX0_MARGIN_IQ(x) ((x) & GENMASK(6, 0)) +#define PMA_RX_IQ_CTRL0_RX0_DELTA_IQ_MASK GENMASK(11, 8) +#define PMA_RX_IQ_CTRL0_RX0_DELTA_IQ(x) (((x) << 8) & GENMASK(11, 8)) +#define PMA_MP_12G_16G_25G_MPLL_CMN_CTRL 0x100E0 +#define PMA_MPLL_CMN_CTRL_MPLL_EN_0 BIT(0) +#define PMA_MPLL_CMN_CTRL_MPLLB_SEL_0 BIT(4) +#define PMA_MP_12G_16G_MPLLA_CTRL0 0x100E2 +#define PMA_MPLLA_CTRL0_MPLLA_MULTIPLIER_MASK GENMASK(7, 0) +#define PMA_MPLLA_CTRL0_MPLLA_MULTIPLIER(x) ((x) & GENMASK(7, 0)) +#define PMA_MP_16G_MPLLA_CTRL1 0x100E4 +#define PMA_MPLLA_CTRL1_MPLLA_SSC_EN BIT(0) +#define PMA_MPLLA_CTRL1_MPLLA_SSC_CLK_SEL BIT(4) +#define PMA_MPLLA_CTRL1_MPLLA_FRACN_CTRL_MASK GENMASK(15, 5) +#define PMA_MPLLA_CTRL1_MPLLA_FRACN_CTRL(x) (((x) << 5) & GENMASK(15, 5)) +#define PMA_MP_12G_16G_MPLLA_CTRL2 0x100E6 +#define PMA_MPLLA_CTRL2_MPLLA_DIV_MULT_MASK GENMASK(6, 0) +#define PMA_MPLLA_CTRL2_MPLLA_DIV_MULT(x) ((x) & GENMASK(6, 0)) +#define PMA_MPLLA_CTRL2_MPLLA_DIV_CLK_EN BIT(7) +#define PMA_MPLLA_CTRL2_MPLLA_DIV8_CLK_EN BIT(8) +#define PMA_MPLLA_CTRL2_MPLLA_DIV10_CLK_EN BIT(9) +#define PMA_MPLLA_CTRL2_MPLLA_DIV16P5_CLK_EN BIT(10) +#define PMA_MPLLA_CTRL2_MPLLA_TX_CLK_DIV_MASK GENMASK(12, 11) +#define PMA_MPLLA_CTRL2_MPLLA_TX_CLK_DIV(x) (((x) << 11) & GENMASK(12, 11)) +#define PMA_MP_16G_MPLLA_CTRL3 0x100EE +#define PMA_MPLLA_CTRL3_MPLLA_BANDWIDTH_MASK GENMASK(15, 0) +#define PMA_MPLLA_CTRL3_MPLLA_BANDWIDTH(x) ((x) & GENMASK(15, 0)) +#define PMA_MP_16G_MPLLA_CTRL4 0x100F2 +#define PMA_MPLLA_CTRL4_MPLLA_SSC_FRQ_CNT_INT_MASK GENMASK(11, 0) +#define PMA_MPLLA_CTRL4_MPLLA_SSC_FRQ_CNT_INT(x) ((x) & GENMASK(11, 0)) +#define PMA_MP_16G_MPLLA_CTRL5 0x100F4 +#define PMA_MPLLA_CTRL5_MPLLA_SSC_FRQ_CNT_PK_MASK GENMASK(7, 0) +#define PMA_MPLLA_CTRL5_MPLLA_SSC_FRQ_CNT_PK(x) ((x) & GENMASK(7, 0)) +#define PMA_MPLLA_CTRL5_MPLLA_SSC_SPD_EN BIT(8) +#define PMA_MP_12G_16G_25G_MISC_CTRL0 0x10120 +#define PMA_MISC_CTRL0_RX_VREF_CTRL_MASK GENMASK(12, 8) +#define PMA_MISC_CTRL0_RX_VREF_CTRL(x) (((x) << 8) & GENMASK(12, 8)) +#define PMA_MP_12G_16G_25G_REF_CLK_CTRL 0x10122 +#define PMA_REF_CLK_CTRL_REF_CLK_DIV2 BIT(2) +#define PMA_REF_CLK_CTRL_REF_RANGE_MASK GENMASK(5, 3) +#define PMA_REF_CLK_CTRL_REF_RANGE(x) (((x) << 3) & GENMASK(5, 3)) +#define PMA_REF_CLK_CTRL_REF_MPLLA_DIV2 BIT(6) +#define PMA_MP_12G_16G_25G_VCO_CAL_LD0 0x10124 +#define PMA_VCO_CAL_LD0_VCO_LD_VAL_0_MASK GENMASK(12, 0) +#define PMA_VCO_CAL_LD0_VCO_LD_VAL_0(x) ((x) & GENMASK(12, 0)) +#define PMA_MP_16G_25G_VCO_CAL_REF0 0x1012C +#define PMA_VCO_CAL_REF0_VCO_REF_LD_0_MASK GENMASK(6, 0) +#define PMA_VCO_CAL_REF0_VCO_REF_LD_0(x) ((x) & GENMASK(6, 0)) +#define PMA_MP_12G_16G_25G_MISC_STS 0x10130 +#define PMA_MISC_STS_RX_ADPT_ACK BIT(12) +#define PMA_MP_12G_16G_25G_SRAM 0x10136 +#define PMA_SRAM_INIT_DN BIT(0) +#define PMA_SRAM_EXT_LD_DN BIT(1) +#define PMA_MP_16G_25G_MISC_CTRL2 0x10138 +#define PMA_MISC_CTRL2_SUP_MISC_MASK GENMASK(7, 0) +#define PMA_MISC_CTRL2_SUP_MISC(x) ((x) & GENMASK(7, 0)) + +/* PCS */ +#define PCS_CTRL1 0x0 +#define PCS_CTRL1_RESET BIT(15) +#define PCS_CTRL2 0xE +#define PCS_CTRL2_PCS_TYPE_SEL_MASK GENMASK(3, 0) +#define PCS_CTRL2_PCS_TYPE_SEL(x) ((x) & GENMASK(3, 0)) +#define PCS_DIG_CTRL1 0x10000 +#define PCS_DIG_CTRL1_USXG_EN BIT(9) +#define PCS_DIG_CTRL1_USRA_RST BIT(10) +#define PCS_DIG_CTRL1_VR_RST BIT(15) +#define PCS_DEBUG_CTRL 0x1000A +#define PCS_DEBUG_CTRL_SUPRESS_LOS_DET BIT(4) +#define PCS_DEBUG_CTRL_RX_DT_EN_CTL BIT(6) +#define PCS_DEBUG_CTRL_TX_PMBL_CTL BIT(8) +#define PCS_KR_CTRL1 0x1000E +#define PCS_KR_CTRL1_USXG_MODE_MASK GENMASK(12, 10) +#define PCS_KR_CTRL1_USXG_MODE(x) (((x) << 10) & GENMASK(12, 10)) + +/* VS MII MMD */ +#define MII_CTRL 0x0 +#define MII_CTRL_SS5 BIT(5) +#define MII_CTRL_SS6 BIT(6) +#define MII_CTRL_AN_ENABLE BIT(12) +#define MII_CTRL_SS13 BIT(13) +#define MII_DIG_CTRL1 0x10000 +#define MII_DIG_CTRL1_CL37_TMR_OVR_RIDE BIT(3) +#define MII_AN_CTRL 0x10002 +#define MII_AN_CTRL_MII_AN_INTR_EN BIT(0) +#define MII_AN_CTRL_TX_CONFIG BIT(3) +#define MII_AN_INTR_STS 0x10004 +#define MII_AN_INTR_STS_CL37_ANCMPLT_INTR BIT(0) +#define MII_LINK_TIMER_CTRL 0x10014 +#define MII_LINK_TIMER_CTRL_CL37_LINK_TIME_MASK GENMASK(15, 0) +#define MII_LINK_TIMER_CTRL_CL37_LINK_TIME(x) ((x) & GENMASK(15, 0)) + +/* E16 MEM MAP */ +#define IDCODE_LO 0x0 +#define IDCODE_HI 0x4 +#define GLOBAL_CTRL_EX_0 0x114 +#define GLOBAL_CTRL_EX_0_PHY_SRAM_BYPASS BIT(0) +#define L0_RX_VCO_OVRD_OUT_0 0x20c +#define L0_RX_VCO_OVRD_OUT_0_RX_ANA_CDR_FREQ_TUNE_MASK GENMASK(12, 3) +#define L0_RX_VCO_OVRD_OUT_0_RX_ANA_CDR_FREQ_TUNE(x) (((x) << 3) & GENMASK(12, 3)) +#define L0_RX_VCO_OVRD_OUT_0_RX_CDR_FREQ_TUNE_OVRD_EN BIT(15) +#define L0_RX_VCO_OVRD_OUT_2 0x214 +#define L0_RX_VCO_OVRD_OUT_2_RX_ANA_CDR_FREQ_TUNE_CLK BIT(0) + +static int enetc_mdio_read(struct mii_dev *bus, int addr, int devad, int reg); +static int enetc_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, u16 val); + +int xpcs_read(struct udevice *dev, int devaddr, u32 reg) +{ + struct enetc_priv *priv = dev_get_priv(dev); + + return enetc_mdio_read(&priv->imdio, ENETC_PCS_PHY_ADDR, devaddr, reg); +} + +int xpcs_write(struct udevice *dev, int devaddr, u32 reg, u16 val) +{ + struct enetc_priv *priv = dev_get_priv(dev); + + return enetc_mdio_write(&priv->imdio, ENETC_PCS_PHY_ADDR, devaddr, reg, val); +} + +int xpcs_phy_read(struct udevice *dev, int devaddr, u32 reg) +{ + struct enetc_priv *priv = dev_get_priv(dev); + + return enetc_mdio_read(&priv->imdio, ENETC_NON_PCS_PHY_ADDR, devaddr, reg); +} + +int xpcs_phy_write(struct udevice *dev, int devaddr, u32 reg, u16 val) +{ + struct enetc_priv *priv = dev_get_priv(dev); + + return enetc_mdio_write(&priv->imdio, ENETC_NON_PCS_PHY_ADDR, devaddr, reg, val); +} + +int xpcs_phy_read_pma(struct udevice *dev, u32 reg) +{ + return xpcs_read(dev, MDIO_MMD_PMAPMD, XPCS_PHY_REG(reg)); +} + +int xpcs_phy_write_pma(struct udevice *dev, int reg, u16 val) +{ + return xpcs_write(dev, MDIO_MMD_PMAPMD, XPCS_PHY_REG(reg), val); +} + +int xpcs_phy_usxgmii_init_seq_2(struct udevice *dev) +{ + ulong begin; + u16 val; + + /* Seq 2.1 Keep preamble data */ + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL)); + val |= PCS_DEBUG_CTRL_TX_PMBL_CTL; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL), val); + + /* Seq 2.2 Power up MPLLA to P1 state */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 2, PMA_POWER_STATE_CTRL_TX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL); + val |= PMA_MPLL_CMN_CTRL_MPLL_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL, val); + + /* Seq 2.3 Assert request of transmitand receive */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val |= PMA_TX_GENCTRL2_TX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val |= PMA_RX_GENCTRL2_RX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + /* Seq 2.4 Poll for acknowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_TX_GENCTRL2_TX_REQ_0); + + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_RX_GENCTRL2_RX_REQ_0); + + /* Seq 2.5 Turn transmit to P0 state */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 0, PMA_POWER_STATE_CTRL_TX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val &= ~PMA_TX_GENCTRL0_TX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL); + val &= ~PMA_POWER_STATE_CTRL_TX_DISABLE_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL); + val |= PMA_MPLL_CMN_CTRL_MPLL_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL, val); + + /* Seq 2.6 Turn receive to P0 state */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val &= ~PMA_RX_GENCTRL1_RX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val &= ~PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK; + val &= ~PMA_RX_POWER_STATE_CTRL_RX_DISABLE_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val &= ~PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK; + val &= ~PMA_RX_POWER_STATE_CTRL_RX_DISABLE_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + /* Seq 2.7 Enable transmitter output driver in the PHY */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val |= PMA_TX_GENCTRL0_TX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + /* Seq 2.8 Enable receiver data output from PHY */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0); + val |= PMA_RX_GENCTRL0_RX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0, val); + + /* Seq 2.9 Assert request of transmit and receive */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val |= PMA_TX_GENCTRL2_TX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val |= PMA_RX_GENCTRL2_RX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + /* Seq 2.10 Poll for acknowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + schedule(); + } while (val & PMA_TX_GENCTRL2_TX_REQ_0); + + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + schedule(); + } while (val & PMA_RX_GENCTRL2_RX_REQ_0); + + return 0; + +timeout: + return -ETIMEDOUT; +} + +void xpcs_phy_reg_lock(struct udevice *dev) +{ + u16 val; + ulong begin; + + if (xpcs_phy_read(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_PHY)) & MAC_ADAPTER_LOCK_LOCK) + return; + + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_PHY), MAC_ADAPTER_LOCK_LOCK); + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_MPLLA), MAC_ADAPTER_LOCK_LOCK); + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_MPLLB), MAC_ADAPTER_LOCK_LOCK); + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_ROM), MAC_ADAPTER_LOCK_LOCK); + xpcs_phy_write(dev, XPCS_PHY_MAC_ADAPTER, XPCS_PHY_REG(MAC_ADAPTER_LOCK_RAM), MAC_ADAPTER_LOCK_LOCK); + + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_SRAM); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (!(val & PMA_SRAM_INIT_DN)); + + /* Work around */ + // xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_SRAM, PMA_SRAM_EXT_LD_DN); + xpcs_phy_write(dev, XPCS_PHY_GLOBAL, XPCS_PHY_REG(GLOBAL_CTRL_EX_0), GLOBAL_CTRL_EX_0_PHY_SRAM_BYPASS); + + begin = get_timer(0); + do { + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_CTRL1)); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PCS_CTRL1_RESET); + + mdelay(1); + +timeout: + return; +} + +int xpcs_phy_usxgmii_pma_config(struct udevice *dev) +{ + ulong begin; + u16 val; + + xpcs_phy_reg_lock(dev); + + /* 1.6 Turn off C37 auto-negotiation */ + val = xpcs_read(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_CTRL)); + val &= ~MII_CTRL_AN_ENABLE; + xpcs_write(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_CTRL), val); + + /* 1.7 Assert tx_reset and rx_reset*/ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val |= PMA_TX_GENCTRL0_TX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val |= PMA_RX_GENCTRL1_RX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + /* 1.8 Wait for more than 1us */ + udelay(5); + + /* 1.9 Deassert tx_reset and rx_reset*/ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val &= ~PMA_TX_GENCTRL0_TX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val &= ~PMA_RX_GENCTRL1_RX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + /* 1.10 Power down MPLLA */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 3, PMA_POWER_STATE_CTRL_TX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL); + val &= ~PMA_MPLL_CMN_CTRL_MPLL_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0); + val &= ~PMA_TX_GENCTRL0_TX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL0, val); + + /* 1.11 Change RX0 power state to P2 */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0); + val &= ~PMA_RX_GENCTRL0_RX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0, val); + + /* TODO: check if it is needed */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 1, PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val = u16_replace_bits(val, 3, PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + /* 1.12 Assert request of transmit and receive */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val |= PMA_TX_GENCTRL2_TX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val |= PMA_RX_GENCTRL2_RX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + /* 1.13 Poll for acknlowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_TX_GENCTRL2_TX_REQ_0); + + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_RX_GENCTRL2_RX_REQ_0); + + /* 2 Config MPLL for 10G XGMII */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL); + val = u16_replace_bits(val, 6, PMA_REF_CLK_CTRL_REF_RANGE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL); + val &= ~PMA_REF_CLK_CTRL_REF_CLK_DIV2; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL); + val |= PMA_REF_CLK_CTRL_REF_MPLLA_DIV2; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_REF_CLK_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val &= ~PMA_MPLLA_CTRL2_MPLLA_DIV8_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV10_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV16P5_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val &= ~PMA_MPLLA_CTRL2_MPLLA_TX_CLK_DIV_MASK; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val = u16_replace_bits(val, 5, PMA_MPLLA_CTRL2_MPLLA_DIV_MULT_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL1); + val &= ~PMA_MPLLA_CTRL1_MPLLA_SSC_EN; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL1); + val &= ~PMA_MPLLA_CTRL1_MPLLA_SSC_CLK_SEL; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL5); + val &= ~PMA_MPLLA_CTRL5_MPLLA_SSC_FRQ_CNT_PK_MASK; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL5, val); + + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL4, 0); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL5); + val &= ~PMA_MPLLA_CTRL5_MPLLA_SSC_SPD_EN; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL5, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_MPLLA_CTRL1); + val &= ~PMA_MPLLA_CTRL1_MPLLA_FRACN_CTRL_MASK; + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL0); + val = u16_replace_bits(val, 33, PMA_MPLLA_CTRL0_MPLLA_MULTIPLIER_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val = u16_replace_bits(val, 5, PMA_TX_GENCTRL1_VBOOST_LVL_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + val = PMA_MPLLA_CTRL3_MPLLA_BANDWIDTH(0xA016); + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL3, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MISC_CTRL0); + val = u16_replace_bits(val, 0x11, PMA_MISC_CTRL0_RX_VREF_CTRL_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MISC_CTRL0, val); + + val = PMA_MISC_CTRL2_SUP_MISC(1); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_MISC_CTRL2, val); + + val = PMA_VCO_CAL_REF0_VCO_REF_LD_0(0x29); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_VCO_CAL_REF0, val); + + val = PMA_VCO_CAL_LD0_VCO_LD_VAL_0(0x549); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_VCO_CAL_LD0, val); + + val = PMA_RX_PPM_CTRL0_RX0_CDR_PPM_MAX(0x12); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_PPM_CTRL0, val); + + /* 3 Configure LANE0 for 10G XGMII */ + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_TX_MISC_CTRL0, 0x0); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_RATE_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL); + val &= ~PMA_MPLL_CMN_CTRL_MPLLB_SEL_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_MPLL_CMN_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val = u16_replace_bits(val, 3, PMA_TX_GENCTRL2_TX0_WIDTH_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val |= PMA_TX_GENCTRL1_VBOOST_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + val = PMA_TX_BOOST_CTRL_TX0_IBOOST(0xf); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_BOOST_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL0); + val = u16_replace_bits(val, 0, PMA_TX_EQ_CTRL0_TX_EQ_PRE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL0, val); + + val = PMA_TX_EQ_CTRL1_TX_EQ_POST(0x20); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL0); + val = u16_replace_bits(val, 0x20, PMA_TX_EQ_CTRL0_TX_EQ_MAIN_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_EQ_CTRL0, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_RATE_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x2, PMA_RX_EQ_CTRL0_CTLE_POLE_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x10, PMA_RX_EQ_CTRL0_CTLE_BOOST_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL3); + val = u16_replace_bits(val, 0x7, PMA_RX_GENCTRL3_LOS_TRSHLD_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL3, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val |= PMA_RX_CDR_CTRL1_VCO_STEP_CTRL_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val |= PMA_RX_CDR_CTRL1_VCO_TEMP_COMP_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = PMA_RX_MISC_CTRL0_RX0_MISC(0x12); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_MISC_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val = u16_replace_bits(val, 0x3, PMA_RX_GENCTRL2_RX0_WIDTH_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val |= PMA_RX_GENCTRL1_RX_DIV16P5_CLK_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_CDR_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL3); + val &= ~PMA_RX_GENCTRL3_LOS_LFPS_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL3, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_GENCTRL4); + val &= ~PMA_RX_GENCTRL4_RX_DFE_BYP_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_GENCTRL4, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_ATTN_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x5, PMA_RX_EQ_CTRL0_VGA1_GAIN_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x5, PMA_RX_EQ_CTRL0_VGA2_GAIN_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_DFE_TAP_CTRL0, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val = u16_replace_bits(val, 0x1, PMA_RX_CDR_CTRL1_VCO_FRQBAND_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val |= PMA_RX_GENCTRL1_RX_TERM_ACDC_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_IQ_CTRL0); + val = u16_replace_bits(val, 0x0, PMA_RX_IQ_CTRL0_RX0_DELTA_IQ_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_IQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5); + val &= ~PMA_RX_EQ_CTRL5_RX_ADPT_SEL_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5); + val = u16_replace_bits(val, 0x3, PMA_RX_EQ_CTRL5_RX0_ADPT_MODE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5, val); + + /* 4 Configure XPCS for 10G XGMII */ + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_CTRL2), 0x0); + + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1)); + val |= PCS_DIG_CTRL1_USXG_EN; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1), val); + + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_KR_CTRL1)); + val = u16_replace_bits(val, 0x0, PCS_KR_CTRL1_USXG_MODE_MASK); + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_KR_CTRL1), val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL0); + val = u16_replace_bits(val, 0x21, PMA_MPLLA_CTRL0_MPLLA_MULTIPLIER_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL0, val); + + val = PMA_MPLLA_CTRL3_MPLLA_BANDWIDTH(0xA016); + xpcs_phy_write_pma(dev, PMA_MP_16G_MPLLA_CTRL3, val); + + val = PMA_VCO_CAL_LD0_VCO_LD_VAL_0(0x549); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_VCO_CAL_LD0, val); + + val = PMA_VCO_CAL_REF0_VCO_REF_LD_0(0x29); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_VCO_CAL_REF0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4); + val |= PMA_RX_EQ_CTRL4_CONT_ADAPT_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4, val); + + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_RATE_CTRL, 0x0); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_RATE_CTRL, 0x0); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2); + val = u16_replace_bits(val, 0x3, PMA_TX_GENCTRL2_TX0_WIDTH_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_TX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val = u16_replace_bits(val, 0x3, PMA_RX_GENCTRL2_RX0_WIDTH_MASK); + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV16P5_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val |= PMA_MPLLA_CTRL2_MPLLA_DIV10_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2); + val &= ~PMA_MPLLA_CTRL2_MPLLA_DIV8_CLK_EN; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_MPLLA_CTRL2, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val |= PMA_TX_GENCTRL1_VBOOST_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0); + val = u16_replace_bits(val, 0x10, PMA_RX_EQ_CTRL0_CTLE_BOOST_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val |= PMA_RX_CDR_CTRL1_VCO_STEP_CTRL_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val |= PMA_RX_CDR_CTRL1_VCO_TEMP_COMP_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = PMA_RX_MISC_CTRL0_RX0_MISC(0x12); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_MISC_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_GENCTRL4); + val &= ~PMA_RX_GENCTRL4_RX_DFE_BYP_0; + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_GENCTRL4, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_RX_CDR_CTRL1); + val = u16_replace_bits(val, 0x1, PMA_RX_CDR_CTRL1_VCO_FRQBAND_0_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_RX_CDR_CTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_IQ_CTRL0); + val = u16_replace_bits(val, 0x0, PMA_RX_IQ_CTRL0_RX0_DELTA_IQ_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_IQ_CTRL0, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5); + val = u16_replace_bits(val, 0x3, PMA_RX_EQ_CTRL5_RX0_ADPT_MODE_MASK); + xpcs_phy_write_pma(dev, PMA_MP_16G_25G_RX_EQ_CTRL5, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val &= ~PMA_TX_GENCTRL1_TX_CLK_RDY_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + /* 5 Assert soft reset */ + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1)); + val |= PCS_DIG_CTRL1_VR_RST; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1), val); + + /* 6 Poll for SRAM initialization done */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_SRAM); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (!(val & PMA_SRAM_INIT_DN)); + + /* 7 Assert SRAM external loading done */ + /* Workaround */ + // xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_SRAM, PMA_SRAM_EXT_LD_DN); + xpcs_phy_write(dev, XPCS_PHY_GLOBAL, XPCS_PHY_REG(GLOBAL_CTRL_EX_0), GLOBAL_CTRL_EX_0_PHY_SRAM_BYPASS); + + /* 8 Poll for vendor-specific soft reset */ + begin = get_timer(0); + do { + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DIG_CTRL1)); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PCS_DIG_CTRL1_VR_RST); + + /* 9 Turn receive to P0 state */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1); + val &= ~PMA_RX_GENCTRL1_RX_RST_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL1, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val &= ~PMA_RX_POWER_STATE_CTRL_RX_DISABLE_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL); + val &= ~PMA_RX_POWER_STATE_CTRL_RX0_PSTATE_MASK; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_POWER_STATE_CTRL, val); + + /* 10 Enable receiver data output from PHY */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0); + val |= PMA_RX_GENCTRL0_RX_DT_EN_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_GENCTRL0, val); + + /* 11 Assert request of receive */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + val |= PMA_RX_GENCTRL2_RX_REQ_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2, val); + + /* 11.1 Poll for acknowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_RX_GENCTRL2); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (val & PMA_RX_GENCTRL2_RX_REQ_0); + + /* 12 Assert TX0 clock is active and stable */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1); + val |= PMA_TX_GENCTRL1_TX_CLK_RDY_0; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_TX_GENCTRL1, val); + + /* + * 13.1 Configure XPCS to consider Loss-of-Signal indicated by the + * PHY while evaluating the receive link status + */ + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL)); + val |= PCS_DEBUG_CTRL_SUPRESS_LOS_DET; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL), val); + /* + * 13.2 Configure XPCS to deassert "receiver data enable" on + * detecting of Loss-of-Signal + */ + val = xpcs_read(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL)); + val |= PCS_DEBUG_CTRL_RX_DT_EN_CTL; + xpcs_write(dev, MDIO_MMD_PCS, XPCS_PHY_REG(PCS_DEBUG_CTRL), val); + + /* 14 Poll for DPLL lock status for Lane 0 */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_RX_LSTS); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (!(val & PMA_RX_LSTS_RX_VALID_0)); + + /* 15 Assert request of receive adaptation */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4); + val |= PMA_RX_EQ_CTRL4_RX_AD_REQ; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4, val); + + /* 16 Poll for acknowledge */ + begin = get_timer(0); + do { + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_MISC_STS); + if (get_timer(begin) > 500) { + dev_err(dev, "Polling timeout, line: %d\n", __LINE__); + goto timeout; + } + mdelay(10); + } while (!(val & PMA_MISC_STS_RX_ADPT_ACK)); + + /* 17 Deassert request of receive adaptation */ + val = xpcs_phy_read_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4); + val &= ~PMA_RX_EQ_CTRL4_RX_AD_REQ; + xpcs_phy_write_pma(dev, PMA_MP_12G_16G_25G_RX_EQ_CTRL4, val); + + /* 18 Set the value of Config_Reg to 0 for Clause 37 autonegotiation. */ + val = xpcs_read(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_AN_CTRL)); + val &= ~MII_AN_CTRL_TX_CONFIG; + xpcs_write(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_AN_CTRL), val); + + /* 19 Select XGMII speed */ + val = xpcs_read(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_CTRL)); + val &= ~MII_CTRL_SS5; + val |= MII_CTRL_SS6 | MII_CTRL_SS13; + xpcs_write(dev, MDIO_MMD_VEND2, XPCS_PHY_REG(MII_CTRL), val); + + val = xpcs_phy_usxgmii_init_seq_2(dev); + if (val) + return val; + + return 0; + +timeout: + return -ETIMEDOUT; +} + +u32 xpcs_phy_get_id(struct udevice *dev) +{ + int ret; + u32 id; + + /* First, search C73 PCS using PCS MMD */ + ret = xpcs_phy_read(dev, XPCS_PHY_GLOBAL, XPCS_PHY_REG(IDCODE_HI)); + if (ret < 0) + return 0xffffffff; + + id = ret << 16; + + ret = xpcs_phy_read(dev, XPCS_PHY_GLOBAL, XPCS_PHY_REG(IDCODE_LO)); + if (ret < 0) + return 0xffffffff; + + /* If Device IDs are not all zeros or all ones, + * we found C73 AN-type device + */ + if ((id | ret) && (id | ret) != 0xffffffff) + return id | ret; + + return 0xffffffff; +} diff --git a/drivers/net/hifemac.c b/drivers/net/hifemac.c index 62182f922f8..7dda8cb8815 100644 --- a/drivers/net/hifemac.c +++ b/drivers/net/hifemac.c @@ -401,9 +401,6 @@ static void hisi_femac_get_strings(struct udevice *dev, u8 *data) strcpy(data + i * ETH_GSTRING_LEN, hisi_femac_stats_table[i].name); } -/* Non-constant mask variant of FIELD_GET/FIELD_PREP */ -#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) - static void hisi_femac_get_stats(struct udevice *dev, u64 *data) { int i; diff --git a/drivers/net/macb.c b/drivers/net/macb.c index cbf5f605518..bea1dfed892 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -38,9 +38,13 @@ #include <linux/mii.h> #include <asm/io.h> #include <linux/dma-mapping.h> -#include <asm/arch/clk.h> #include <linux/errno.h> +/* Without CLK, we rely on the arch definition */ +#if !defined(CONFIG_CLK) +#include <asm/arch/clk.h> +#endif + #include "macb.h" DECLARE_GLOBAL_DATA_PTR; @@ -768,18 +772,40 @@ static int macb_phy_init(struct udevice *dev, const char *name) lpa); } else { /* if macb port is a fixed link */ - /* TODO : manage gigabit capable processors */ + const char *human_readable_speed; + speed = macb->speed; duplex = macb->duplex; + switch (speed) { + case 2: + human_readable_speed = "1000"; + break; + case 1: + human_readable_speed = "100"; + break; + case 0: + human_readable_speed = "10"; + break; + default: + printf("%s: speed %d not supported\n", name, speed); + return -EINVAL; + } printf("%s: link up, %sMbps %s-duplex\n", name, - speed ? "100" : "10", + human_readable_speed, duplex ? "full" : "half"); } ncfgr = macb_readl(macb, NCFGR); ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD) | GEM_BIT(GBE)); - if (speed) { + if (speed == 2) { + if (!gem_is_gigabit_capable(macb)) { + printf("%s: is not gigabit Ethernet capable\n", name); + return -EINVAL; + } + ncfgr |= GEM_BIT(GBE); + ret = macb_linkspd_cb(dev, _1000BASET); + } else if (speed == 1) { ncfgr |= MACB_BIT(SPD); ret = macb_linkspd_cb(dev, _100BASET); } else { @@ -923,26 +949,39 @@ static int _macb_init(struct udevice *dev, const char *name) /* Check the multi queue and initialize the queue for tx */ gmac_init_multi_queues(macb); - /* - * When the GMAC IP with GE feature, this bit is used to - * select interface between RGMII and GMII. - * When the GMAC IP without GE feature, this bit is used - * to select interface between RMII and MII. + /* This driver uses the user I/O to select the PHY features, + * but some GEM instances come with a fixed configuration and + * no USERIO. */ - if (macb->phy_interface == PHY_INTERFACE_MODE_RGMII || - macb->phy_interface == PHY_INTERFACE_MODE_RGMII_ID || - macb->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID || - macb->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) - val = macb->config->usrio->rgmii; - else if (macb->phy_interface == PHY_INTERFACE_MODE_RMII) - val = macb->config->usrio->rmii; - else if (macb->phy_interface == PHY_INTERFACE_MODE_MII) - val = macb->config->usrio->mii; + if (gem_readl(macb, DCFG1) & GEM_BIT(USERIO)) { + /* + * When the GMAC IP with GE feature, this bit is used to + * select interface between RGMII and GMII. + * When he GMAC IP without GE feature, this bit is used + * to select interface between RMII and MII. + */ + switch (macb->phy_interface) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + val = macb->config->usrio->rgmii; + break; + case PHY_INTERFACE_MODE_RMII: + val = macb->config->usrio->rmii; + break; + case PHY_INTERFACE_MODE_MII: + val = macb->config->usrio->mii; + break; + default: + break; + } - if (macb->config->caps & MACB_CAPS_USRIO_HAS_CLKEN) - val |= macb->config->usrio->clken; + if (macb->config->caps & MACB_CAPS_USRIO_HAS_CLKEN) + val |= macb->config->usrio->clken; - gem_writel(macb, USRIO, val); + gem_writel(macb, USRIO, val); + } if (macb->phy_interface == PHY_INTERFACE_MODE_SGMII) { unsigned int ncfgr = macb_readl(macb, NCFGR); @@ -1003,9 +1042,14 @@ static int _macb_write_hwaddr(struct macb_device *macb, unsigned char *enetaddr) /* set hardware address */ hwaddr_bottom = enetaddr[0] | enetaddr[1] << 8 | enetaddr[2] << 16 | enetaddr[3] << 24; - macb_writel(macb, SA1B, hwaddr_bottom); hwaddr_top = enetaddr[4] | enetaddr[5] << 8; - macb_writel(macb, SA1T, hwaddr_top); + if (macb_is_gem(macb)) { + gem_writel(macb, SA1B, hwaddr_bottom); + gem_writel(macb, SA1T, hwaddr_top); + } else { + macb_writel(macb, SA1B, hwaddr_bottom); + macb_writel(macb, SA1T, hwaddr_top); + } return 0; } @@ -1307,7 +1351,9 @@ static int macb_eth_of_to_plat(struct udevice *dev) macb->phy_addr = PHY_MAX_ADDR + 1; macb->duplex = fdtdec_get_bool(blob, fl_node, "full-duplex"); speed_fdt = fdtdec_get_int(blob, fl_node, "speed", 0); - if (speed_fdt == 100) { + if (speed_fdt == 1000) { + macb->speed = 2; + } else if (speed_fdt == 100) { macb->speed = 1; } else if (speed_fdt == 10) { macb->speed = 0; diff --git a/drivers/net/macb.h b/drivers/net/macb.h index 0eb90574618..002d5bd31b2 100644 --- a/drivers/net/macb.h +++ b/drivers/net/macb.h @@ -443,6 +443,8 @@ #define MACB_REV_SIZE 16 /* Bitfields in DCFG1. */ +#define GEM_USERIO_OFFSET 9 +#define GEM_USERIO_SIZE 1 #define GEM_IRQCOR_OFFSET 23 #define GEM_IRQCOR_SIZE 1 #define GEM_DBWDEF_OFFSET 25 diff --git a/drivers/net/mcfmii.c b/drivers/net/mcfmii.c index 9bf887035d7..79ad6348de8 100644 --- a/drivers/net/mcfmii.c +++ b/drivers/net/mcfmii.c @@ -112,7 +112,7 @@ uint mii_send(uint mii_cmd) ep->eir = FEC_EIR_MII; /* clear MII complete */ #ifdef ET_DEBUG printf("%s[%d] %s: sent=0x%8.8x, reply=0x%8.8x\n", - __FILE__, __LINE__, __FUNCTION__, mii_cmd, mii_reply); + __FILE__, __LINE__, __func__, mii_cmd, mii_reply); #endif return (mii_reply & 0xffff); /* data read from phy */ diff --git a/drivers/net/mtk_eth/Kconfig b/drivers/net/mtk_eth/Kconfig index 5d4e54ab90e..7d58f542bde 100644 --- a/drivers/net/mtk_eth/Kconfig +++ b/drivers/net/mtk_eth/Kconfig @@ -5,6 +5,7 @@ config MEDIATEK_ETH select PHYLIB select DM_GPIO select DM_RESET + select LMB_LIMIT_DMA_BELOW_RAM_TOP help This Driver support MediaTek Ethernet GMAC Say Y to enable support for the MediaTek Ethernet GMAC. diff --git a/drivers/net/mvgbe.c b/drivers/net/mvgbe.c index 107a33aa9f5..4dc738980cb 100644 --- a/drivers/net/mvgbe.c +++ b/drivers/net/mvgbe.c @@ -256,8 +256,8 @@ static void set_dram_access(struct mvgbe_registers *regs) win_param.access_ctrl = EWIN_ACCESS_FULL; win_param.high_addr = 0; /* Get bank base and size */ - win_param.base_addr = gd->bd->bi_dram[i].start; - win_param.size = gd->bd->bi_dram[i].size; + win_param.base_addr = gd->dram[i].start; + win_param.size = gd->dram[i].size; if (win_param.size == 0) win_param.enable = 0; else diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c index f9e979c4d58..ae5920a0201 100644 --- a/drivers/net/mvpp2.c +++ b/drivers/net/mvpp2.c @@ -4528,7 +4528,7 @@ static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) */ if (phy_dev && phy_dev->drv->uid == 0xffffffff) {/* Generic phy */ - dev_warn(port->phy_dev->dev, + dev_warn(dev, "Marking phy as invalid, link will not be checked\n"); /* set phy_addr to invalid value */ port->phyaddr = PHY_MAX_ADDR; @@ -4540,7 +4540,7 @@ static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) port->phy_dev = phy_dev; if (!phy_dev) { - dev_err(port->phy_dev->dev, "cannot connect to phy\n"); + dev_err(dev, "cannot connect to phy\n"); return; } phy_dev->supported &= PHY_GBIT_FEATURES; @@ -4731,33 +4731,32 @@ static int mvpp2_port_init(struct udevice *dev, struct mvpp2_port *port) static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port) { - int port_node = dev_of_offset(dev); - int phy_node; + ofnode port_node = dev_ofnode(dev); + ofnode phy_node; u32 id; int phyaddr = 0; - int fixed_link = 0; + ofnode fixed_link; int ret; - phy_node = fdtdec_lookup_phandle(gd->fdt_blob, port_node, "phy"); - fixed_link = fdt_subnode_offset(gd->fdt_blob, port_node, "fixed-link"); + phy_node = ofnode_parse_phandle(port_node, "phy", 0); + fixed_link = ofnode_find_subnode(port_node, "fixed-link"); - if (phy_node > 0) { - int parent; + if (ofnode_valid(phy_node)) { + ofnode parent; - if (fixed_link != -FDT_ERR_NOTFOUND) { + if (ofnode_valid(fixed_link)) { /* phy_addr is set to invalid value for fixed links */ phyaddr = PHY_MAX_ADDR; } else { - phyaddr = fdtdec_get_int(gd->fdt_blob, phy_node, - "reg", 0); + phyaddr = ofnode_read_s32_default(phy_node, "reg", 0); if (phyaddr < 0) { dev_err(dev, "could not find phy address\n"); return -1; } } - parent = fdt_parent_offset(gd->fdt_blob, phy_node); - ret = uclass_get_device_by_of_offset(UCLASS_MDIO, parent, - &port->mdio_dev); + parent = ofnode_get_parent(phy_node); + ret = uclass_get_device_by_ofnode(UCLASS_MDIO, parent, + &port->mdio_dev); if (ret) return ret; } else { @@ -4771,7 +4770,7 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port) return -EINVAL; } - id = fdtdec_get_int(gd->fdt_blob, port_node, "port-id", -1); + id = dev_read_s32_default(dev, "port-id", -1); if (id == -1) { dev_err(dev, "missing port-id value\n"); return -EINVAL; @@ -4812,7 +4811,7 @@ static void mvpp2_gpio_init(struct mvpp2_port *port) /* Ports initialization */ static int mvpp2_port_probe(struct udevice *dev, struct mvpp2_port *port, - int port_node, + ofnode port_node, struct mvpp2 *priv) { int err; @@ -5296,16 +5295,16 @@ static int mvpp2_base_probe(struct udevice *dev) } /* Save base addresses for later use */ - priv->base = devfdt_get_addr_index_ptr(dev, 0); + priv->base = dev_read_addr_index_ptr(dev, 0); if (!priv->base) return -EINVAL; if (priv->hw_version == MVPP21) { - priv->lms_base = devfdt_get_addr_index_ptr(dev, 1); + priv->lms_base = dev_read_addr_index_ptr(dev, 1); if (!priv->lms_base) return -EINVAL; } else { - priv->iface_base = devfdt_get_addr_index_ptr(dev, 1); + priv->iface_base = dev_read_addr_index_ptr(dev, 1); if (!priv->iface_base) return -EINVAL; @@ -5346,13 +5345,11 @@ static int mvpp2_probe(struct udevice *dev) if (priv->hw_version == MVPP21) { int priv_common_regs_num = 2; - port->base = devfdt_get_addr_index_ptr( - dev->parent, priv_common_regs_num + port->id); + port->base = dev_read_addr_index_ptr(dev->parent, priv_common_regs_num + port->id); if (!port->base) return -EINVAL; } else { - port->gop_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "gop-port-id", -1); + port->gop_id = ofnode_read_s32_default(dev_ofnode(dev), "gop-port-id", -1); if (port->gop_id == -1) { dev_err(dev, "missing gop-port-id value\n"); return -EINVAL; @@ -5376,7 +5373,7 @@ static int mvpp2_probe(struct udevice *dev) priv->probe_done = 1; } - err = mvpp2_port_probe(dev, port, dev_of_offset(dev), priv); + err = mvpp2_port_probe(dev, port, dev_ofnode(dev), priv); if (err) return err; @@ -5437,13 +5434,11 @@ static struct driver mvpp2_driver = { */ static int mvpp2_base_bind(struct udevice *parent) { - const void *blob = gd->fdt_blob; - int node = dev_of_offset(parent); struct uclass_driver *drv; struct udevice *dev; struct eth_pdata *plat; char *name; - int subnode; + ofnode subnode; u32 id; int base_id_add; @@ -5456,19 +5451,19 @@ static int mvpp2_base_bind(struct udevice *parent) base_id_add = base_id; - fdt_for_each_subnode(subnode, blob, node) { + dev_for_each_subnode(subnode, parent) { /* Increment base_id for all subnodes, also the disabled ones */ base_id++; /* Skip disabled ports */ - if (!fdtdec_get_is_enabled(blob, subnode)) + if (!ofnode_is_enabled(subnode)) continue; plat = calloc(1, sizeof(*plat)); if (!plat) return -ENOMEM; - id = fdtdec_get_int(blob, subnode, "port-id", -1); + id = ofnode_read_s32_default(subnode, "port-id", -1); id += base_id_add; name = calloc(1, 16); @@ -5479,8 +5474,7 @@ static int mvpp2_base_bind(struct udevice *parent) sprintf(name, "mvpp2-%d", id); /* Create child device UCLASS_ETH and bind it */ - device_bind(parent, &mvpp2_driver, name, plat, - offset_to_ofnode(subnode), &dev); + device_bind(parent, &mvpp2_driver, name, plat, subnode, &dev); } return 0; diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 5d2277a4602..ee438524490 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -7,7 +7,7 @@ config MV88E6352_SWITCH menuconfig PHYLIB bool "Ethernet PHY (physical media interface) support" - depends on NET || NET_LWIP + depends on NET help Enable Ethernet PHY (physical media interface) support. @@ -81,7 +81,7 @@ config PHYLIB_10G config PHY_ADIN bool "Analog Devices Industrial Ethernet PHYs" help - Add support for configuring RGMII on Analog Devices ADIN PHYs. + Add support for configuring RGMII on Analog Devices ADIN PHYs. menuconfig PHY_AQUANTIA bool "Aquantia Ethernet PHYs support" @@ -126,9 +126,9 @@ config SYS_CORTINA_NO_FW_UPLOAD bool "Cortina firmware loading support" depends on PHY_CORTINA help - Cortina phy has provision to store phy firmware in attached dedicated - EEPROM. And boards designed with such EEPROM does not require firmware - upload. + Cortina phy has provision to store phy firmware in attached dedicated + EEPROM. And boards designed with such EEPROM does not require firmware + upload. choice prompt "Location of the Cortina firmware" @@ -167,7 +167,7 @@ config PHY_CORTINA_ACCESS default y depends on CORTINA_NI_ENET help - Cortina Access Ethernet PHYs init process + Cortina Access Ethernet PHYs init process config PHY_DAVICOM bool "Davicom Ethernet PHYs support" @@ -233,7 +233,7 @@ config PHY_MICREL_KSZ8XXX endif # PHY_MICREL config PHY_MOTORCOMM - tristate "Motorcomm PHYs" + bool "Motorcomm PHYs" help Enables support for Motorcomm network PHYs. Currently supports the YT8511 and YT8531 Gigabit Ethernet PHYs. @@ -246,7 +246,7 @@ config PHY_NATSEMI bool "National Semiconductor Ethernet PHYs support" config PHY_NXP_C45_TJA11XX - tristate "NXP C45 TJA11XX PHYs" + bool "NXP C45 TJA11XX PHYs" select DEVRES help Enable support for NXP C45 TJA11XX PHYs. @@ -317,13 +317,13 @@ config PHY_TERANETICS config PHY_TI bool "Texas Instruments Ethernet PHYs support" - ---help--- + help Adds PHY registration support for TI PHYs. config PHY_TI_DP83867 select PHY_TI bool "Texas Instruments Ethernet DP83867 PHY support" - ---help--- + help Adds support for the TI DP83867 1Gbit PHY. config SPL_PHY_TI_DP83867 @@ -333,13 +333,13 @@ config SPL_PHY_TI_DP83867 config PHY_TI_DP83869 select PHY_TI bool "Texas Instruments Ethernet DP83869 PHY support" - ---help--- + help Adds support for the TI DP83869 1Gbit PHY. config PHY_TI_GENERIC select PHY_TI bool "Texas Instruments Generic Ethernet PHYs support" - ---help--- + help Adds support for Generic TI PHYs that don't need special handling but the PHY name is associated with a PHY ID. @@ -381,7 +381,7 @@ config PHY_FIXED config PHY_NCSI bool "NC-SI based PHY" - depends on NET + depends on NET_LEGACY endif #PHYLIB diff --git a/drivers/net/phy/adin.c b/drivers/net/phy/adin.c index ce448810ff6..4d42e56dada 100644 --- a/drivers/net/phy/adin.c +++ b/drivers/net/phy/adin.c @@ -10,6 +10,7 @@ #include <linux/bitops.h> #include <linux/bitfield.h> +#define PHY_ID_ADIN1200 0x0283bc20 #define PHY_ID_ADIN1300 0x0283bc30 #define ADIN1300_EXT_REG_PTR 0x10 #define ADIN1300_EXT_REG_DATA 0x11 @@ -263,6 +264,18 @@ static int adin1300_config(struct phy_device *phydev) return genphy_config(phydev); } +U_BOOT_PHY_DRIVER(ADIN1200) = { + .name = "ADIN1200", + .uid = PHY_ID_ADIN1200, + .mask = 0xffffffff, + .features = PHY_BASIC_FEATURES, + .config = adin1300_config, + .startup = genphy_startup, + .shutdown = genphy_shutdown, + .readext = adin_extread, + .writeext = adin_extwrite, +}; + U_BOOT_PHY_DRIVER(ADIN1300) = { .name = "ADIN1300", .uid = PHY_ID_ADIN1300, diff --git a/drivers/net/phy/airoha/Kconfig b/drivers/net/phy/airoha/Kconfig index da8747939e3..2d58d674200 100644 --- a/drivers/net/phy/airoha/Kconfig +++ b/drivers/net/phy/airoha/Kconfig @@ -2,11 +2,25 @@ menuconfig PHY_AIROHA bool "Airoha Ethernet PHYs support" +config PHY_AIROHA_AN8801 + bool "Airoha Ethernet AN8801 support" + depends on PHY_AIROHA + select PHY_AIROHA_PHYLIB + help + Currently support AIROHA AN8801 1G PHY. + config PHY_AIROHA_EN8811 bool "Airoha Ethernet EN8811H support" depends on PHY_AIROHA depends on SUPPORTS_FW_LOADER select FW_LOADER + select PHY_AIROHA_PHYLIB + select PHY_COMMON_PROPS help AIROHA EN8811H supported. AIROHA AN8811HB supported. + +config PHY_AIROHA_PHYLIB + bool + help + Airoha Ethernet PHY common library diff --git a/drivers/net/phy/airoha/Makefile b/drivers/net/phy/airoha/Makefile index 84d23b19ab0..25e44004cfd 100644 --- a/drivers/net/phy/airoha/Makefile +++ b/drivers/net/phy/airoha/Makefile @@ -1,3 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PHY_AIROHA_AN8801) += air_an8801.o obj-$(CONFIG_PHY_AIROHA_EN8811) += air_en8811.o +obj-$(CONFIG_PHY_AIROHA_PHYLIB) += air_phy_lib.o diff --git a/drivers/net/phy/airoha/air_an8801.c b/drivers/net/phy/airoha/air_an8801.c new file mode 100644 index 00000000000..9d9958fc665 --- /dev/null +++ b/drivers/net/phy/airoha/air_an8801.c @@ -0,0 +1,594 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * air_an8801.c - PHY driver for Airoha AN8801. + * Copyright (c) 2026 Airoha Technology Corp. + * Copyright (C) 2026 BayLibre, SAS. + * Author: Kevin-KW Huang <[email protected]> + * Sita Huang <[email protected]> + * Julien Stephan <[email protected]> + */ + +#include <malloc.h> +#include <phy.h> +#include <dm/device_compat.h> + +#include "air_phy_lib.h" + +#define AN8801R_PHY_ID1 0xc0ff +#define AN8801R_PHY_ID2 0x0421 +#define AN8801R_PHY_ID ((u32)((AN8801R_PHY_ID1 << 16) | AN8801R_PHY_ID2)) + +#define AN8801R_MAX_LED_SIZE 3 + +/* MII Registers - Airoha Page 4 */ +#define AN8801_PBUS_ACCESS BIT(28) + +/* BPBUS Registers */ +#define AN8801_BPBUS_REG_LED_GPIO 0x54 +#define AN8801_BPBUS_REG_LED_ID_SEL 0x58 +#define LED_ID_GPIO_SEL(led, gpio) ((led) << ((gpio) * 3)) + +#define AN8801_BPBUS_REG_GPIO_MODE 0x70 + +#define AN8801_BPBUS_REG_LINK_MODE 0x5054 +#define AN8801_BPBUS_LINK_MODE_1000 BIT(0) + +#define AN8801_BPBUS_REG_BYPASS_PTP 0x21c004 +#define AN8801_BYP_PTP_RGMII_TO_GPHY BIT(0) + +#define AN8801_BPBUS_REG_TXDLY_STEP 0x21c024 +#define RGMII_DELAY_STEP_MASK GENMASK(2, 0) +#define AIR_RGMII_DELAY_NOSTEP 0 +#define AIR_RGMII_DELAY_STEP_1 1 +#define AIR_RGMII_DELAY_STEP_2 2 +#define AIR_RGMII_DELAY_STEP_3 3 +#define AIR_RGMII_DELAY_STEP_4 4 +#define AIR_RGMII_DELAY_STEP_5 5 +#define AIR_RGMII_DELAY_STEP_6 6 +#define AIR_RGMII_DELAY_STEP_7 7 +#define RGMII_TXDELAY_FORCE_MODE BIT(24) + +#define AN8801_BPBUS_REG_RXDLY_STEP 0x21c02c +#define RGMII_RXDELAY_ALIGN BIT(4) +#define RGMII_RXDELAY_FORCE_MODE BIT(24) + +#define AN8801_BPBUS_REG_EFIFO_CTL(x) (0x270004 + (0x100 * (x))) /* 0..2 */ +#define AN8801_EFIFO_ALL_EN GENMASK(7, 0) +#define AN8801_EFIFO_RX_EN BIT(0) +#define AN8801_EFIFO_TX_EN BIT(1) +#define AN8801_EFIFO_RX_CLK_EN BIT(2) +#define AN8801_EFIFO_TX_CLK_EN BIT(3) +#define AN8801_EFIFO_RX_EEE_EN BIT(4) +#define AN8801_EFIFO_TX_EEE_EN BIT(5) +#define AN8801_EFIFO_RX_ODD_NIBBLE_EN BIT(6) +#define AN8801_EFIFO_TX_ODD_NIBBLE_EN BIT(7) + +#define AN8801_BPBUS_REG_HWRST_DE_GLITCH 0xc8 +#define AN8801_DE_GLITCH_EN BIT(2) +#define AN8801_11_CYCLE_XTAL_PERIOD_DE_GLITCH GENMASK(1, 0) + +#define LED_BCR 0x21 +#define LED_BCR_MODE_MASK GENMASK(1, 0) +#define LED_BCR_TIME_TEST BIT(2) +#define LED_BCR_CLK_EN BIT(3) +#define LED_BCR_EVT_ALL BIT(4) +#define LED_BCR_EXT_CTRL BIT(15) +#define LED_BCR_MODE_DISABLE 0 +#define LED_BCR_MODE_2LED 1 +#define LED_BCR_MODE_3LED_1 2 +#define LED_BCR_MODE_3LED_2 3 + +#define LED_ON_DUR 0x22 +#define LED_ON_DUR_MASK GENMASK(15, 0) + +#define LED_BLINK_DUR 0x23 +#define LED_BLINK_DUR_MASK GENMASK(15, 0) + +#define LED_ON_CTRL(i) (0x024 + ((i) * 2)) +#define LED_ON_EVT_MASK GENMASK(6, 0) +#define LED_ON_EVT_LINK_1000M BIT(0) +#define LED_ON_EVT_LINK_100M BIT(1) +#define LED_ON_EVT_LINK_10M BIT(2) +#define LED_ON_EVT_LINK_DN BIT(3) +#define LED_ON_EVT_FDX BIT(4) +#define LED_ON_EVT_HDX BIT(5) +#define LED_ON_EVT_FORCE BIT(6) +#define LED_ON_POL BIT(14) +#define LED_ON_EN BIT(15) + +#define LED_BLINK_CTRL(i) (0x025 + ((i) * 2)) +#define LED_BLINK_EVT_MASK GENMASK(9, 0) +#define LED_BLINK_EVT_1000M_TX BIT(0) +#define LED_BLINK_EVT_1000M_RX BIT(1) +#define LED_BLINK_EVT_100M_TX BIT(2) +#define LED_BLINK_EVT_100M_RX BIT(3) +#define LED_BLINK_EVT_10M_TX BIT(4) +#define LED_BLINK_EVT_10M_RX BIT(5) +#define LED_BLINK_EVT_FORCE BIT(9) + +#define UNIT_LED_BLINK_DURATION 780 +#define LED_BLINK_DURATION(f) (UNIT_LED_BLINK_DURATION << (f)) + +/* Link on(1G/100M/10M), no activity */ +#define AIR_LED0_ON \ + (LED_ON_EVT_LINK_1000M | LED_ON_EVT_LINK_100M | LED_ON_EVT_LINK_10M) +#define AIR_LED0_BLINK 0x0 +/* No link on, activity(1G/100M/10M TX/RX) */ +#define AIR_LED1_ON 0x0 +#define AIR_LED1_BLINK \ + (LED_BLINK_EVT_1000M_TX | LED_BLINK_EVT_1000M_RX | \ + LED_BLINK_EVT_100M_TX | LED_BLINK_EVT_100M_RX | \ + LED_BLINK_EVT_10M_TX | LED_BLINK_EVT_10M_RX) +/* Link on(100M/10M), activity(100M/10M TX/RX) */ +#define AIR_LED2_ON \ + (LED_ON_EVT_LINK_100M | LED_ON_EVT_LINK_10M) +#define AIR_LED2_BLINK \ + (LED_BLINK_EVT_100M_TX | LED_BLINK_EVT_100M_RX | \ + LED_BLINK_EVT_10M_TX | LED_BLINK_EVT_10M_RX) + +#define INVALID_DATA GENMASK(31, 0) + +#define AN8801_REG_PHY_INTERNAL0 0x600 +#define AN8801_REG_PHY_INTERNAL1 0x601 + +#define AN8801_LED_ENABLE 1 + +enum air_led_gpio_pin { + AIR_LED_GPIO1 = 1, + AIR_LED_GPIO2, + AIR_LED_GPIO3 +}; + +enum air_led { + AIR_LED0 = 0, + AIR_LED1, + AIR_LED2, + AIR_LED3 +}; + +enum air_led_blink_dut { + AIR_LED_BLINK_DUR_32M = 0, + AIR_LED_BLINK_DUR_64M, + AIR_LED_BLINK_DUR_128M, + AIR_LED_BLINK_DUR_256M, + AIR_LED_BLINK_DUR_512M, + AIR_LED_BLINK_DUR_1024M, + AIR_LED_BLINK_DUR_LAST +}; + +enum air_led_polarity { + AIR_ACTIVE_LOW = 0, + AIR_ACTIVE_HIGH, +}; + +enum air_led_mode { + AIR_LED_MODE_DISABLE = 0, + AIR_LED_MODE_USER_DEFINE, + AIR_LED_MODE_LAST +}; + +struct air_led_cfg { + u16 led_en; + u16 gpio; + u16 led_polarity; + u16 led_on_cfg; + u16 led_blk_cfg; +}; + +struct an8801r_priv { + struct air_led_cfg led_cfg[AN8801R_MAX_LED_SIZE]; + u32 led_blink_cfg; + u8 rxdelay_force; + u8 txdelay_force; + u16 rxdelay_step; + u8 rxdelay_align; + u16 txdelay_step; +}; + +#define phydev_cfg(phy) ((struct an8801r_priv *)(phy)->priv) + +/* + * GPIO1 <-> LED0, + * GPIO2 <-> LED1, + * GPIO3 <-> LED2, + */ +static const struct an8801r_priv an8801r_priv_defaults = { + .led_cfg = { + /* LED Enable, GPIO, LED Polarity, LED ON, LED Blink */ + {AN8801_LED_ENABLE, AIR_LED_GPIO1, AIR_ACTIVE_LOW, AIR_LED0_ON, AIR_LED0_BLINK}, + {AN8801_LED_ENABLE, AIR_LED_GPIO2, AIR_ACTIVE_HIGH, AIR_LED1_ON, AIR_LED1_BLINK}, + {AN8801_LED_ENABLE, AIR_LED_GPIO3, AIR_ACTIVE_HIGH, AIR_LED2_ON, AIR_LED2_BLINK}, + }, + .led_blink_cfg = AIR_LED_BLINK_DUR_64M, + .rxdelay_force = false, + .txdelay_force = false, + .rxdelay_step = AIR_RGMII_DELAY_NOSTEP, + .rxdelay_align = false, + .txdelay_step = AIR_RGMII_DELAY_NOSTEP, +}; + +static int an8801_buckpbus_reg_rmw(struct phy_device *phydev, + u32 addr, u32 mask, u32 set) +{ + return air_phy_buckpbus_reg_modify(phydev, + addr | AN8801_PBUS_ACCESS, + mask, set); +} + +static int an8801_buckpbus_reg_set_bits(struct phy_device *phydev, + u32 addr, u32 mask) +{ + return air_phy_buckpbus_reg_modify(phydev, + addr | AN8801_PBUS_ACCESS, + mask, mask); +} + +static int an8801_buckpbus_reg_clear_bits(struct phy_device *phydev, + u32 addr, u32 mask) +{ + return air_phy_buckpbus_reg_modify(phydev, + addr | AN8801_PBUS_ACCESS, + mask, 0); +} + +static int an8801_buckpbus_reg_write(struct phy_device *phydev, u32 addr, u32 data) +{ + return air_phy_buckpbus_reg_write(phydev, addr | AN8801_PBUS_ACCESS, data); +} + +static int an8801r_led_set_usr_def(struct phy_device *phydev, u8 entity, + u16 polar, u16 on_evt, u16 blk_evt) +{ + int ret; + + if (polar == AIR_ACTIVE_HIGH) + on_evt |= LED_ON_POL; + else + on_evt &= ~LED_ON_POL; + + on_evt |= LED_ON_EN; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(entity), on_evt); + if (ret) + return ret; + + return phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(entity), blk_evt); +} + +static int an8801r_led_set_blink(struct phy_device *phydev, u16 blink) +{ + int ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_DUR, + LED_BLINK_DURATION(blink)); + if (ret) + return ret; + + return phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_ON_DUR, + LED_BLINK_DURATION(blink) / 2); +} + +static int an8801r_led_set_mode(struct phy_device *phydev, u8 mode) +{ + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, LED_BCR); + if (ret < 0) + return ret; + + switch (mode) { + case AIR_LED_MODE_DISABLE: + ret &= ~LED_BCR_EXT_CTRL; + ret &= ~LED_BCR_MODE_MASK; + ret |= LED_BCR_MODE_DISABLE; + break; + case AIR_LED_MODE_USER_DEFINE: + ret |= LED_BCR_EXT_CTRL | LED_BCR_CLK_EN; + break; + } + return phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_BCR, ret); +} + +static int an8801r_led_set_state(struct phy_device *phydev, u8 entity, u8 state) +{ + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(entity)); + if (ret < 0) + return ret; + + if (state) + ret |= LED_ON_EN; + else + ret &= ~LED_ON_EN; + + return phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(entity), ret); +} + +static int an8801r_led_init(struct phy_device *phydev) +{ + struct an8801r_priv *priv = phydev_cfg(phydev); + struct air_led_cfg *led_cfg = priv->led_cfg; + u16 led_blink_cfg = priv->led_blink_cfg; + int ret, led_id; + + ret = an8801r_led_set_blink(phydev, led_blink_cfg); + if (ret) + return ret; + + ret = an8801r_led_set_mode(phydev, AIR_LED_MODE_USER_DEFINE); + if (ret) { + dev_err(phydev->dev, "AN8801R: Fail to set LED mode, ret %d!\n", ret); + return ret; + } + + for (led_id = AIR_LED0; led_id < AN8801R_MAX_LED_SIZE; led_id++) { + ret = an8801r_led_set_state(phydev, led_id, led_cfg[led_id].led_en); + if (ret) { + dev_err(phydev->dev, "AN8801R: Fail to set LED%d state, ret %d!\n", + led_id, ret); + return ret; + } + + if (!led_cfg[led_id].led_en) + continue; + + ret = an8801_buckpbus_reg_set_bits(phydev, AN8801_BPBUS_REG_LED_GPIO, + BIT(led_cfg[led_id].gpio)); + if (ret) + return ret; + + ret = an8801_buckpbus_reg_set_bits(phydev, AN8801_BPBUS_REG_LED_ID_SEL, + LED_ID_GPIO_SEL(led_id, + led_cfg[led_id].gpio)); + if (ret) + return ret; + + ret = an8801_buckpbus_reg_clear_bits(phydev, AN8801_BPBUS_REG_GPIO_MODE, + BIT(led_cfg[led_id].gpio)); + if (ret) + return ret; + + ret = an8801r_led_set_usr_def(phydev, led_id, + led_cfg[led_id].led_polarity, + led_cfg[led_id].led_on_cfg, + led_cfg[led_id].led_blk_cfg); + if (ret) { + dev_err(phydev->dev, "AN8801R: Fail to set LED%d, ret %d!\n", + led_id, ret); + return ret; + } + } + return 0; +} + +static int an8801r_of_init(struct phy_device *phydev) +{ + struct an8801r_priv *priv = phydev_cfg(phydev); + ofnode node = phy_get_ofnode(phydev); + u32 val = 0; + int ret; + + if (!ofnode_valid(node)) + return -EINVAL; + + if (ofnode_has_property(node, "airoha,rxclk-delay")) { + ret = ofnode_read_u32(node, "airoha,rxclk-delay", &val); + if (ret) { + dev_err(phydev->dev, "airoha,rxclk-delay value is invalid.\n"); + return ret; + } + if (val > AIR_RGMII_DELAY_STEP_7) { + dev_err(phydev->dev, "airoha,rxclk-delay value %u out of range.\n", val); + return -EINVAL; + } + priv->rxdelay_force = true; + priv->rxdelay_step = val; + priv->rxdelay_align = ofnode_read_bool(node, + "airoha,rxclk-delay-align"); + } + + if (ofnode_has_property(node, "airoha,txclk-delay")) { + ret = ofnode_read_u32(node, "airoha,txclk-delay", &val); + if (ret) { + dev_err(phydev->dev, "airoha,txclk-delay value is invalid.\n"); + return ret; + } + if (val > AIR_RGMII_DELAY_STEP_7) { + dev_err(phydev->dev, "airoha,txclk-delay value %u out of range.\n", val); + return -EINVAL; + } + priv->txdelay_force = true; + priv->txdelay_step = val; + } + return 0; +} + +static int an8801r_rgmii_rxdelay(struct phy_device *phydev, u16 delay, u8 align) +{ + u32 reg_val = delay & RGMII_DELAY_STEP_MASK; + int ret; + + if (align) { + reg_val |= RGMII_RXDELAY_ALIGN; + debug("AN8801R: Rxdelay align\n"); + } + reg_val |= RGMII_RXDELAY_FORCE_MODE; + ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_RXDLY_STEP, reg_val); + if (ret) + return ret; + + debug("AN8801R: Force rxdelay = %d(0x%x)\n", delay, reg_val); + return 0; +} + +static int an8801r_rgmii_txdelay(struct phy_device *phydev, u16 delay) +{ + u32 reg_val = delay & RGMII_DELAY_STEP_MASK; + int ret; + + reg_val |= RGMII_TXDELAY_FORCE_MODE; + ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_TXDLY_STEP, reg_val); + if (ret) + return ret; + + debug("AN8801R: Force txdelay = %d(0x%x)\n", delay, reg_val); + return 0; +} + +static int an8801r_rgmii_delay_config(struct phy_device *phydev) +{ + struct an8801r_priv *priv = phydev_cfg(phydev); + int ret; + + switch (phydev->interface) { + case PHY_INTERFACE_MODE_RGMII_TXID: + return an8801r_rgmii_txdelay(phydev, AIR_RGMII_DELAY_STEP_4); + case PHY_INTERFACE_MODE_RGMII_RXID: + return an8801r_rgmii_rxdelay(phydev, AIR_RGMII_DELAY_NOSTEP, true); + case PHY_INTERFACE_MODE_RGMII_ID: + ret = an8801r_rgmii_txdelay(phydev, AIR_RGMII_DELAY_STEP_4); + if (ret) + return ret; + return an8801r_rgmii_rxdelay(phydev, AIR_RGMII_DELAY_NOSTEP, true); + case PHY_INTERFACE_MODE_RGMII: + default: + if (priv->rxdelay_force) { + ret = an8801r_rgmii_rxdelay(phydev, priv->rxdelay_step, + priv->rxdelay_align); + if (ret) + return ret; + } + if (priv->txdelay_force) + return an8801r_rgmii_txdelay(phydev, priv->txdelay_step); + return 0; + } +} + +static int an8801r_config_init(struct phy_device *phydev) +{ + int ret; + + ret = an8801r_of_init(phydev); + if (ret < 0) + return ret; + + ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_HWRST_DE_GLITCH, + AN8801_DE_GLITCH_EN | + AN8801_11_CYCLE_XTAL_PERIOD_DE_GLITCH); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AN8801_REG_PHY_INTERNAL0, 0x1e); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AN8801_REG_PHY_INTERNAL1, 0x02); + if (ret) + return ret; + + ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0); + if (ret) + return ret; + + ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_BYPASS_PTP, + AN8801_BYP_PTP_RGMII_TO_GPHY); + if (ret) + return ret; + + ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(0), + AN8801_EFIFO_RX_EN | + AN8801_EFIFO_TX_EN | + AN8801_EFIFO_RX_CLK_EN | + AN8801_EFIFO_TX_CLK_EN | + AN8801_EFIFO_RX_EEE_EN | + AN8801_EFIFO_TX_EEE_EN); + if (ret) + return ret; + + ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(1), + AN8801_EFIFO_ALL_EN); + if (ret) + return ret; + + ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(2), + AN8801_EFIFO_ALL_EN); + if (ret) + return ret; + + ret = an8801r_rgmii_delay_config(phydev); + if (ret) + return ret; + + ret = an8801r_led_init(phydev); + if (ret) { + dev_err(phydev->dev, "AN8801R: LED initialize fail, ret %d!\n", ret); + return ret; + } + return 0; +} + +static int an8801r_phy_probe(struct phy_device *phydev) +{ + struct an8801r_priv *priv; + u32 phy_id; + int ret; + + ret = get_phy_id(phydev->bus, phydev->addr, MDIO_DEVAD_NONE, &phy_id); + if (ret) + return ret; + + if (phy_id != AN8801R_PHY_ID) { + dev_err(phydev->dev, + "AN8801R can't be detected (id=0x%08x).\n", phy_id); + return -ENODEV; + } + + priv = malloc(sizeof(*priv)); + if (!priv) + return -ENOMEM; + + *priv = an8801r_priv_defaults; + + phydev->priv = priv; + + return 0; +} + +static int an8801r_read_status(struct phy_device *phydev) +{ + u32 data; + + if (!phydev->link) + return 0; + + debug("AN8801R: SPEED %d\n", phydev->speed); + data = phydev->speed == SPEED_1000 ? AN8801_BPBUS_LINK_MODE_1000 : 0; + + return an8801_buckpbus_reg_rmw(phydev, AN8801_BPBUS_REG_LINK_MODE, + AN8801_BPBUS_LINK_MODE_1000, data); +} + +static int an8801r_startup(struct phy_device *phydev) +{ + int ret; + + ret = genphy_startup(phydev); + if (ret) + return ret; + + return an8801r_read_status(phydev); +} + +U_BOOT_PHY_DRIVER(an8801r) = { + .name = "Airoha AN8801R", + .uid = AN8801R_PHY_ID, + .mask = 0x0ffffff0, + .features = PHY_GBIT_FEATURES, + .probe = &an8801r_phy_probe, + .config = &an8801r_config_init, + .read_page = &air_phy_read_page, + .write_page = &air_phy_write_page, + .startup = &an8801r_startup, + .shutdown = &genphy_shutdown, +}; diff --git a/drivers/net/phy/airoha/air_en8811.c b/drivers/net/phy/airoha/air_en8811.c index 0b974472732..7a07be2e956 100644 --- a/drivers/net/phy/airoha/air_en8811.c +++ b/drivers/net/phy/airoha/air_en8811.c @@ -23,6 +23,9 @@ #include <linux/compat.h> #include <dm/device_compat.h> #include <u-boot/crc.h> +#include <linux/phy/phy-common-props.h> + +#include "air_phy_lib.h" /* MII Registers */ #define AIR_AUX_CTRL_STATUS 0x1d @@ -32,10 +35,6 @@ #define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8 #define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc -#define AIR_EXT_PAGE_ACCESS 0x1f -#define AIR_PHY_PAGE_STANDARD 0x0000 -#define AIR_PHY_PAGE_EXTENDED_4 0x0004 - #define AIR_PBUS_MODE_ADDR_HIGH 0x1c /* MII Registers Page 4 */ #define AIR_BPBUS_MODE 0x10 @@ -309,166 +308,6 @@ static int air_pbus_reg_write(struct phy_device *phydev, return ret; } -static int air_buckpbus_reg_write(struct phy_device *phydev, - u32 pbus_address, u32 pbus_data) -{ - int ret, saved_page; - - saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); - if (saved_page < 0) - return saved_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, - AIR_BPBUS_MODE_ADDR_FIXED); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH, - upper_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW, - lower_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH, - upper_16_bits(pbus_data)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW, - lower_16_bits(pbus_data)); - if (ret < 0) - goto restore_page; - -restore_page: - if (ret < 0) - dev_err(phydev->dev, "%s 0x%08x failed: %d\n", __func__, - pbus_address, ret); - - return phy_restore_page(phydev, saved_page, ret); -} - -static int air_buckpbus_reg_read(struct phy_device *phydev, - u32 pbus_address, u32 *pbus_data) -{ - int pbus_data_low, pbus_data_high; - int ret = 0, saved_page; - - saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); - if (saved_page < 0) - return saved_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, - AIR_BPBUS_MODE_ADDR_FIXED); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH, - upper_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW, - lower_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_HIGH); - if (pbus_data_high < 0) { - ret = pbus_data_high; - goto restore_page; - } - - pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_LOW); - if (pbus_data_low < 0) { - ret = pbus_data_low; - goto restore_page; - } - - *pbus_data = pbus_data_low | (pbus_data_high << 16); - -restore_page: - if (ret < 0) - dev_err(phydev->dev, "%s 0x%08x failed: %d\n", __func__, - pbus_address, ret); - - return phy_restore_page(phydev, saved_page, ret); -} - -static int air_buckpbus_reg_modify(struct phy_device *phydev, - u32 pbus_address, u32 mask, u32 set) -{ - int pbus_data_low, pbus_data_high; - u32 pbus_data_old, pbus_data_new; - int ret = 0, saved_page; - - saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); - if (saved_page < 0) - return saved_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, - AIR_BPBUS_MODE_ADDR_FIXED); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH, - upper_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW, - lower_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_HIGH); - if (pbus_data_high < 0) { - ret = pbus_data_high; - goto restore_page; - } - - pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_DATA_LOW); - if (pbus_data_low < 0) { - ret = pbus_data_low; - goto restore_page; - } - - pbus_data_old = pbus_data_low | (pbus_data_high << 16); - pbus_data_new = (pbus_data_old & ~mask) | set; - if (pbus_data_new == pbus_data_old) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH, - upper_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW, - lower_16_bits(pbus_address)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH, - upper_16_bits(pbus_data_new)); - if (ret < 0) - goto restore_page; - - ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW, - lower_16_bits(pbus_data_new)); - if (ret < 0) - goto restore_page; - -restore_page: - if (ret < 0) - dev_err(phydev->dev, "%s 0x%08x failed: %d\n", __func__, - pbus_address, ret); - - return phy_restore_page(phydev, saved_page, ret); -} - static int air_write_buf(struct phy_device *phydev, unsigned long address, unsigned long array_size, const unsigned char *buffer) { @@ -539,12 +378,12 @@ static int an8811hb_check_crc(struct phy_device *phydev, u32 pbus_value; /* Configure CRC */ - ret = air_buckpbus_reg_modify(phydev, set1, AN8811HB_CRC_RD_EN, - AN8811HB_CRC_RD_EN); + ret = air_phy_buckpbus_reg_modify(phydev, set1, AN8811HB_CRC_RD_EN, + AN8811HB_CRC_RD_EN); if (ret < 0) return ret; - ret = air_buckpbus_reg_read(phydev, set1, &pbus_value); + ret = air_phy_buckpbus_reg_read(phydev, set1, &pbus_value); if (ret < 0) return ret; @@ -553,14 +392,14 @@ static int an8811hb_check_crc(struct phy_device *phydev, do { mdelay(300); - ret = air_buckpbus_reg_read(phydev, mon2, &pbus_value); + ret = air_phy_buckpbus_reg_read(phydev, mon2, &pbus_value); if (ret < 0) return ret; debug("%d: reg 0x%x val 0x%x!\n", __LINE__, mon2, pbus_value); if (pbus_value & AN8811HB_CRC_ST) { - ret = air_buckpbus_reg_read(phydev, mon3, &pbus_value); + ret = air_phy_buckpbus_reg_read(phydev, mon3, &pbus_value); if (ret < 0) return ret; @@ -584,11 +423,11 @@ static int an8811hb_check_crc(struct phy_device *phydev, } } while (--retry); - ret = air_buckpbus_reg_modify(phydev, set1, AN8811HB_CRC_RD_EN, 0); + ret = air_phy_buckpbus_reg_modify(phydev, set1, AN8811HB_CRC_RD_EN, 0); if (ret < 0) return ret; - ret = air_buckpbus_reg_read(phydev, set1, &pbus_value); + ret = air_phy_buckpbus_reg_read(phydev, set1, &pbus_value); if (ret < 0) return ret; @@ -646,9 +485,9 @@ static int an8811hb_surge_protect_cfg(struct phy_device *phydev) return ret; } - ret = air_buckpbus_reg_modify(phydev, AIR_PHY_CONTROL, - AIR_PHY_CONTROL_SURGE_5R, - AIR_PHY_CONTROL_SURGE_5R); + ret = air_phy_buckpbus_reg_modify(phydev, AIR_PHY_CONTROL, + AIR_PHY_CONTROL_SURGE_5R, + AIR_PHY_CONTROL_SURGE_5R); if (ret < 0) return ret; @@ -706,14 +545,14 @@ static int en8811h_load_firmware(struct phy_device *phydev) goto en8811h_load_firmware_out; } - ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, - EN8811H_FW_CTRL_1_START); + ret = air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_START); if (ret < 0) goto en8811h_load_firmware_out; - ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, - EN8811H_FW_CTRL_2_LOADING, - EN8811H_FW_CTRL_2_LOADING); + ret = air_phy_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, + EN8811H_FW_CTRL_2_LOADING, + EN8811H_FW_CTRL_2_LOADING); if (ret < 0) goto en8811h_load_firmware_out; @@ -727,13 +566,13 @@ static int en8811h_load_firmware(struct phy_device *phydev) if (ret < 0) goto en8811h_load_firmware_out; - ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, - EN8811H_FW_CTRL_2_LOADING, 0); + ret = air_phy_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2, + EN8811H_FW_CTRL_2_LOADING, 0); if (ret < 0) goto en8811h_load_firmware_out; - ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, - EN8811H_FW_CTRL_1_FINISH); + ret = air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_FINISH); if (ret < 0) goto en8811h_load_firmware_out; @@ -741,8 +580,8 @@ static int en8811h_load_firmware(struct phy_device *phydev) if (ret < 0) goto en8811h_load_firmware_out; - air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, - &priv->firmware_version); + air_phy_buckpbus_reg_read(phydev, EN8811H_FW_VERSION, + &priv->firmware_version); dev_info(phydev->dev, "MD32 firmware version: %08x\n", priv->firmware_version); @@ -778,8 +617,8 @@ static int an8811hb_load_firmware(struct phy_device *phydev) if (ret < 0) goto an8811hb_load_firmware_out; - ret = air_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1, - AIR_PHY_FW_CTRL_1_START); + ret = air_phy_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1, + AIR_PHY_FW_CTRL_1_START); if (ret < 0) goto an8811hb_load_firmware_out; @@ -803,8 +642,8 @@ static int an8811hb_load_firmware(struct phy_device *phydev) if (ret < 0) goto an8811hb_load_firmware_out; - ret = air_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1, - AIR_PHY_FW_CTRL_1_FINISH); + ret = air_phy_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1, + AIR_PHY_FW_CTRL_1_FINISH); if (ret < 0) goto an8811hb_load_firmware_out; @@ -817,7 +656,7 @@ static int an8811hb_load_firmware(struct phy_device *phydev) do { mdelay(300); - ret = air_buckpbus_reg_read(phydev, AIR_PHY_FW_CTRL_1, ®_val); + ret = air_phy_buckpbus_reg_read(phydev, AIR_PHY_FW_CTRL_1, ®_val); if (ret < 0) goto an8811hb_load_firmware_out; @@ -827,8 +666,8 @@ static int an8811hb_load_firmware(struct phy_device *phydev) debug("%d: reg 0x%x val 0x%x!\n", __LINE__, AIR_PHY_FW_CTRL_1, reg_val); - ret = air_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1, - AIR_PHY_FW_CTRL_1_FINISH); + ret = air_phy_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1, + AIR_PHY_FW_CTRL_1_FINISH); if (ret < 0) goto an8811hb_load_firmware_out; @@ -838,8 +677,8 @@ static int an8811hb_load_firmware(struct phy_device *phydev) if (ret < 0) goto an8811hb_load_firmware_out; - air_buckpbus_reg_read(phydev, AIR_PHY_MD32FW_VERSION, - &priv->firmware_version); + air_phy_buckpbus_reg_read(phydev, AIR_PHY_MD32FW_VERSION, + &priv->firmware_version); debug("MD32 firmware version: %08x\n", priv->firmware_version); @@ -858,17 +697,17 @@ int an8811hb_cko_cfg(struct phy_device *phydev) int ret = 0; if (!ofnode_read_bool(node, "airoha,phy-output-clock")) { - ret = air_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV, - AN8811HB_CLK_DRV_CKO_MASK, - AN8811HB_CLK_DRV_CKOPWD | - AN8811HB_CLK_DRV_CKO_LDPWD | - AN8811HB_CLK_DRV_CKO_LPPWD); + ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV, + AN8811HB_CLK_DRV_CKO_MASK, + AN8811HB_CLK_DRV_CKOPWD | + AN8811HB_CLK_DRV_CKO_LDPWD | + AN8811HB_CLK_DRV_CKO_LPPWD); if (ret < 0) return ret; debug("CKO Output mode - Disabled\n"); } else { - ret = air_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value); + ret = air_phy_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value); if (ret < 0) return ret; @@ -887,13 +726,13 @@ static int en8811h_restart_mcu(struct phy_device *phydev) if (ret < 0) return ret; - ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, - EN8811H_FW_CTRL_1_START); + ret = air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_START); if (ret < 0) return ret; - return air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, - EN8811H_FW_CTRL_1_FINISH); + return air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1, + EN8811H_FW_CTRL_1_FINISH); } static int air_led_hw_control_set(struct phy_device *phydev, u8 index, @@ -1046,11 +885,51 @@ static int air_leds_init(struct phy_device *phydev, int num, u16 dur, int mode) return 0; } -static int en8811h_config(struct phy_device *phydev) +static int en8811h_config_serdes_polarity(struct phy_device *phydev) { - struct en8811h_priv *priv = phydev->priv; ofnode node = phy_get_ofnode(phydev); + unsigned int pol, default_pol; u32 pbus_value = 0; + int ret; + + if (!ofnode_valid(node)) + return 0; + + default_pol = PHY_POL_NORMAL; + if (ofnode_read_bool(node, "airoha,pnswap-rx")) + default_pol = PHY_POL_INVERT; + + ret = phy_get_rx_polarity(node, + phy_string_for_interface(phydev->interface), + BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT), + default_pol, &pol); + if (ret) + return ret; + if (pol == PHY_POL_INVERT) + pbus_value |= EN8811H_POLARITY_RX_REVERSE; + + default_pol = PHY_POL_NORMAL; + if (ofnode_read_bool(node, "airoha,pnswap-tx")) + default_pol = PHY_POL_INVERT; + + ret = phy_get_tx_polarity(node, + phy_string_for_interface(phydev->interface), + BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT), + default_pol, &pol); + if (ret) + return ret; + if (pol == PHY_POL_NORMAL) + pbus_value |= EN8811H_POLARITY_TX_NORMAL; + + return air_phy_buckpbus_reg_modify(phydev, EN8811H_POLARITY, + EN8811H_POLARITY_RX_REVERSE | + EN8811H_POLARITY_TX_NORMAL, + pbus_value); +} + +static int en8811h_config(struct phy_device *phydev) +{ + struct en8811h_priv *priv = phydev->priv; int ret = 0; /* If restart happened in .probe(), no need to restart now */ @@ -1081,20 +960,8 @@ static int en8811h_config(struct phy_device *phydev) if (ret < 0) return ret; - /* Serdes polarity */ - pbus_value = 0; - if (ofnode_read_bool(node, "airoha,pnswap-rx")) - pbus_value |= EN8811H_POLARITY_RX_REVERSE; - else - pbus_value &= ~EN8811H_POLARITY_RX_REVERSE; - if (ofnode_read_bool(node, "airoha,pnswap-tx")) - pbus_value &= ~EN8811H_POLARITY_TX_NORMAL; - else - pbus_value |= EN8811H_POLARITY_TX_NORMAL; - ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY, - EN8811H_POLARITY_RX_REVERSE | - EN8811H_POLARITY_TX_NORMAL, - pbus_value); + /* Configure Serdes polarity from device tree */ + ret = en8811h_config_serdes_polarity(phydev); if (ret < 0) return ret; @@ -1142,12 +1009,12 @@ static int an8811hb_config(struct phy_device *phydev) priv->mcu_needs_restart = true; } - ret = air_buckpbus_reg_read(phydev, AN8811HB_PRO_ID, &pbus_value); + ret = air_phy_buckpbus_reg_read(phydev, AN8811HB_PRO_ID, &pbus_value); if (ret < 0) return ret; priv->pro_id = (pbus_value & AN8811HB_PRO_ID_VERSION) + 1; - ret = air_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value); + ret = air_phy_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value); if (ret < 0) return ret; priv->pkg_sel = (pbus_value & AN8811HB_HWTRAP2_PKG) >> 12; @@ -1163,8 +1030,8 @@ static int an8811hb_config(struct phy_device *phydev) pbus_value |= AN8811HB_RX_POLARITY_NORMAL; debug("1 pbus_value 0x%x\n", pbus_value); - ret = air_buckpbus_reg_modify(phydev, AN8811HB_RX_POLARITY, - AN8811HB_RX_POLARITY_NORMAL, pbus_value); + ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_RX_POLARITY, + AN8811HB_RX_POLARITY_NORMAL, pbus_value); if (ret < 0) return ret; @@ -1175,35 +1042,35 @@ static int an8811hb_config(struct phy_device *phydev) pbus_value |= AN8811HB_TX_POLARITY_NORMAL; debug("2 pbus_value 0x%x\n", pbus_value); - ret = air_buckpbus_reg_modify(phydev, AN8811HB_TX_POLARITY, - AN8811HB_TX_POLARITY_NORMAL, pbus_value); + ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_TX_POLARITY, + AN8811HB_TX_POLARITY_NORMAL, pbus_value); if (ret < 0) return ret; /* Configure led gpio pins as output */ if (priv->pkg_sel) { - ret = air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT, - AN8811HB_GPIO_OUTPUT_MASK, - AN8811HB_GPIO_OUTPUT_0115); + ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT, + AN8811HB_GPIO_OUTPUT_MASK, + AN8811HB_GPIO_OUTPUT_0115); if (ret < 0) return ret; - ret = air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_SEL_1, - AN8811HB_GPIO_SEL_1_0_MASK | - AN8811HB_GPIO_SEL_1_1_MASK, - AN8811HB_GPIO_SEL_1_0 | - AN8811HB_GPIO_SEL_1_1); + ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_GPIO_SEL_1, + AN8811HB_GPIO_SEL_1_0_MASK | + AN8811HB_GPIO_SEL_1_1_MASK, + AN8811HB_GPIO_SEL_1_0 | + AN8811HB_GPIO_SEL_1_1); if (ret < 0) return ret; - ret = air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_SEL_2, - AN8811HB_GPIO_SEL_2_15_MASK, - AN8811HB_GPIO_SEL_2_15); + ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_GPIO_SEL_2, + AN8811HB_GPIO_SEL_2_15_MASK, + AN8811HB_GPIO_SEL_2_15); if (ret < 0) return ret; } else { - ret = air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT, - AN8811HB_GPIO_OUTPUT_345, - AN8811HB_GPIO_OUTPUT_345); + ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT, + AN8811HB_GPIO_OUTPUT_345, + AN8811HB_GPIO_OUTPUT_345); if (ret < 0) return ret; } @@ -1373,16 +1240,6 @@ static int en8811h_probe(struct phy_device *phydev) return 0; } -static int air_phy_read_page(struct phy_device *phydev) -{ - return phy_read(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS); -} - -static int air_phy_write_page(struct phy_device *phydev, int page) -{ - return phy_write(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS, page); -} - U_BOOT_PHY_DRIVER(en8811h) = { .name = "Airoha EN8811H", .uid = EN8811H_PHY_ID, diff --git a/drivers/net/phy/airoha/air_phy_lib.c b/drivers/net/phy/airoha/air_phy_lib.c new file mode 100644 index 00000000000..61c3bf82822 --- /dev/null +++ b/drivers/net/phy/airoha/air_phy_lib.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Airoha Ethernet PHY common library + * + * Copyright (C) 2026 Airoha Technology Corp. + * Copyright (C) 2026 Collabora Ltd. + * Louis-Alexis Eyraud <[email protected]> + * + * Adapated from https://lore.kernel.org/all/20260326-add-airoha-an8801-support-v2-2-1a42d6b6050f@collabora.com/ + */ + +#include <dm/device_compat.h> +#include <linux/compat.h> +#include <phy.h> + +#include "air_phy_lib.h" + +#define AIR_EXT_PAGE_ACCESS 0x1f + +static int __air_buckpbus_reg_read(struct phy_device *phydev, + u32 pbus_address, u32 *pbus_data) +{ + int pbus_data_low, pbus_data_high; + int ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, + AIR_BPBUS_MODE_ADDR_FIXED); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH, + upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW, + lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + + pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, + AIR_BPBUS_RD_DATA_HIGH); + if (pbus_data_high < 0) + return pbus_data_high; + + pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, + AIR_BPBUS_RD_DATA_LOW); + if (pbus_data_low < 0) + return pbus_data_low; + + *pbus_data = pbus_data_low | (pbus_data_high << 16); + return 0; +} + +static int __air_buckpbus_reg_write(struct phy_device *phydev, + u32 pbus_address, u32 pbus_data) +{ + int ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, + AIR_BPBUS_MODE_ADDR_FIXED); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH, + upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW, + lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH, + upper_16_bits(pbus_data)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW, + lower_16_bits(pbus_data)); + if (ret < 0) + return ret; + + return 0; +} + +static int __air_buckpbus_reg_modify(struct phy_device *phydev, + u32 pbus_address, u32 mask, u32 set) +{ + int pbus_data_low, pbus_data_high; + u32 pbus_data_old, pbus_data_new; + int ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_MODE, + AIR_BPBUS_MODE_ADDR_FIXED); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_HIGH, + upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_RD_ADDR_LOW, + lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + + pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, + AIR_BPBUS_RD_DATA_HIGH); + if (pbus_data_high < 0) + return pbus_data_high; + + pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, + AIR_BPBUS_RD_DATA_LOW); + if (pbus_data_low < 0) + return pbus_data_low; + + pbus_data_old = pbus_data_low | (pbus_data_high << 16); + pbus_data_new = (pbus_data_old & ~mask) | set; + if (pbus_data_new == pbus_data_old) + return 0; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_HIGH, + upper_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_ADDR_LOW, + lower_16_bits(pbus_address)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_HIGH, + upper_16_bits(pbus_data_new)); + if (ret < 0) + return ret; + + ret = phy_write(phydev, MDIO_DEVAD_NONE, AIR_BPBUS_WR_DATA_LOW, + lower_16_bits(pbus_data_new)); + if (ret < 0) + return ret; + + return 0; +} + +int air_phy_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address, + u32 *pbus_data) +{ + int saved_page; + int ret = 0; + + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + + if (saved_page >= 0) { + ret = __air_buckpbus_reg_read(phydev, pbus_address, pbus_data); + if (ret < 0) + dev_err(phydev->dev, "%s 0x%08x failed: %d\n", __func__, + pbus_address, ret); + } + + return phy_restore_page(phydev, saved_page, ret); +} + +int air_phy_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address, + u32 pbus_data) +{ + int saved_page; + int ret = 0; + + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + + if (saved_page >= 0) { + ret = __air_buckpbus_reg_write(phydev, pbus_address, + pbus_data); + if (ret < 0) + dev_err(phydev->dev, "%s 0x%08x failed: %d\n", __func__, + pbus_address, ret); + } + + return phy_restore_page(phydev, saved_page, ret); +} + +int air_phy_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_address, + u32 mask, u32 set) +{ + int saved_page; + int ret = 0; + + saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4); + + if (saved_page >= 0) { + ret = __air_buckpbus_reg_modify(phydev, pbus_address, mask, + set); + if (ret < 0) + dev_err(phydev->dev, "%s 0x%08x failed: %d\n", __func__, + pbus_address, ret); + } + + return phy_restore_page(phydev, saved_page, ret); +} + +int air_phy_read_page(struct phy_device *phydev) +{ + return phy_read(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS); +} + +int air_phy_write_page(struct phy_device *phydev, int page) +{ + return phy_write(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS, page); +} + +MODULE_DESCRIPTION("Airoha PHY Library"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Louis-Alexis Eyraud"); diff --git a/drivers/net/phy/airoha/air_phy_lib.h b/drivers/net/phy/airoha/air_phy_lib.h new file mode 100644 index 00000000000..845d2f7cfb4 --- /dev/null +++ b/drivers/net/phy/airoha/air_phy_lib.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2026 Airoha Technology Corp. + * Copyright (C) 2026 Collabora Ltd. + * Louis-Alexis Eyraud <[email protected]> + */ + +#ifndef __AIR_PHY_LIB_H +#define __AIR_PHY_LIB_H + +#define AIR_EXT_PAGE_ACCESS 0x1f + +#define AIR_PHY_PAGE_STANDARD 0x0000 +#define AIR_PHY_PAGE_EXTENDED_1 0x0001 +#define AIR_PHY_PAGE_EXTENDED_4 0x0004 + +/* MII Registers Page 4*/ +#define AIR_BPBUS_MODE 0x10 +#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000 +#define AIR_BPBUS_MODE_ADDR_INCR BIT(15) +#define AIR_BPBUS_WR_ADDR_HIGH 0x11 +#define AIR_BPBUS_WR_ADDR_LOW 0x12 +#define AIR_BPBUS_WR_DATA_HIGH 0x13 +#define AIR_BPBUS_WR_DATA_LOW 0x14 +#define AIR_BPBUS_RD_ADDR_HIGH 0x15 +#define AIR_BPBUS_RD_ADDR_LOW 0x16 +#define AIR_BPBUS_RD_DATA_HIGH 0x17 +#define AIR_BPBUS_RD_DATA_LOW 0x18 + +int air_phy_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_address, + u32 mask, u32 set); +int air_phy_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address, + u32 *pbus_data); +int air_phy_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address, + u32 pbus_data); +int air_phy_read_page(struct phy_device *phydev); +int air_phy_write_page(struct phy_device *phydev, int page); + +#endif /* __AIR_PHY_LIB_H */ diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 10b87dfb8ab..83da3e1cc77 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -400,7 +400,7 @@ int aquantia_config(struct phy_device *phydev) int interface = phydev->interface; u32 val, id, rstatus, fault; u32 reg_val1 = 0; - int num_retries = 5; + int num_retries = 200; int usx_an = 0; /* diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 7ce03b59b6a..ebed61de133 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -203,32 +203,24 @@ static int dp83867_of_init(struct phy_device *phydev) "Should be 'rgmii-id' to use internal delays\n"); } - /* RX delay *must* be specified if internal delay of RX is used. */ + dp83867->rx_id_delay = DP83867_RGMIIDCTL_2_00_NS; if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) { ret = ofnode_read_u32(node, "ti,rx-internal-delay", &dp83867->rx_id_delay); - if (ret) { - pr_debug("ti,rx-internal-delay must be specified\n"); - return ret; - } - if (dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) { + if (!ret && dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) { pr_debug("ti,rx-internal-delay value of %u out of range\n", dp83867->rx_id_delay); return -EINVAL; } } - /* TX delay *must* be specified if internal delay of RX is used. */ + dp83867->tx_id_delay = DP83867_RGMIIDCTL_2_00_NS; if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) { ret = ofnode_read_u32(node, "ti,tx-internal-delay", &dp83867->tx_id_delay); - if (ret) { - debug("ti,tx-internal-delay must be specified\n"); - return ret; - } - if (dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) { + if (!ret && dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) { pr_debug("ti,tx-internal-delay value of %u out of range\n", dp83867->tx_id_delay); return -EINVAL; diff --git a/drivers/net/phy/mscc.c b/drivers/net/phy/mscc.c index a65e81dff0c..d96970949bc 100644 --- a/drivers/net/phy/mscc.c +++ b/drivers/net/phy/mscc.c @@ -23,6 +23,7 @@ #define PHY_ID_VSC8502 0x00070630 #define PHY_ID_VSC8540 0x00070760 #define PHY_ID_VSC8541 0x00070770 +#define PHY_ID_VSC8572 0x000704d0 #define PHY_ID_VSC8574 0x000704a0 #define PHY_ID_VSC8584 0x000707c0 @@ -1612,6 +1613,16 @@ U_BOOT_PHY_DRIVER(vsc8541) = { .shutdown = &genphy_shutdown, }; +U_BOOT_PHY_DRIVER(vsc8572) = { + .name = "Microsemi VSC8572", + .uid = PHY_ID_VSC8572, + .mask = 0x000ffff0, + .features = PHY_GBIT_FEATURES, + .config = &vsc8574_config, + .startup = &mscc_startup, + .shutdown = &genphy_shutdown, +}; + U_BOOT_PHY_DRIVER(vsc8574) = { .name = "Microsemi VSC8574", .uid = PHY_ID_VSC8574, diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c index a1e4c3d053b..9814ac498ed 100644 --- a/drivers/net/phy/nxp-c45-tja11xx.c +++ b/drivers/net/phy/nxp-c45-tja11xx.c @@ -343,7 +343,7 @@ static int nxp_c45_probe(struct phy_device *phydev) { struct nxp_c45_phy *priv; - priv = devm_kzalloc(phydev->priv, sizeof(*priv), GFP_KERNEL); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/net/qe/dm_qe_uec.c b/drivers/net/qe/dm_qe_uec.c index ac3aedd8b49..f9bc5d49c8f 100644 --- a/drivers/net/qe/dm_qe_uec.c +++ b/drivers/net/qe/dm_qe_uec.c @@ -1133,7 +1133,7 @@ static int qe_uec_of_to_plat(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); - pdata->iobase = (phys_addr_t)devfdt_get_addr(dev); + pdata->iobase = (phys_addr_t)dev_read_addr(dev); pdata->phy_interface = dev_read_phy_mode(dev); if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 5b093623619..e203faed26b 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -404,7 +404,7 @@ static int rtl8169_init_board(unsigned long dev_iobase, const char *name) u32 tmp; #ifdef DEBUG_RTL8169 - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif ioaddr = dev_iobase; @@ -534,7 +534,7 @@ static int rtl_recv_common(struct udevice *dev, unsigned long dev_iobase, int length = 0; #ifdef DEBUG_RTL8169_RX - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif ioaddr = dev_iobase; @@ -608,7 +608,7 @@ static int rtl_send_common(struct udevice *dev, unsigned long dev_iobase, #ifdef DEBUG_RTL8169_TX int stime = currticks(); - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); printf("sending %d bytes\n", len); #endif @@ -679,7 +679,7 @@ static void rtl8169_set_rx_mode(void) u32 tmp = 0; #ifdef DEBUG_RTL8169 - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif /* IFF_ALLMULTI */ @@ -701,7 +701,7 @@ static void rtl8169_hw_start(struct udevice *dev) #ifdef DEBUG_RTL8169 int stime = currticks(); - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif #if 0 @@ -771,7 +771,7 @@ static void rtl8169_init_ring(struct udevice *dev) #ifdef DEBUG_RTL8169 int stime = currticks(); - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif tpc->cur_rx = 0; @@ -810,7 +810,7 @@ static void rtl8169_common_start(struct udevice *dev, unsigned char *enetaddr, #ifdef DEBUG_RTL8169 int stime = currticks(); - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif ioaddr = dev_iobase; @@ -851,7 +851,7 @@ static void rtl_halt_common(struct udevice *dev) int i; #ifdef DEBUG_RTL8169 - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif ioaddr = priv->iobase; @@ -906,7 +906,7 @@ static int rtl_init(unsigned long dev_ioaddr, const char *name, int option = -1, Cap10_100 = 0, Cap1000 = 0; #ifdef DEBUG_RTL8169 - printf ("%s\n", __FUNCTION__); + printf("%s\n", __func__); #endif ioaddr = dev_ioaddr; diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c index 0ea50c484c0..e1daeb6c1e6 100644 --- a/drivers/net/sandbox.c +++ b/drivers/net/sandbox.c @@ -15,7 +15,7 @@ /* * Structure definitions for network protocols. Since this file is used for - * both NET and NET_LWIP, and given that the two network stacks do have + * both NET_LEGACY and NET_LWIP, and given that the two network stacks do have * conflicting types (for instance struct icmp_hdr), it is on purpose that the * structures are defined locally with minimal dependencies -- <asm/types.h> is * included for the bit types and that's it. diff --git a/drivers/net/ti/Kconfig b/drivers/net/ti/Kconfig index 93c3a0c35f2..2d72af8aade 100644 --- a/drivers/net/ti/Kconfig +++ b/drivers/net/ti/Kconfig @@ -14,7 +14,7 @@ config DRIVER_TI_EMAC bool "TI Davinci EMAC" depends on ARCH_DAVINCI || ARCH_OMAP2PLUS help - Support for davinci emac + Support for davinci emac config DRIVER_TI_EMAC_USE_RMII depends on DRIVER_TI_EMAC @@ -26,7 +26,7 @@ config DRIVER_TI_KEYSTONE_NET bool "TI Keystone 2 Ethernet" depends on ARCH_KEYSTONE help - This driver supports the TI Keystone 2 Ethernet subsystem + This driver supports the TI Keystone 2 Ethernet subsystem choice prompt "TI Keystone 2 Ethernet NETCP IP revision" diff --git a/drivers/net/ti/cpsw.c b/drivers/net/ti/cpsw.c index d7746f454ba..7a7cb83bd98 100644 --- a/drivers/net/ti/cpsw.c +++ b/drivers/net/ti/cpsw.c @@ -33,6 +33,7 @@ #define PKT_MAX (1500 + 14 + 4 + 4) #define CLEAR_BIT 1 #define GIGABITEN BIT(7) +#define GMII_EN BIT(5) #define FULLDUPLEXEN BIT(0) #define MIIEN BIT(15) #define CTL_EXT_EN BIT(18) @@ -216,6 +217,10 @@ struct cpsw_priv { u32 phy_mask; }; +struct cpsw_driver_data { + void (*gmii_sel)(struct cpsw_priv *priv, phy_interface_t phy_mode); +}; + static inline int cpsw_ale_get_field(u32 *ale_entry, u32 start, u32 bits) { int idx; @@ -1064,9 +1069,17 @@ static void cpsw_gmii_sel_dra7xx(struct cpsw_priv *priv, writel(reg, priv->data->gmii_sel); } -static void cpsw_phy_sel(struct cpsw_priv *priv, const char *compat, - phy_interface_t phy_mode) +static void cpsw_phy_sel(struct cpsw_priv *priv, phy_interface_t phy_mode) { + const char *compat = priv->data->phy_sel_compat; + const struct cpsw_driver_data *drv_data = + (const struct cpsw_driver_data *)dev_get_driver_data(priv->dev); + + if (drv_data && drv_data->gmii_sel) { + drv_data->gmii_sel(priv, phy_mode); + return; + } + if (!strcmp(compat, "ti,am3352-cpsw-phy-sel")) cpsw_gmii_sel_am3352(priv, phy_mode); if (!strcmp(compat, "ti,am43xx-cpsw-phy-sel")) @@ -1084,8 +1097,7 @@ static int cpsw_eth_probe(struct udevice *dev) priv->data = pdata->priv_pdata; ti_cm_get_macid(dev, priv->data, pdata->enetaddr); /* Select phy interface in control module */ - cpsw_phy_sel(priv, priv->data->phy_sel_compat, - pdata->phy_interface); + cpsw_phy_sel(priv, pdata->phy_interface); return _cpsw_register(priv); } @@ -1122,33 +1134,13 @@ static void cpsw_eth_of_parse_slave(struct cpsw_platform_data *data, "max-speed", 0); } -static int cpsw_eth_of_to_plat(struct udevice *dev) +static int cpsw_eth_of_to_plat_legacy(struct udevice *dev, + struct cpsw_platform_data *data) { - struct eth_pdata *pdata = dev_get_plat(dev); - struct cpsw_platform_data *data; - struct gpio_desc *mode_gpios; int slave_index = 0; - int num_mode_gpios; ofnode subnode; int ret; - data = calloc(1, sizeof(struct cpsw_platform_data)); - if (!data) - return -ENOMEM; - - pdata->priv_pdata = data; - pdata->iobase = dev_read_addr(dev); - data->version = CPSW_CTRL_VERSION_2; - data->bd_ram_ofs = CPSW_BD_OFFSET; - data->ale_reg_ofs = CPSW_ALE_OFFSET; - data->cpdma_reg_ofs = CPSW_CPDMA_OFFSET; - data->mdio_div = CPSW_MDIO_DIV; - data->host_port_reg_ofs = CPSW_HOST_PORT_OFFSET, - - pdata->phy_interface = -1; - - data->cpsw_base = pdata->iobase; - ret = dev_read_s32(dev, "cpdma_channels", &data->channels); if (ret) { printf("error: cpdma_channels not found in dt\n"); @@ -1177,21 +1169,10 @@ static int cpsw_eth_of_to_plat(struct udevice *dev) ret = dev_read_u32(dev, "mac_control", &data->mac_control); if (ret) { - printf("error: ale_entries not found in dt\n"); + printf("error: mac_control not found in dt\n"); return ret; } - num_mode_gpios = gpio_get_list_count(dev, "mode-gpios"); - if (num_mode_gpios > 0) { - mode_gpios = malloc(sizeof(struct gpio_desc) * - num_mode_gpios); - gpio_request_list_by_name(dev, "mode-gpios", mode_gpios, - num_mode_gpios, GPIOD_IS_OUT); - free(mode_gpios); - } - - data->active_slave = dev_read_u32_default(dev, "active_slave", 0); - ofnode_for_each_subnode(subnode, dev_ofnode(dev)) { const char *name; @@ -1222,16 +1203,118 @@ static int cpsw_eth_of_to_plat(struct udevice *dev) if (ofnode_read_bool(subnode, "rmii-clock-ext")) data->rmii_clock_external = true; + } + } - data->phy_sel_compat = ofnode_read_string(subnode, - "compatible"); - if (!data->phy_sel_compat) { - pr_err("Not able to get gmii_sel compatible\n"); - return -ENOENT; - } + return 0; +} + +static int cpsw_eth_of_to_plat_switch(struct udevice *dev, + struct cpsw_platform_data *data) +{ + ofnode eth_ports_node, subnode; + int ret; + + data->channels = 8; + data->ale_entries = 1024; + data->mac_control = GMII_EN; + + eth_ports_node = ofnode_find_subnode(dev_ofnode(dev), "ethernet-ports"); + data->slaves = ofnode_get_child_count(eth_ports_node); + if (!data->slaves) { + pr_err("cpsw: No ethernet-ports defined\n"); + return -EINVAL; + } + + data->slave_data = malloc(sizeof(struct cpsw_slave_data) * data->slaves); + if (!data->slave_data) + return -ENOMEM; + + ofnode_for_each_subnode(subnode, eth_ports_node) { + struct ofnode_phandle_args args; + u32 port_id; + + ret = ofnode_read_u32(subnode, "reg", &port_id); + if (ret || !port_id || port_id > data->slaves) { + pr_err("cpsw: invalid or missing reg in port node\n"); + return -EINVAL; + } + + cpsw_eth_of_parse_slave(data, port_id - 1, subnode); + + if (!data->gmii_sel) { + ret = ofnode_parse_phandle_with_args(subnode, "phys", "#phy-cells", + 0, 0, &args); + if (!ret) + data->gmii_sel = ofnode_get_addr(args.node); + } + } + + if (!data->gmii_sel) { + pr_err("No port specified phys correctly\n"); + return -ENOENT; + } + + ofnode_for_each_subnode(subnode, dev_ofnode(dev)) { + const char *name = ofnode_get_name(subnode); + + if (strncmp(name, "mdio", 4)) + continue; + + data->mdio_base = ofnode_get_addr(subnode); + if (data->mdio_base == FDT_ADDR_T_NONE) { + pr_err("Not able to get MDIO address space\n"); + return -ENOENT; } } + return 0; +} + +static int cpsw_eth_of_to_plat(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_plat(dev); + struct cpsw_platform_data *data; + struct gpio_desc *mode_gpios; + int num_mode_gpios; + int ret; + bool switch_dt_bindings = + ofnode_valid(ofnode_find_subnode(dev_ofnode(dev), "ethernet-ports")); + + data = calloc(1, sizeof(struct cpsw_platform_data)); + if (!data) + return -ENOMEM; + + pdata->priv_pdata = data; + pdata->iobase = dev_read_addr(dev); + data->version = CPSW_CTRL_VERSION_2; + data->bd_ram_ofs = CPSW_BD_OFFSET; + data->ale_reg_ofs = CPSW_ALE_OFFSET; + data->cpdma_reg_ofs = CPSW_CPDMA_OFFSET; + data->mdio_div = CPSW_MDIO_DIV; + data->host_port_reg_ofs = CPSW_HOST_PORT_OFFSET; + + pdata->phy_interface = -1; + + data->cpsw_base = pdata->iobase; + + num_mode_gpios = gpio_get_list_count(dev, "mode-gpios"); + if (num_mode_gpios > 0) { + mode_gpios = malloc(sizeof(struct gpio_desc) * num_mode_gpios); + gpio_request_list_by_name(dev, "mode-gpios", mode_gpios, + num_mode_gpios, GPIOD_IS_OUT); + free(mode_gpios); + } + + data->active_slave = dev_read_u32_default(dev, "active_slave", 0); + + if (switch_dt_bindings) + ret = cpsw_eth_of_to_plat_switch(dev, data); + else + ret = cpsw_eth_of_to_plat_legacy(dev, data); + if (ret) + return ret; + data->slave_data[0].slave_reg_ofs = CPSW_SLAVE0_OFFSET; data->slave_data[0].sliver_reg_ofs = CPSW_SLIVER0_OFFSET; @@ -1253,9 +1336,22 @@ static int cpsw_eth_of_to_plat(struct udevice *dev) return 0; } +static const struct cpsw_driver_data cpsw_data_am3352 = { + .gmii_sel = cpsw_gmii_sel_am3352, +}; + +static const struct cpsw_driver_data cpsw_data_dra7xx = { + .gmii_sel = cpsw_gmii_sel_dra7xx, +}; + static const struct udevice_id cpsw_eth_ids[] = { - { .compatible = "ti,cpsw" }, - { .compatible = "ti,am335x-cpsw" }, + { .compatible = "ti,cpsw", .data = (ulong)&cpsw_data_am3352 }, + { .compatible = "ti,am335x-cpsw", .data = (ulong)&cpsw_data_am3352 }, + { .compatible = "ti,am4372-cpsw", .data = (ulong)&cpsw_data_am3352 }, + { .compatible = "ti,dra7-cpsw", .data = (ulong)&cpsw_data_dra7xx }, + { .compatible = "ti,am335x-cpsw-switch", .data = (ulong)&cpsw_data_am3352 }, + { .compatible = "ti,am4372-cpsw-switch", .data = (ulong)&cpsw_data_am3352 }, + { .compatible = "ti,dra7-cpsw-switch", .data = (ulong)&cpsw_data_dra7xx }, { } }; #endif diff --git a/drivers/net/ti/icssg_prueth.c b/drivers/net/ti/icssg_prueth.c index 12a162b9d68..4796d0d67cd 100644 --- a/drivers/net/ti/icssg_prueth.c +++ b/drivers/net/ti/icssg_prueth.c @@ -496,14 +496,15 @@ static int prueth_port_probe(struct udevice *dev) { struct prueth_priv *priv = dev_get_priv(dev); struct prueth *prueth; - char portname[15]; + char portname[64]; int ret; priv->dev = dev; prueth = dev_get_priv(dev->parent); priv->prueth = prueth; - sprintf(portname, "%s-%s", dev->parent->name, dev->name); + snprintf(portname, sizeof(portname), "%s-%s", dev->parent->name, dev->name); + portname[sizeof(portname) - 1] = '\0'; device_set_name(dev, portname); diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index bd4ebdd745a..d03368b9408 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -37,6 +37,23 @@ ) #endif /* CFG_TSEC_TBICR_SETTINGS */ +struct tsec_private { + struct txbd8 __iomem txbd[TX_BUF_CNT]; + struct rxbd8 __iomem rxbd[PKTBUFSRX]; + struct tsec __iomem *regs; + struct tsec_mii_mng __iomem *phyregs_sgmii; + struct phy_device *phydev; + phy_interface_t interface; + struct mii_dev *bus; + uint phyaddr; + uint tbiaddr; + char mii_devname[16]; + u32 flags; + uint rx_idx; /* index of the current RX buffer */ + uint tx_idx; /* index of the current TX buffer */ + struct udevice *dev; +}; + /* Configure the TBI for SGMII operation */ static void tsec_configure_serdes(struct tsec_private *priv) { diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c index e9cc5db52d2..1ea81fe1830 100644 --- a/drivers/net/xilinx_axi_emac.c +++ b/drivers/net/xilinx_axi_emac.c @@ -28,6 +28,10 @@ #define XAE_EMMC_LINKSPD_100 0x40000000 /* Link Speed mask for 100 Mbit */ #define XAE_EMMC_LINKSPD_1000 0x80000000 /* Link Speed mask for 1000 Mbit */ +/* Reset and Address Filter (RAF) Register bit definitions */ +#define XAE_RAF_MCSTREJ_MASK 0x00000002 /* Reject rx multicast dst addr */ +#define XAE_RAF_BCSTREJ_MASK 0x00000004 /* Reject rx broadcast dst addr */ + /* Interrupt Status/Enable/Mask Registers bit definitions */ #define XAE_INT_RXRJECT_MASK 0x00000008 /* Rx frame rejected */ #define XAE_INT_MGTRDY_MASK 0x00000080 /* MGT clock Lock */ @@ -153,7 +157,8 @@ static struct axidma_bd tx_bd __attribute((aligned(DMAALIGN))); static struct axidma_bd rx_bd __attribute((aligned(DMAALIGN))); struct axi_regs { - u32 reserved[3]; + u32 raf; /* 0x0: Reset and Address Filter */ + u32 reserved[2]; u32 is; /* 0xC: Interrupt status */ u32 reserved2; u32 ie; /* 0x14: Interrupt enable */ @@ -528,6 +533,19 @@ static int axi_ethernet_init(struct axidma_priv *priv) /* Set default MDIO divisor */ writel(XAE_MDIO_DIV_DFT | XAE_MDIO_MC_MDIOEN_MASK, ®s->mdio_mc); + /* + * Reject broadcast and multicast frames at MAC level to reduce + * unnecessary traffic processing. Multicast rejection is only + * enabled when IPv6 is not configured because IPv6 Neighbor + * Discovery and DHCPv6 rely on multicast. + */ + if (!IS_ENABLED(CONFIG_IPV6)) + writel(readl(®s->raf) | XAE_RAF_MCSTREJ_MASK | + XAE_RAF_BCSTREJ_MASK, ®s->raf); + else + writel(readl(®s->raf) | XAE_RAF_BCSTREJ_MASK, + ®s->raf); + debug("axiemac: InitHw done\n"); return 0; } diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index a50d5aee03f..f570ae9ee73 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -69,10 +69,13 @@ #define ZYNQ_GEM_NWCFG_SGMII_ENBL 0x08000000 /* SGMII Enable */ #define ZYNQ_GEM_NWCFG_PCS_SEL 0x00000800 /* PCS select */ +#define ZYNQ_GEM_DBUS_WIDTH_MASK (3 << 21) /* bits 22:21 */ #ifdef CONFIG_ARM64 # define ZYNQ_GEM_DBUS_WIDTH (1 << 21) /* 64 bit bus */ +# define ZYNQ_GEM_DBUS_WIDTH_128 (2 << 21) /* 128 bit bus */ #else # define ZYNQ_GEM_DBUS_WIDTH (0 << 21) /* 32 bit bus */ +# define ZYNQ_GEM_DBUS_WIDTH_128 (0 << 21) /* 32 bit bus */ #endif #define ZYNQ_GEM_NWCFG_INIT (ZYNQ_GEM_DBUS_WIDTH | \ @@ -134,6 +137,7 @@ #define ZYNQ_GEM_FREQUENCY_10 2500000UL #define ZYNQ_GEM_FREQUENCY_100 25000000UL #define ZYNQ_GEM_FREQUENCY_1000 125000000UL +#define ZYNQ_GEM_FREQUENCY_10000 150000000UL #define RXCLK_EN BIT(0) @@ -470,28 +474,6 @@ static int zynq_gem_init(struct udevice *dev) for (i = 0; i < STAT_SIZE; i++) readl(®s->stat[i]); - /* Setup RxBD space */ - memset(priv->rx_bd, 0, RX_BUF * sizeof(struct emac_bd)); - - for (i = 0; i < RX_BUF; i++) { - priv->rx_bd[i].status = 0xF0000000; - priv->rx_bd[i].addr = - (lower_32_bits((ulong)(priv->rxbuffers) - + (i * PKTSIZE_ALIGN))); -#if defined(CONFIG_PHYS_64BIT) - priv->rx_bd[i].addr_hi = - (upper_32_bits((ulong)(priv->rxbuffers) - + (i * PKTSIZE_ALIGN))); -#endif - } - /* WRAP bit to last BD */ - priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; - /* Write RxBDs to IP */ - writel(lower_32_bits((ulong)priv->rx_bd), ®s->rxqbase); -#if defined(CONFIG_PHYS_64BIT) - writel(upper_32_bits((ulong)priv->rx_bd), ®s->upper_rxqbase); -#endif - /* Setup for DMA Configuration register */ writel(ZYNQ_GEM_DMACR_INIT, ®s->dmacr); @@ -520,6 +502,35 @@ static int zynq_gem_init(struct udevice *dev) priv->init++; } + /* + * Reinitialize RX BDs on every init. The 10GBE USX block asserts + * RX_SYNC_RESET during setup which resets the GEM RX DMA pointer + * back to rxqbase, so BDs and rxqbase must be refreshed each time + * to keep the hardware and driver ring indices in sync. + */ + priv->rxbd_current = 0; + priv->rx_first_buf = 0; + memset(priv->rx_bd, 0, RX_BUF * sizeof(struct emac_bd)); + for (i = 0; i < RX_BUF; i++) { + priv->rx_bd[i].status = 0xF0000000; + priv->rx_bd[i].addr = + (lower_32_bits((ulong)(priv->rxbuffers) + + (i * PKTSIZE_ALIGN))); +#if defined(CONFIG_PHYS_64BIT) + priv->rx_bd[i].addr_hi = + (upper_32_bits((ulong)(priv->rxbuffers) + + (i * PKTSIZE_ALIGN))); +#endif + } + /* WRAP bit to last BD */ + priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; + + /* Write RxBDs to IP */ + writel(lower_32_bits((ulong)priv->rx_bd), ®s->rxqbase); +#if defined(CONFIG_PHYS_64BIT) + writel(upper_32_bits((ulong)priv->rx_bd), ®s->upper_rxqbase); +#endif + ret = phy_startup(priv->phydev); if (ret) return ret; @@ -532,6 +543,8 @@ static int zynq_gem_init(struct udevice *dev) nwconfig = ZYNQ_GEM_NWCFG_INIT; if (device_is_compatible(dev, "amd,versal2-10gbe")) { + nwconfig &= ~ZYNQ_GEM_DBUS_WIDTH_MASK; + nwconfig |= ZYNQ_GEM_DBUS_WIDTH_128; if (priv->interface == PHY_INTERFACE_MODE_10GBASER) { ctrl = readl(®s->nwcfg); ctrl |= PCSSEL; @@ -602,6 +615,9 @@ static int zynq_gem_init(struct udevice *dev) } switch (priv->phydev->speed) { + case SPEED_10000: + clk_rate = ZYNQ_GEM_FREQUENCY_10000; + break; case SPEED_1000: nwconfig |= ZYNQ_GEM_NWCFG_SPEED1000; clk_rate = ZYNQ_GEM_FREQUENCY_1000; @@ -615,6 +631,7 @@ static int zynq_gem_init(struct udevice *dev) break; } nwcfg = readl(®s->nwcfg); + nwcfg &= ~(ZYNQ_GEM_NWCFG_SPEED100 | ZYNQ_GEM_NWCFG_SPEED1000); nwcfg |= nwconfig; if (nwcfg) writel(nwcfg, ®s->nwcfg); diff --git a/drivers/nvme/nvme-uclass.c b/drivers/nvme/nvme-uclass.c index 44c88ad27f3..4ab9567450f 100644 --- a/drivers/nvme/nvme-uclass.c +++ b/drivers/nvme/nvme-uclass.c @@ -44,7 +44,7 @@ UCLASS_DRIVER(nvme) = { .id = UCLASS_NVME, }; -struct bootdev_ops nvme_bootdev_ops = { +static const struct bootdev_ops nvme_bootdev_ops = { }; static const struct udevice_id nvme_bootdev_ids[] = { diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index 2b14437f69c..147a104149e 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -27,6 +27,23 @@ #define IO_TIMEOUT 30 #define MAX_PRP_POOL 512 +/** + * nvme_invalidate_cache_aligned() - invalidate cache with proper alignment + * + * Aligns cache invalidation to cacheline boundaries to ensure correct + * behavior even when the DMA buffer is not aligned to page boundaries. + * + * @addr: The start address of the buffer + * @length: The length of the buffer in bytes + */ +static inline void nvme_invalidate_cache_aligned(uintptr_t addr, int length) +{ + uintptr_t start_addr = addr & ~(ARCH_DMA_MINALIGN - 1); + uintptr_t end_addr = ALIGN(addr + length, ARCH_DMA_MINALIGN); + + invalidate_dcache_range(start_addr, end_addr); +} + static int nvme_wait_csts(struct nvme_dev *dev, u32 mask, u32 val) { int timeout; @@ -94,7 +111,7 @@ static int nvme_setup_prps(struct nvme_dev *dev, u64 *prp2, *(prp_pool + i) = cpu_to_le64((ulong)prp_pool + page_size); i = 0; - prp_pool += page_size; + prp_pool = (u64 *)((uintptr_t)prp_pool + page_size); } *(prp_pool + i++) = cpu_to_le64(dma_addr); dma_addr += page_size; @@ -112,7 +129,10 @@ static __le16 nvme_get_cmd_id(void) { static unsigned short cmdid; - return cpu_to_le16((cmdid < USHRT_MAX) ? cmdid++ : 0); + if (cmdid >= USHRT_MAX) + cmdid = 0; + + return cpu_to_le16(cmdid++); } static u16 nvme_read_completion_status(struct nvme_queue *nvmeq, u16 index) @@ -179,8 +199,10 @@ static int nvme_submit_sync_cmd(struct nvme_queue *nvmeq, if ((status & 0x01) == phase) break; if (timeout_us > 0 && (timer_get_us() - start_time) - >= timeout_us) + >= timeout_us) { + pr_warn("nvme: cmd %#x timed out\n", cmd->common.command_id); return -ETIMEDOUT; + } } ops = (struct nvme_ops *)nvmeq->dev->udev->driver->ops; @@ -278,11 +300,6 @@ static int nvme_delete_queue(struct nvme_dev *dev, u8 opcode, u16 id) return nvme_submit_admin_cmd(dev, &c, NULL); } -static int nvme_delete_sq(struct nvme_dev *dev, u16 sqid) -{ - return nvme_delete_queue(dev, nvme_admin_delete_sq, sqid); -} - static int nvme_delete_cq(struct nvme_dev *dev, u16 cqid) { return nvme_delete_queue(dev, nvme_admin_delete_cq, cqid); @@ -453,6 +470,7 @@ int nvme_identify(struct nvme_dev *dev, unsigned nsid, u32 page_size = dev->page_size; int offset = dma_addr & (page_size - 1); int length = sizeof(struct nvme_id_ctrl); + dma_addr_t orig_dma_addr = dma_addr; int ret; memset(&c, 0, sizeof(c)); @@ -470,13 +488,13 @@ int nvme_identify(struct nvme_dev *dev, unsigned nsid, c.identify.cns = cpu_to_le32(cns); - invalidate_dcache_range(dma_addr, - dma_addr + sizeof(struct nvme_id_ctrl)); + nvme_invalidate_cache_aligned((uintptr_t)orig_dma_addr, + sizeof(struct nvme_id_ctrl)); ret = nvme_submit_admin_cmd(dev, &c, NULL); if (!ret) - invalidate_dcache_range(dma_addr, - dma_addr + sizeof(struct nvme_id_ctrl)); + nvme_invalidate_cache_aligned((uintptr_t)orig_dma_addr, + sizeof(struct nvme_id_ctrl)); return ret; } @@ -542,20 +560,19 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) nvmeq->cq_vector = qid - 1; result = nvme_alloc_cq(dev, qid, nvmeq); if (result < 0) - goto release_cq; + goto release_ret; result = nvme_alloc_sq(dev, qid, nvmeq); if (result < 0) - goto release_sq; + goto release_cq; nvme_init_queue(nvmeq, qid); return result; - release_sq: - nvme_delete_sq(dev, qid); release_cq: nvme_delete_cq(dev, qid); + release_ret: return result; } @@ -865,14 +882,14 @@ int nvme_init(struct udevice *udev) if (!ndev->prp_pool) { ret = -ENOMEM; printf("Error: %s: Out of memory!\n", udev->name); - goto free_nvme; + goto free_queue; } ndev->prp_entry_num = MAX_PRP_POOL >> 3; ret = nvme_setup_io_queues(ndev); if (ret) { log_debug("Unable to setup I/O queues(err=%dE)\n", ret); - goto free_queue; + goto free_prp_pool; } nvme_get_info_from_identify(ndev); @@ -882,7 +899,7 @@ int nvme_init(struct udevice *udev) id = memalign(ndev->page_size, sizeof(struct nvme_id_ns)); if (!id) { ret = -ENOMEM; - goto free_queue; + goto free_prp_pool; } for (int i = 1; i <= ndev->nn; i++) { @@ -927,6 +944,8 @@ int nvme_init(struct udevice *udev) free_id: free(id); +free_prp_pool: + free((void *)ndev->prp_pool); free_queue: free((void *)ndev->queues); free_nvme: diff --git a/drivers/nvme/nvme_apple.c b/drivers/nvme/nvme_apple.c index 7e7538553e3..e674eda8344 100644 --- a/drivers/nvme/nvme_apple.c +++ b/drivers/nvme/nvme_apple.c @@ -13,6 +13,7 @@ #include <asm/arch/rtkit.h> #include <asm/arch/sart.h> #include <linux/iopoll.h> +#include <linux/sizes.h> /* ASC registers */ #define REG_CPU_CTRL 0x0044 @@ -87,6 +88,9 @@ static int apple_nvme_setup_queue(struct nvme_queue *nvmeq) } priv->tcbs[nvmeq->qid] = (void *)memalign(4096, ANS_NVMMU_TCB_SIZE); + if (!priv->tcbs[nvmeq->qid]) + return -ENOMEM; + memset((void *)priv->tcbs[nvmeq->qid], 0, ANS_NVMMU_TCB_SIZE); switch (nvmeq->qid) { @@ -287,6 +291,7 @@ static const struct nvme_ops apple_nvme_ops = { }; static const struct udevice_id apple_nvme_ids[] = { + { .compatible = "apple,t8103-nvme-ans2" }, { .compatible = "apple,nvme-ans2" }, { /* sentinel */ } }; diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 8fc57895a78..9ffccc3a80b 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -101,11 +101,11 @@ config PCI_ENHANCED_ALLOCATION devices in place of traditional BARS for allocation of resources. config PCI_ARID - bool "Enable Alternate Routing-ID support for PCI" - help - Say Y here if you want to enable Alternate Routing-ID capability - support on PCI devices. This helps to skip some devices in BDF - scan that are not present. + bool "Enable Alternate Routing-ID support for PCI" + help + Say Y here if you want to enable Alternate Routing-ID capability + support on PCI devices. This helps to skip some devices in BDF + scan that are not present. config PCI_SCAN_SHOW bool "Show PCI devices during startup" @@ -287,7 +287,7 @@ config PCI_IOMMU_EXTRA_MAPPINGS the node describing the PCI controller. The intent is to cover SR-IOV scenarios which need mappings for VFs and PCI hot-plug scenarios. More documentation can be found under: - arch/arm/cpu/armv8/fsl-layerscape/doc/README.pci_iommu_extra + arch/arm/cpu/armv8/fsl-layerscape/doc/README.pci_iommu_extra config PCIE_LAYERSCAPE_EP bool "Layerscape PCIe Endpoint mode support" @@ -440,8 +440,8 @@ config PCIE_XILINX_NWL bool "Xilinx NWL PCIe controller" depends on ARCH_ZYNQMP help - Say 'Y' here if you want support for Xilinx / AMD NWL PCIe - controller as Root Port. + Say 'Y' here if you want support for Xilinx / AMD NWL PCIe + controller as Root Port. config PCIE_PLDA_COMMON bool @@ -456,6 +456,17 @@ config PCIE_STARFIVE_JH7110 Say Y here if you want to enable PLDA XpressRich PCIe controller support on StarFive JH7110 SoC. +config PCIE_DW_AMD + bool "AMD Versal2 DW PCIe host controller" + depends on ARCH_VERSAL2 + depends on DM_GPIO + select PCIE_DW_COMMON + select SYS_PCI_64BIT + help + Say Y here to enable support for the AMD Versal Gen 2 PCIe + host controller. This is a DesignWare-based PCIe controller + used in AMD Versal Gen 2 SoCs. + config PCIE_DW_IMX bool "i.MX DW PCIe controller support" depends on ARCH_IMX8M || ARCH_IMX9 diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 98f3c226f63..e6d71fd172b 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -56,4 +56,5 @@ obj-$(CONFIG_PCIE_UNIPHIER) += pcie_uniphier.o obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o obj-$(CONFIG_PCIE_PLDA_COMMON) += pcie_plda_common.o obj-$(CONFIG_PCIE_STARFIVE_JH7110) += pcie_starfive_jh7110.o +obj-$(CONFIG_PCIE_DW_AMD) += pcie_dw_amd.o obj-$(CONFIG_PCIE_DW_IMX) += pcie_dw_imx.o diff --git a/drivers/pci/pci-rcar-gen2.c b/drivers/pci/pci-rcar-gen2.c index 08d5c4fbb8b..53cb0916741 100644 --- a/drivers/pci/pci-rcar-gen2.c +++ b/drivers/pci/pci-rcar-gen2.c @@ -10,6 +10,7 @@ #include <clk.h> #include <dm.h> #include <errno.h> +#include <fdtdec.h> #include <pci.h> #include <linux/bitops.h> @@ -235,9 +236,9 @@ static int rcar_gen2_pci_of_to_plat(struct udevice *dev) { struct rcar_gen2_pci_priv *priv = dev_get_priv(dev); - priv->cfg_base = devfdt_get_addr_index(dev, 0); - priv->mem_base = devfdt_get_addr_index(dev, 1); - if (!priv->cfg_base || !priv->mem_base) + priv->cfg_base = dev_read_addr_index(dev, 0); + priv->mem_base = dev_read_addr_index(dev, 1); + if (priv->cfg_base == FDT_ADDR_T_NONE || priv->mem_base == FDT_ADDR_T_NONE) return -EINVAL; return 0; diff --git a/drivers/pci/pci-rcar-gen3.c b/drivers/pci/pci-rcar-gen3.c index d4b4037ce19..1925d968c16 100644 --- a/drivers/pci/pci-rcar-gen3.c +++ b/drivers/pci/pci-rcar-gen3.c @@ -19,6 +19,7 @@ #include <clk.h> #include <dm.h> #include <errno.h> +#include <fdtdec.h> #include <pci.h> #include <wait_bit.h> #include <linux/bitops.h> @@ -391,8 +392,8 @@ static int rcar_gen3_pcie_of_to_plat(struct udevice *dev) { struct rcar_gen3_pcie_priv *priv = dev_get_plat(dev); - priv->regs = devfdt_get_addr_index(dev, 0); - if (!priv->regs) + priv->regs = dev_read_addr_index(dev, 0); + if (priv->regs == FDT_ADDR_T_NONE) return -EINVAL; return 0; diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 83b76d01f24..4bdd1f7477f 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -927,7 +927,7 @@ int pci_bind_bus_devices(struct udevice *bus) if (PCI_FUNC(bdf) && !found_multi) continue; - if (only_one_child(bus) && (PCI_MASK_BUS(bdf) > 0)) + if (only_one_child(bus) && (PCI_DEV(bdf) > 0)) continue; /* Check only the first access, we don't expect problems */ @@ -1126,14 +1126,14 @@ static int decode_regions(struct pci_controller *hose, ofnode parent_node, return 0; for (i = 0; i < CONFIG_NR_DRAM_BANKS; ++i) { - if (bd->bi_dram[i].size) { - phys_addr_t start = bd->bi_dram[i].start; + if (gd->dram[i].size) { + phys_addr_t start = gd->dram[i].start; if (IS_ENABLED(CONFIG_PCI_MAP_SYSTEM_MEMORY)) - start = virt_to_phys((void *)(uintptr_t)bd->bi_dram[i].start); + start = virt_to_phys((void *)(uintptr_t)gd->dram[i].start); pci_set_region(hose->regions + hose->region_count++, - start, start, bd->bi_dram[i].size, + start, start, gd->dram[i].size, PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); } } diff --git a/drivers/pci/pci_mpc85xx.c b/drivers/pci/pci_mpc85xx.c index c07feba7976..96550a9ff8f 100644 --- a/drivers/pci/pci_mpc85xx.c +++ b/drivers/pci/pci_mpc85xx.c @@ -170,13 +170,14 @@ static int mpc85xx_pci_dm_remove(struct udevice *dev) static int mpc85xx_pci_of_to_plat(struct udevice *dev) { struct mpc85xx_pci_priv *priv = dev_get_priv(dev); - fdt_addr_t addr; + void __iomem *addr; - addr = devfdt_get_addr_index(dev, 0); - if (addr == FDT_ADDR_T_NONE) + addr = dev_remap_addr_index(dev, 0); + if (!addr) return -EINVAL; - priv->cfg_addr = (void __iomem *)map_physmem(addr, 0, MAP_NOCACHE); - priv->cfg_data = (void __iomem *)((ulong)priv->cfg_addr + 4); + + priv->cfg_addr = addr; + priv->cfg_data = priv->cfg_addr + 4; return 0; } diff --git a/drivers/pci/pcie_brcmstb.c b/drivers/pci/pcie_brcmstb.c index f089c48f028..1b03b0a7b05 100644 --- a/drivers/pci/pcie_brcmstb.c +++ b/drivers/pci/pcie_brcmstb.c @@ -21,6 +21,7 @@ #include <linux/bitfield.h> #include <linux/log2.h> #include <linux/iopoll.h> +#include <reset.h> /* PCIe parameters */ #define BRCM_NUM_PCIE_OUT_WINS 4 @@ -49,6 +50,47 @@ #define SSC_STATUS_PLL_LOCK_MASK 0x800 #define SSC_STATUS_PLL_LOCK_SHIFT 11 +#define PCIE_RC_PL_PHY_CTL_15 0x184c +#define PCIE_RC_PL_PHY_CTL_15_DIS_PLL_PD_MASK 0x400000 +#define PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK 0xff + +#define PCIE_MISC_UBUS_CTRL 0x40a4 +#define PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_ERR_DIS_MASK BIT(13) +#define PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_DECERR_DIS_MASK BIT(19) +#define PCIE_MISC_AXI_READ_ERROR_DATA 0x4170 +#define PCIE_MISC_UBUS_TIMEOUT 0x40A8 +#define PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT 0x405c +#define PCIE_MISC_RC_BAR4_CONFIG_LO 0x40d4 +#define PCIE_MISC_RC_BAR4_CONFIG_HI 0x40d8 +#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK 0xff +#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_HI 0x4110 +#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE 0x1 +#define PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK 0xfffff000 +#define PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO 0x410c + +#define PCIE_MISC_UBUS_BAR1_CONFIG_REMAP 0x40ac +#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP 0x40b4 +#define PCIE_MISC_UBUS_BAR2_CONFIG_REMAP_ACCESS_ENABLE_MASK BIT(0) +#define MISC_CTRL_PCIE_RCB_MPS_MODE_MASK 0x400 + +enum { + RGR1_SW_INIT_1, + PCIE_HARD_DEBUG, +}; + +enum brcm_pcie_type { + BCM2711, + BCM2712 +}; + +struct brcm_pcie; + +struct brcm_pcie_cfg_data { + const int *offsets; + const enum brcm_pcie_type type; + void (*perst_set)(struct brcm_pcie *pcie, u32 val); +}; + /** * struct brcm_pcie - the PCIe controller state * @base: Base address of memory mapped IO registers of the controller @@ -61,6 +103,9 @@ struct brcm_pcie { int gen; bool ssc; + struct reset_ctl rescal; + struct reset_ctl bridge_reset; + const struct brcm_pcie_cfg_data *pcie_cfg; }; /** @@ -79,8 +124,8 @@ static int brcm_pcie_encode_ibar_size(u64 size) if (log2_in >= 12 && log2_in <= 15) /* Covers 4KB to 32KB (inclusive) */ return (log2_in - 12) + 0x1c; - else if (log2_in >= 16 && log2_in <= 37) - /* Covers 64KB to 32GB, (inclusive) */ + else if (log2_in >= 16 && log2_in <= 36) + /* Covers 64KB to 64GB, (inclusive) */ return log2_in - 15; /* Something is awry so disable */ @@ -104,6 +149,80 @@ static bool brcm_pcie_rc_mode(struct brcm_pcie *pcie) return (val & STATUS_PCIE_PORT_MASK) >> STATUS_PCIE_PORT_SHIFT; } +static void brcm_pcie_perst_set_generic(struct brcm_pcie *pcie, u32 val) +{ + if (val) + setbits_le32(pcie->base + pcie->pcie_cfg->offsets[RGR1_SW_INIT_1], + RGR1_SW_INIT_1_PERST_MASK); + else + clrbits_le32(pcie->base + pcie->pcie_cfg->offsets[RGR1_SW_INIT_1], + RGR1_SW_INIT_1_PERST_MASK); +} + +static void brcm_pcie_perst_set_2712(struct brcm_pcie *pcie, u32 val) +{ + u32 tmp; + + /* Perst bit has moved and assert value is 0 */ + tmp = readl(pcie->base + PCIE_MISC_PCIE_CTRL); + u32p_replace_bits(&tmp, !val, RGR1_SW_INIT_1_PERSTB_MASK); + writel(tmp, pcie->base + PCIE_MISC_PCIE_CTRL); +} + +static int brcm_pcie_get_resets_dt(struct udevice *dev) +{ + struct brcm_pcie *pcie = dev_get_priv(dev); + int ret; + + ret = reset_get_by_name(dev, "rescal", &pcie->rescal); + if (ret) { + printf("Unable to get rescal reset\n"); + return ret; + } + + ret = reset_get_by_name(dev, "bridge", &pcie->bridge_reset); + if (ret) + printf("Unable to get bridge reset\n"); + + return ret; +} + +static int brcm_pcie_do_reset(struct udevice *dev) +{ + struct brcm_pcie *pcie = dev_get_priv(dev); + int ret; + + ret = reset_deassert(&pcie->rescal); + if (ret) + printf("failed to deassert 'rescal'\n"); + return ret; +} + +static int brcm_pcie_bridge_sw_init_set(struct brcm_pcie *pcie, u32 val) +{ + int ret = 0; + + if (reset_valid(&pcie->bridge_reset)) + { + if (val) + ret = reset_assert(&pcie->bridge_reset); + else + ret = reset_deassert(&pcie->bridge_reset); + if (ret) + log_err("failed to %sassert bridge reset, err=%d\n", + val ? "" : "de", ret); + return ret; + } + + if (val) + setbits_le32(pcie->base + pcie->pcie_cfg->offsets[RGR1_SW_INIT_1], + RGR1_SW_INIT_1_INIT_MASK); + else + clrbits_le32(pcie->base + pcie->pcie_cfg->offsets[RGR1_SW_INIT_1], + RGR1_SW_INIT_1_INIT_MASK); + return 0; +} + /** * brcm_pcie_link_up() - Check whether the PCIe link is up * @pcie: Pointer to the PCIe controller state @@ -125,7 +244,7 @@ static int brcm_pcie_config_address(const struct udevice *dev, pci_dev_t bdf, uint offset, void **paddress) { struct brcm_pcie *pcie = dev_get_priv(dev); - unsigned int pci_bus = PCI_BUS(bdf); + unsigned int pci_bus = PCI_BUS(bdf) - dev_seq(dev); unsigned int pci_dev = PCI_DEV(bdf); unsigned int pci_func = PCI_FUNC(bdf); int idx; @@ -345,28 +464,150 @@ static void brcm_pcie_set_outbound_win(struct brcm_pcie *pcie, writel(tmp, base + PCIE_MEM_WIN0_LIMIT_HI(win)); } +static u32 brcm_bar_reg_offset(int bar) +{ + if (bar <= 3) + return PCIE_MISC_RC_BAR1_CONFIG_LO + 8 * (bar - 1); + else + return PCIE_MISC_RC_BAR4_CONFIG_LO + 8 * (bar - 4); +} + +static u32 brcm_ubus_reg_offset(int bar) +{ + if (bar <= 3) + return PCIE_MISC_UBUS_BAR1_CONFIG_REMAP + 8 * (bar - 1); + else + return PCIE_MISC_UBUS_BAR4_CONFIG_REMAP_LO + 8 * (bar - 4); +} + +/* + * Round size up to the next power of two, as required by + * brcm_pcie_encode_ibar_size(). If size is already a power of two + * fls64(size - 1) still gives the correct result because the hardware + * encodes the exponent, not the raw value. + */ +static u64 brcm_ibar_round_size(u64 size) +{ + return 1ULL << fls64(size - 1); +} + +static void brcm_pcie_set_inbound_windows(struct udevice *dev) +{ + struct brcm_pcie *pcie = dev_get_priv(dev); + void __iomem *base = pcie->base; + bool is_2712 = (pcie->pcie_cfg->type == BCM2712); + int i, ibar_no, ret; + u32 tmp; + + ibar_no = 0; + /* pre-2712 chips leave the first entry empty */ + if (pcie->pcie_cfg->type != BCM2712) + ibar_no++; + + /* program inbound windows from OF property "dma-regions" */ + for (i = 0; i < 7; i++, ibar_no++) { + u64 bar_cpu, bar_size, bar_pci; + struct pci_region region; + int ubus_bar_offset, rc_bar_offset; + + ret = pci_get_dma_regions(dev, ®ion, i); + if (ret) /* no region #i? Then we're done. */ + break; + ubus_bar_offset = brcm_ubus_reg_offset(ibar_no + 1); + rc_bar_offset = brcm_bar_reg_offset(ibar_no + 1); + + bar_pci = region.bus_start; + bar_cpu = region.phys_start; + bar_size = region.size; + + if (is_2712) { + /* BCM2712: BAR holds raw PCI address; UBUS remap + * registers supply the CPU-side translation. */ + tmp = lower_32_bits(bar_pci); + u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(bar_size), + RC_BAR2_CONFIG_LO_SIZE_MASK); + writel(tmp, base + rc_bar_offset); + writel(upper_32_bits(bar_pci), base + rc_bar_offset + 4); + + tmp = lower_32_bits(bar_cpu) & + PCIE_MISC_UBUS_BAR_CONFIG_REMAP_LO_MASK; + tmp |= PCIE_MISC_UBUS_BAR_CONFIG_REMAP_ENABLE; + writel(tmp, base + ubus_bar_offset); + + tmp = upper_32_bits(bar_cpu) & + PCIE_MISC_UBUS_BAR_CONFIG_REMAP_HI_MASK; + writel(tmp, base + ubus_bar_offset + 4); + } else { + /* Pre-BCM2712 (e.g. BCM2711 / RPi4): the BAR config + * register holds the offset (bus_start - phys_start), + * not the raw PCI address. The size must be rounded + * up to the next power of two before encoding. */ + u64 bar_offset = bar_pci - bar_cpu; + u64 bar_size_po2 = brcm_ibar_round_size(bar_size); + + tmp = lower_32_bits(bar_offset); + u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(bar_size_po2), + RC_BAR2_CONFIG_LO_SIZE_MASK); + writel(tmp, base + rc_bar_offset); + writel(upper_32_bits(bar_offset), base + rc_bar_offset + 4); + /* UBUS remap registers are not used on pre-2712 hardware. */ + } + } +} + +static void brcm_pcie_munge_pll(struct brcm_pcie *pcie) +{ + u32 tmp; + int ret, i; + u8 regs[] = { 0x16, 0x17, 0x18, 0x19, 0x1b, 0x1c, 0x1e }; + u16 data[] = { 0x50b9, 0xbda1, 0x0094, 0x97b4, 0x5030, 0x5030, 0x0007 }; + + ret = brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, SET_ADDR_OFFSET, + 0x1600); + for (i = 0; i < ARRAY_SIZE(regs); i++) { + brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, regs[i], &tmp); + debug("PCIE MDIO pre_refclk 0x%02x = 0x%04x\n", + regs[i], tmp); + } + for (i = 0; i < ARRAY_SIZE(regs); i++) { + brcm_pcie_mdio_write(pcie->base, MDIO_PORT0, regs[i], data[i]); + brcm_pcie_mdio_read(pcie->base, MDIO_PORT0, regs[i], &tmp); + debug("PCIE MDIO post_refclk 0x%02x = 0x%04x\n", + regs[i], tmp); + } + + udelay(200); +} + static int brcm_pcie_probe(struct udevice *dev) { struct udevice *ctlr = pci_get_controller(dev); struct pci_controller *hose = dev_get_uclass_priv(ctlr); struct brcm_pcie *pcie = dev_get_priv(dev); void __iomem *base = pcie->base; - struct pci_region region; bool ssc_good = false; int num_out_wins = 0; - u64 rc_bar2_offset, rc_bar2_size; - unsigned int scb_size_val; - int i, ret; + int i, ret = 0; u16 nlw, cls, lnksta; u32 tmp; /* + * Ensure rescal reset for BCM2712 is really disabled. + */ + if (pcie->pcie_cfg->type == BCM2712) + ret = brcm_pcie_do_reset(dev); + if (ret) + return ret; + /* * Reset the bridge, assert the fundamental reset. Note for some SoCs, * e.g. BCM7278, the fundamental reset should not be asserted here. * This will need to be changed when support for other SoCs is added. */ - setbits_le32(base + PCIE_RGR1_SW_INIT_1, - PCIE_RGR1_SW_INIT_1_INIT_MASK | PCIE_RGR1_SW_INIT_1_PERST_MASK); + ret = brcm_pcie_bridge_sw_init_set(pcie, 1); + if (ret) + return ret; + if (pcie->pcie_cfg->type != BCM2712) + pcie->pcie_cfg->perst_set(pcie, 1); /* * The delay is a safety precaution to preclude the reset signal * from looking like a glitch. @@ -374,39 +615,77 @@ static int brcm_pcie_probe(struct udevice *dev) udelay(100); /* Take the bridge out of reset */ - clrbits_le32(base + PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_INIT_MASK); - - clrbits_le32(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG, + ret = brcm_pcie_bridge_sw_init_set(pcie, 0); + if (ret) + return ret; + clrbits_le32(base + pcie->pcie_cfg->offsets[PCIE_HARD_DEBUG], PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); /* Wait for SerDes to be stable */ udelay(100); + if (pcie->pcie_cfg->type == BCM2712) { + /* Allow a 54MHz (xosc) refclk source */ + brcm_pcie_munge_pll(pcie); + /* Fix for L1SS errata */ + tmp = readl(base + PCIE_RC_PL_PHY_CTL_15); + tmp &= ~PCIE_RC_PL_PHY_CTL_15_PM_CLK_PERIOD_MASK; + /* PM clock period is 18.52ns (round down) */ + tmp |= 0x12; + writel(tmp, base + PCIE_RC_PL_PHY_CTL_15); + } + + tmp = (pcie->pcie_cfg->type == BCM2712) ? + MISC_CTRL_MAX_BURST_SIZE_128_2712 : + MISC_CTRL_MAX_BURST_SIZE_128; /* Set SCB_MAX_BURST_SIZE, CFG_READ_UR_MODE, SCB_ACCESS_EN */ clrsetbits_le32(base + PCIE_MISC_MISC_CTRL, MISC_CTRL_MAX_BURST_SIZE_MASK, MISC_CTRL_SCB_ACCESS_EN_MASK | MISC_CTRL_CFG_READ_UR_MODE_MASK | - MISC_CTRL_MAX_BURST_SIZE_128); + MISC_CTRL_PCIE_RCB_MPS_MODE_MASK | + tmp); - pci_get_dma_regions(dev, ®ion, 0); - rc_bar2_offset = region.bus_start - region.phys_start; - rc_bar2_size = 1ULL << fls64(region.size - 1); + tmp = readl(base + PCIE_MISC_MISC_CTRL); + if (pcie->pcie_cfg->type == BCM2712) { + /* BCM2712: fixed 32GB SCB0 window */ + u32p_replace_bits(&tmp, 20, MISC_CTRL_SCB0_SIZE_MASK); + } else { + /* Pre-BCM2712: size SCB0 to match the actual DMA region. + * rc_bar2_size must be a power of two; ilog2(size) - 15 + * gives the hardware encoding (e.g. 1GB -> 15). */ + struct pci_region region; + u64 rc_bar2_size; - tmp = lower_32_bits(rc_bar2_offset); - u32p_replace_bits(&tmp, brcm_pcie_encode_ibar_size(rc_bar2_size), - RC_BAR2_CONFIG_LO_SIZE_MASK); - writel(tmp, base + PCIE_MISC_RC_BAR2_CONFIG_LO); - writel(upper_32_bits(rc_bar2_offset), - base + PCIE_MISC_RC_BAR2_CONFIG_HI); + pci_get_dma_regions(dev, ®ion, 0); + rc_bar2_size = brcm_ibar_round_size(region.size); + u32p_replace_bits(&tmp, rc_bar2_size ? ilog2(rc_bar2_size) - 15 : 0xf, + MISC_CTRL_SCB0_SIZE_MASK); + } + writel(tmp, base + PCIE_MISC_MISC_CTRL); - scb_size_val = rc_bar2_size ? - ilog2(rc_bar2_size) - 15 : 0xf; /* 0xf is 1GB */ + if (pcie->pcie_cfg->type == BCM2712) { + /* Suppress AXI error responses and return 1s for read failures */ + tmp = readl(base + PCIE_MISC_UBUS_CTRL); + u32p_replace_bits(&tmp, 1, PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_ERR_DIS_MASK); + u32p_replace_bits(&tmp, 1, PCIE_MISC_UBUS_CTRL_UBUS_PCIE_REPLY_DECERR_DIS_MASK); + writel(tmp, base + PCIE_MISC_UBUS_CTRL); + writel(0xffffffff, base + PCIE_MISC_AXI_READ_ERROR_DATA); - tmp = readl(base + PCIE_MISC_MISC_CTRL); - u32p_replace_bits(&tmp, scb_size_val, - MISC_CTRL_SCB0_SIZE_MASK); - writel(tmp, base + PCIE_MISC_MISC_CTRL); + /* + * Adjust timeouts. The UBUS timeout also affects CRS + * completion retries, as the request will get terminated if + * either timeout expires, so both have to be a large value + * (in clocks of 750MHz). + * Set UBUS timeout to 250ms, then set RC config retry timeout + * to be ~240ms. + * + * Setting CRSVis=1 will stop the core from blocking on a CRS + * response, but does require the device to be well-behaved... + */ + writel(0xB2D0000, base + PCIE_MISC_UBUS_TIMEOUT); + writel(0xABA0000, base + PCIE_MISC_RC_CONFIG_RETRY_TIMEOUT); + } /* Disable the PCIe->GISB memory window (RC_BAR1) */ clrbits_le32(base + PCIE_MISC_RC_BAR1_CONFIG_LO, @@ -422,12 +701,13 @@ static int brcm_pcie_probe(struct udevice *dev) /* Clear any interrupts we find on boot */ writel(0xffffffff, base + PCIE_MSI_INTR2_CLR); + brcm_pcie_set_inbound_windows(dev); + if (pcie->gen) brcm_pcie_set_gen(pcie, pcie->gen); /* Unassert the fundamental reset */ - clrbits_le32(pcie->base + PCIE_RGR1_SW_INIT_1, - PCIE_RGR1_SW_INIT_1_PERST_MASK); + pcie->pcie_cfg->perst_set(pcie, 0); /* * Wait for 100ms after PERST# deassertion; see PCIe CEM specification @@ -514,14 +794,25 @@ static int brcm_pcie_remove(struct udevice *dev) void __iomem *base = pcie->base; /* Assert fundamental reset */ - setbits_le32(base + PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_PERST_MASK); + setbits_le32(base + pcie->pcie_cfg->offsets[RGR1_SW_INIT_1], + PCIE_RGR1_SW_INIT_1_PERST_MASK); /* Turn off SerDes */ - setbits_le32(base + PCIE_MISC_HARD_PCIE_HARD_DEBUG, + setbits_le32(base + pcie->pcie_cfg->offsets[PCIE_HARD_DEBUG], PCIE_HARD_DEBUG_SERDES_IDDQ_MASK); /* Shutdown bridge */ - setbits_le32(base + PCIE_RGR1_SW_INIT_1, PCIE_RGR1_SW_INIT_1_INIT_MASK); + brcm_pcie_bridge_sw_init_set(pcie, 1); + + /* + * For the controllers that are utilizing reset for bridge Sw init, + * such as BCM2712, reset should be deasserted after assertion. + * Leaving it in asserted state may lead to unexpected hangs in + * the Linux Kernel driver because it do not perform reset initialization + * and start accessing device memory. + */ + if (pcie->pcie_cfg->type == BCM2712) + brcm_pcie_bridge_sw_init_set(pcie, 0); return 0; } @@ -546,6 +837,11 @@ static int brcm_pcie_of_to_plat(struct udevice *dev) else pcie->gen = max_link_speed; + pcie->pcie_cfg = (const struct brcm_pcie_cfg_data *)dev_get_driver_data(dev); + + if (pcie->pcie_cfg->type == BCM2712) + return brcm_pcie_get_resets_dt(dev); + return 0; } @@ -554,8 +850,31 @@ static const struct dm_pci_ops brcm_pcie_ops = { .write_config = brcm_pcie_write_config, }; +static const int pcie_offsets[] = { + [RGR1_SW_INIT_1] = 0x9210, + [PCIE_HARD_DEBUG] = 0x4204, +}; + +static const struct brcm_pcie_cfg_data bcm2711_cfg = { + .offsets = pcie_offsets, + .type = BCM2711, + .perst_set = brcm_pcie_perst_set_generic, +}; + +static const int pcie_offsets_bcm2712[] = { + [RGR1_SW_INIT_1] = 0x0, + [PCIE_HARD_DEBUG] = 0x4304, +}; + +static const struct brcm_pcie_cfg_data bcm2712_cfg = { + .offsets = pcie_offsets_bcm2712, + .type = BCM2712, + .perst_set = brcm_pcie_perst_set_2712, +}; + static const struct udevice_id brcm_pcie_ids[] = { - { .compatible = "brcm,bcm2711-pcie" }, + { .compatible = "brcm,bcm2711-pcie", .data = (ulong)&bcm2711_cfg }, + { .compatible = "brcm,bcm2712-pcie", .data = (ulong)&bcm2712_cfg }, { } }; diff --git a/drivers/pci/pcie_dw_amd.c b/drivers/pci/pcie_dw_amd.c new file mode 100644 index 00000000000..81c6d8f2817 --- /dev/null +++ b/drivers/pci/pcie_dw_amd.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Versal2 DesignWare PCIe host controller driver + * + * Copyright (C) 2025 - 2026, Advanced Micro Devices, Inc. + * Author: Pranav Sanwal <[email protected]> + */ + +#include <dm.h> +#include <log.h> +#include <pci.h> +#include <wait_bit.h> + +#include <asm/gpio.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <dm/ofnode.h> +#include <linux/delay.h> + +#include "pcie_dw_common.h" + +/* + * SLCR (System Level Control Register) Interrupt Register Offsets + * These are relative to the SLCR base address from device tree + */ +#define AMD_DW_TLP_IR_STATUS_MISC 0x4c0 +#define AMD_DW_TLP_IR_DISABLE_MISC 0x4cc + +/* Interrupt bit definitions */ +#define AMD_DW_PCIE_INTR_CMPL_TIMEOUT 15 +#define AMD_DW_PCIE_INTR_PM_PME_RCVD 24 +#define AMD_DW_PCIE_INTR_PME_TO_ACK_RCVD 25 +#define AMD_DW_PCIE_INTR_MISC_CORRECTABLE 26 +#define AMD_DW_PCIE_INTR_NONFATAL 27 +#define AMD_DW_PCIE_INTR_FATAL 28 + +#define AMD_DW_PCIE_INTR_INTX_MASK GENMASK(23, 16) + +#define AMD_DW_PCIE_IMR_ALL_MASK \ + (BIT(AMD_DW_PCIE_INTR_CMPL_TIMEOUT) | \ + BIT(AMD_DW_PCIE_INTR_PM_PME_RCVD) | \ + BIT(AMD_DW_PCIE_INTR_PME_TO_ACK_RCVD) | \ + BIT(AMD_DW_PCIE_INTR_MISC_CORRECTABLE) | \ + BIT(AMD_DW_PCIE_INTR_NONFATAL) | \ + BIT(AMD_DW_PCIE_INTR_FATAL) | \ + AMD_DW_PCIE_INTR_INTX_MASK) + +/* DW PCIe Debug Registers (in DBI space) */ +#define AMD_DW_PCIE_PORT_DEBUG1 0x72c +#define AMD_DW_PCIE_PORT_DEBUG1_LINK_UP BIT(4) +#define AMD_DW_PCIE_PORT_DEBUG1_LINK_IN_TRAINING BIT(29) +#define AMD_DW_PCIE_DBI_64BIT_MEM_DECODE BIT(0) + +/* Link training timeout */ +#define LINK_WAIT_MSLEEP_MAX 1000 + +/* PCIe spec timing requirements */ +#define PCIE_RESET_CONFIG_WAIT_MS 100 +#define PCIE_T_PERST_WAIT_MS 1 + +/** + * struct amd_dw_pcie - AMD DesignWare PCIe controller private data + * @dw: DesignWare PCIe common structure + * @slcr_base: System Level Control Register base (for interrupts) + */ +struct amd_dw_pcie { + struct pcie_dw dw; + void __iomem *slcr_base; +}; + +static void amd_dw_pcie_init_port(struct amd_dw_pcie *pcie) +{ + u32 val; + + if (!pcie->slcr_base) + return; + + /* Disable all TLP interrupts */ + writel(AMD_DW_PCIE_IMR_ALL_MASK, + pcie->slcr_base + AMD_DW_TLP_IR_DISABLE_MISC); + + /* Clear any pending TLP interrupts */ + val = readl(pcie->slcr_base + AMD_DW_TLP_IR_STATUS_MISC); + val &= AMD_DW_PCIE_IMR_ALL_MASK; + writel(val, pcie->slcr_base + AMD_DW_TLP_IR_STATUS_MISC); +} + +static void amd_dw_pcie_start_link(struct amd_dw_pcie *pcie) +{ + void __iomem *reg = pcie->dw.dbi_base + AMD_DW_PCIE_PORT_DEBUG1; + struct udevice *dev = pcie->dw.dev; + struct pcie_dw *pci = &pcie->dw; + int ret; + + ret = wait_for_bit_le32(reg, AMD_DW_PCIE_PORT_DEBUG1_LINK_UP, + true, LINK_WAIT_MSLEEP_MAX, + false); + if (!ret) + ret = wait_for_bit_le32(reg, + AMD_DW_PCIE_PORT_DEBUG1_LINK_IN_TRAINING, + false, LINK_WAIT_MSLEEP_MAX, false); + if (ret) + dev_warn(dev, "PCIE-%d: Link down\n", dev_seq(dev)); + else + dev_dbg(dev, "PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", + dev_seq(dev), pcie_dw_get_link_speed(pci), + pcie_dw_get_link_width(pci), pci->first_busno); +} + +static void amd_dw_pcie_host_init(struct amd_dw_pcie *pcie) +{ + struct pcie_dw *pci = &pcie->dw; + + /* + * Set 64-bit prefetchable memory decode capability. U-Boot's pci_auto.c + * reads this bit before assigning prefetchable BARs. If cleared, it skips + * PCI_PREF_BASE_UPPER32 programming, causing 64-bit BAR assignment to fail. + */ + dw_pcie_dbi_write_enable(pci, true); + setbits_le32(pci->dbi_base + PCI_PREF_MEMORY_BASE, + AMD_DW_PCIE_DBI_64BIT_MEM_DECODE); + dw_pcie_dbi_write_enable(pci, false); + + amd_dw_pcie_init_port(pcie); + pcie_dw_setup_host(pci); +} + +static void amd_dw_pcie_request_gpio(struct udevice *dev) +{ + struct gpio_desc perst_gpio; + ofnode child_node; + int ret; + + /* + * PERST# reset GPIO is optional. Child PCI endpoint nodes may carry a + * 'reset-gpios' property to toggle the endpoint reset signal during + * initialization. If absent, the endpoint is assumed to be already + * released from reset. + */ + ofnode_for_each_subnode(child_node, dev_ofnode(dev)) { + ret = gpio_request_by_name_nodev(child_node, "reset-gpios", 0, + &perst_gpio, GPIOD_IS_OUT); + if (!ret) { + dev_dbg(dev, "Found reset-gpios in child node %s\n", + ofnode_get_name(child_node)); + dm_gpio_set_value(&perst_gpio, 1); + mdelay(PCIE_T_PERST_WAIT_MS); + dm_gpio_set_value(&perst_gpio, 0); + mdelay(PCIE_RESET_CONFIG_WAIT_MS); + dm_gpio_free(dev, &perst_gpio); + } + } +} + +static int amd_dw_pcie_of_to_plat(struct udevice *dev) +{ + struct pci_region *io_region, *mem_region, *pref_region; + struct amd_dw_pcie *pcie = dev_get_priv(dev); + struct pcie_dw *pci = &pcie->dw; + int ret; + + pci->dev = dev; + + pci->dbi_base = dev_read_addr_name_ptr(dev, "dbi"); + if (!pci->dbi_base) { + dev_err(dev, "Missing 'dbi' register region\n"); + return -EINVAL; + } + + pci->cfg_base = dev_read_addr_size_name_ptr(dev, "config", &pci->cfg_size); + if (!pci->cfg_base) { + dev_err(dev, "Missing 'config' register region\n"); + return -EINVAL; + } + + pci->atu_base = dev_read_addr_name_ptr(dev, "atu"); + if (!pci->atu_base) { + dev_dbg(dev, "No 'atu' region, using default offset from DBI\n"); + pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; + } + + pcie->slcr_base = dev_read_addr_name_ptr(dev, "slcr"); + if (!pcie->slcr_base) + dev_dbg(dev, "No 'slcr' region, interrupt features disabled\n"); + + ret = pci_get_regions(dev, &io_region, &mem_region, &pref_region); + if (ret < 0) { + dev_err(dev, "Failed to get PCI regions: %d\n", ret); + return ret; + } + + if (mem_region) + pci->mem = *mem_region; + + return 0; +} + +static int amd_dw_pcie_probe(struct udevice *dev) +{ + struct amd_dw_pcie *pcie = dev_get_priv(dev); + struct pcie_dw *pci = &pcie->dw; + + /* Set first bus number */ + pci->first_busno = dev_seq(dev); + + amd_dw_pcie_request_gpio(dev); + amd_dw_pcie_host_init(pcie); + amd_dw_pcie_start_link(pcie); + + if (pci->mem.size) { + dev_dbg(dev, "Programming ATU region 0 for MEM: phys=0x%llx bus=0x%llx size=0x%llx\n", + (unsigned long long)pci->mem.phys_start, + (unsigned long long)pci->mem.bus_start, + (unsigned long long)pci->mem.size); + pcie_dw_prog_outbound_atu_unroll(pci, + PCIE_ATU_REGION_INDEX0, + PCIE_ATU_TYPE_MEM, + pci->mem.phys_start, + pci->mem.bus_start, + pci->mem.size); + } else { + dev_warn(dev, "No MEM region configured!\n"); + } + + dev_dbg(dev, "dbi: 0x%lx | config: 0x%lx | atu: 0x%lx | slcr: 0x%lx\n", + (long)pci->dbi_base, (long)pci->cfg_base, + (long)pci->atu_base, (long)pcie->slcr_base); + + return 0; +} + +static const struct dm_pci_ops amd_dw_pcie_ops = { + .read_config = pcie_dw_read_config, + .write_config = pcie_dw_write_config, +}; + +static const struct udevice_id amd_dw_pcie_ids[] = { + { .compatible = "amd,versal2-mdb-host" }, + { } +}; + +U_BOOT_DRIVER(pcie_dw_amd) = { + .name = "pcie_dw_amd", + .id = UCLASS_PCI, + .of_match = amd_dw_pcie_ids, + .ops = &amd_dw_pcie_ops, + .of_to_plat = amd_dw_pcie_of_to_plat, + .probe = amd_dw_pcie_probe, + .priv_auto = sizeof(struct amd_dw_pcie), +}; diff --git a/drivers/pci/pcie_dw_mvebu.c b/drivers/pci/pcie_dw_mvebu.c index 43b919175c9..5a177478afc 100644 --- a/drivers/pci/pcie_dw_mvebu.c +++ b/drivers/pci/pcie_dw_mvebu.c @@ -565,13 +565,12 @@ static int pcie_dw_mvebu_of_to_plat(struct udevice *dev) struct pcie_dw_mvebu *pcie = dev_get_priv(dev); /* Get the controller base address */ - pcie->ctrl_base = devfdt_get_addr_index_ptr(dev, 0); + pcie->ctrl_base = dev_read_addr_index_ptr(dev, 0); if (!pcie->ctrl_base) return -EINVAL; /* Get the config space base address and size */ - pcie->cfg_base = devfdt_get_addr_size_index_ptr(dev, 1, - &pcie->cfg_size); + pcie->cfg_base = dev_read_addr_size_index_ptr(dev, 1, &pcie->cfg_size); if (!pcie->cfg_base) return -EINVAL; diff --git a/drivers/pci/pcie_dw_qcom.c b/drivers/pci/pcie_dw_qcom.c index 10c45aaba20..ce6b4d97d1d 100644 --- a/drivers/pci/pcie_dw_qcom.c +++ b/drivers/pci/pcie_dw_qcom.c @@ -22,7 +22,7 @@ struct qcom_pcie; -struct qcom_pcie_ops { +static const struct qcom_pcie_ops { int (*config_sid)(struct qcom_pcie *priv); }; diff --git a/drivers/pci/pcie_imx.c b/drivers/pci/pcie_imx.c index 8d853ecf2c2..c8b8e171e39 100644 --- a/drivers/pci/pcie_imx.c +++ b/drivers/pci/pcie_imx.c @@ -774,8 +774,8 @@ static int imx_pcie_of_to_plat(struct udevice *dev) { struct imx_pcie_priv *priv = dev_get_priv(dev); - priv->dbi_base = devfdt_get_addr_index_ptr(dev, 0); - priv->cfg_base = devfdt_get_addr_index_ptr(dev, 1); + priv->dbi_base = dev_read_addr_index_ptr(dev, 0); + priv->cfg_base = dev_read_addr_index_ptr(dev, 1); if (!priv->dbi_base || !priv->cfg_base) return -EINVAL; diff --git a/drivers/pci/pcie_layerscape.h b/drivers/pci/pcie_layerscape.h index d5f4930e181..e6d47241e71 100644 --- a/drivers/pci/pcie_layerscape.h +++ b/drivers/pci/pcie_layerscape.h @@ -10,6 +10,7 @@ #include <fdtdec.h> #include <pci.h> +#include <linux/ioport.h> #include <linux/sizes.h> #include <linux/types.h> #include <asm/arch-fsl-layerscape/svr.h> @@ -164,7 +165,7 @@ struct ls_pcie_rc { }; struct ls_pcie_ep { - struct fdt_resource addr_res; + struct resource addr_res; struct ls_pcie *pcie; struct udevice *bus; void __iomem *addr; diff --git a/drivers/pci/pcie_layerscape_ep.c b/drivers/pci/pcie_layerscape_ep.c index 3520488b345..b7809857565 100644 --- a/drivers/pci/pcie_layerscape_ep.c +++ b/drivers/pci/pcie_layerscape_ep.c @@ -7,7 +7,6 @@ #include <config.h> #include <asm/arch/fsl_serdes.h> #include <dm.h> -#include <asm/global_data.h> #include <dm/devres.h> #include <errno.h> #include <pci_ep.h> @@ -16,8 +15,6 @@ #include <linux/log2.h> #include "pcie_layerscape.h" -DECLARE_GLOBAL_DATA_PTR; - static void ls_pcie_ep_enable_cfg(struct ls_pcie_ep *pcie_ep) { struct ls_pcie *pcie = pcie_ep->pcie; @@ -250,17 +247,15 @@ static int ls_pcie_ep_probe(struct udevice *dev) pcie_ep->pcie = pcie; - pcie->dbi = devfdt_get_addr_index_ptr(dev, 0); + pcie->dbi = dev_read_addr_index_ptr(dev, 0); if (!pcie->dbi) return -EINVAL; - pcie->ctrl = devfdt_get_addr_index_ptr(dev, 1); + pcie->ctrl = dev_read_addr_index_ptr(dev, 1); if (!pcie->ctrl) return -EINVAL; - ret = fdt_get_named_resource(gd->fdt_blob, dev_of_offset(dev), - "reg", "reg-names", - "addr_space", &pcie_ep->addr_res); + ret = dev_read_resource_byname(dev, "addr_space", &pcie_ep->addr_res); if (ret) { printf("%s: resource \"addr_space\" not found\n", dev->name); return ret; @@ -273,8 +268,7 @@ static int ls_pcie_ep_probe(struct udevice *dev) if (!is_serdes_configured(PCIE_SRDS_PRTCL(pcie->idx))) return 0; - pcie->big_endian = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), - "big-endian"); + pcie->big_endian = dev_read_bool(dev, "big-endian"); svr = SVR_SOC_VER(get_svr()); @@ -294,13 +288,9 @@ static int ls_pcie_ep_probe(struct udevice *dev) if (pcie->mode != PCI_HEADER_TYPE_NORMAL) return 0; - pcie_ep->max_functions = fdtdec_get_int(gd->fdt_blob, - dev_of_offset(dev), - "max-functions", 1); - pcie_ep->num_ib_wins = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "num-ib-windows", 8); - pcie_ep->num_ob_wins = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "num-ob-windows", 8); + pcie_ep->max_functions = dev_read_s32_default(dev, "max-functions", 1); + pcie_ep->num_ib_wins = dev_read_s32_default(dev, "num-ib-windows", 8); + pcie_ep->num_ob_wins = dev_read_s32_default(dev, "num-ob-windows", 8); printf("PCIe%u: %s %s", PCIE_SRDS_PRTCL(pcie->idx), dev->name, "Endpoint"); diff --git a/drivers/pci_endpoint/Kconfig b/drivers/pci_endpoint/Kconfig index 9900481daa6..d1db4951a0c 100644 --- a/drivers/pci_endpoint/Kconfig +++ b/drivers/pci_endpoint/Kconfig @@ -9,10 +9,10 @@ config PCI_ENDPOINT bool "PCI Endpoint Support" depends on DM help - Enable this configuration option to support configurable PCI - endpoints. This should be enabled if the platform has a PCI - controllers that can operate in endpoint mode (as a device - connected to PCI host or bridge). + Enable this configuration option to support configurable PCI + endpoints. This should be enabled if the platform has a PCI + controllers that can operate in endpoint mode (as a device + connected to PCI host or bridge). config PCIE_CADENCE_EP bool "Cadence PCIe endpoint controller" diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 09810b62b51..89d84df96ae 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -72,14 +72,14 @@ config AB8500_USB_PHY Support for the USB OTG PHY in ST-Ericsson AB8500. config APPLE_ATCPHY - bool "Apple Type-C PHY Driver" - depends on PHY && ARCH_APPLE - default y - help - Support for the Apple Type-C PHY. + bool "Apple Type-C PHY Driver" + depends on PHY && ARCH_APPLE + default y + help + Support for the Apple Type-C PHY. - This is a dummy driver since the PHY is initialized - sufficiently by previous stage firmware. + This is a dummy driver since the PHY is initialized + sufficiently by previous stage firmware. config BCM6318_USBH_PHY bool "BCM6318 USBH PHY support" @@ -114,7 +114,7 @@ config BCM_SR_PCIE_PHY If unsure, say N. config PHY_DA8XX_USB - tristate "TI DA8xx USB PHY Driver" + bool "TI DA8xx USB PHY Driver" depends on PHY && ARCH_DAVINCI help Enable this to support the USB PHY on DA8xx SoCs. @@ -138,7 +138,7 @@ config SPL_PIPE3_PHY and omap5 config AM654_PHY - tristate "TI AM654 SERDES support" + bool "TI AM654 SERDES support" depends on PHY && ARCH_K3 select REGMAP select SYSCON @@ -155,7 +155,7 @@ config STI_USB_PHY STiH407 SoC families. config PHY_RCAR_GEN2 - tristate "Renesas R-Car Gen2 USB PHY" + bool "Renesas R-Car Gen2 USB PHY" depends on PHY && RCAR_GEN2 help Support for the Renesas R-Car Gen2 USB PHY. This driver operates the @@ -163,7 +163,7 @@ config PHY_RCAR_GEN2 allows configuring the module multiplexing. config PHY_RCAR_GEN3 - tristate "Renesas R-Car Gen3 USB PHY" + bool "Renesas R-Car Gen3 USB PHY" depends on PHY && CLK && DM_REGULATOR && (RCAR_GEN3 || RZG2L) default y if (RCAR_GEN3 || RZG2L) help @@ -171,7 +171,7 @@ config PHY_RCAR_GEN3 PHY connected to EHCI USB module and controls USB OTG operation. config PHY_STM32_USBPHYC - tristate "STMicroelectronics STM32 SoC USB HS PHY driver" + bool "STMicroelectronics STM32 SoC USB HS PHY driver" depends on PHY && ARCH_STM32MP help Enable this to support the High-Speed USB transceiver that is part of @@ -249,14 +249,14 @@ config MT7620_USB_PHY depends on PHY depends on SOC_MT7620 help - Support the intergated USB PHY in MediaTek MT7620 SoC + Support the intergated USB PHY in MediaTek MT7620 SoC config MT76X8_USB_PHY bool "MediaTek MT76x8 (7628/88) USB PHY support" depends on PHY depends on SOC_MT7628 help - Support the USB PHY in MT76x8 SoCs + Support the USB PHY in MT76x8 SoCs This PHY is found on MT76x8 devices supporting USB. @@ -283,7 +283,7 @@ config PHY_MTK_TPHY so you can easily distinguish them by banks layout. config PHY_MTK_UFS - tristate "MediaTek UFS M-PHY driver" + bool "MediaTek UFS M-PHY driver" depends on ARCH_MEDIATEK depends on PHY help @@ -292,6 +292,17 @@ config PHY_MTK_UFS initialization, power on and power off flow of specified M-PHYs. +config PHY_MTK_XSPHY + bool "MediaTek XS-PHY Driver" + depends on PHY + depends on ARCH_MEDIATEK + select REGMAP + select SYSCON + help + Enable this to support the SuperSpeedPlus XS-PHY transceiver for + USB3.1 GEN2 controllers on MediaTek chips. The driver supports + multiple USB2.0, USB3.1 GEN2 ports. + config PHY_NPCM_USB bool "Nuvoton NPCM USB PHY support" depends on PHY @@ -326,7 +337,7 @@ config PHY_IMX8M_PCIE This PHY is found on i.MX8M devices supporting PCIe. config PHY_XILINX_ZYNQMP - tristate "Xilinx ZynqMP PHY driver" + bool "Xilinx ZynqMP PHY driver" depends on PHY && ARCH_ZYNQMP help Enable this to support ZynqMP High Speed Gigabit Transceiver @@ -339,4 +350,12 @@ source "drivers/phy/qcom/Kconfig" source "drivers/phy/renesas/Kconfig" source "drivers/phy/starfive/Kconfig" +config PHY_COMMON_PROPS + bool "Common PHY properties support" + help + Enable support for common PHY properties defined in the device tree, + such as rx-polarity and tx-polarity. This provides helpers for PHY + drivers to read polarity and other standard PHY properties from the + device tree node. + endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 83102349669..e46c362878d 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -38,10 +38,12 @@ 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_MTK_UFS) += phy-mtk-ufs.o +obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-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-$(CONFIG_PHY_COMMON_PROPS) += phy-common-props.o obj-y += cadence/ obj-y += ti/ obj-y += qcom/ diff --git a/drivers/phy/cadence/Kconfig b/drivers/phy/cadence/Kconfig index 8c0ab80fbbc..f5f096889fe 100644 --- a/drivers/phy/cadence/Kconfig +++ b/drivers/phy/cadence/Kconfig @@ -1,11 +1,11 @@ config PHY_CADENCE_SIERRA - tristate "Cadence Sierra PHY Driver" + bool "Cadence Sierra PHY Driver" depends on DM_RESET help Enable this to support the Cadence Sierra PHY driver config PHY_CADENCE_TORRENT - tristate "Cadence Torrent PHY Driver" + bool "Cadence Torrent PHY Driver" depends on DM_RESET help Enable this to support the Cadence Torrent PHY driver diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index bd7ab9d1b77..9f8a6d8d43d 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -1068,12 +1068,12 @@ static int cdns_sierra_phy_probe(struct udevice *dev) sp->dev = dev; - sp->base = devfdt_remap_addr_index(dev, 0); + sp->base = dev_remap_addr_index(dev, 0); if (!sp->base) { dev_err(dev, "unable to map regs\n"); return -ENOMEM; } - devfdt_get_addr_size_index(dev, 0, (fdt_size_t *)&sp->size); + dev_read_addr_size_index(dev, 0, (fdt_size_t *)&sp->size); /* Get init data for this PHY */ data = (struct cdns_sierra_data *)dev_get_driver_data(dev); diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 933533b2b0b..814aff15070 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -791,10 +791,10 @@ static int cdns_torrent_phy_probe(struct udevice *dev) return ret; } - cdns_phy->sd_base = devfdt_remap_addr_index(dev, 0); - if (IS_ERR(cdns_phy->sd_base)) - return PTR_ERR(cdns_phy->sd_base); - devfdt_get_addr_size_index(dev, 0, (fdt_size_t *)&cdns_phy->size); + cdns_phy->sd_base = dev_remap_addr_index(dev, 0); + if (!cdns_phy->sd_base) + return -EINVAL; + dev_read_addr_size_index(dev, 0, (fdt_size_t *)&cdns_phy->size); dev_for_each_subnode(child, dev) subnodes++; diff --git a/drivers/phy/marvell/comphy_core.c b/drivers/phy/marvell/comphy_core.c index b074d58f9f6..0ab5f9a3f0a 100644 --- a/drivers/phy/marvell/comphy_core.c +++ b/drivers/phy/marvell/comphy_core.c @@ -84,11 +84,11 @@ static int comphy_probe(struct udevice *dev) int res; /* Save base addresses for later use */ - chip_cfg->comphy_base_addr = devfdt_get_addr_index_ptr(dev, 0); + chip_cfg->comphy_base_addr = dev_read_addr_index_ptr(dev, 0); if (!chip_cfg->comphy_base_addr) return -EINVAL; - chip_cfg->hpipe3_base_addr = devfdt_get_addr_index_ptr(dev, 1); + chip_cfg->hpipe3_base_addr = dev_read_addr_index_ptr(dev, 1); if (!chip_cfg->hpipe3_base_addr) return -EINVAL; diff --git a/drivers/phy/phy-common-props.c b/drivers/phy/phy-common-props.c new file mode 100644 index 00000000000..0a0b4439430 --- /dev/null +++ b/drivers/phy/phy-common-props.c @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * phy-common-props.c -- Common PHY properties + * + * Copyright 2025-2026 NXP + */ +#include <dm/ofnode.h> +#include <log.h> +#include <malloc.h> +#include <linux/phy/phy-common-props.h> +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/errno.h> + +/** + * ofnode_count_u32_prop - Count number of u32 elements in a property + * @node: Device tree node + * @propname: Property name + * + * Return: number of u32 elements, or negative error code + */ +static int ofnode_count_u32_prop(ofnode node, const char *propname) +{ + int size; + + size = ofnode_read_size(node, propname); + if (size < 0) { + pr_debug("%s: property '%s' not found (err=%d)\n", + __func__, propname, size); + return size; + } + + pr_debug("%s: property '%s' has %zu bytes (%zu elements)\n", + __func__, propname, (size_t)size, (size_t)(size / sizeof(u32))); + + return size / sizeof(u32); +} + +/** + * ofnode_get_u32_prop_for_name - Find u32 property by name, or default value + * @node: Device tree node; if invalid or @props_title is absent, @default_val is used + * @name: Property name used as lookup key in @names_title (must not be NULL) + * @props_title: Name of u32 array property holding values + * @names_title: Name of string array property holding lookup keys + * @default_val: Default value if @node is invalid, @props_title is absent, or empty + * @val: Pointer to store the returned value + * + * This function retrieves a u32 value from @props_title based on a name lookup + * in @names_title. The value stored in @val is determined as follows: + * + * - If @node is invalid or @props_title is absent: @default_val is used + * - If @props_title exists but is empty: @default_val is used + * - If @props_title has exactly one element and @names_title is empty: + * that element is used + * - Otherwise: @val is set to the element at the same index where @name is + * found in @names_title. + * - If @name is not found, the function looks for a "default" entry in + * @names_title and uses the corresponding value from @props_title + * + * When both @props_title and @names_title are present, they must have the + * same number of elements (except when @props_title has exactly one element). + * + * Return: zero on success, negative error on failure. + */ +static int ofnode_get_u32_prop_for_name(ofnode node, const char *name, + const char *props_title, + const char *names_title, + unsigned int default_val, + unsigned int *val) +{ + int err, n_props, n_names, idx; + u32 *props; + + if (!name) { + pr_err("Error: Lookup key inside \"%s\" is mandatory\n", + names_title); + return -EINVAL; + } + + pr_debug("%s: looking up '%s' in props='%s' names='%s' default=%u\n", + __func__, name, props_title, names_title, default_val); + + n_props = ofnode_count_u32_prop(node, props_title); + if (n_props < 0) { + /* property is absent */ + pr_debug("%s: '%s' is absent, using default value %u\n", + __func__, props_title, default_val); + *val = default_val; + return 0; + } + if (n_props == 0) { + /* property exists but is empty, use default */ + pr_debug("%s: '%s' is empty, using default value %u\n", + __func__, props_title, default_val); + *val = default_val; + return 0; + } + + n_names = ofnode_read_string_count(node, names_title); + + pr_debug("%s: '%s' has %d elements, '%s' has %d entries\n", + __func__, props_title, n_props, names_title, n_names); + if (n_names >= 0 && n_props != n_names) { + pr_err("Error: mismatch between \"%s\" and \"%s\" property count (%d vs %d)\n", + props_title, names_title, n_props, n_names); + return -EINVAL; + } + + idx = ofnode_stringlist_search(node, names_title, name); + if (idx >= 0) { + pr_debug("%s: found '%s' at index %d in '%s'\n", + __func__, name, idx, names_title); + } else { + pr_debug("%s: '%s' not found in '%s', trying 'default'\n", + __func__, name, names_title); + idx = ofnode_stringlist_search(node, names_title, "default"); + if (idx >= 0) + pr_debug("%s: 'default' entry found at index %d\n", + __func__, idx); + else + pr_debug("%s: 'default' entry not found in '%s'\n", + __func__, names_title); + } + /* + * If the mode name is missing, it can only mean the specified property + * is the default one for all modes, so reject any other property count + * than 1. + */ + if (idx < 0 && n_props != 1) { + pr_err("Error: \"%s\" property has %d elements, but cannot find \"%s\" in \"%s\" and there is no default value\n", + props_title, n_props, name, names_title); + return -EINVAL; + } + + if (n_props == 1) { + pr_debug("%s: single-element '%s', reading directly\n", + __func__, props_title); + err = ofnode_read_u32(node, props_title, val); + if (err) { + pr_debug("%s: failed to read '%s' (err=%d)\n", + __func__, props_title, err); + return err; + } + pr_debug("%s: resolved value %u for name '%s' from '%s'\n", + __func__, *val, name, props_title); + return 0; + } + + /* We implicitly know idx >= 0 here */ + props = calloc(n_props, sizeof(*props)); + if (!props) + return -ENOMEM; + + err = ofnode_read_u32_array(node, props_title, props, n_props); + if (err >= 0) { + *val = props[idx]; + pr_debug("%s: resolved value %u at index %d for name '%s' from '%s'\n", + __func__, *val, idx, name, props_title); + } else { + pr_debug("%s: failed to read u32 array '%s' (err=%d)\n", + __func__, props_title, err); + } + + free(props); + + return err; +} + +/** + * phy_get_polarity_for_mode - Get polarity for a specific PHY mode + * @node: Device tree node + * @mode_name: The name of the PHY mode to look up + * @supported: Bit mask of supported polarity values + * @default_val: Default polarity value if property is missing + * @polarity_prop: Name of the polarity property + * @names_prop: Name of the names property + * @val: Pointer to returned polarity + * + * Return: zero on success, negative error on failure. + */ +static int phy_get_polarity_for_mode(ofnode node, const char *mode_name, + unsigned int supported, + unsigned int default_val, + const char *polarity_prop, + const char *names_prop, + unsigned int *val) +{ + int err; + + pr_debug("%s: querying '%s' for mode '%s' (supported=0x%x, default=%u)\n", + __func__, polarity_prop, mode_name, supported, default_val); + + err = ofnode_get_u32_prop_for_name(node, mode_name, polarity_prop, + names_prop, default_val, val); + if (err) { + pr_debug("%s: '%s' lookup failed for mode '%s' (err=%d)\n", + __func__, polarity_prop, mode_name, err); + return err; + } + + pr_debug("%s: '%s' for mode '%s' = %u\n", + __func__, polarity_prop, mode_name, *val); + + if (!(supported & BIT(*val))) { + pr_err("Error: %d is not a supported value for '%s' element '%s'\n", + *val, polarity_prop, mode_name); + err = -EOPNOTSUPP; + } + + return err; +} + +/** + * phy_get_rx_polarity - Get RX polarity for PHY differential lane + * @node: Pointer to the PHY's device tree node. + * @mode_name: The name of the PHY mode to look up. + * @supported: Bit mask of PHY_POL_NORMAL, PHY_POL_INVERT and PHY_POL_AUTO + * @default_val: Default polarity value if property is missing + * @val: Pointer to returned polarity. + * + * Return: zero on success, negative error on failure. + */ +int phy_get_rx_polarity(ofnode node, const char *mode_name, + unsigned int supported, unsigned int default_val, + unsigned int *val) +{ + return phy_get_polarity_for_mode(node, mode_name, supported, + default_val, "rx-polarity", + "rx-polarity-names", val); +} + +/** + * phy_get_tx_polarity - Get TX polarity for PHY differential lane + * @node: Pointer to the PHY's device tree node. + * @mode_name: The name of the PHY mode to look up. + * @supported: Bit mask of PHY_POL_NORMAL, PHY_POL_INVERT and PHY_POL_AUTO + * @default_val: Default polarity value if property is missing + * @val: Pointer to returned polarity. + * + * Return: zero on success, negative error on failure. + */ +int phy_get_tx_polarity(ofnode node, const char *mode_name, + unsigned int supported, unsigned int default_val, + unsigned int *val) +{ + return phy_get_polarity_for_mode(node, mode_name, supported, + default_val, "tx-polarity", + "tx-polarity-names", val); +} + +/** + * phy_get_manual_rx_polarity - Get manual RX polarity for PHY differential lane + * @node: Pointer to the PHY's device tree node. + * @mode_name: The name of the PHY mode to look up. + * @val: Pointer to returned polarity. + * + * Helper for PHYs which do not support protocols with automatic RX polarity + * detection and correction. + * + * Return: zero on success, negative error on failure. + */ +int phy_get_manual_rx_polarity(ofnode node, const char *mode_name, + unsigned int *val) +{ + return phy_get_rx_polarity(node, mode_name, + BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT), + PHY_POL_NORMAL, val); +} + +/** + * phy_get_manual_tx_polarity - Get manual TX polarity for PHY differential lane + * @node: Pointer to the PHY's device tree node. + * @mode_name: The name of the PHY mode to look up. + * @val: Pointer to returned polarity. + * + * Helper for PHYs without any custom default value for the TX polarity. + * + * Return: zero on success, negative error on failure. + */ +int phy_get_manual_tx_polarity(ofnode node, const char *mode_name, + unsigned int *val) +{ + return phy_get_tx_polarity(node, mode_name, + BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT), + PHY_POL_NORMAL, val); +} diff --git a/drivers/phy/phy-mtk-ufs.c b/drivers/phy/phy-mtk-ufs.c index 1eda3df858d..c4c214dcde0 100644 --- a/drivers/phy/phy-mtk-ufs.c +++ b/drivers/phy/phy-mtk-ufs.c @@ -6,52 +6,41 @@ * Copyright (c) 2025, Igor Belwon <[email protected]> */ -#include "dm/ofnode.h" -#include "dm/read.h" -#include <clk.h> -#include <dm.h> -#include <generic-phy.h> -#include <malloc.h> -#include <mapmem.h> -#include <regmap.h> -#include <syscon.h> #include <asm/io.h> +#include <clk.h> +#include <dm/device.h> #include <dm/device_compat.h> -#include <dm/devres.h> -#include <linux/bitfield.h> +#include <dm/read.h> +#include <generic-phy.h> #include <linux/bitops.h> #include <linux/delay.h> - -#include <dt-bindings/phy/phy.h> +#include <mapmem.h> /* mphy register and offsets */ -#define MP_GLB_DIG_8C 0x008C -#define FRC_PLL_ISO_EN BIT(8) -#define PLL_ISO_EN BIT(9) -#define FRC_FRC_PWR_ON BIT(10) -#define PLL_PWR_ON BIT(11) - -#define MP_LN_DIG_RX_9C 0xA09C -#define FSM_DIFZ_FRC BIT(18) +#define MP_GLB_DIG_8C 0x008C +#define FRC_PLL_ISO_EN BIT(8) +#define PLL_ISO_EN BIT(9) +#define FRC_FRC_PWR_ON BIT(10) +#define PLL_PWR_ON BIT(11) -#define MP_LN_DIG_RX_AC 0xA0AC -#define FRC_RX_SQ_EN BIT(0) -#define RX_SQ_EN BIT(1) +#define MP_LN_DIG_RX_9C 0xA09C +#define FSM_DIFZ_FRC BIT(18) -#define MP_LN_RX_44 0xB044 -#define FRC_CDR_PWR_ON BIT(17) -#define CDR_PWR_ON BIT(18) -#define FRC_CDR_ISO_EN BIT(19) -#define CDR_ISO_EN BIT(20) +#define MP_LN_DIG_RX_AC 0xA0AC +#define FRC_RX_SQ_EN BIT(0) +#define RX_SQ_EN BIT(1) -#define UFSPHY_CLKS_CNT 2 +#define MP_LN_RX_44 0xB044 +#define FRC_CDR_PWR_ON BIT(17) +#define CDR_PWR_ON BIT(18) +#define FRC_CDR_ISO_EN BIT(19) +#define CDR_ISO_EN BIT(20) struct mtk_ufs_phy { struct udevice *dev; void __iomem *mmio; - struct clk *unipro_clk; - struct clk *mp_clk; + struct clk_bulk clk_bulk; }; static void ufs_mtk_phy_set_active(struct mtk_ufs_phy *phy) @@ -88,16 +77,9 @@ static int mtk_phy_power_on(struct phy *phy) struct mtk_ufs_phy *ufs_phy = dev_get_priv(phy->dev); int ret; - ret = clk_enable(ufs_phy->mp_clk); - if (ret < 0) { - dev_err(phy->dev, "failed to enable mp_clk\n"); - return ret; - } - - ret = clk_enable(ufs_phy->unipro_clk); - if (ret < 0) { - dev_err(phy->dev, "failed to enable unipro_clk %d\n", ret); - clk_disable(ufs_phy->unipro_clk); + ret = clk_enable_bulk(&ufs_phy->clk_bulk); + if (ret) { + dev_err(phy->dev, "failed to enable clocks (ret=%d)\n", ret); return ret; } @@ -106,34 +88,44 @@ static int mtk_phy_power_on(struct phy *phy) return 0; } -static int mtk_phy_power_off(struct phy *phy) +static void ufs_mtk_phy_set_inactive(struct mtk_ufs_phy *phy) { - struct mtk_ufs_phy *ufs_phy = dev_get_priv(phy->dev); - /* Set PHY to Deep Hibernate mode */ - setbits_le32(ufs_phy->mmio + MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); + setbits_le32(phy->mmio + MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); /* force DA_MP_RX0_SQ_EN */ - setbits_le32(ufs_phy->mmio + MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); - clrbits_le32(ufs_phy->mmio + MP_LN_DIG_RX_AC, RX_SQ_EN); + setbits_le32(phy->mmio + MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); + clrbits_le32(phy->mmio + MP_LN_DIG_RX_AC, RX_SQ_EN); /* force DA_MP_CDR_ISO_EN */ - setbits_le32(ufs_phy->mmio + MP_LN_RX_44, FRC_CDR_ISO_EN); - setbits_le32(ufs_phy->mmio + MP_LN_RX_44, CDR_ISO_EN); + setbits_le32(phy->mmio + MP_LN_RX_44, FRC_CDR_ISO_EN); + setbits_le32(phy->mmio + MP_LN_RX_44, CDR_ISO_EN); /* force DA_MP_CDR_PWR_ON */ - setbits_le32(ufs_phy->mmio + MP_LN_RX_44, FRC_CDR_PWR_ON); - clrbits_le32(ufs_phy->mmio + MP_LN_RX_44, CDR_PWR_ON); + setbits_le32(phy->mmio + MP_LN_RX_44, FRC_CDR_PWR_ON); + clrbits_le32(phy->mmio + MP_LN_RX_44, CDR_PWR_ON); /* force DA_MP_PLL_ISO_EN */ - setbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, FRC_PLL_ISO_EN); - setbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, PLL_ISO_EN); + setbits_le32(phy->mmio + MP_GLB_DIG_8C, FRC_PLL_ISO_EN); + setbits_le32(phy->mmio + MP_GLB_DIG_8C, PLL_ISO_EN); /* force DA_MP_PLL_PWR_ON */ - setbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, FRC_FRC_PWR_ON); - clrbits_le32(ufs_phy->mmio + MP_GLB_DIG_8C, PLL_PWR_ON); + setbits_le32(phy->mmio + MP_GLB_DIG_8C, FRC_FRC_PWR_ON); + clrbits_le32(phy->mmio + MP_GLB_DIG_8C, PLL_PWR_ON); +} - return 0; +static int mtk_phy_power_off(struct phy *phy) +{ + struct mtk_ufs_phy *ufs_phy = dev_get_priv(phy->dev); + int ret; + + ufs_mtk_phy_set_inactive(ufs_phy); + + ret = clk_disable_bulk(&ufs_phy->clk_bulk); + if (ret) + dev_err(phy->dev, "failed to disable clocks (ret=%d)\n", ret); + + return ret; } static const struct phy_ops mtk_ufs_phy_ops = { @@ -147,10 +139,6 @@ static int mtk_ufs_phy_probe(struct udevice *dev) fdt_addr_t addr; int ret; - phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); - if (!phy) - return -ENOMEM; - addr = dev_read_addr(dev); if (addr == FDT_ADDR_T_NONE) return -ENOMEM; @@ -158,21 +146,11 @@ static int mtk_ufs_phy_probe(struct udevice *dev) phy->dev = dev; phy->mmio = map_sysmem(addr, 0); - phy->mp_clk = devm_clk_get(dev, "mp"); - if (IS_ERR(phy->mp_clk)) { - ret = PTR_ERR(phy->mp_clk); - dev_err(dev, "Failed to get mp clock (ret=%d)\n", ret); - return ret; - } + ret = clk_get_bulk(dev, &phy->clk_bulk); + if (ret) + dev_err(dev, "Failed to get clocks (ret=%d)\n", ret); - phy->unipro_clk = devm_clk_get(dev, "unipro"); - if (IS_ERR(phy->unipro_clk)) { - ret = PTR_ERR(phy->unipro_clk); - dev_err(dev, "Failed to get unipro clock (ret=%d)\n", ret); - return ret; - } - - return 0; + return ret; } static const struct udevice_id mtk_ufs_phy_id_table[] = { diff --git a/drivers/phy/phy-mtk-xsphy.c b/drivers/phy/phy-mtk-xsphy.c new file mode 100644 index 00000000000..d3418ffb101 --- /dev/null +++ b/drivers/phy/phy-mtk-xsphy.c @@ -0,0 +1,600 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MediaTek USB3.1 gen2 xsphy Driver + * + * Copyright (c) 2026 MediaTek Inc. + * Copyright (c) 2026 BayLibre, SAS + * + * Based on Linux mtk-xsphy driver: + * Copyright (c) 2018 MediaTek Inc. + * Author: Chunfeng Yun <[email protected]> + * + * And U-Boot mtk-tphy driver: + * Copyright (c) 2015 - 2019 MediaTek Inc. + * Author: Chunfeng Yun <[email protected]> + * Ryder Lee <[email protected]> + */ + +#include <clk.h> +#include <dm.h> +#include <generic-phy.h> +#include <malloc.h> +#include <mapmem.h> +#include <regmap.h> +#include <syscon.h> + +#include <asm/io.h> +#include <dm/device_compat.h> +#include <dm/devres.h> +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/iopoll.h> + +#include <dt-bindings/phy/phy.h> + +/* u2 phy banks */ +#define SSUSB_SIFSLV_MISC 0x000 +#define SSUSB_SIFSLV_U2FREQ 0x100 +#define SSUSB_SIFSLV_U2PHY_COM 0x300 + +/* u3 phy shared banks */ +#define SSPXTP_SIFSLV_DIG_GLB 0x000 +#define SSPXTP_SIFSLV_PHYA_GLB 0x100 + +/* u3 phy banks */ +#define SSPXTP_SIFSLV_DIG_LN_TOP 0x000 +#define SSPXTP_SIFSLV_DIG_LN_TX0 0x100 +#define SSPXTP_SIFSLV_DIG_LN_RX0 0x200 +#define SSPXTP_SIFSLV_DIG_LN_DAIF 0x300 +#define SSPXTP_SIFSLV_PHYA_LN 0x400 + +#define XSP_U2FREQ_FMCR0 ((SSUSB_SIFSLV_U2FREQ) + 0x00) +#define P2F_RG_FREQDET_EN BIT(24) +#define P2F_RG_CYCLECNT GENMASK(23, 0) + +#define XSP_U2FREQ_MMONR0 ((SSUSB_SIFSLV_U2FREQ) + 0x0c) + +#define XSP_U2FREQ_FMMONR1 ((SSUSB_SIFSLV_U2FREQ) + 0x10) +#define P2F_RG_FRCK_EN BIT(8) +#define P2F_USB_FM_VALID BIT(0) + +#define XSP_USBPHYACR0 ((SSUSB_SIFSLV_U2PHY_COM) + 0x00) +#define P2A0_RG_INTR_EN BIT(5) + +#define XSP_USBPHYACR1 ((SSUSB_SIFSLV_U2PHY_COM) + 0x04) +#define P2A1_RG_INTR_CAL GENMASK(23, 19) +#define P2A1_RG_VRT_SEL GENMASK(14, 12) +#define P2A1_RG_TERM_SEL GENMASK(10, 8) + +#define XSP_USBPHYACR5 ((SSUSB_SIFSLV_U2PHY_COM) + 0x014) +#define P2A5_RG_HSTX_SRCAL_EN BIT(15) +#define P2A5_RG_HSTX_SRCTRL GENMASK(14, 12) + +#define XSP_USBPHYACR6 ((SSUSB_SIFSLV_U2PHY_COM) + 0x018) +#define P2A6_RG_BC11_SW_EN BIT(23) +#define P2A6_RG_OTG_VBUSCMP_EN BIT(20) + +#define XSP_U2PHYDTM1 ((SSUSB_SIFSLV_U2PHY_COM) + 0x06C) +#define P2D_FORCE_IDDIG BIT(9) +#define P2D_RG_VBUSVALID BIT(5) +#define P2D_RG_SESSEND BIT(4) +#define P2D_RG_AVALID BIT(2) +#define P2D_RG_IDDIG BIT(1) + +#define SSPXTP_PHYA_GLB_00 ((SSPXTP_SIFSLV_PHYA_GLB) + 0x00) +#define RG_XTP_GLB_BIAS_INTR_CTRL GENMASK(21, 16) + +#define SSPXTP_PHYA_LN_04 ((SSPXTP_SIFSLV_PHYA_LN) + 0x04) +#define RG_XTP_LN0_TX_IMPSEL GENMASK(4, 0) + +#define SSPXTP_PHYA_LN_14 ((SSPXTP_SIFSLV_PHYA_LN) + 0x014) +#define RG_XTP_LN0_RX_IMPSEL GENMASK(4, 0) + +#define XSP_REF_CLK_MHZ 26 +#define XSP_SLEW_RATE_COEF 17 +#define XSP_SR_COEF_DIVISOR 1000 +#define XSP_FM_DET_CYCLE_CNT 1024 + +/* PHY switch between pcie/usb3/sgmii */ +#define USB_PHY_SWITCH_CTRL 0x0 +#define RG_PHY_SW_TYPE GENMASK(3, 0) +#define RG_PHY_SW_PCIE 0x0 +#define RG_PHY_SW_USB3 0x1 +#define RG_PHY_SW_SGMII 0x2 + +struct mtk_xsphy_instance { + void __iomem *port_base; + struct device_node *np; + struct clk ref_clk; /* reference clock of analog phy */ + u32 index; + u32 type; + struct regmap *type_sw; + u32 type_sw_reg; + u32 type_sw_index; + /* only for HQA test */ + u32 efuse_intr; + u32 efuse_tx_imp; + u32 efuse_rx_imp; + /* u2 eye diagram */ + u32 eye_src; + u32 eye_vrt; + u32 eye_term; +}; + +struct mtk_xsphy { + struct udevice *dev; + void __iomem *sif_base; + struct mtk_xsphy_instance **phys; + u32 nphys; + u32 src_ref_clk_mhz; /* reference clock for slew rate calibrate */ + u32 src_coef; /* coefficient for slew rate calibrate */ +}; + +static void mtk_xsphy_u2_slew_rate_calibrate(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance) +{ + void __iomem *pbase = instance->port_base; + u32 calib_val; + u32 fm_out; + u32 tmp; + + /* use force value */ + if (instance->eye_src) + return; + + /* enable USB ring oscillator */ + setbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCAL_EN); + /* wait for clock to become stable */ + udelay(1); + + /* enable free run clock */ + setbits_le32(pbase + XSP_U2FREQ_FMMONR1, P2F_RG_FRCK_EN); + + /* set cycle count as 1024 */ + clrsetbits_le32(pbase + XSP_U2FREQ_FMCR0, P2F_RG_CYCLECNT, + FIELD_PREP(P2F_RG_CYCLECNT, XSP_FM_DET_CYCLE_CNT)); + + /* enable frequency meter */ + setbits_le32(pbase + XSP_U2FREQ_FMCR0, P2F_RG_FREQDET_EN); + + /* ignore return value */ + readl_poll_sleep_timeout(pbase + XSP_U2FREQ_FMMONR1, tmp, + (tmp & P2F_USB_FM_VALID), 10, 200); + + fm_out = readl(pbase + XSP_U2FREQ_MMONR0); + + /* disable frequency meter */ + clrbits_le32(pbase + XSP_U2FREQ_FMCR0, P2F_RG_FREQDET_EN); + + /* disable free run clock */ + clrbits_le32(pbase + XSP_U2FREQ_FMMONR1, P2F_RG_FRCK_EN); + + if (fm_out) { + /* (1024 / FM_OUT) x reference clock frequency x coefficient */ + tmp = xsphy->src_ref_clk_mhz * xsphy->src_coef; + tmp = (tmp * XSP_FM_DET_CYCLE_CNT) / fm_out; + calib_val = DIV_ROUND_CLOSEST(tmp, XSP_SR_COEF_DIVISOR); + } else { + /* if FM detection fail, set default value */ + calib_val = 3; + } + dev_dbg(xsphy->dev, "phy.%u, fm_out:%u, calib:%u (clk:%u, coef:%u)\n", + instance->index, fm_out, calib_val, xsphy->src_ref_clk_mhz, + xsphy->src_coef); + + /* set HS slew rate */ + clrsetbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCTRL, + FIELD_PREP(P2A5_RG_HSTX_SRCTRL, calib_val)); + + /* disable USB ring oscillator */ + clrbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCAL_EN); +} + +static void mtk_xsphy_u2_instance_init(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance) +{ + void __iomem *pbase = instance->port_base; + + /* DP/DM BC1.1 path Disable */ + clrbits_le32(pbase + XSP_USBPHYACR6, P2A6_RG_BC11_SW_EN); + + setbits_le32(pbase + XSP_USBPHYACR0, P2A0_RG_INTR_EN); +} + +static void mtk_xsphy_u2_instance_power_on(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance) +{ + void __iomem *pbase = instance->port_base; + + setbits_le32(pbase + XSP_USBPHYACR6, P2A6_RG_OTG_VBUSCMP_EN); + + clrsetbits_le32(pbase + XSP_U2PHYDTM1, + P2D_RG_VBUSVALID | P2D_RG_AVALID | P2D_RG_SESSEND, + P2D_RG_VBUSVALID | P2D_RG_AVALID); + + dev_dbg(xsphy->dev, "%s(%u)\n", __func__, instance->index); +} + +static void mtk_xsphy_u2_instance_power_off(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance) +{ + void __iomem *pbase = instance->port_base; + + clrbits_le32(pbase + XSP_USBPHYACR6, P2A6_RG_OTG_VBUSCMP_EN); + + clrsetbits_le32(pbase + XSP_U2PHYDTM1, + P2D_RG_VBUSVALID | P2D_RG_AVALID | P2D_RG_SESSEND, + P2D_RG_SESSEND); + + dev_dbg(xsphy->dev, "%s(%u)\n", __func__, instance->index); +} + +static void mtk_xsphy_u2_instance_set_mode(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance, + enum phy_mode mode) +{ + u32 tmp; + + tmp = readl(instance->port_base + XSP_U2PHYDTM1); + + switch (mode) { + case PHY_MODE_USB_DEVICE: + tmp |= P2D_FORCE_IDDIG | P2D_RG_IDDIG; + break; + case PHY_MODE_USB_HOST: + tmp |= P2D_FORCE_IDDIG; + tmp &= ~P2D_RG_IDDIG; + break; + case PHY_MODE_USB_OTG: + tmp &= ~(P2D_FORCE_IDDIG | P2D_RG_IDDIG); + break; + default: + return; + } + + writel(tmp, instance->port_base + XSP_U2PHYDTM1); +} + +static void mtk_xsphy_parse_property(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance) +{ + ofnode node = np_to_ofnode(instance->np); + + switch (instance->type) { + case PHY_TYPE_USB2: + ofnode_read_u32(node, "mediatek,efuse-intr", &instance->efuse_intr); + ofnode_read_u32(node, "mediatek,eye-src", &instance->eye_src); + ofnode_read_u32(node, "mediatek,eye-vrt", &instance->eye_vrt); + ofnode_read_u32(node, "mediatek,eye-term", &instance->eye_term); + + dev_dbg(xsphy->dev, "intr:%u, src:%u, vrt:%u, term:%u\n", + instance->efuse_intr, instance->eye_src, + instance->eye_vrt, instance->eye_term); + return; + case PHY_TYPE_USB3: + ofnode_read_u32(node, "mediatek,efuse-intr", &instance->efuse_intr); + ofnode_read_u32(node, "mediatek,efuse-tx-imp", &instance->efuse_tx_imp); + ofnode_read_u32(node, "mediatek,efuse-rx-imp", &instance->efuse_rx_imp); + + dev_dbg(xsphy->dev, "intr:%u, tx-imp:%u, rx-imp:%u\n", + instance->efuse_intr, instance->efuse_tx_imp, + instance->efuse_rx_imp); + return; + case PHY_TYPE_PCIE: + case PHY_TYPE_SGMII: + /* nothing to do */ + return; + default: + dev_err(xsphy->dev, "incompatible PHY type\n"); + return; + } +} + +static void mtk_xsphy_u2_props_set(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance) +{ + void __iomem *pbase = instance->port_base; + + if (instance->efuse_intr) + clrsetbits_le32(pbase + XSP_USBPHYACR1, P2A1_RG_INTR_CAL, + FIELD_PREP(P2A1_RG_INTR_CAL, instance->efuse_intr)); + + if (instance->eye_src) + clrsetbits_le32(pbase + XSP_USBPHYACR5, P2A5_RG_HSTX_SRCTRL, + FIELD_PREP(P2A5_RG_HSTX_SRCTRL, instance->eye_src)); + + if (instance->eye_vrt) + clrsetbits_le32(pbase + XSP_USBPHYACR1, P2A1_RG_VRT_SEL, + FIELD_PREP(P2A1_RG_VRT_SEL, instance->eye_vrt)); + + if (instance->eye_term) + clrsetbits_le32(pbase + XSP_USBPHYACR1, P2A1_RG_TERM_SEL, + FIELD_PREP(P2A1_RG_TERM_SEL, instance->eye_term)); +} + +static void mtk_xsphy_u3_props_set(struct mtk_xsphy *xsphy, + struct mtk_xsphy_instance *instance) +{ + void __iomem *pbase = instance->port_base; + + if (instance->efuse_intr) + clrsetbits_le32(xsphy->sif_base + SSPXTP_PHYA_GLB_00, + RG_XTP_GLB_BIAS_INTR_CTRL, + FIELD_PREP(RG_XTP_GLB_BIAS_INTR_CTRL, instance->efuse_intr)); + + if (instance->efuse_tx_imp) + clrsetbits_le32(pbase + SSPXTP_PHYA_LN_04, RG_XTP_LN0_TX_IMPSEL, + FIELD_PREP(RG_XTP_LN0_TX_IMPSEL, instance->efuse_tx_imp)); + + if (instance->efuse_rx_imp) + clrsetbits_le32(pbase + SSPXTP_PHYA_LN_14, RG_XTP_LN0_RX_IMPSEL, + FIELD_PREP(RG_XTP_LN0_RX_IMPSEL, instance->efuse_rx_imp)); +} + +/* type switch for usb3/pcie/sgmii */ +static int mtk_xsphy_type_syscon_get(struct udevice *dev, + struct mtk_xsphy_instance *instance, + ofnode dn) +{ + struct ofnode_phandle_args args; + int ret; + + if (!ofnode_read_bool(dn, "mediatek,syscon-type")) + return 0; + + ret = ofnode_parse_phandle_with_args(dn, "mediatek,syscon-type", + NULL, 2, 0, &args); + if (ret) + return ret; + + instance->type_sw_reg = args.args[0]; + instance->type_sw_index = args.args[1] & 0x3; /* <=3 */ + instance->type_sw = syscon_node_to_regmap(args.node); + if (IS_ERR(instance->type_sw)) + return PTR_ERR(instance->type_sw); + + dev_dbg(dev, "phy-%s.%d: type_sw - reg %#x, index %d\n", + dev->name, instance->index, instance->type_sw_reg, + instance->type_sw_index); + + return 0; +} + +static int mtk_xsphy_type_set(struct mtk_xsphy_instance *instance) +{ + int type; + u32 offset; + + if (!instance->type_sw) + return 0; + + switch (instance->type) { + case PHY_TYPE_USB3: + type = RG_PHY_SW_USB3; + break; + case PHY_TYPE_PCIE: + type = RG_PHY_SW_PCIE; + break; + case PHY_TYPE_SGMII: + type = RG_PHY_SW_SGMII; + break; + case PHY_TYPE_USB2: + default: + return 0; + } + + offset = instance->type_sw_index * BITS_PER_BYTE; + regmap_update_bits(instance->type_sw, instance->type_sw_reg, + RG_PHY_SW_TYPE << offset, type << offset); + + return 0; +} + +static int mtk_xsphy_init(struct phy *phy) +{ + struct mtk_xsphy *xsphy = dev_get_priv(phy->dev); + struct mtk_xsphy_instance *instance = xsphy->phys[phy->id]; + int ret; + + ret = clk_enable(&instance->ref_clk); + if (ret) { + dev_err(xsphy->dev, "failed to enable ref_clk\n"); + return ret; + } + + switch (instance->type) { + case PHY_TYPE_USB2: + mtk_xsphy_u2_instance_init(xsphy, instance); + mtk_xsphy_u2_props_set(xsphy, instance); + break; + case PHY_TYPE_USB3: + mtk_xsphy_u3_props_set(xsphy, instance); + break; + case PHY_TYPE_PCIE: + case PHY_TYPE_SGMII: + /* nothing to do, only used to set type */ + break; + default: + dev_err(xsphy->dev, "incompatible PHY type\n"); + clk_disable(&instance->ref_clk); + return -EINVAL; + } + + return 0; +} + +static int mtk_xsphy_power_on(struct phy *phy) +{ + struct mtk_xsphy *xsphy = dev_get_priv(phy->dev); + struct mtk_xsphy_instance *instance = xsphy->phys[phy->id]; + + if (instance->type == PHY_TYPE_USB2) { + mtk_xsphy_u2_instance_power_on(xsphy, instance); + mtk_xsphy_u2_slew_rate_calibrate(xsphy, instance); + } + + return 0; +} + +static int mtk_xsphy_power_off(struct phy *phy) +{ + struct mtk_xsphy *xsphy = dev_get_priv(phy->dev); + struct mtk_xsphy_instance *instance = xsphy->phys[phy->id]; + + if (instance->type == PHY_TYPE_USB2) + mtk_xsphy_u2_instance_power_off(xsphy, instance); + + return 0; +} + +static int mtk_xsphy_exit(struct phy *phy) +{ + struct mtk_xsphy *xsphy = dev_get_priv(phy->dev); + struct mtk_xsphy_instance *instance = xsphy->phys[phy->id]; + + clk_disable(&instance->ref_clk); + + return 0; +} + +static int mtk_xsphy_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct mtk_xsphy *xsphy = dev_get_priv(phy->dev); + struct mtk_xsphy_instance *instance = xsphy->phys[phy->id]; + + if (instance->type == PHY_TYPE_USB2) + mtk_xsphy_u2_instance_set_mode(xsphy, instance, mode); + + return 0; +} + +static int mtk_xsphy_xlate(struct phy *phy, struct ofnode_phandle_args *args) +{ + struct mtk_xsphy *xsphy = dev_get_priv(phy->dev); + struct mtk_xsphy_instance *instance = NULL; + const struct device_node *phy_np = ofnode_to_np(args->node); + u32 index; + + if (!phy_np) { + dev_err(phy->dev, "null pointer phy node\n"); + return -EINVAL; + } + + if (args->args_count != 2) { + dev_err(phy->dev, "invalid number of cells in 'phy' property\n"); + return -EINVAL; + } + + for (index = 0; index < xsphy->nphys; index++) + if (phy_np == xsphy->phys[index]->np) { + instance = xsphy->phys[index]; + break; + } + + if (!instance) { + dev_err(phy->dev, "failed to find appropriate phy\n"); + return -EINVAL; + } + + phy->id = index; + instance->type = args->args[1]; + if (!(instance->type == PHY_TYPE_USB2 || + instance->type == PHY_TYPE_USB3 || + instance->type == PHY_TYPE_PCIE || + instance->type == PHY_TYPE_SGMII)) { + dev_err(phy->dev, "unsupported PHY type\n"); + return -EINVAL; + } + + mtk_xsphy_parse_property(xsphy, instance); + mtk_xsphy_type_set(instance); + + return 0; +} + +static const struct phy_ops mtk_xsphy_ops = { + .init = mtk_xsphy_init, + .exit = mtk_xsphy_exit, + .power_on = mtk_xsphy_power_on, + .power_off = mtk_xsphy_power_off, + .set_mode = mtk_xsphy_set_mode, + .of_xlate = mtk_xsphy_xlate, +}; + +static int mtk_xsphy_probe(struct udevice *dev) +{ + struct mtk_xsphy *xsphy = dev_get_priv(dev); + fdt_addr_t sif_addr; + ofnode subnode; + int index = 0; + + xsphy->nphys = dev_get_child_count(dev); + + xsphy->phys = devm_kcalloc(dev, xsphy->nphys, sizeof(*xsphy->phys), + GFP_KERNEL); + if (!xsphy->phys) + return -ENOMEM; + + xsphy->dev = dev; + + sif_addr = ofnode_get_addr(dev_ofnode(dev)); + /* optional, may not exist if no u3 phys */ + if (sif_addr != FDT_ADDR_T_NONE) + xsphy->sif_base = map_sysmem(sif_addr, 0); + + xsphy->src_ref_clk_mhz = XSP_REF_CLK_MHZ; + xsphy->src_coef = XSP_SLEW_RATE_COEF; + /* update parameters of slew rate calibrate if exist */ + ofnode_read_u32(dev_ofnode(dev), "mediatek,src-ref-clk-mhz", + &xsphy->src_ref_clk_mhz); + ofnode_read_u32(dev_ofnode(dev), "mediatek,src-coef", &xsphy->src_coef); + + dev_for_each_subnode(subnode, dev) { + struct mtk_xsphy_instance *inst; + fdt_addr_t addr; + int ret; + + inst = devm_kzalloc(dev, sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + xsphy->phys[index] = inst; + + addr = ofnode_get_addr(subnode); + if (addr == FDT_ADDR_T_NONE) + return -EADDRNOTAVAIL; + + inst->port_base = map_sysmem(addr, 0); + inst->index = index; + inst->np = ofnode_to_np(subnode); + + ret = clk_get_by_name_nodev(subnode, "ref", &inst->ref_clk); + if (ret) { + dev_err(dev, "failed to get ref_clk(id-%d)\n", index); + return ret; + } + + ret = mtk_xsphy_type_syscon_get(dev, inst, subnode); + if (ret) + return ret; + + index++; + } + + return 0; +} + +static const struct udevice_id mtk_xsphy_id_table[] = { + { .compatible = "mediatek,xsphy" }, + { } +}; + +U_BOOT_DRIVER(mtk_xsphy) = { + .name = "mtk-xsphy", + .id = UCLASS_PHY, + .of_match = mtk_xsphy_id_table, + .ops = &mtk_xsphy_ops, + .probe = mtk_xsphy_probe, + .priv_auto = sizeof(struct mtk_xsphy), +}; diff --git a/drivers/phy/qcom/Kconfig b/drivers/phy/qcom/Kconfig index 0dd69f7ffd0..1fdadaccb12 100644 --- a/drivers/phy/qcom/Kconfig +++ b/drivers/phy/qcom/Kconfig @@ -2,37 +2,45 @@ config MSM8916_USB_PHY bool select PHY help - Support the Qualcomm MSM8916 USB PHY + Support the Qualcomm MSM8916 USB PHY This PHY is found on qualcomm dragonboard410c development board. config PHY_QCOM_IPQ4019_USB - tristate "Qualcomm IPQ4019 USB PHY driver" + bool "Qualcomm IPQ4019 USB PHY driver" depends on PHY && ARCH_IPQ40XX help Support for the USB PHY-s on Qualcomm IPQ40xx SoC-s. +config PHY_QCOM_QMP_COMBO + bool "Qualcomm QMP USB3-DP Combo PHY driver" + depends on PHY && ARCH_SNAPDRAGON + help + Enable this to support the USB3-DP Combo QMP PHY on various Qualcomm + chipsets. This driver supports the USB3 PHY functionality of the combo + PHY (USB3 + DisplayPort). Currently only USB3 mode is supported. + config PHY_QCOM_QMP_PCIE - tristate "Qualcomm QMP PCIe PHY driver" + bool "Qualcomm QMP PCIe PHY driver" depends on PHY && ARCH_SNAPDRAGON help Enable this to support the PCIe QMP PHY on various Qualcomm chipsets. config PHY_QCOM_QMP_UFS - tristate "Qualcomm QMP UFS PHY driver" + bool "Qualcomm QMP UFS PHY driver" depends on PHY && ARCH_SNAPDRAGON help Enable this to support the UFS QMP PHY on various Qualcomm chipsets. config PHY_QCOM_QUSB2 - tristate "Qualcomm USB QUSB2 PHY driver" + bool "Qualcomm USB QUSB2 PHY driver" depends on PHY && ARCH_SNAPDRAGON help Enable this to support the Super-Speed USB transceiver on various Qualcomm chipsets. config PHY_QCOM_USB_SNPS_FEMTO_V2 - tristate "Qualcomm SNPS FEMTO USB HS PHY v2" + bool "Qualcomm SNPS FEMTO USB HS PHY v2" depends on PHY && ARCH_SNAPDRAGON help Enable this to support the Qualcomm Synopsys DesignWare Core 7nm @@ -40,7 +48,7 @@ config PHY_QCOM_USB_SNPS_FEMTO_V2 is usually paired with Synopsys DWC3 USB IPs on MSM SOCs. config PHY_QCOM_SNPS_EUSB2 - tristate "Qualcomm Synopsys eUSB2 High-Speed PHY" + bool "Qualcomm Synopsys eUSB2 High-Speed PHY" depends on PHY && ARCH_SNAPDRAGON help Enable this to support the Qualcomm Synopsys DesignWare eUSB2 @@ -48,7 +56,7 @@ config PHY_QCOM_SNPS_EUSB2 is usually paired with Synopsys DWC3 USB IPs on MSM SOCs. config PHY_QCOM_USB_HS_28NM - tristate "Qualcomm 28nm High-Speed PHY" + bool "Qualcomm 28nm High-Speed PHY" depends on PHY && ARCH_SNAPDRAGON help Enable this to support the Qualcomm Synopsys DesignWare Core 28nm @@ -57,7 +65,7 @@ config PHY_QCOM_USB_HS_28NM IPs on MSM SOCs. config PHY_QCOM_USB_SS - tristate "Qualcomm USB Super-Speed PHY driver" + bool "Qualcomm USB Super-Speed PHY driver" depends on PHY && ARCH_SNAPDRAGON help Enable this to support the Super-Speed USB transceiver on various diff --git a/drivers/phy/qcom/Makefile b/drivers/phy/qcom/Makefile index 1c4e7d8d391..714013dc572 100644 --- a/drivers/phy/qcom/Makefile +++ b/drivers/phy/qcom/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_PHY_QCOM_IPQ4019_USB) += phy-qcom-ipq4019-usb.o obj-$(CONFIG_MSM8916_USB_PHY) += msm8916-usbh-phy.o +obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o obj-$(CONFIG_PHY_QCOM_QMP_PCIE) += phy-qcom-qmp-pcie.o obj-$(CONFIG_PHY_QCOM_QMP_UFS) += phy-qcom-qmp-ufs.o obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o diff --git a/drivers/phy/qcom/phy-qcom-qmp-combo.c b/drivers/phy/qcom/phy-qcom-qmp-combo.c new file mode 100644 index 00000000000..0d63e482ee4 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-combo.c @@ -0,0 +1,643 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#include <clk.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <dm/devres.h> +#include <generic-phy.h> +#include <reset.h> +#include <power/regulator.h> +#include <asm/io.h> +#include <linux/bitops.h> +#include <linux/compat.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <linux/err.h> + +#include "phy-qcom-qmp-common.h" + +#include "phy-qcom-qmp.h" +#include "phy-qcom-qmp-pcs-misc-v3.h" +#include "phy-qcom-qmp-pcs-usb-v4.h" +#include "phy-qcom-qmp-dp-com-v3.h" + +/* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */ +/* DP PHY soft reset */ +#define SW_DPPHY_RESET BIT(0) +/* mux to select DP PHY reset control, 0:HW control, 1: software reset */ +#define SW_DPPHY_RESET_MUX BIT(1) +/* USB3 PHY soft reset */ +#define SW_USB3PHY_RESET BIT(2) +/* mux to select USB3 PHY reset control, 0:HW control, 1: software reset */ +#define SW_USB3PHY_RESET_MUX BIT(3) + +/* QPHY_V3_DP_COM_PHY_MODE_CTRL register bits */ +#define USB3_MODE BIT(0) /* enables USB3 mode */ +#define DP_MODE BIT(1) /* enables DP mode */ + +/* QPHY_V3_DP_COM_TYPEC_CTRL register bits */ +#define SW_PORTSELECT_MUX BIT(1) + +/* PHY slot identifiers for device tree phandle arguments */ +#define QMP_USB43DP_USB3_PHY 0 +#define QMP_USB43DP_DP_PHY 1 + +#define PHY_INIT_COMPLETE_TIMEOUT 10000 + +struct qmp_combo_offsets { + u16 com; + u16 txa; + u16 rxa; + u16 txb; + u16 rxb; + u16 usb3_serdes; + u16 usb3_pcs_misc; + u16 usb3_pcs; + u16 usb3_pcs_usb; +}; + +/* + * Initialisation tables + */ + +static const struct qmp_combo_offsets qmp_combo_offsets_v3 = { + .com = 0x0000, + .txa = 0x1200, + .rxa = 0x1400, + .txb = 0x1600, + .rxb = 0x1800, + .usb3_serdes = 0x1000, + .usb3_pcs_misc = 0x1a00, + .usb3_pcs = 0x1c00, + .usb3_pcs_usb = 0x1f00, +}; + +static const struct qmp_phy_init_tbl sm8150_usb3_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0, 0xde), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1, 0xde), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_BUF_ENABLE, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CMN_IPTRIM, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE1, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE1, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE1, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0xea), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE1, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE1, 0xea), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE1_MODE0, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE1_MODE1, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE2_MODE1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xca), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xca), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x11), +}; + +static const struct qmp_phy_init_tbl sm8250_usb3_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_TX, 0x60), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_RX, 0x60), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_TX, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RES_CODE_LANE_OFFSET_RX, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0xd5), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG_LANE(QSERDES_V4_TX_PI_QEC_CTRL, 0x40, 1), + QMP_PHY_INIT_CFG_LANE(QSERDES_V4_TX_PI_QEC_CTRL, 0x54, 2), +}; + +static const struct qmp_phy_init_tbl sm8250_usb3_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_GAIN, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CONTROLS, 0x99), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_THRESH1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_THRESH2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_GAIN1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SB2_GAIN2, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL1, 0x54), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL2, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4a), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0xc0), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_CNTRL, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL, 0x0e), + QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_LOW, 0xff, 1), + QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_LOW, 0x7f, 2), + QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_HIGH, 0x7f, 1), + QMP_PHY_INIT_CFG_LANE(QSERDES_V4_RX_RX_MODE_00_HIGH, 0xff, 2), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x97), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0xdc), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0xdc), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0x5c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH3, 0x7b), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0xb4), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_EN_TIMER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_AUX_DATA_TCOARSE_TFINE, 0xa0), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_DCC_CTRL1, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_GM_CAL, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_VTH_CODE, 0x10), +}; + +static const struct qmp_phy_init_tbl sm8250_usb3_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG1, 0xd0), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG2, 0x07), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG3, 0x20), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG6, 0x13), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xa9), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_CDR_RESET_TIME, 0x0a), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG1, 0x88), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG2, 0x13), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCS_TX_RX_CONFIG, 0x0c), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG1, 0x4b), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG5, 0x10), +}; + +static const struct qmp_phy_init_tbl sm8250_usb3_pcs_usb_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07), +}; + +struct qmp_phy_cfg { + const struct qmp_combo_offsets *offsets; + const struct qmp_phy_init_tbl *serdes_tbl; + int serdes_tbl_num; + const struct qmp_phy_init_tbl *tx_tbl; + int tx_tbl_num; + const struct qmp_phy_init_tbl *rx_tbl; + int rx_tbl_num; + const struct qmp_phy_init_tbl *pcs_tbl; + int pcs_tbl_num; + const struct qmp_phy_init_tbl *pcs_usb_tbl; + int pcs_usb_tbl_num; + const char * const *vreg_list; + int num_vregs; + /* true, if PHY needs delay after POWER_DOWN */ + bool has_pwrdn_delay; +}; + +/* list of clocks required by phy */ +static const char * const qmp_combo_phy_clk_l[] = { + "aux", "com_aux", +}; + +/* list of regulators */ +static const char * const qmp_phy_vreg_l[] = { + "vdda-phy-supply", + "vdda-pll-supply", +}; + +struct qmp_combo { + struct udevice *dev; + void __iomem *com; + void __iomem *serdes; + void __iomem *tx; + void __iomem *rx; + void __iomem *tx2; + void __iomem *rx2; + void __iomem *pcs; + void __iomem *pcs_usb; + void __iomem *pcs_misc; + struct clk *clks; + struct clk *pipe_clk; + int num_clks; + struct reset_ctl_bulk resets; + int num_resets; + struct udevice **vregs; + int num_vregs; + const struct qmp_phy_cfg *cfg; +}; + +static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) +{ + u32 reg; + + reg = readl(base + offset); + reg |= val; + writel(reg, base + offset); + + /* ensure that above write is through */ + readl(base + offset); +} + +static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val) +{ + u32 reg; + + reg = readl(base + offset); + reg &= ~val; + writel(reg, base + offset); + + /* ensure that above write is through */ + readl(base + offset); +} + +static int qmp_combo_com_exit(struct qmp_combo *qmp) +{ + int i, ret; + + for (i = 0; i < qmp->num_clks; i++) + clk_disable(&qmp->clks[i]); + + reset_assert_bulk(&qmp->resets); + + for (i = qmp->num_vregs - 1; i >= 0; i--) { + ret = regulator_set_enable(qmp->vregs[i], false); + if (ret) + dev_warn(qmp->dev, "failed to disable %s: %d\n", + qmp->cfg->vreg_list[i], ret); + } + + return 0; +} + +static int qmp_combo_com_init(struct qmp_combo *qmp) +{ + void __iomem *com = qmp->com; + void __iomem *pcs = qmp->pcs; + u32 val; + int ret, i; + + ret = reset_assert_bulk(&qmp->resets); + if (ret) { + printf("Failed to assert resets: %d\n", ret); + return ret; + } + + ret = reset_deassert_bulk(&qmp->resets); + if (ret) { + printf("Failed to deassert resets: %d\n", ret); + return ret; + } + + for (i = 0; i < qmp->num_vregs; i++) { + ret = regulator_set_enable(qmp->vregs[i], true); + if (ret) { + dev_err(qmp->dev, "Failed to enable regulator %d: %d\n", i, ret); + while (--i >= 0) + regulator_set_enable(qmp->vregs[i], false); + reset_assert_bulk(&qmp->resets); + return ret; + } + } + + for (i = 0; i < qmp->num_clks; i++) { + ret = clk_enable(&qmp->clks[i]); + if (ret) { + printf("Failed to enable clock %d: %d\n", i, ret); + while (--i >= 0) + clk_disable(&qmp->clks[i]); + for (i = qmp->num_vregs - 1; i >= 0; i--) + regulator_set_enable(qmp->vregs[i], false); + reset_assert_bulk(&qmp->resets); + return ret; + } + } + + /* Common block register writes */ + qphy_setbits(com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, SW_PWRDN); + qphy_setbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, + SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | + SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); + + val = SW_PORTSELECT_MUX; + writel(val, com + QPHY_V3_DP_COM_TYPEC_CTRL); + + writel(USB3_MODE | DP_MODE, com + QPHY_V3_DP_COM_PHY_MODE_CTRL); + + qphy_clrbits(com, QPHY_V3_DP_COM_RESET_OVRD_CTRL, + SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | + SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET); + + qphy_clrbits(com, QPHY_V3_DP_COM_SWI_CTRL, 0x03); + + qphy_clrbits(com, QPHY_V3_DP_COM_SW_RESET, SW_RESET); + + qphy_setbits(pcs, QPHY_V4_PCS_POWER_DOWN_CONTROL, SW_PWRDN); + + return 0; +} + +static int qmp_combo_usb_power_on(struct qmp_combo *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *serdes = qmp->serdes; + void __iomem *tx = qmp->tx; + void __iomem *rx = qmp->rx; + void __iomem *tx2 = qmp->tx2; + void __iomem *rx2 = qmp->rx2; + void __iomem *pcs = qmp->pcs; + void __iomem *pcs_usb = qmp->pcs_usb; + u32 val; + int ret; + + /* Serdes configuration */ + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl, cfg->serdes_tbl_num); + + ret = clk_prepare_enable(qmp->pipe_clk); + if (ret) { + dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret); + return ret; + } + + /* Tx, Rx configurations */ + qmp_configure_lane(qmp->dev, tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_configure_lane(qmp->dev, tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); + + qmp_configure_lane(qmp->dev, rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); + qmp_configure_lane(qmp->dev, rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); + + /* PCS configuration */ + qmp_configure(qmp->dev, pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); + + if (pcs_usb) { + qmp_configure(qmp->dev, pcs_usb, + cfg->pcs_usb_tbl, + cfg->pcs_usb_tbl_num); + } + + if (cfg->has_pwrdn_delay) + udelay(20); + + /* Pull PHY out of reset */ + qphy_clrbits(pcs, QPHY_V4_PCS_SW_RESET, SW_RESET); + + /* Start SerDes and Phy-Coding-Sublayer */ + qphy_setbits(pcs, QPHY_V4_PCS_START_CONTROL, + SERDES_START | PCS_START); + + /* Wait for PHY initialization */ + ret = readl_poll_timeout(pcs + QPHY_V4_PCS_PCS_STATUS1, val, + !(val & PHYSTATUS), PHY_INIT_COMPLETE_TIMEOUT); + + if (ret) { + printf("QMP USB3 PHY initialization timeout\n"); + clk_disable(qmp->pipe_clk); + return ret; + } + + return 0; +} + +static int qmp_combo_power_on(struct phy *phy) +{ + struct qmp_combo *qmp = dev_get_priv(phy->dev); + int ret; + + /* Initialize common block */ + ret = qmp_combo_com_init(qmp); + if (ret) + return ret; + + /* Initialize USB3-specific configuration */ + ret = qmp_combo_usb_power_on(qmp); + if (ret) { + qmp_combo_com_exit(qmp); + return ret; + } + + return 0; +} + +static int qmp_combo_power_off(struct phy *phy) +{ + struct qmp_combo *qmp = dev_get_priv(phy->dev); + void __iomem *com = qmp->com; + + clk_disable(qmp->pipe_clk); + + /* PHY reset */ + qphy_setbits(qmp->pcs, QPHY_V4_PCS_SW_RESET, SW_RESET); + + /* Stop SerDes and Phy-Coding-Sublayer */ + qphy_clrbits(qmp->pcs, QPHY_V4_PCS_START_CONTROL, + SERDES_START | PCS_START); + + /* Put PHY into POWER DOWN state: active low */ + qphy_clrbits(qmp->pcs, QPHY_V4_PCS_POWER_DOWN_CONTROL, SW_PWRDN); + + /* Power down common block */ + qphy_clrbits(com, QPHY_V3_DP_COM_POWER_DOWN_CTRL, SW_PWRDN); + + return qmp_combo_com_exit(qmp); +} + +static int qmp_combo_reset_init(struct qmp_combo *qmp) +{ + struct udevice *dev = qmp->dev; + int ret; + + ret = reset_get_bulk(dev, &qmp->resets); + if (ret) { + printf("Failed to get resets: %d\n", ret); + return ret; + } + + qmp->num_resets = qmp->resets.count; + + return 0; +} + +static int qmp_combo_clk_init(struct qmp_combo *qmp) +{ + struct udevice *dev = qmp->dev; + int num = ARRAY_SIZE(qmp_combo_phy_clk_l); + int i, ret; + + qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL); + if (!qmp->clks) + return -ENOMEM; + + for (i = 0; i < num; i++) { + ret = clk_get_by_name(dev, qmp_combo_phy_clk_l[i], &qmp->clks[i]); + if (ret) { + dev_err(dev, "failed to get %s clock: %d\n", + qmp_combo_phy_clk_l[i], ret); + return ret; + } + } + + qmp->num_clks = num; + return 0; +} + +static int qmp_combo_vreg_init(struct qmp_combo *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + struct udevice *dev = qmp->dev; + int num = cfg->num_vregs; + int i, ret; + + if (!num) + return 0; + + qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); + if (!qmp->vregs) + return -ENOMEM; + + for (i = 0; i < num; i++) { + ret = device_get_supply_regulator(dev, cfg->vreg_list[i], + &qmp->vregs[i]); + if (ret) { + dev_err(dev, "failed to get regulator %s: %d\n", + cfg->vreg_list[i], ret); + return ret; + } + } + + qmp->num_vregs = num; + return 0; +} + +static int qmp_combo_parse_dt(struct qmp_combo *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + const struct qmp_combo_offsets *offs = cfg->offsets; + struct udevice *dev = qmp->dev; + void __iomem *base; + int ret; + + if (!offs) + return -EINVAL; + + base = (void __iomem *)dev_read_addr(dev); + if (IS_ERR(base)) + return PTR_ERR(base); + + qmp->com = base + offs->com; + qmp->serdes = base + offs->usb3_serdes; + qmp->tx = base + offs->txa; + qmp->rx = base + offs->rxa; + qmp->tx2 = base + offs->txb; + qmp->rx2 = base + offs->rxb; + qmp->pcs = base + offs->usb3_pcs; + qmp->pcs_usb = base + offs->usb3_pcs_usb; + qmp->pcs_misc = base + offs->usb3_pcs_misc; + + ret = qmp_combo_clk_init(qmp); + if (ret) + return ret; + + qmp->pipe_clk = devm_clk_get(dev, "usb3_pipe"); + if (IS_ERR(qmp->pipe_clk)) { + dev_err(dev, "failed to get pipe clock (%ld)\n", + PTR_ERR(qmp->pipe_clk)); + return ret; + } + + ret = qmp_combo_reset_init(qmp); + if (ret) + return ret; + + ret = qmp_combo_vreg_init(qmp); + if (ret) + return ret; + + return 0; +} + +static int qmp_combo_probe(struct udevice *dev) +{ + struct qmp_combo *qmp = dev_get_priv(dev); + int ret; + + qmp->dev = dev; + qmp->cfg = (const struct qmp_phy_cfg *)dev_get_driver_data(dev); + if (!qmp->cfg) { + printf("Failed to get PHY configuration\n"); + return -EINVAL; + } + + ret = qmp_combo_parse_dt(qmp); + + return ret; +} + +static const struct qmp_phy_cfg sc7280_usb3dpphy_cfg = { + .offsets = &qmp_combo_offsets_v3, + .serdes_tbl = sm8150_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), + .tx_tbl = sm8250_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(sm8250_usb3_tx_tbl), + .rx_tbl = sm8250_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sm8250_usb3_rx_tbl), + .pcs_tbl = sm8250_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(sm8250_usb3_pcs_tbl), + .pcs_usb_tbl = sm8250_usb3_pcs_usb_tbl, + .pcs_usb_tbl_num = ARRAY_SIZE(sm8250_usb3_pcs_usb_tbl), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + + .has_pwrdn_delay = true, +}; + +static int qmp_combo_xlate(struct phy *phy, struct ofnode_phandle_args *args) +{ + if (args->args_count != 1) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + /* We only support the USB3 phy at slot 0 */ + if (args->args[0] == QMP_USB43DP_DP_PHY) + return -EINVAL; + + phy->id = QMP_USB43DP_USB3_PHY; + + return 0; +} + +static struct phy_ops qmp_combo_ops = { + .init = qmp_combo_power_on, + .exit = qmp_combo_power_off, + .of_xlate = qmp_combo_xlate, +}; + +static const struct udevice_id qmp_combo_ids[] = { + { + .compatible = "qcom,sc7280-qmp-usb3-dp-phy", + .data = (ulong)&sc7280_usb3dpphy_cfg, + }, + { } +}; + +U_BOOT_DRIVER(qmp_combo) = { + .name = "qcom-qmp-usb3-dp-phy", + .id = UCLASS_PHY, + .of_match = qmp_combo_ids, + .ops = &qmp_combo_ops, + .probe = qmp_combo_probe, + .priv_auto = sizeof(struct qmp_combo), +}; diff --git a/drivers/phy/qcom/phy-qcom-qmp-common.h b/drivers/phy/qcom/phy-qcom-qmp-common.h new file mode 100644 index 00000000000..71356fb7dd0 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-common.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_COMMON_H_ +#define QCOM_PHY_QMP_COMMON_H_ + +struct qmp_phy_init_tbl { + unsigned int offset; + unsigned int val; + char *name; + /* + * mask of lanes for which this register is written + * for cases when second lane needs different values + */ + u8 lane_mask; +}; + +#define QMP_PHY_INIT_CFG(o, v) \ + { \ + .offset = o, \ + .val = v, \ + .name = #o, \ + .lane_mask = 0xff, \ + } + +#define QMP_PHY_INIT_CFG_LANE(o, v, l) \ + { \ + .offset = o, \ + .val = v, \ + .name = #o, \ + .lane_mask = l, \ + } + +static inline void qmp_configure_lane(struct udevice *dev, void __iomem *base, + const struct qmp_phy_init_tbl tbl[], + int num, u8 lane_mask) +{ + int i; + const struct qmp_phy_init_tbl *t = tbl; + + if (!t) + return; + + for (i = 0; i < num; i++, t++) { + if (!(t->lane_mask & lane_mask)) + continue; + + dev_dbg(dev, "Writing Reg: %s Offset: 0x%04x Val: 0x%02x\n", + t->name, t->offset, t->val); + writel(t->val, base + t->offset); + } +} + +static inline void qmp_configure(struct udevice *dev, void __iomem *base, + const struct qmp_phy_init_tbl tbl[], int num) +{ + qmp_configure_lane(dev, base, tbl, num, 0xff); +} + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-dp-com-v3.h b/drivers/phy/qcom/phy-qcom-qmp-dp-com-v3.h new file mode 100644 index 00000000000..396179ef38b --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-dp-com-v3.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_COM_V3_H_ +#define QCOM_PHY_QMP_DP_COM_V3_H_ + +/* Only for QMP V3 & V4 PHY - DP COM registers */ +#define QPHY_V3_DP_COM_PHY_MODE_CTRL 0x00 +#define QPHY_V3_DP_COM_SW_RESET 0x04 +#define QPHY_V3_DP_COM_POWER_DOWN_CTRL 0x08 +#define QPHY_V3_DP_COM_SWI_CTRL 0x0c +#define QPHY_V3_DP_COM_TYPEC_CTRL 0x10 +#define QPHY_V3_DP_COM_TYPEC_PWRDN_CTRL 0x14 +#define QPHY_V3_DP_COM_RESET_OVRD_CTRL 0x1c + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-pcs-usb-v4.h b/drivers/phy/qcom/phy-qcom-qmp-pcs-usb-v4.h new file mode 100644 index 00000000000..d7fd4ac0fc5 --- /dev/null +++ b/drivers/phy/qcom/phy-qcom-qmp-pcs-usb-v4.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_USB_V4_H_ +#define QCOM_PHY_QMP_PCS_USB_V4_H_ + +/* Only for QMP V4 PHY - USB3 PCS registers */ +#define QPHY_V4_PCS_USB3_POWER_STATE_CONFIG1 0x000 +#define QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_STATUS 0x004 +#define QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_CTRL 0x008 +#define QPHY_V4_PCS_USB3_AUTONOMOUS_MODE_CTRL2 0x00c +#define QPHY_V4_PCS_USB3_LFPS_RXTERM_IRQ_SOURCE_STATUS 0x010 +#define QPHY_V4_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR 0x014 +#define QPHY_V4_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL 0x018 +#define QPHY_V4_PCS_USB3_LFPS_TX_ECSTART 0x01c +#define QPHY_V4_PCS_USB3_LFPS_PER_TIMER_VAL 0x020 +#define QPHY_V4_PCS_USB3_LFPS_TX_END_CNT_U3_START 0x024 +#define QPHY_V4_PCS_USB3_RXEQTRAINING_LOCK_TIME 0x028 +#define QPHY_V4_PCS_USB3_RXEQTRAINING_WAIT_TIME 0x02c +#define QPHY_V4_PCS_USB3_RXEQTRAINING_CTLE_TIME 0x030 +#define QPHY_V4_PCS_USB3_RXEQTRAINING_WAIT_TIME_S2 0x034 +#define QPHY_V4_PCS_USB3_RXEQTRAINING_DFE_TIME_S2 0x038 +#define QPHY_V4_PCS_USB3_RCVR_DTCT_DLY_U3_L 0x03c +#define QPHY_V4_PCS_USB3_RCVR_DTCT_DLY_U3_H 0x040 +#define QPHY_V4_PCS_USB3_ARCVR_DTCT_EN_PERIOD 0x044 +#define QPHY_V4_PCS_USB3_ARCVR_DTCT_CM_DLY 0x048 +#define QPHY_V4_PCS_USB3_TXONESZEROS_RUN_LENGTH 0x04c +#define QPHY_V4_PCS_USB3_ALFPS_DEGLITCH_VAL 0x050 +#define QPHY_V4_PCS_USB3_SIGDET_STARTUP_TIMER_VAL 0x054 +#define QPHY_V4_PCS_USB3_TEST_CONTROL 0x058 + +#endif diff --git a/drivers/phy/qcom/phy-qcom-qmp-ufs.c b/drivers/phy/qcom/phy-qcom-qmp-ufs.c index 907f34744eb..3df88189a90 100644 --- a/drivers/phy/qcom/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qcom/phy-qcom-qmp-ufs.c @@ -119,6 +119,68 @@ static const unsigned int ufsphy_v6_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V6_PCS_UFS_POWER_DOWN_CONTROL, }; +static const struct qmp_ufs_init_tbl milos_ufsphy_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x17), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x98), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x32), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x0f), +}; + +static const struct qmp_ufs_init_tbl milos_ufsphy_tx[] = { + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_RX, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_FR_DCC_CTRL, 0xcc), +}; + +static const struct qmp_ufs_init_tbl milos_ufsphy_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x3e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xce), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xce), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B2, 0x18), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B4, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B6, 0x60), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B3, 0x9e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B6, 0x60), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B3, 0x9e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B4, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B5, 0x36), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CTRL1, 0x94), +}; + +static const struct qmp_ufs_init_tbl milos_ufsphy_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x0b), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x68), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04), +}; + static const struct qmp_ufs_init_tbl sdm845_ufsphy_serdes[] = { QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02), QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04), @@ -982,6 +1044,31 @@ static const struct qmp_ufs_offsets qmp_ufs_offsets_v6 = { .rx2 = 0x1a00, }; +static const struct qmp_ufs_cfg milos_ufsphy_cfg = { + .lanes = 2, + + .offsets = &qmp_ufs_offsets_v6, + + .tbls = { + .serdes = milos_ufsphy_serdes, + .serdes_num = ARRAY_SIZE(milos_ufsphy_serdes), + .tx = milos_ufsphy_tx, + .tx_num = ARRAY_SIZE(milos_ufsphy_tx), + .rx = milos_ufsphy_rx, + .rx_num = ARRAY_SIZE(milos_ufsphy_rx), + .pcs = milos_ufsphy_pcs, + .pcs_num = ARRAY_SIZE(milos_ufsphy_pcs), + }, + .tbls_hs_b = { + .serdes = sm8550_ufsphy_hs_b_serdes, + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes), + }, + + .vreg_list = qmp_ufs_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_ufs_vreg_l), + .regs = ufsphy_v6_regs_layout, +}; + static const struct qmp_ufs_cfg sdm845_ufsphy_cfg = { .lanes = 2, @@ -1651,8 +1738,11 @@ static struct phy_ops qmp_ufs_ops = { }; static const struct udevice_id qmp_ufs_ids[] = { + { .compatible = "qcom,milos-qmp-ufs-phy", .data = (ulong)&milos_ufsphy_cfg, }, { .compatible = "qcom,sa8775p-qmp-ufs-phy", .data = (ulong)&sa8775p_ufsphy_cfg, }, { .compatible = "qcom,sdm845-qmp-ufs-phy", .data = (ulong)&sdm845_ufsphy_cfg }, + { .compatible = "qcom,sm6115-qmp-ufs-phy", .data = (ulong)&sm6115_ufsphy_cfg, }, + { .compatible = "qcom,sm6125-qmp-ufs-phy", .data = (ulong)&sm6115_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 }, diff --git a/drivers/phy/qcom/phy-qcom-qmp.h b/drivers/phy/qcom/phy-qcom-qmp.h index 99f4d447caf..06dac21ddc4 100644 --- a/drivers/phy/qcom/phy-qcom-qmp.h +++ b/drivers/phy/qcom/phy-qcom-qmp.h @@ -12,12 +12,17 @@ #include "phy-qcom-qmp-qserdes-com-v3.h" #include "phy-qcom-qmp-qserdes-txrx-v3.h" +#include "phy-qcom-qmp-qserdes-com-v4.h" +#include "phy-qcom-qmp-qserdes-txrx-v4.h" + #include "phy-qcom-qmp-qserdes-pll.h" #include "phy-qcom-qmp-pcs-v2.h" #include "phy-qcom-qmp-pcs-v3.h" +#include "phy-qcom-qmp-pcs-v4.h" + /* Only for QMP V3 & V4 PHY - DP COM registers */ #define QPHY_V3_DP_COM_PHY_MODE_CTRL 0x00 #define QPHY_V3_DP_COM_SW_RESET 0x04 @@ -112,4 +117,16 @@ #define QSERDES_V6_DP_PHY_AUX_INTERRUPT_STATUS 0x0e0 #define QSERDES_V6_DP_PHY_STATUS 0x0e4 +/* QPHY_SW_RESET bit */ +#define SW_RESET BIT(0) +/* QPHY_POWER_DOWN_CONTROL */ +#define SW_PWRDN BIT(0) + +/* QPHY_START_CONTROL bits */ +#define SERDES_START BIT(0) +#define PCS_START BIT(1) + +/* QPHY_PCS_STATUS bit */ +#define PHYSTATUS BIT(6) + #endif diff --git a/drivers/phy/renesas/Kconfig b/drivers/phy/renesas/Kconfig index affbee0500c..3358d454e59 100644 --- a/drivers/phy/renesas/Kconfig +++ b/drivers/phy/renesas/Kconfig @@ -3,19 +3,19 @@ # Phy drivers for Renesas platforms config PHY_R8A779F0_ETHERNET_SERDES - tristate "Renesas R-Car S4-8 Ethernet SERDES driver" + bool "Renesas R-Car S4-8 Ethernet SERDES driver" 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" + bool "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" + bool "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/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig index 80128335d52..6f3d7ebe29e 100644 --- a/drivers/phy/rockchip/Kconfig +++ b/drivers/phy/rockchip/Kconfig @@ -49,7 +49,7 @@ config PHY_ROCKCHIP_SNPS_PCIE3 also be able splited into multiple combinations of lanes. config PHY_ROCKCHIP_USBDP - tristate "Rockchip USBDP COMBO PHY Driver" + bool "Rockchip USBDP COMBO PHY Driver" depends on ARCH_ROCKCHIP select PHY help diff --git a/drivers/phy/ti-pipe3-phy.c b/drivers/phy/ti-pipe3-phy.c index 62f6cc2bfbf..080016ba417 100644 --- a/drivers/phy/ti-pipe3-phy.c +++ b/drivers/phy/ti-pipe3-phy.c @@ -6,6 +6,7 @@ #include <dm.h> #include <dm/device.h> +#include <dm/device_compat.h> #include <generic-phy.h> #include <asm/global_data.h> #include <asm/io.h> @@ -428,10 +429,10 @@ static int pipe3_exit(struct phy *phy) static void *get_reg(struct udevice *dev, const char *name) { + struct ofnode_phandle_args phandle; struct udevice *syscon; struct regmap *regmap; - const fdt32_t *cell; - int len, err; + int err; void *base; err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, @@ -449,10 +450,14 @@ static void *get_reg(struct udevice *dev, const char *name) return NULL; } - cell = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), name, - &len); - if (len < 2*sizeof(fdt32_t)) { - pr_err("offset not available for %s\n", name); + err = dev_read_phandle_with_args(dev, name, NULL, 0, 0, &phandle); + if (err) { + dev_err(dev, "parse %s failed: %d\n", name, err); + return NULL; + } + + if (phandle.args_count < 1) { + dev_err(dev, "%s: missing args\n", name); return NULL; } @@ -460,7 +465,7 @@ static void *get_reg(struct udevice *dev, const char *name) if (!base) return NULL; - return fdtdec_get_number(cell + 1, 1) + base; + return base + phandle.args[0]; } static int pipe3_phy_probe(struct udevice *dev) @@ -471,7 +476,7 @@ static int pipe3_phy_probe(struct udevice *dev) struct pipe3_data *data; /* PHY_RX */ - addr = devfdt_get_addr_size_index(dev, 0, &sz); + addr = dev_read_addr_size_index(dev, 0, &sz); if (addr == FDT_ADDR_T_NONE) { pr_err("missing phy_rx address\n"); return -EINVAL; @@ -484,7 +489,7 @@ static int pipe3_phy_probe(struct udevice *dev) } /* PLLCTRL */ - addr = devfdt_get_addr_size_index(dev, 2, &sz); + addr = dev_read_addr_size_index(dev, 2, &sz); if (addr == FDT_ADDR_T_NONE) { pr_err("missing pll ctrl address\n"); return -EINVAL; diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig index df750b26d66..fe96eb6806f 100644 --- a/drivers/phy/ti/Kconfig +++ b/drivers/phy/ti/Kconfig @@ -1,5 +1,5 @@ config PHY_J721E_WIZ - tristate "TI J721E WIZ (SERDES Wrapper) support" + bool "TI J721E WIZ (SERDES Wrapper) support" depends on ARCH_K3 help This option enables support for WIZ module present in TI's J721E diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 578edbf8168..fd30aaeeaa8 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -378,6 +378,26 @@ config ASPEED_AST2600_PINCTRL uses Generic Pinctrl framework and is compatible with the Linux driver, i.e. it uses the same device tree configuration. +config ASPEED_AST2700_SOC0_PINCTRL + bool "Aspeed AST2700 SoC0 pin control driver" + depends on DM && PINCTRL_GENERIC && ASPEED_AST2700 + select PINCONF + default y + help + Support pin multiplexing control on Aspeed ast2700 SoC0. The driver + uses Generic Pinctrl framework and is compatible with the Linux + driver, i.e. it uses the same device tree configuration. + +config ASPEED_AST2700_SOC1_PINCTRL + bool "Aspeed AST2700 SoC1 pin control driver" + depends on DM && PINCTRL_GENERIC && ASPEED_AST2700 + select PINCONF + default y + help + Support pin multiplexing control on Aspeed ast2700 SoC1. The driver + uses Generic Pinctrl framework and is compatible with the Linux + driver, i.e. it uses the same device tree configuration. + config PINCTRL_K210 bool "Kendryte K210 Fully-Programmable Input/Output Array driver" depends on DM && PINCTRL_GENERIC @@ -405,6 +425,7 @@ config SPL_PINCTRL_ZYNQMP endif +source "drivers/pinctrl/airoha/Kconfig" source "drivers/pinctrl/broadcom/Kconfig" source "drivers/pinctrl/exynos/Kconfig" source "drivers/pinctrl/intel/Kconfig" @@ -419,6 +440,7 @@ source "drivers/pinctrl/nxp/Kconfig" source "drivers/pinctrl/qcom/Kconfig" source "drivers/pinctrl/renesas/Kconfig" source "drivers/pinctrl/rockchip/Kconfig" +source "drivers/pinctrl/spacemit/Kconfig" source "drivers/pinctrl/sunxi/Kconfig" source "drivers/pinctrl/tegra/Kconfig" source "drivers/pinctrl/uniphier/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 29fb9b484d0..91149796bb5 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -3,39 +3,43 @@ obj-y += pinctrl-uclass.o obj-$(CONFIG_$(PHASE_)PINCTRL_GENERIC) += pinctrl-generic.o +obj-y += broadcom/ +obj-y += nxp/ + +obj-$(CONFIG_ARCH_ASPEED) += aspeed/ +obj-$(CONFIG_ARCH_ATH79) += ath79/ +obj-$(CONFIG_ARCH_MTMIPS) += mtmips/ +obj-$(CONFIG_ARCH_MVEBU) += mvebu/ +obj-$(CONFIG_ARCH_NEXELL) += nexell/ +obj-$(CONFIG_ARCH_NPCM) += nuvoton/ +obj-$(CONFIG_ARCH_RENESAS) += renesas/ + obj-$(CONFIG_PINCTRL_ADI) += pinctrl-adi-adsp.o +obj-$(CONFIG_PINCTRL_AIROHA) += airoha/ obj-$(CONFIG_PINCTRL_APPLE) += pinctrl-apple.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o -obj-y += nxp/ +obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ +obj-$(CONFIG_PINCTRL_INTEL) += intel/ +obj-$(CONFIG_PINCTRL_K210) += pinctrl-k210.o +obj-$(CONFIG_PINCTRL_MESON) += meson/ +obj-$(CONFIG_PINCTRL_MSCC) += mscc/ +obj-$(CONFIG_PINCTRL_MTK) += mediatek/ +obj-$(CONFIG_PINCTRL_PIC32) += pinctrl_pic32.o +obj-$(CONFIG_PINCTRL_QCOM) += qcom/ +obj-$(CONFIG_PINCTRL_QE) += pinctrl-qe-io.o obj-$(CONFIG_$(PHASE_)PINCTRL_ROCKCHIP) += rockchip/ -obj-$(CONFIG_ARCH_ASPEED) += aspeed/ -obj-$(CONFIG_ARCH_ATH79) += ath79/ -obj-$(CONFIG_PINCTRL_INTEL) += intel/ -obj-$(CONFIG_ARCH_MTMIPS) += mtmips/ -obj-$(CONFIG_ARCH_NPCM) += nuvoton/ -obj-$(CONFIG_PINCTRL_QCOM) += qcom/ -obj-$(CONFIG_ARCH_RENESAS) += renesas/ -obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o -obj-$(CONFIG_PINCTRL_SUNXI) += sunxi/ -obj-$(CONFIG_$(PHASE_)PINCTRL_TEGRA) += tegra/ -obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ -obj-$(CONFIG_PINCTRL_PIC32) += pinctrl_pic32.o -obj-$(CONFIG_PINCTRL_EXYNOS) += exynos/ -obj-$(CONFIG_PINCTRL_K210) += pinctrl-k210.o -obj-$(CONFIG_PINCTRL_MESON) += meson/ -obj-$(CONFIG_PINCTRL_MTK) += mediatek/ -obj-$(CONFIG_PINCTRL_MSCC) += mscc/ -obj-$(CONFIG_ARCH_MVEBU) += mvebu/ -obj-$(CONFIG_ARCH_NEXELL) += nexell/ -obj-$(CONFIG_PINCTRL_QE) += pinctrl-qe-io.o -obj-$(CONFIG_PINCTRL_SCMI) += pinctrl-scmi.o -obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o -obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o -obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o -obj-$(CONFIG_$(PHASE_)PINCTRL_SX150X) += pinctrl-sx150x.o +obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o +obj-$(CONFIG_PINCTRL_SCMI) += pinctrl-scmi.o +obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o +obj-$(CONFIG_$(PHASE_)PINCTRL_SPACEMIT_K1) += spacemit/ +obj-$(CONFIG_PINCTRL_STARFIVE) += starfive/ +obj-$(CONFIG_PINCTRL_STI) += pinctrl-sti.o +obj-$(CONFIG_PINCTRL_STM32) += pinctrl_stm32.o obj-$(CONFIG_$(PHASE_)PINCTRL_STMFX) += pinctrl-stmfx.o -obj-$(CONFIG_PINCTRL_TH1520) += pinctrl-th1520.o -obj-y += broadcom/ +obj-$(CONFIG_PINCTRL_SUNXI) += sunxi/ +obj-$(CONFIG_$(PHASE_)PINCTRL_SX150X) += pinctrl-sx150x.o +obj-$(CONFIG_$(PHASE_)PINCTRL_TEGRA) += tegra/ +obj-$(CONFIG_PINCTRL_TH1520) += pinctrl-th1520.o +obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/ obj-$(CONFIG_$(PHASE_)PINCTRL_ZYNQMP) += pinctrl-zynqmp.o -obj-$(CONFIG_PINCTRL_STARFIVE) += starfive/ diff --git a/drivers/pinctrl/airoha/Kconfig b/drivers/pinctrl/airoha/Kconfig new file mode 100644 index 00000000000..f5d948b27eb --- /dev/null +++ b/drivers/pinctrl/airoha/Kconfig @@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config PINCTRL_AIROHA + depends on ARCH_AIROHA + select PINCTRL_FULL + select PINCTRL_GENERIC + select PINMUX + select PINCONF + select REGMAP + select SYSCON + bool + +config PINCTRL_AIROHA_EN7523 + bool "Airoha EN7523 pin controller and gpio driver" + depends on TARGET_EN7523 + select PINCTRL_AIROHA + +config PINCTRL_AIROHA_AN7581 + bool "Airoha AN7581 pin controller and gpio driver" + depends on TARGET_AN7581 + select PINCTRL_AIROHA + +config PINCTRL_AIROHA_AN7583 + bool "Airoha AN7583 pin controller and gpio driver" + depends on TARGET_AN7583 + select PINCTRL_AIROHA diff --git a/drivers/pinctrl/airoha/Makefile b/drivers/pinctrl/airoha/Makefile new file mode 100644 index 00000000000..b90bd180591 --- /dev/null +++ b/drivers/pinctrl/airoha/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_PINCTRL_AIROHA) += pinctrl-airoha.o + +obj-$(CONFIG_PINCTRL_AIROHA_EN7523) += pinctrl-en7523.o +obj-$(CONFIG_PINCTRL_AIROHA_AN7581) += pinctrl-an7581.o +obj-$(CONFIG_PINCTRL_AIROHA_AN7583) += pinctrl-an7583.o diff --git a/drivers/pinctrl/airoha/airoha-common.h b/drivers/pinctrl/airoha/airoha-common.h new file mode 100644 index 00000000000..4354b0eb6b4 --- /dev/null +++ b/drivers/pinctrl/airoha/airoha-common.h @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __AIROHA_COMMON_HEADER__ +#define __AIROHA_COMMON_HEADER__ + +#include <linux/types.h> +#include <linux/bitops.h> +#include <linux/bitfield.h> +#include <linux/pinctrl/pinctrl.h> + +#include <dm/device.h> +#include <dm/pinctrl.h> + +/* GPIOs */ +#define REG_GPIO_CTRL 0x0000 +#define REG_GPIO_DATA 0x0004 +#define REG_GPIO_INT 0x0008 +#define REG_GPIO_INT_EDGE 0x000c +#define REG_GPIO_INT_LEVEL 0x0010 +#define REG_GPIO_OE 0x0014 +#define REG_GPIO_CTRL1 0x0020 +#define REG_GPIO_CTRL2 0x0060 +#define REG_GPIO_CTRL3 0x0064 +#define REG_GPIO_DATA1 0x0070 +#define REG_GPIO_OE1 0x0078 +#define REG_GPIO_INT1 0x007c +#define REG_GPIO_INT_EDGE1 0x0080 +#define REG_GPIO_INT_EDGE2 0x0084 +#define REG_GPIO_INT_EDGE3 0x0088 +#define REG_GPIO_INT_LEVEL1 0x008c +#define REG_GPIO_INT_LEVEL2 0x0090 +#define REG_GPIO_INT_LEVEL3 0x0094 + +#define AIROHA_NUM_PINS 64 +#define AIROHA_PIN_BANK_SIZE (AIROHA_NUM_PINS / 2) +#define AIROHA_REG_GPIOCTRL_NUM_PIN (AIROHA_NUM_PINS / 4) + +#define PINCTRL_PIN_GROUP(id, table) \ + PINCTRL_PINGROUP(id, table##_pins, ARRAY_SIZE(table##_pins)) + +#define PINCTRL_FUNC_DESC(id, table) \ + { \ + .desc = PINCTRL_PINFUNCTION(id, table##_groups, \ + ARRAY_SIZE(table##_groups)),\ + .groups = table##_func_group, \ + .group_size = ARRAY_SIZE(table##_func_group), \ + } + +#define PINCTRL_CONF_DESC(p, offset, mask) \ + { \ + .pin = p, \ + .reg = { offset, mask }, \ + } + +struct airoha_pinctrl_reg { + u32 offset; + u32 mask; +}; + +enum airoha_pinctrl_mux_func { + AIROHA_FUNC_MUX, + AIROHA_FUNC_PWM_MUX, + AIROHA_FUNC_PWM_EXT_MUX, +}; + +struct airoha_pinctrl_func_group { + const char *name; + struct { + enum airoha_pinctrl_mux_func mux; + u32 offset; + u32 mask; + u32 val; + } regmap[2]; + int regmap_size; +}; + +struct airoha_pinctrl_func { + const struct pinfunction desc; + const struct airoha_pinctrl_func_group *groups; + u8 group_size; +}; + +struct airoha_pinctrl_conf { + u32 pin; + struct airoha_pinctrl_reg reg; +}; + +struct airoha_pinctrl_gpiochip { + /* gpio */ + const u32 *data; + const u32 *dir; + const u32 *out; + /* irq */ + const u32 *status; + const u32 *level; + const u32 *edge; + + u32 irq_type[AIROHA_NUM_PINS]; +}; + +struct airoha_pinctrl_confs_info { + const struct airoha_pinctrl_conf *confs; + unsigned int num_confs; +}; + +enum airoha_pinctrl_confs_type { + AIROHA_PINCTRL_CONFS_PULLUP, + AIROHA_PINCTRL_CONFS_PULLDOWN, + AIROHA_PINCTRL_CONFS_DRIVE_E2, + AIROHA_PINCTRL_CONFS_DRIVE_E4, + AIROHA_PINCTRL_CONFS_PCIE_RST_OD, + + AIROHA_PINCTRL_CONFS_MAX +}; + +struct airoha_pinctrl { + struct udevice *dev; + + struct regmap *chip_scu; + struct regmap *regmap; + + struct airoha_pinctrl_match_data *data; + + struct airoha_pinctrl_gpiochip gpiochip; +}; + +struct airoha_pinctrl_match_data { + const int gpio_offs; + const int gpio_pin_cnt; + const char *chip_scu_compatible; + const struct pinctrl_pin_desc *pins; + const unsigned int num_pins; + const struct pingroup *grps; + const unsigned int num_grps; + const struct airoha_pinctrl_func *funcs; + const unsigned int num_funcs; + const struct airoha_pinctrl_confs_info confs_info[AIROHA_PINCTRL_CONFS_MAX]; +}; + +extern const struct pinctrl_ops airoha_pinctrl_ops; + +int airoha_pinctrl_probe(struct udevice *dev); +int airoha_pinctrl_bind(struct udevice *dev); + +#endif diff --git a/drivers/pinctrl/airoha/pinctrl-airoha.c b/drivers/pinctrl/airoha/pinctrl-airoha.c new file mode 100644 index 00000000000..60c48c0960c --- /dev/null +++ b/drivers/pinctrl/airoha/pinctrl-airoha.c @@ -0,0 +1,958 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Author: Lorenzo Bianconi <[email protected]> + * Author: Benjamin Larsson <[email protected]> + * Author: Markus Gothe <[email protected]> + * Author: Mikhail Kshevetskiy <[email protected]> + */ +#include <dm.h> +#include <dm/device_compat.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/ofnode.h> +#include <asm-generic/gpio.h> +#include <asm/arch/scu-regmap.h> +#include <dt-bindings/pinctrl/mt65xx.h> +#include <regmap.h> +#include <syscon.h> + +#include "airoha-common.h" + +#define airoha_pinctrl_get_pullup_conf(pinctrl, pin, val) \ + airoha_pinctrl_get_conf((pinctrl), AIROHA_PINCTRL_CONFS_PULLUP, \ + (pin), (val)) +#define airoha_pinctrl_get_pulldown_conf(pinctrl, pin, val) \ + airoha_pinctrl_get_conf((pinctrl), AIROHA_PINCTRL_CONFS_PULLDOWN, \ + (pin), (val)) +#define airoha_pinctrl_get_drive_e2_conf(pinctrl, pin, val) \ + airoha_pinctrl_get_conf((pinctrl), AIROHA_PINCTRL_CONFS_DRIVE_E2, \ + (pin), (val)) +#define airoha_pinctrl_get_drive_e4_conf(pinctrl, pin, val) \ + airoha_pinctrl_get_conf((pinctrl), AIROHA_PINCTRL_CONFS_DRIVE_E4, \ + (pin), (val)) +#define airoha_pinctrl_get_pcie_rst_od_conf(pinctrl, pin, val) \ + airoha_pinctrl_get_conf((pinctrl), AIROHA_PINCTRL_CONFS_PCIE_RST_OD, \ + (pin), (val)) +#define airoha_pinctrl_set_pullup_conf(pinctrl, pin, val) \ + airoha_pinctrl_set_conf((pinctrl), AIROHA_PINCTRL_CONFS_PULLUP, \ + (pin), (val)) +#define airoha_pinctrl_set_pulldown_conf(pinctrl, pin, val) \ + airoha_pinctrl_set_conf((pinctrl), AIROHA_PINCTRL_CONFS_PULLDOWN, \ + (pin), (val)) +#define airoha_pinctrl_set_drive_e2_conf(pinctrl, pin, val) \ + airoha_pinctrl_set_conf((pinctrl), AIROHA_PINCTRL_CONFS_DRIVE_E2, \ + (pin), (val)) +#define airoha_pinctrl_set_drive_e4_conf(pinctrl, pin, val) \ + airoha_pinctrl_set_conf((pinctrl), AIROHA_PINCTRL_CONFS_DRIVE_E4, \ + (pin), (val)) +#define airoha_pinctrl_set_pcie_rst_od_conf(pinctrl, pin, val) \ + airoha_pinctrl_set_conf((pinctrl), AIROHA_PINCTRL_CONFS_PCIE_RST_OD, \ + (pin), (val)) + +static const u32 gpio_data_regs[] = { + REG_GPIO_DATA, + REG_GPIO_DATA1 +}; + +static const u32 gpio_out_regs[] = { + REG_GPIO_OE, + REG_GPIO_OE1 +}; + +static const u32 gpio_dir_regs[] = { + REG_GPIO_CTRL, + REG_GPIO_CTRL1, + REG_GPIO_CTRL2, + REG_GPIO_CTRL3 +}; + +static const u32 irq_status_regs[] = { + REG_GPIO_INT, + REG_GPIO_INT1 +}; + +static const u32 irq_level_regs[] = { + REG_GPIO_INT_LEVEL, + REG_GPIO_INT_LEVEL1, + REG_GPIO_INT_LEVEL2, + REG_GPIO_INT_LEVEL3 +}; + +static const u32 irq_edge_regs[] = { + REG_GPIO_INT_EDGE, + REG_GPIO_INT_EDGE1, + REG_GPIO_INT_EDGE2, + REG_GPIO_INT_EDGE3 +}; + +static int pin_in_group(unsigned int pin, const struct pingroup *grp) +{ + for (int i = 0; i < grp->npins; i++) { + if (grp->pins[i] == pin) + return 1; + } + + return 0; +} + +static int pin_to_gpio(struct airoha_pinctrl *pinctrl, unsigned int pin) +{ + struct airoha_pinctrl_match_data *data = pinctrl->data; + + if (pin < data->gpio_offs || + pin >= data->gpio_offs + data->gpio_pin_cnt) + return -EINVAL; + + return pin - data->gpio_offs; +} + +/* gpio callbacks */ +static int airoha_gpio_set(struct airoha_pinctrl *pinctrl, unsigned int gpio, + int value) +{ + u32 offset = gpio % AIROHA_PIN_BANK_SIZE; + u8 index = gpio / AIROHA_PIN_BANK_SIZE; + + return regmap_update_bits(pinctrl->regmap, + pinctrl->gpiochip.data[index], + BIT(offset), value ? BIT(offset) : 0); +} + +static int airoha_gpio_get(struct airoha_pinctrl *pinctrl, unsigned int gpio) +{ + u32 val, pin = gpio % AIROHA_PIN_BANK_SIZE; + u8 index = gpio / AIROHA_PIN_BANK_SIZE; + int err; + + err = regmap_read(pinctrl->regmap, + pinctrl->gpiochip.data[index], &val); + + return err ? err : !!(val & BIT(pin)); +} + +static int airoha_gpio_get_direction(struct airoha_pinctrl *pinctrl, unsigned int gpio) +{ + u32 mask, index, val; + int err, field_shift; + + field_shift = 2 * (gpio % AIROHA_REG_GPIOCTRL_NUM_PIN); + mask = GENMASK(field_shift + 1, field_shift); + index = gpio / AIROHA_REG_GPIOCTRL_NUM_PIN; + + err = regmap_read(pinctrl->regmap, + pinctrl->gpiochip.dir[index], &val); + if (err) + return err; + + if ((val & mask) > BIT(field_shift)) + return -EINVAL; + + return (val & mask) ? GPIOF_OUTPUT : GPIOF_INPUT; +} + +static int airoha_gpio_set_direction(struct airoha_pinctrl *pinctrl, + unsigned int gpio, bool input) +{ + u32 mask, index; + int err, field_shift; + + /* set output enable */ + mask = BIT(gpio % AIROHA_PIN_BANK_SIZE); + index = gpio / AIROHA_PIN_BANK_SIZE; + err = regmap_update_bits(pinctrl->regmap, pinctrl->gpiochip.out[index], + mask, !input ? mask : 0); + if (err) + return err; + + /* set direction */ + field_shift = 2 * (gpio % AIROHA_REG_GPIOCTRL_NUM_PIN); + mask = GENMASK(field_shift + 1, field_shift); + index = gpio / AIROHA_REG_GPIOCTRL_NUM_PIN; + + return regmap_update_bits(pinctrl->regmap, + pinctrl->gpiochip.dir[index], + mask, !input ? BIT(field_shift) : 0); +} + +/* pinmux callbacks */ +static int airoha_pinmux_set_mux(struct airoha_pinctrl *pinctrl, + unsigned int func_selector, + unsigned int group_selector) +{ + const struct airoha_pinctrl_func *func; + const struct pingroup *grp; + int i; + + func = &pinctrl->data->funcs[func_selector]; + grp = &pinctrl->data->grps[group_selector]; + + dev_dbg(pinctrl->dev, "enable function %s group %s\n", + func->desc.name, grp->name); + + for (i = 0; i < func->group_size; i++) { + const struct airoha_pinctrl_func_group *group; + int j; + + group = &func->groups[i]; + if (strcmp(group->name, grp->name)) + continue; + + for (j = 0; j < group->regmap_size; j++) { + switch (group->regmap[j].mux) { + case AIROHA_FUNC_PWM_EXT_MUX: + case AIROHA_FUNC_PWM_MUX: + regmap_update_bits(pinctrl->regmap, + group->regmap[j].offset, + group->regmap[j].mask, + group->regmap[j].val); + break; + default: + regmap_update_bits(pinctrl->chip_scu, + group->regmap[j].offset, + group->regmap[j].mask, + group->regmap[j].val); + break; + } + } + return 0; + } + + return -EINVAL; +} + +static int airoha_pinmux_set_direction(struct airoha_pinctrl *pinctrl, + unsigned int p, bool input) +{ + int gpio; + + gpio = pin_to_gpio(pinctrl, p); + if (gpio < 0) + return gpio; + + return airoha_gpio_set_direction(pinctrl, gpio, input); +} + +/* pinconf callbacks */ +static const struct airoha_pinctrl_reg * +airoha_pinctrl_get_conf_reg(const struct airoha_pinctrl_conf *conf, + int conf_size, int pin) +{ + int i; + + for (i = 0; i < conf_size; i++) { + if (conf[i].pin == pin) + return &conf[i].reg; + } + + return NULL; +} + +static int airoha_pinctrl_get_conf(struct airoha_pinctrl *pinctrl, + enum airoha_pinctrl_confs_type conf_type, + int pin, u32 *val) +{ + const struct airoha_pinctrl_confs_info *confs_info; + const struct airoha_pinctrl_reg *reg; + + confs_info = &pinctrl->data->confs_info[conf_type]; + + reg = airoha_pinctrl_get_conf_reg(confs_info->confs, + confs_info->num_confs, + pin); + if (!reg) + return -EINVAL; + + if (regmap_read(pinctrl->chip_scu, reg->offset, val)) + return -EINVAL; + + *val = field_get(reg->mask, *val); + + return 0; +} + +static int airoha_pinctrl_set_conf(struct airoha_pinctrl *pinctrl, + enum airoha_pinctrl_confs_type conf_type, + int pin, u32 val) +{ + const struct airoha_pinctrl_confs_info *confs_info; + const struct airoha_pinctrl_reg *reg = NULL; + + confs_info = &pinctrl->data->confs_info[conf_type]; + + reg = airoha_pinctrl_get_conf_reg(confs_info->confs, + confs_info->num_confs, + pin); + if (!reg) + return -EINVAL; + + if (regmap_update_bits(pinctrl->chip_scu, reg->offset, reg->mask, + field_prep(reg->mask, val))) + return -EINVAL; + + return 0; +} + +static int airoha_pinconf_get_direction(struct airoha_pinctrl *pinctrl, u32 p) +{ + int gpio; + + gpio = pin_to_gpio(pinctrl, p); + if (gpio < 0) + return gpio; + + return airoha_gpio_get_direction(pinctrl, gpio); +} + +static int airoha_pinconf_get(struct airoha_pinctrl *pinctrl, + unsigned int pin, unsigned long *config) +{ + enum pin_config_param param = pinconf_to_config_param(*config); + u32 arg; + + switch (param) { + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: { + u32 pull_up, pull_down; + + if (airoha_pinctrl_get_pullup_conf(pinctrl, pin, &pull_up) || + airoha_pinctrl_get_pulldown_conf(pinctrl, pin, &pull_down)) + return -EINVAL; + + if (param == PIN_CONFIG_BIAS_PULL_UP && + !(pull_up && !pull_down)) + return -EINVAL; + else if (param == PIN_CONFIG_BIAS_PULL_DOWN && + !(pull_down && !pull_up)) + return -EINVAL; + else if (pull_up || pull_down) + return -EINVAL; + + arg = 1; + break; + } + case PIN_CONFIG_DRIVE_STRENGTH: { + u32 e2, e4; + + if (airoha_pinctrl_get_drive_e2_conf(pinctrl, pin, &e2) || + airoha_pinctrl_get_drive_e4_conf(pinctrl, pin, &e4)) + return -EINVAL; + + arg = e4 << 1 | e2; + break; + } + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (airoha_pinctrl_get_pcie_rst_od_conf(pinctrl, pin, &arg)) + return -EINVAL; + break; + case PIN_CONFIG_OUTPUT_ENABLE: + case PIN_CONFIG_INPUT_ENABLE: + arg = airoha_pinconf_get_direction(pinctrl, pin); + if ((param != PIN_CONFIG_OUTPUT_ENABLE || arg != GPIOF_OUTPUT) && + (param != PIN_CONFIG_INPUT_ENABLE || arg != GPIOF_INPUT)) + return -EINVAL; + + arg = 1; + break; + default: + return -EOPNOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int airoha_pinconf_set_pin_value(struct airoha_pinctrl *pinctrl, + unsigned int p, bool value) +{ + int gpio; + + gpio = pin_to_gpio(pinctrl, p); + if (gpio < 0) + return gpio; + + return airoha_gpio_set(pinctrl, gpio, value); +} + +static int airoha_pinconf_set(struct airoha_pinctrl *pinctrl, + unsigned int pin, unsigned long *configs, + unsigned int num_configs) +{ + int i, err; + + for (i = 0; i < num_configs; i++) { + u32 param = pinconf_to_config_param(configs[i]); + u32 arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + err = airoha_pinctrl_set_pulldown_conf(pinctrl, pin, 0); + if (err) + return err; + + err = airoha_pinctrl_set_pullup_conf(pinctrl, pin, 0); + if (err) + return err; + + break; + + case PIN_CONFIG_BIAS_PULL_UP: + err = airoha_pinctrl_set_pulldown_conf(pinctrl, pin, 0); + if (err) + return err; + + err = airoha_pinctrl_set_pullup_conf(pinctrl, pin, 1); + if (err) + return err; + + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + err = airoha_pinctrl_set_pulldown_conf(pinctrl, pin, 1); + if (err) + return err; + + err = airoha_pinctrl_set_pullup_conf(pinctrl, pin, 0); + if (err) + return err; + + break; + + case PIN_CONFIG_DRIVE_STRENGTH: { + u32 e2 = 0, e4 = 0; + + switch (arg) { + case MTK_DRIVE_2mA: + break; + case MTK_DRIVE_4mA: + e2 = 1; + break; + case MTK_DRIVE_6mA: + e4 = 1; + break; + case MTK_DRIVE_8mA: + e2 = 1; + e4 = 1; + break; + default: + return -EINVAL; + } + + err = airoha_pinctrl_set_drive_e2_conf(pinctrl, pin, e2); + if (err) + return err; + + err = airoha_pinctrl_set_drive_e4_conf(pinctrl, pin, e4); + if (err) + return err; + + break; + } + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + err = airoha_pinctrl_set_pcie_rst_od_conf(pinctrl, pin, !!arg); + if (err) + return err; + + break; + + case PIN_CONFIG_OUTPUT_ENABLE: + case PIN_CONFIG_INPUT_ENABLE: + case PIN_CONFIG_OUTPUT: { + bool input = param == PIN_CONFIG_INPUT_ENABLE; + + err = airoha_pinmux_set_direction(pinctrl, pin, input); + if (err) + return err; + + if (param == PIN_CONFIG_OUTPUT) { + err = airoha_pinconf_set_pin_value(pinctrl, + pin, !!arg); + if (err) + return err; + } + + break; + } + default: + return -EOPNOTSUPP; + } + } + + return 0; +} + +static int airoha_pinconf_group_set(struct airoha_pinctrl *pinctrl, + unsigned int group, unsigned long *configs, + unsigned int num_configs) +{ + int i; + + for (i = 0; i < pinctrl->data->grps[group].npins; i++) { + int err; + + err = airoha_pinconf_set(pinctrl, + pinctrl->data->grps[group].pins[i], + configs, num_configs); + if (err) + return err; + } + + return 0; +} + +static int func_grp_active(struct airoha_pinctrl *pinctrl, + const struct airoha_pinctrl_func *func, + const char *grp_name) +{ + const struct airoha_pinctrl_func_group *func_grp; + u32 val, match; + int ret; + + for (int i = 0; i < func->group_size; i++) { + if (strcmp(func->groups[i].name, grp_name)) + continue; + + match = 0; + func_grp = &func->groups[i]; + for (int j = 0; j < func_grp->regmap_size; j++) { + switch (func_grp->regmap[j].mux) { + case AIROHA_FUNC_PWM_EXT_MUX: + case AIROHA_FUNC_PWM_MUX: + ret = regmap_read(pinctrl->regmap, + func_grp->regmap[j].offset, + &val); + break; + default: + ret = regmap_read(pinctrl->chip_scu, + func_grp->regmap[j].offset, + &val); + break; + } + + if (ret) + break; + + if ((val & func_grp->regmap[j].mask) != + func_grp->regmap[j].val) + break; + + match++; + } + + return match == func->groups[i].regmap_size; + } + + return 0; +} + +/*********************** + * gpio driver interface + ***********************/ +static int airoha_pinctrl_gpio_set(struct udevice *dev, unsigned int gpio, + int value) +{ + return airoha_gpio_set(dev_get_priv(dev->parent), gpio, value); +} + +static int airoha_pinctrl_gpio_get(struct udevice *dev, unsigned int gpio) +{ + return airoha_gpio_get(dev_get_priv(dev->parent), gpio); +} + +static int airoha_pinctrl_gpio_get_direction(struct udevice *dev, + unsigned int gpio) +{ + return airoha_gpio_get_direction(dev_get_priv(dev->parent), gpio); +} + +static int airoha_pinctrl_gpio_direction_input(struct udevice *dev, + unsigned int gpio) +{ + return airoha_gpio_set_direction(dev_get_priv(dev->parent), + gpio, true); +} + +static int airoha_pinctrl_gpio_direction_output(struct udevice *dev, + unsigned int gpio, int val) +{ + struct airoha_pinctrl *pinctrl = dev_get_priv(dev->parent); + int err; + + err = airoha_gpio_set_direction(pinctrl, gpio, false); + if (err) + return err; + + return airoha_gpio_set(pinctrl, gpio, val); +} + +static int airoha_pinctrl_gpio_probe(struct udevice *dev) +{ + struct airoha_pinctrl *pinctrl = dev_get_priv(dev->parent); + struct gpio_dev_priv *uc_priv; + + uc_priv = dev_get_uclass_priv(dev); + uc_priv->bank_name = "airoha"; + uc_priv->gpio_count = pinctrl->data->gpio_pin_cnt; + + return 0; +} + +static int airoha_pinctrl_gpio_bind(struct udevice *dev) +{ + dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND); + + return 0; +} + +static const struct dm_gpio_ops airoha_pinctrl_gpio_ops = { + .set_value = airoha_pinctrl_gpio_set, + .get_value = airoha_pinctrl_gpio_get, + .get_function = airoha_pinctrl_gpio_get_direction, + .direction_input = airoha_pinctrl_gpio_direction_input, + .direction_output = airoha_pinctrl_gpio_direction_output, +}; + +static struct driver airoha_pinctrl_gpio_driver = { + .name = "airoha_pinctrl_gpio", + .id = UCLASS_GPIO, + .probe = airoha_pinctrl_gpio_probe, + .bind = airoha_pinctrl_gpio_bind, + .ops = &airoha_pinctrl_gpio_ops, +}; + +static int airoha_pinctrl_gpio_register(struct udevice *parent) +{ + struct uclass_driver *drv; + ofnode node; + int ret; + + drv = lists_uclass_lookup(UCLASS_GPIO); + if (!drv) + return -ENOENT; + + /* + * Support upstream linux DTSI that define gpio-controller + * in the root node (instead of a dedicated subnode) + */ + if (dev_read_bool(parent, "gpio-controller")) { + /* upstream DTSI, use current node */ + node = dev_ofnode(parent); + } else { + /* legacy DTSI, search for gpio-controller subnode */ + ret = -ENOENT; + dev_for_each_subnode(node, parent) + if (ofnode_read_bool(node, "gpio-controller")) { + ret = 0; + break; + } + + if (ret) + return ret; + } + + return device_bind_with_driver_data(parent, + &airoha_pinctrl_gpio_driver, + "airoha_pinctrl_gpio", + 0, node, NULL); +} + +/************************** + * pinctrl driver interface + **************************/ +static int airoha_get_pins_count(struct udevice *dev) +{ + struct airoha_pinctrl *pinctrl = dev_get_priv(dev); + + return pinctrl->data->num_pins; +} + +static const char *airoha_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + struct airoha_pinctrl *pinctrl = dev_get_priv(dev); + + return pinctrl->data->pins[selector].name; +} + +static int airoha_get_groups_count(struct udevice *dev) +{ + struct airoha_pinctrl *pinctrl = dev_get_priv(dev); + + return pinctrl->data->num_grps; +} + +static const char *airoha_get_group_name(struct udevice *dev, + unsigned int selector) +{ + struct airoha_pinctrl *pinctrl = dev_get_priv(dev); + + return pinctrl->data->grps[selector].name; +} + +static int airoha_get_funcs_count(struct udevice *dev) +{ + struct airoha_pinctrl *pinctrl = dev_get_priv(dev); + + return pinctrl->data->num_funcs; +} + +static const char *airoha_get_func_name(struct udevice *dev, + unsigned int selector) +{ + struct airoha_pinctrl *pinctrl = dev_get_priv(dev); + + return pinctrl->data->funcs[selector].desc.name; +} + +static int airoha_pinmux_group_set(struct udevice *dev, + unsigned int group_selector, + unsigned int func_selector) +{ + struct airoha_pinctrl *pinctrl = dev_get_priv(dev); + + dev_dbg(dev, "enabling %s function for pin group %s\n", + airoha_get_func_name(dev, func_selector), + airoha_get_group_name(dev, group_selector)); + + return airoha_pinmux_set_mux(pinctrl, func_selector, group_selector); +} + +static int airoha_pinmux_set(struct udevice *dev, + unsigned int pin_selector, + unsigned int func_selector) +{ + struct airoha_pinctrl *pinctrl = dev_get_priv(dev); + const struct airoha_pinctrl_match_data *data = pinctrl->data; + const char *pin_name; + unsigned int selector; + + pin_name = data->pins[pin_selector].name; + + /* find group matching the pin_name */ + for (selector = 0; selector < data->num_grps; selector++) { + if (!strcmp(pin_name, data->grps[selector].name)) + return airoha_pinmux_group_set(dev, selector, + func_selector); + } + + return -ENOENT; +} + +static const struct pinconf_param airoha_pinconf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, + { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 }, + { "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 }, + { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, +}; + +static const char *airoha_pinconf_param_name(unsigned int param) +{ + for (int i = 0; i < ARRAY_SIZE(airoha_pinconf_params); i++) { + if (airoha_pinconf_params[i].param == param) + return airoha_pinconf_params[i].property; + } + + return NULL; +} + +static int airoha_pinconf_set_handler(struct udevice *dev, + unsigned pin_selector, + unsigned int param, + unsigned int argument) +{ + struct airoha_pinctrl *pinctrl = dev_get_priv(dev); + unsigned long configs[1] = { pinconf_to_config_packed(param, argument) }; + unsigned int pin = pinctrl->data->pins[pin_selector].number; + + dev_dbg(dev, "enabling %s=%d property for pin %s\n", + airoha_pinconf_param_name(param), argument, + airoha_get_pin_name(dev, pin_selector)); + + return airoha_pinconf_set(pinctrl, pin, configs, + ARRAY_SIZE(configs)); +} + +static int airoha_pinconf_group_set_handler(struct udevice *dev, + unsigned int group_selector, + unsigned int param, + unsigned int argument) +{ + struct airoha_pinctrl *pinctrl = dev_get_priv(dev); + unsigned long configs[1] = { pinconf_to_config_packed(param, argument) }; + + dev_dbg(dev, "enabling %s=%d property for pin group %s\n", + airoha_pinconf_param_name(param), argument, + airoha_get_group_name(dev, group_selector)); + + return airoha_pinconf_group_set(pinctrl, group_selector, + configs, ARRAY_SIZE(configs)); +} + +static int airoha_get_pin_muxing(struct udevice *dev, unsigned int selector, + char *buf, int size) +{ + struct airoha_pinctrl *pinctrl = dev_get_priv(dev); + struct airoha_pinctrl_match_data *data = pinctrl->data; + const char *name, *type; + int ret, gpio, found = 0; + unsigned long config; + unsigned int param, pin; + u32 val; + + pin = data->pins[selector].number; + for (int i = 0; i < data->num_grps; i++) { + if (!pin_in_group(pin, &data->grps[i])) + continue; + + name = data->grps[i].name; + for (int j = 0; j < data->num_funcs; j++) { + if (!func_grp_active(pinctrl, &data->funcs[j], name)) + continue; + + ret = scnprintf(buf, size, "%s(%s)", + data->funcs[j].desc.name, name); + if (ret < 0) + return -ENOSPC; + + found = 1; + buf += ret; + size -= ret; + break; + } + + if (found) + break; + } + + if (!found) { + gpio = pin_to_gpio(pinctrl, pin); + if (gpio < 0) { + /* + * WARNING: non-gpio pin with unknown function. + * + * This should not have happened, the function group + * tables are incomplete. Please fix ASAP. + */ + ret = scnprintf(buf, size, "default"); + } else { + /* assume gpio */ + val = airoha_gpio_get(pinctrl, gpio); + switch (airoha_gpio_get_direction(pinctrl, gpio)) { + case GPIOF_INPUT: + type = "input"; + break; + case GPIOF_OUTPUT: + type = "output"; + break; + default: + type = "unknown"; + break; + }; + ret = scnprintf(buf, size, "gpio%d, %s(%d)", + gpio, type, val); + } + + if (ret < 0) + return -ENOSPC; + + buf += ret; + size -= ret; + } + + for (int i = 0; i < ARRAY_SIZE(airoha_pinconf_params); i++) { + param = airoha_pinconf_params[i].param; + config = pinconf_to_config_packed(param, 0); + ret = airoha_pinconf_get(pinctrl, pin, &config); + if (ret < 0) + continue; + + name = airoha_pinconf_params[i].property; + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = scnprintf(buf, size, ", %s", name); + break; + + case PIN_CONFIG_DRIVE_STRENGTH: + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + val = pinconf_to_config_argument(config); + ret = scnprintf(buf, size, ", %s(%d)", name, val); + break; + + default: + break; + } + + if (ret < 0) + return -ENOSPC; + + buf += ret; + size -= ret; + } + + return 0; +} + +const struct pinctrl_ops airoha_pinctrl_ops = { + .get_pins_count = airoha_get_pins_count, + .get_pin_name = airoha_get_pin_name, + .get_groups_count = airoha_get_groups_count, + .get_group_name = airoha_get_group_name, + .get_functions_count = airoha_get_funcs_count, + .get_function_name = airoha_get_func_name, + .pinmux_set = airoha_pinmux_set, + .pinmux_group_set = airoha_pinmux_group_set, + + .pinconf_num_params = ARRAY_SIZE(airoha_pinconf_params), + .pinconf_params = airoha_pinconf_params, + .pinconf_set = airoha_pinconf_set_handler, + .pinconf_group_set = airoha_pinconf_group_set_handler, + + .set_state = pinctrl_generic_set_state, + .get_pin_muxing = airoha_get_pin_muxing, +}; + +int airoha_pinctrl_probe(struct udevice *dev) +{ + struct airoha_pinctrl *pinctrl = dev_get_priv(dev); + + pinctrl->dev = dev; + pinctrl->data = (struct airoha_pinctrl_match_data *)dev_get_driver_data(dev); + + pinctrl->regmap = syscon_node_to_regmap(dev_ofnode(dev->parent)); + if (IS_ERR(pinctrl->regmap)) + return PTR_ERR(pinctrl->regmap); + + pinctrl->chip_scu = airoha_get_chip_scu_regmap(); + if (IS_ERR(pinctrl->chip_scu)) + return PTR_ERR(pinctrl->chip_scu); + + pinctrl->gpiochip.data = gpio_data_regs; + pinctrl->gpiochip.dir = gpio_dir_regs; + pinctrl->gpiochip.out = gpio_out_regs; + pinctrl->gpiochip.status = irq_status_regs; + pinctrl->gpiochip.level = irq_level_regs; + pinctrl->gpiochip.edge = irq_edge_regs; + + return 0; +} + +int airoha_pinctrl_bind(struct udevice *dev) +{ + if (airoha_pinctrl_gpio_register(dev)) + debug("Warning: can't bind gpio driver with device node\n"); + + /* + * Make sure that the pinctrl driver gets probed after binding, + * otherwise GPIO interface driver will not be probed as well. + * GPIOs of non-probed driver can't be used. + */ + dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND); + + return 0; +} diff --git a/drivers/pinctrl/airoha/pinctrl-an7581.c b/drivers/pinctrl/airoha/pinctrl-an7581.c new file mode 100644 index 00000000000..4f7da74a1cf --- /dev/null +++ b/drivers/pinctrl/airoha/pinctrl-an7581.c @@ -0,0 +1,1484 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Author: Lorenzo Bianconi <[email protected]> + * Author: Benjamin Larsson <[email protected]> + * Author: Markus Gothe <[email protected]> + */ + +#include "airoha-common.h" + +/* MUX */ +#define REG_GPIO_2ND_I2C_MODE 0x0214 +#define GPIO_MDC_IO_MASTER_MODE_MASK BIT(14) +#define GPIO_I2C_MASTER_MODE_MODE BIT(13) +#define GPIO_I2S_MODE_MASK BIT(12) +#define GPIO_I2C_SLAVE_MODE_MODE BIT(11) +#define GPIO_LAN3_LED1_MODE_MASK BIT(10) +#define GPIO_LAN3_LED0_MODE_MASK BIT(9) +#define GPIO_LAN2_LED1_MODE_MASK BIT(8) +#define GPIO_LAN2_LED0_MODE_MASK BIT(7) +#define GPIO_LAN1_LED1_MODE_MASK BIT(6) +#define GPIO_LAN1_LED0_MODE_MASK BIT(5) +#define GPIO_LAN0_LED1_MODE_MASK BIT(4) +#define GPIO_LAN0_LED0_MODE_MASK BIT(3) +#define PON_TOD_1PPS_MODE_MASK BIT(2) +#define GSW_TOD_1PPS_MODE_MASK BIT(1) +#define GPIO_2ND_I2C_MODE_MASK BIT(0) + +#define REG_GPIO_SPI_CS1_MODE 0x0218 +#define GPIO_PCM_SPI_CS4_MODE_MASK BIT(21) +#define GPIO_PCM_SPI_CS3_MODE_MASK BIT(20) +#define GPIO_PCM_SPI_CS2_MODE_P156_MASK BIT(19) +#define GPIO_PCM_SPI_CS2_MODE_P128_MASK BIT(18) +#define GPIO_PCM_SPI_CS1_MODE_MASK BIT(17) +#define GPIO_PCM_SPI_MODE_MASK BIT(16) +#define GPIO_PCM2_MODE_MASK BIT(13) +#define GPIO_PCM1_MODE_MASK BIT(12) +#define GPIO_PCM_INT_MODE_MASK BIT(9) +#define GPIO_PCM_RESET_MODE_MASK BIT(8) +#define GPIO_SPI_QUAD_MODE_MASK BIT(4) +#define GPIO_SPI_CS4_MODE_MASK BIT(3) +#define GPIO_SPI_CS3_MODE_MASK BIT(2) +#define GPIO_SPI_CS2_MODE_MASK BIT(1) +#define GPIO_SPI_CS1_MODE_MASK BIT(0) + +#define REG_GPIO_PON_MODE 0x021c +#define GPIO_PARALLEL_NAND_MODE_MASK BIT(14) +#define GPIO_SGMII_MDIO_MODE_MASK BIT(13) +#define GPIO_PCIE_RESET2_MASK BIT(12) +#define SIPO_RCLK_MODE_MASK BIT(11) +#define GPIO_PCIE_RESET1_MASK BIT(10) +#define GPIO_PCIE_RESET0_MASK BIT(9) +#define GPIO_UART5_MODE_MASK BIT(8) +#define GPIO_UART4_MODE_MASK BIT(7) +#define GPIO_HSUART_CTS_RTS_MODE_MASK BIT(6) +#define GPIO_HSUART_MODE_MASK BIT(5) +#define GPIO_UART2_CTS_RTS_MODE_MASK BIT(4) +#define GPIO_UART2_MODE_MASK BIT(3) +#define GPIO_SIPO_MODE_MASK BIT(2) +#define GPIO_EMMC_MODE_MASK BIT(1) +#define GPIO_PON_MODE_MASK BIT(0) + +#define REG_NPU_UART_EN 0x0224 +#define JTAG_UDI_EN_MASK BIT(4) +#define JTAG_DFD_EN_MASK BIT(3) + +#define REG_FORCE_GPIO_EN 0x0228 +#define FORCE_GPIO_EN(n) BIT(n) + +/* LED MAP */ +#define REG_LAN_LED0_MAPPING 0x027c +#define REG_LAN_LED1_MAPPING 0x0280 + +#define LAN4_LED_MAPPING_MASK GENMASK(18, 16) +#define LAN4_PHY_LED_MAP(_n) FIELD_PREP_CONST(LAN4_LED_MAPPING_MASK, (_n)) + +#define LAN3_LED_MAPPING_MASK GENMASK(14, 12) +#define LAN3_PHY_LED_MAP(_n) FIELD_PREP_CONST(LAN3_LED_MAPPING_MASK, (_n)) + +#define LAN2_LED_MAPPING_MASK GENMASK(10, 8) +#define LAN2_PHY_LED_MAP(_n) FIELD_PREP_CONST(LAN2_LED_MAPPING_MASK, (_n)) + +#define LAN1_LED_MAPPING_MASK GENMASK(6, 4) +#define LAN1_PHY_LED_MAP(_n) FIELD_PREP_CONST(LAN1_LED_MAPPING_MASK, (_n)) + +#define LAN0_LED_MAPPING_MASK GENMASK(2, 0) +#define LAN0_PHY_LED_MAP(_n) FIELD_PREP_CONST(LAN0_LED_MAPPING_MASK, (_n)) + +/* CONF */ +#define REG_I2C_SDA_E2 0x001c +#define SPI_MISO_E2_MASK BIT(14) +#define SPI_MOSI_E2_MASK BIT(13) +#define SPI_CLK_E2_MASK BIT(12) +#define SPI_CS0_E2_MASK BIT(11) +#define PCIE2_RESET_E2_MASK BIT(10) +#define PCIE1_RESET_E2_MASK BIT(9) +#define PCIE0_RESET_E2_MASK BIT(8) +#define UART1_RXD_E2_MASK BIT(3) +#define UART1_TXD_E2_MASK BIT(2) +#define I2C_SCL_E2_MASK BIT(1) +#define I2C_SDA_E2_MASK BIT(0) + +#define REG_I2C_SDA_E4 0x0020 +#define SPI_MISO_E4_MASK BIT(14) +#define SPI_MOSI_E4_MASK BIT(13) +#define SPI_CLK_E4_MASK BIT(12) +#define SPI_CS0_E4_MASK BIT(11) +#define PCIE2_RESET_E4_MASK BIT(10) +#define PCIE1_RESET_E4_MASK BIT(9) +#define PCIE0_RESET_E4_MASK BIT(8) +#define UART1_RXD_E4_MASK BIT(3) +#define UART1_TXD_E4_MASK BIT(2) +#define I2C_SCL_E4_MASK BIT(1) +#define I2C_SDA_E4_MASK BIT(0) + +#define REG_GPIO_L_E2 0x0024 +#define REG_GPIO_L_E4 0x0028 +#define REG_GPIO_H_E2 0x002c +#define REG_GPIO_H_E4 0x0030 + +#define REG_I2C_SDA_PU 0x0044 +#define SPI_MISO_PU_MASK BIT(14) +#define SPI_MOSI_PU_MASK BIT(13) +#define SPI_CLK_PU_MASK BIT(12) +#define SPI_CS0_PU_MASK BIT(11) +#define PCIE2_RESET_PU_MASK BIT(10) +#define PCIE1_RESET_PU_MASK BIT(9) +#define PCIE0_RESET_PU_MASK BIT(8) +#define UART1_RXD_PU_MASK BIT(3) +#define UART1_TXD_PU_MASK BIT(2) +#define I2C_SCL_PU_MASK BIT(1) +#define I2C_SDA_PU_MASK BIT(0) + +#define REG_I2C_SDA_PD 0x0048 +#define SPI_MISO_PD_MASK BIT(14) +#define SPI_MOSI_PD_MASK BIT(13) +#define SPI_CLK_PD_MASK BIT(12) +#define SPI_CS0_PD_MASK BIT(11) +#define PCIE2_RESET_PD_MASK BIT(10) +#define PCIE1_RESET_PD_MASK BIT(9) +#define PCIE0_RESET_PD_MASK BIT(8) +#define UART1_RXD_PD_MASK BIT(3) +#define UART1_TXD_PD_MASK BIT(2) +#define I2C_SCL_PD_MASK BIT(1) +#define I2C_SDA_PD_MASK BIT(0) + +#define REG_GPIO_L_PU 0x004c +#define REG_GPIO_L_PD 0x0050 +#define REG_GPIO_H_PU 0x0054 +#define REG_GPIO_H_PD 0x0058 + +#define REG_PCIE_RESET_OD 0x018c +#define PCIE2_RESET_OD_MASK BIT(2) +#define PCIE1_RESET_OD_MASK BIT(1) +#define PCIE0_RESET_OD_MASK BIT(0) + +/* PWM MODE CONF */ +#define REG_GPIO_FLASH_MODE_CFG 0x0034 +#define GPIO15_FLASH_MODE_CFG BIT(15) +#define GPIO14_FLASH_MODE_CFG BIT(14) +#define GPIO13_FLASH_MODE_CFG BIT(13) +#define GPIO12_FLASH_MODE_CFG BIT(12) +#define GPIO11_FLASH_MODE_CFG BIT(11) +#define GPIO10_FLASH_MODE_CFG BIT(10) +#define GPIO9_FLASH_MODE_CFG BIT(9) +#define GPIO8_FLASH_MODE_CFG BIT(8) +#define GPIO7_FLASH_MODE_CFG BIT(7) +#define GPIO6_FLASH_MODE_CFG BIT(6) +#define GPIO5_FLASH_MODE_CFG BIT(5) +#define GPIO4_FLASH_MODE_CFG BIT(4) +#define GPIO3_FLASH_MODE_CFG BIT(3) +#define GPIO2_FLASH_MODE_CFG BIT(2) +#define GPIO1_FLASH_MODE_CFG BIT(1) +#define GPIO0_FLASH_MODE_CFG BIT(0) + +/* PWM MODE CONF EXT */ +#define REG_GPIO_FLASH_MODE_CFG_EXT 0x0068 +#define GPIO51_FLASH_MODE_CFG BIT(31) +#define GPIO50_FLASH_MODE_CFG BIT(30) +#define GPIO49_FLASH_MODE_CFG BIT(29) +#define GPIO48_FLASH_MODE_CFG BIT(28) +#define GPIO47_FLASH_MODE_CFG BIT(27) +#define GPIO46_FLASH_MODE_CFG BIT(26) +#define GPIO45_FLASH_MODE_CFG BIT(25) +#define GPIO44_FLASH_MODE_CFG BIT(24) +#define GPIO43_FLASH_MODE_CFG BIT(23) +#define GPIO42_FLASH_MODE_CFG BIT(22) +#define GPIO41_FLASH_MODE_CFG BIT(21) +#define GPIO40_FLASH_MODE_CFG BIT(20) +#define GPIO39_FLASH_MODE_CFG BIT(19) +#define GPIO38_FLASH_MODE_CFG BIT(18) +#define GPIO37_FLASH_MODE_CFG BIT(17) +#define GPIO36_FLASH_MODE_CFG BIT(16) +#define GPIO31_FLASH_MODE_CFG BIT(15) +#define GPIO30_FLASH_MODE_CFG BIT(14) +#define GPIO29_FLASH_MODE_CFG BIT(13) +#define GPIO28_FLASH_MODE_CFG BIT(12) +#define GPIO27_FLASH_MODE_CFG BIT(11) +#define GPIO26_FLASH_MODE_CFG BIT(10) +#define GPIO25_FLASH_MODE_CFG BIT(9) +#define GPIO24_FLASH_MODE_CFG BIT(8) +#define GPIO23_FLASH_MODE_CFG BIT(7) +#define GPIO22_FLASH_MODE_CFG BIT(6) +#define GPIO21_FLASH_MODE_CFG BIT(5) +#define GPIO20_FLASH_MODE_CFG BIT(4) +#define GPIO19_FLASH_MODE_CFG BIT(3) +#define GPIO18_FLASH_MODE_CFG BIT(2) +#define GPIO17_FLASH_MODE_CFG BIT(1) +#define GPIO16_FLASH_MODE_CFG BIT(0) + +#define AIROHA_PINCTRL_GPIO(gpio, mux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_PON_MODE, \ + (mux_val), \ + (mux_val) \ + }, \ + .regmap_size = 1, \ + } + +#define AIROHA_PINCTRL_GPIO_EXT(gpio, mux_val, smux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_PWM_EXT_MUX, \ + REG_GPIO_FLASH_MODE_CFG_EXT, \ + (mux_val), \ + 0 \ + }, \ + .regmap[1] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_PON_MODE, \ + (smux_val), \ + (smux_val) \ + }, \ + .regmap_size = 2, \ + } + +/* PWM */ +#define AIROHA_PINCTRL_PWM(gpio, mux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_PWM_MUX, \ + REG_GPIO_FLASH_MODE_CFG, \ + (mux_val), \ + (mux_val) \ + }, \ + .regmap_size = 1, \ + } + +#define AIROHA_PINCTRL_PWM_EXT(gpio, mux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_PWM_EXT_MUX, \ + REG_GPIO_FLASH_MODE_CFG_EXT, \ + (mux_val), \ + (mux_val) \ + }, \ + .regmap_size = 1, \ + } + +#define AIROHA_PINCTRL_PWM_EXT_SEC(gpio, mux_val, smux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_PWM_EXT_MUX, \ + REG_GPIO_FLASH_MODE_CFG_EXT, \ + (mux_val), \ + (mux_val) \ + }, \ + .regmap[1] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_PON_MODE, \ + (smux_val), \ + (smux_val) \ + }, \ + .regmap_size = 2, \ + } + +#define AIROHA_PINCTRL_PHY_LED0(gpio, mux_val, map_mask, map_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_2ND_I2C_MODE, \ + (mux_val), \ + (mux_val), \ + }, \ + .regmap[1] = { \ + AIROHA_FUNC_MUX, \ + REG_LAN_LED0_MAPPING, \ + (map_mask), \ + (map_val), \ + }, \ + .regmap_size = 2, \ + } + +#define AIROHA_PINCTRL_PHY_LED1(gpio, mux_val, map_mask, map_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_2ND_I2C_MODE, \ + (mux_val), \ + (mux_val), \ + }, \ + .regmap[1] = { \ + AIROHA_FUNC_MUX, \ + REG_LAN_LED1_MAPPING, \ + (map_mask), \ + (map_val), \ + }, \ + .regmap_size = 2, \ + } + +static struct pinctrl_pin_desc pinctrl_pins[] = { + PINCTRL_PIN(0, "uart1_txd"), + PINCTRL_PIN(1, "uart1_rxd"), + PINCTRL_PIN(2, "i2c_scl"), + PINCTRL_PIN(3, "i2c_sda"), + PINCTRL_PIN(4, "spi_cs0"), + PINCTRL_PIN(5, "spi_clk"), + PINCTRL_PIN(6, "spi_mosi"), + PINCTRL_PIN(7, "spi_miso"), + PINCTRL_PIN(13, "gpio0"), + PINCTRL_PIN(14, "gpio1"), + PINCTRL_PIN(15, "gpio2"), + PINCTRL_PIN(16, "gpio3"), + PINCTRL_PIN(17, "gpio4"), + PINCTRL_PIN(18, "gpio5"), + PINCTRL_PIN(19, "gpio6"), + PINCTRL_PIN(20, "gpio7"), + PINCTRL_PIN(21, "gpio8"), + PINCTRL_PIN(22, "gpio9"), + PINCTRL_PIN(23, "gpio10"), + PINCTRL_PIN(24, "gpio11"), + PINCTRL_PIN(25, "gpio12"), + PINCTRL_PIN(26, "gpio13"), + PINCTRL_PIN(27, "gpio14"), + PINCTRL_PIN(28, "gpio15"), + PINCTRL_PIN(29, "gpio16"), + PINCTRL_PIN(30, "gpio17"), + PINCTRL_PIN(31, "gpio18"), + PINCTRL_PIN(32, "gpio19"), + PINCTRL_PIN(33, "gpio20"), + PINCTRL_PIN(34, "gpio21"), + PINCTRL_PIN(35, "gpio22"), + PINCTRL_PIN(36, "gpio23"), + PINCTRL_PIN(37, "gpio24"), + PINCTRL_PIN(38, "gpio25"), + PINCTRL_PIN(39, "gpio26"), + PINCTRL_PIN(40, "gpio27"), + PINCTRL_PIN(41, "gpio28"), + PINCTRL_PIN(42, "gpio29"), + PINCTRL_PIN(43, "gpio30"), + PINCTRL_PIN(44, "gpio31"), + PINCTRL_PIN(45, "gpio32"), + PINCTRL_PIN(46, "gpio33"), + PINCTRL_PIN(47, "gpio34"), + PINCTRL_PIN(48, "gpio35"), + PINCTRL_PIN(49, "gpio36"), + PINCTRL_PIN(50, "gpio37"), + PINCTRL_PIN(51, "gpio38"), + PINCTRL_PIN(52, "gpio39"), + PINCTRL_PIN(53, "gpio40"), + PINCTRL_PIN(54, "gpio41"), + PINCTRL_PIN(55, "gpio42"), + PINCTRL_PIN(56, "gpio43"), + PINCTRL_PIN(57, "gpio44"), + PINCTRL_PIN(58, "gpio45"), + PINCTRL_PIN(59, "gpio46"), + PINCTRL_PIN(60, "pcie_reset0"), + PINCTRL_PIN(61, "pcie_reset1"), + PINCTRL_PIN(62, "pcie_reset2"), +}; + +static const int pon_pins[] = { 49, 50, 51, 52, 53, 54 }; +static const int pon_tod_1pps_pins[] = { 46 }; +static const int gsw_tod_1pps_pins[] = { 46 }; +static const int sipo_pins[] = { 16, 17 }; +static const int sipo_rclk_pins[] = { 16, 17, 43 }; +static const int mdio_pins[] = { 14, 15 }; +static const int uart2_pins[] = { 48, 55 }; +static const int uart2_cts_rts_pins[] = { 46, 47 }; +static const int hsuart_pins[] = { 28, 29 }; +static const int hsuart_cts_rts_pins[] = { 26, 27 }; +static const int uart4_pins[] = { 38, 39 }; +static const int uart5_pins[] = { 18, 19 }; +static const int i2c0_pins[] = { 2, 3 }; +static const int i2c1_pins[] = { 14, 15 }; +static const int jtag_udi_pins[] = { 16, 17, 18, 19, 20 }; +static const int jtag_dfd_pins[] = { 16, 17, 18, 19, 20 }; +static const int i2s_pins[] = { 26, 27, 28, 29 }; +static const int pcm1_pins[] = { 22, 23, 24, 25 }; +static const int pcm2_pins[] = { 18, 19, 20, 21 }; +static const int spi_quad_pins[] = { 32, 33 }; +static const int spi_pins[] = { 4, 5, 6, 7 }; +static const int spi_cs1_pins[] = { 34 }; +static const int pcm_spi_pins[] = { 18, 19, 20, 21, 22, 23, 24, 25 }; +static const int pcm_spi_int_pins[] = { 14 }; +static const int pcm_spi_rst_pins[] = { 15 }; +static const int pcm_spi_cs1_pins[] = { 43 }; +static const int pcm_spi_cs2_pins[] = { 40 }; +static const int pcm_spi_cs2_p128_pins[] = { 40 }; +static const int pcm_spi_cs2_p156_pins[] = { 40 }; +static const int pcm_spi_cs3_pins[] = { 41 }; +static const int pcm_spi_cs4_pins[] = { 42 }; +static const int emmc_pins[] = { + 4, 5, 6, 30, 31, 32, 33, 34, 35, 36, 37 +}; +static const int pnand_pins[] = { + 4, 5, 6, 7, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42 +}; +static const int gpio0_pins[] = { 13 }; +static const int gpio1_pins[] = { 14 }; +static const int gpio2_pins[] = { 15 }; +static const int gpio3_pins[] = { 16 }; +static const int gpio4_pins[] = { 17 }; +static const int gpio5_pins[] = { 18 }; +static const int gpio6_pins[] = { 19 }; +static const int gpio7_pins[] = { 20 }; +static const int gpio8_pins[] = { 21 }; +static const int gpio9_pins[] = { 22 }; +static const int gpio10_pins[] = { 23 }; +static const int gpio11_pins[] = { 24 }; +static const int gpio12_pins[] = { 25 }; +static const int gpio13_pins[] = { 26 }; +static const int gpio14_pins[] = { 27 }; +static const int gpio15_pins[] = { 28 }; +static const int gpio16_pins[] = { 29 }; +static const int gpio17_pins[] = { 30 }; +static const int gpio18_pins[] = { 31 }; +static const int gpio19_pins[] = { 32 }; +static const int gpio20_pins[] = { 33 }; +static const int gpio21_pins[] = { 34 }; +static const int gpio22_pins[] = { 35 }; +static const int gpio23_pins[] = { 36 }; +static const int gpio24_pins[] = { 37 }; +static const int gpio25_pins[] = { 38 }; +static const int gpio26_pins[] = { 39 }; +static const int gpio27_pins[] = { 40 }; +static const int gpio28_pins[] = { 41 }; +static const int gpio29_pins[] = { 42 }; +static const int gpio30_pins[] = { 43 }; +static const int gpio31_pins[] = { 44 }; +static const int gpio32_pins[] = { 45 }; +static const int gpio33_pins[] = { 46 }; +static const int gpio34_pins[] = { 47 }; +static const int gpio35_pins[] = { 48 }; +static const int gpio36_pins[] = { 49 }; +static const int gpio37_pins[] = { 50 }; +static const int gpio38_pins[] = { 51 }; +static const int gpio39_pins[] = { 52 }; +static const int gpio40_pins[] = { 53 }; +static const int gpio41_pins[] = { 54 }; +static const int gpio42_pins[] = { 55 }; +static const int gpio43_pins[] = { 56 }; +static const int gpio44_pins[] = { 57 }; +static const int gpio45_pins[] = { 58 }; +static const int gpio46_pins[] = { 59 }; +static const int gpio47_pins[] = { 60 }; +static const int gpio48_pins[] = { 61 }; +static const int gpio49_pins[] = { 62 }; +static const int pcie_reset0_pins[] = { 60 }; +static const int pcie_reset1_pins[] = { 61 }; +static const int pcie_reset2_pins[] = { 62 }; + +static const struct pingroup pinctrl_groups[] = { + PINCTRL_PIN_GROUP("pon", pon), + PINCTRL_PIN_GROUP("pon_tod_1pps", pon_tod_1pps), + PINCTRL_PIN_GROUP("gsw_tod_1pps", gsw_tod_1pps), + PINCTRL_PIN_GROUP("sipo", sipo), + PINCTRL_PIN_GROUP("sipo_rclk", sipo_rclk), + PINCTRL_PIN_GROUP("mdio", mdio), + PINCTRL_PIN_GROUP("uart2", uart2), + PINCTRL_PIN_GROUP("uart2_cts_rts", uart2_cts_rts), + PINCTRL_PIN_GROUP("hsuart", hsuart), + PINCTRL_PIN_GROUP("hsuart_cts_rts", hsuart_cts_rts), + PINCTRL_PIN_GROUP("uart4", uart4), + PINCTRL_PIN_GROUP("uart5", uart5), + PINCTRL_PIN_GROUP("i2c0", i2c0), + PINCTRL_PIN_GROUP("i2c1", i2c1), + PINCTRL_PIN_GROUP("jtag_udi", jtag_udi), + PINCTRL_PIN_GROUP("jtag_dfd", jtag_dfd), + PINCTRL_PIN_GROUP("i2s", i2s), + PINCTRL_PIN_GROUP("pcm1", pcm1), + PINCTRL_PIN_GROUP("pcm2", pcm2), + PINCTRL_PIN_GROUP("spi", spi), + PINCTRL_PIN_GROUP("spi_quad", spi_quad), + PINCTRL_PIN_GROUP("spi_cs1", spi_cs1), + PINCTRL_PIN_GROUP("pcm_spi", pcm_spi), + PINCTRL_PIN_GROUP("pcm_spi_int", pcm_spi_int), + PINCTRL_PIN_GROUP("pcm_spi_rst", pcm_spi_rst), + PINCTRL_PIN_GROUP("pcm_spi_cs1", pcm_spi_cs1), + PINCTRL_PIN_GROUP("pcm_spi_cs2_p128", pcm_spi_cs2_p128), + PINCTRL_PIN_GROUP("pcm_spi_cs2_p156", pcm_spi_cs2_p156), + PINCTRL_PIN_GROUP("pcm_spi_cs2", pcm_spi_cs2), + PINCTRL_PIN_GROUP("pcm_spi_cs3", pcm_spi_cs3), + PINCTRL_PIN_GROUP("pcm_spi_cs4", pcm_spi_cs4), + PINCTRL_PIN_GROUP("emmc", emmc), + PINCTRL_PIN_GROUP("pnand", pnand), + PINCTRL_PIN_GROUP("gpio0", gpio0), + PINCTRL_PIN_GROUP("gpio1", gpio1), + PINCTRL_PIN_GROUP("gpio2", gpio2), + PINCTRL_PIN_GROUP("gpio3", gpio3), + PINCTRL_PIN_GROUP("gpio4", gpio4), + PINCTRL_PIN_GROUP("gpio5", gpio5), + PINCTRL_PIN_GROUP("gpio6", gpio6), + PINCTRL_PIN_GROUP("gpio7", gpio7), + PINCTRL_PIN_GROUP("gpio8", gpio8), + PINCTRL_PIN_GROUP("gpio9", gpio9), + PINCTRL_PIN_GROUP("gpio10", gpio10), + PINCTRL_PIN_GROUP("gpio11", gpio11), + PINCTRL_PIN_GROUP("gpio12", gpio12), + PINCTRL_PIN_GROUP("gpio13", gpio13), + PINCTRL_PIN_GROUP("gpio14", gpio14), + PINCTRL_PIN_GROUP("gpio15", gpio15), + PINCTRL_PIN_GROUP("gpio16", gpio16), + PINCTRL_PIN_GROUP("gpio17", gpio17), + PINCTRL_PIN_GROUP("gpio18", gpio18), + PINCTRL_PIN_GROUP("gpio19", gpio19), + PINCTRL_PIN_GROUP("gpio20", gpio20), + PINCTRL_PIN_GROUP("gpio21", gpio21), + PINCTRL_PIN_GROUP("gpio22", gpio22), + PINCTRL_PIN_GROUP("gpio23", gpio23), + PINCTRL_PIN_GROUP("gpio24", gpio24), + PINCTRL_PIN_GROUP("gpio25", gpio25), + PINCTRL_PIN_GROUP("gpio26", gpio26), + PINCTRL_PIN_GROUP("gpio27", gpio27), + PINCTRL_PIN_GROUP("gpio28", gpio28), + PINCTRL_PIN_GROUP("gpio29", gpio29), + PINCTRL_PIN_GROUP("gpio30", gpio30), + PINCTRL_PIN_GROUP("gpio31", gpio31), + PINCTRL_PIN_GROUP("gpio32", gpio32), + PINCTRL_PIN_GROUP("gpio33", gpio33), + PINCTRL_PIN_GROUP("gpio34", gpio34), + PINCTRL_PIN_GROUP("gpio35", gpio35), + PINCTRL_PIN_GROUP("gpio36", gpio36), + PINCTRL_PIN_GROUP("gpio37", gpio37), + PINCTRL_PIN_GROUP("gpio38", gpio38), + PINCTRL_PIN_GROUP("gpio39", gpio39), + PINCTRL_PIN_GROUP("gpio40", gpio40), + PINCTRL_PIN_GROUP("gpio41", gpio41), + PINCTRL_PIN_GROUP("gpio42", gpio42), + PINCTRL_PIN_GROUP("gpio43", gpio43), + PINCTRL_PIN_GROUP("gpio44", gpio44), + PINCTRL_PIN_GROUP("gpio45", gpio45), + PINCTRL_PIN_GROUP("gpio46", gpio46), + PINCTRL_PIN_GROUP("gpio47", gpio47), + PINCTRL_PIN_GROUP("gpio48", gpio48), + PINCTRL_PIN_GROUP("gpio49", gpio49), + PINCTRL_PIN_GROUP("pcie_reset0", pcie_reset0), + PINCTRL_PIN_GROUP("pcie_reset1", pcie_reset1), + PINCTRL_PIN_GROUP("pcie_reset2", pcie_reset2), +}; + +static const char *const pon_groups[] = { "pon" }; +static const char *const tod_1pps_groups[] = { + "pon_tod_1pps", "gsw_tod_1pps" +}; +static const char *const sipo_groups[] = { "sipo", "sipo_rclk" }; +static const char *const mdio_groups[] = { "mdio" }; +static const char *const uart_groups[] = { + "uart2", "uart2_cts_rts", "hsuart", "hsuart_cts_rts", + "uart4", "uart5" +}; +static const char *const i2c_groups[] = { "i2c1" }; +static const char *const jtag_groups[] = { "jtag_udi", "jtag_dfd" }; +static const char *const pcm_groups[] = { "pcm1", "pcm2" }; +static const char *const spi_groups[] = { "spi_quad", "spi_cs1" }; +static const char *const pcm_spi_groups[] = { + "pcm_spi", "pcm_spi_int", "pcm_spi_rst", "pcm_spi_cs1", + "pcm_spi_cs2_p156", "pcm_spi_cs2_p128", "pcm_spi_cs3", + "pcm_spi_cs4" +}; +static const char *const i2s_groups[] = { "i2s" }; +static const char *const emmc_groups[] = { "emmc" }; +static const char *const pnand_groups[] = { "pnand" }; +static const char *const gpio_groups[] = { "gpio47", "gpio48", "gpio49" }; +static const char *const pcie_reset_groups[] = { + "pcie_reset0", "pcie_reset1", "pcie_reset2" +}; +static const char *const pwm_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", + "gpio6", "gpio7", "gpio8", "gpio9", "gpio10", "gpio11", + "gpio12", "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", + "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", "gpio23", + "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", + "gpio30", "gpio31", "gpio36", "gpio37", "gpio38", "gpio39", + "gpio40", "gpio41", "gpio42", "gpio43", "gpio44", "gpio45", + "gpio46", "gpio47", "gpio48", "gpio49" +}; +static const char *const phy1_led0_groups[] = { + "gpio33", "gpio34", "gpio35", "gpio42" +}; +static const char *const phy2_led0_groups[] = { + "gpio33", "gpio34", "gpio35", "gpio42" +}; +static const char *const phy3_led0_groups[] = { + "gpio33", "gpio34", "gpio35", "gpio42" +}; +static const char *const phy4_led0_groups[] = { + "gpio33", "gpio34", "gpio35", "gpio42" +}; +static const char *const phy1_led1_groups[] = { + "gpio43", "gpio44", "gpio45", "gpio46" +}; +static const char *const phy2_led1_groups[] = { + "gpio43", "gpio44", "gpio45", "gpio46" +}; +static const char *const phy3_led1_groups[] = { + "gpio43", "gpio44", "gpio45", "gpio46" +}; +static const char *const phy4_led1_groups[] = { + "gpio43", "gpio44", "gpio45", "gpio46" +}; + +static const struct airoha_pinctrl_func_group pon_func_group[] = { + { + .name = "pon", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PON_MODE_MASK, + GPIO_PON_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group tod_1pps_func_group[] = { + { + .name = "pon_tod_1pps", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + PON_TOD_1PPS_MODE_MASK, + PON_TOD_1PPS_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "gsw_tod_1pps", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GSW_TOD_1PPS_MODE_MASK, + GSW_TOD_1PPS_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group sipo_func_group[] = { + { + .name = "sipo", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK, + GPIO_SIPO_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "sipo_rclk", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK, + GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group mdio_func_group[] = { + { + .name = "mdio", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_MDC_IO_MASTER_MODE_MASK, + GPIO_MDC_IO_MASTER_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_FORCE_GPIO_EN, + FORCE_GPIO_EN(1) | FORCE_GPIO_EN(2), + FORCE_GPIO_EN(1) | FORCE_GPIO_EN(2) + }, + .regmap_size = 2, + }, +}; + +static const struct airoha_pinctrl_func_group uart_func_group[] = { + { + .name = "uart2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_UART2_MODE_MASK, + GPIO_UART2_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "uart2_cts_rts", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_UART2_MODE_MASK | GPIO_UART2_CTS_RTS_MODE_MASK, + GPIO_UART2_MODE_MASK | GPIO_UART2_CTS_RTS_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "hsuart", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK, + GPIO_HSUART_MODE_MASK + }, + .regmap_size = 1, + }, + { + .name = "hsuart_cts_rts", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK, + GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "uart4", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_UART4_MODE_MASK, + GPIO_UART4_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "uart5", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_UART5_MODE_MASK, + GPIO_UART5_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group i2c_func_group[] = { + { + .name = "i2c1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_2ND_I2C_MODE_MASK, + GPIO_2ND_I2C_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group jtag_func_group[] = { + { + .name = "jtag_udi", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_NPU_UART_EN, + JTAG_UDI_EN_MASK, + JTAG_UDI_EN_MASK + }, + .regmap_size = 1, + }, { + .name = "jtag_dfd", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_NPU_UART_EN, + JTAG_DFD_EN_MASK, + JTAG_DFD_EN_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pcm_func_group[] = { + { + .name = "pcm1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM1_MODE_MASK, + GPIO_PCM1_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM2_MODE_MASK, + GPIO_PCM2_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group spi_func_group[] = { + { + .name = "spi_quad", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_QUAD_MODE_MASK, + GPIO_SPI_QUAD_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "spi_cs1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_CS1_MODE_MASK, + GPIO_SPI_CS1_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "spi_cs2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_CS2_MODE_MASK, + GPIO_SPI_CS2_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "spi_cs3", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_CS3_MODE_MASK, + GPIO_SPI_CS3_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "spi_cs4", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_CS4_MODE_MASK, + GPIO_SPI_CS4_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = { + { + .name = "pcm_spi", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_MODE_MASK, + GPIO_PCM_SPI_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_int", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_INT_MODE_MASK, + GPIO_PCM_INT_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_rst", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_RESET_MODE_MASK, + GPIO_PCM_RESET_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS1_MODE_MASK, + GPIO_PCM_SPI_CS1_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs2_p128", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS2_MODE_P128_MASK, + GPIO_PCM_SPI_CS2_MODE_P128_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs2_p156", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS2_MODE_P156_MASK, + GPIO_PCM_SPI_CS2_MODE_P156_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs3", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS3_MODE_MASK, + GPIO_PCM_SPI_CS3_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs4", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS4_MODE_MASK, + GPIO_PCM_SPI_CS4_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group i2s_func_group[] = { + { + .name = "i2s", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_I2S_MODE_MASK, + GPIO_I2S_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group emmc_func_group[] = { + { + .name = "emmc", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_EMMC_MODE_MASK, + GPIO_EMMC_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pnand_func_group[] = { + { + .name = "pnand", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PARALLEL_NAND_MODE_MASK, + GPIO_PARALLEL_NAND_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group gpio_func_group[] = { + AIROHA_PINCTRL_GPIO_EXT("gpio47", GPIO47_FLASH_MODE_CFG, + GPIO_PCIE_RESET0_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio48", GPIO48_FLASH_MODE_CFG, + GPIO_PCIE_RESET1_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio49", GPIO49_FLASH_MODE_CFG, + GPIO_PCIE_RESET2_MASK), +}; + +static const struct airoha_pinctrl_func_group pcie_reset_func_group[] = { + { + .name = "pcie_reset0", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PCIE_RESET0_MASK, + 0 + }, + .regmap_size = 1, + }, { + .name = "pcie_reset1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PCIE_RESET1_MASK, + 0 + }, + .regmap_size = 1, + }, { + .name = "pcie_reset2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PCIE_RESET2_MASK, + 0 + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pwm_func_group[] = { + AIROHA_PINCTRL_PWM("gpio0", GPIO0_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio1", GPIO1_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio2", GPIO2_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio3", GPIO3_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio4", GPIO4_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio5", GPIO5_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio6", GPIO6_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio7", GPIO7_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio8", GPIO8_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio9", GPIO9_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio10", GPIO10_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio11", GPIO11_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio12", GPIO12_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio13", GPIO13_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio14", GPIO14_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio15", GPIO15_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio16", GPIO16_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio17", GPIO17_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio18", GPIO18_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio19", GPIO19_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio20", GPIO20_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio21", GPIO21_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio22", GPIO22_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio23", GPIO23_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio24", GPIO24_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio25", GPIO25_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio26", GPIO26_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio27", GPIO27_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio28", GPIO28_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio29", GPIO29_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio30", GPIO30_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio31", GPIO31_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio36", GPIO36_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio37", GPIO37_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio38", GPIO38_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio39", GPIO39_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio40", GPIO40_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio41", GPIO41_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio42", GPIO42_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio43", GPIO43_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio44", GPIO44_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio45", GPIO45_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio46", GPIO46_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio47", GPIO47_FLASH_MODE_CFG, + GPIO_PCIE_RESET0_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio48", GPIO48_FLASH_MODE_CFG, + GPIO_PCIE_RESET1_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio49", GPIO49_FLASH_MODE_CFG, + GPIO_PCIE_RESET2_MASK), +}; + +static const struct airoha_pinctrl_func_group phy1_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio33", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio34", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio35", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio42", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)), +}; + +static const struct airoha_pinctrl_func_group phy2_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio33", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio34", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio35", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio42", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)), +}; + +static const struct airoha_pinctrl_func_group phy3_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio33", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio34", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio35", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio42", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)), +}; + +static const struct airoha_pinctrl_func_group phy4_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio33", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio34", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio35", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio42", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)), +}; + +static const struct airoha_pinctrl_func_group phy1_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio43", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio44", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio45", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio46", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)), +}; + +static const struct airoha_pinctrl_func_group phy2_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio43", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio44", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio45", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio46", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)), +}; + +static const struct airoha_pinctrl_func_group phy3_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio43", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio44", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio45", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio46", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)), +}; + +static const struct airoha_pinctrl_func_group phy4_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio43", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED1("gpio44", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED1("gpio45", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED1("gpio46", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)), +}; + +static const struct airoha_pinctrl_func pinctrl_funcs[] = { + PINCTRL_FUNC_DESC("pon", pon), + PINCTRL_FUNC_DESC("tod_1pps", tod_1pps), + PINCTRL_FUNC_DESC("sipo", sipo), + PINCTRL_FUNC_DESC("mdio", mdio), + PINCTRL_FUNC_DESC("uart", uart), + PINCTRL_FUNC_DESC("i2c", i2c), + PINCTRL_FUNC_DESC("jtag", jtag), + PINCTRL_FUNC_DESC("pcm", pcm), + PINCTRL_FUNC_DESC("spi", spi), + PINCTRL_FUNC_DESC("pcm_spi", pcm_spi), + PINCTRL_FUNC_DESC("i2s", i2s), + PINCTRL_FUNC_DESC("emmc", emmc), + PINCTRL_FUNC_DESC("pnand", pnand), + PINCTRL_FUNC_DESC("gpio", gpio), + PINCTRL_FUNC_DESC("pcie_reset", pcie_reset), + PINCTRL_FUNC_DESC("pwm", pwm), + PINCTRL_FUNC_DESC("phy1_led0", phy1_led0), + PINCTRL_FUNC_DESC("phy2_led0", phy2_led0), + PINCTRL_FUNC_DESC("phy3_led0", phy3_led0), + PINCTRL_FUNC_DESC("phy4_led0", phy4_led0), + PINCTRL_FUNC_DESC("phy1_led1", phy1_led1), + PINCTRL_FUNC_DESC("phy2_led1", phy2_led1), + PINCTRL_FUNC_DESC("phy3_led1", phy3_led1), + PINCTRL_FUNC_DESC("phy4_led1", phy4_led1), +}; + +static const struct airoha_pinctrl_conf pinctrl_pullup_conf[] = { + PINCTRL_CONF_DESC(0, REG_I2C_SDA_PU, UART1_TXD_PU_MASK), + PINCTRL_CONF_DESC(1, REG_I2C_SDA_PU, UART1_RXD_PU_MASK), + PINCTRL_CONF_DESC(2, REG_I2C_SDA_PU, I2C_SDA_PU_MASK), + PINCTRL_CONF_DESC(3, REG_I2C_SDA_PU, I2C_SCL_PU_MASK), + PINCTRL_CONF_DESC(4, REG_I2C_SDA_PU, SPI_CS0_PU_MASK), + PINCTRL_CONF_DESC(5, REG_I2C_SDA_PU, SPI_CLK_PU_MASK), + PINCTRL_CONF_DESC(6, REG_I2C_SDA_PU, SPI_MOSI_PU_MASK), + PINCTRL_CONF_DESC(7, REG_I2C_SDA_PU, SPI_MISO_PU_MASK), + PINCTRL_CONF_DESC(13, REG_GPIO_L_PU, BIT(0)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_PU, BIT(1)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_PU, BIT(2)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_PU, BIT(3)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_PU, BIT(4)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_PU, BIT(5)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_PU, BIT(6)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_PU, BIT(7)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_PU, BIT(8)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_PU, BIT(9)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_PU, BIT(10)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_PU, BIT(11)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_PU, BIT(12)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_PU, BIT(13)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_PU, BIT(14)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_PU, BIT(15)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_PU, BIT(16)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_PU, BIT(17)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_PU, BIT(18)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_PU, BIT(19)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_PU, BIT(20)), + PINCTRL_CONF_DESC(34, REG_GPIO_L_PU, BIT(21)), + PINCTRL_CONF_DESC(35, REG_GPIO_L_PU, BIT(22)), + PINCTRL_CONF_DESC(36, REG_GPIO_L_PU, BIT(23)), + PINCTRL_CONF_DESC(37, REG_GPIO_L_PU, BIT(24)), + PINCTRL_CONF_DESC(38, REG_GPIO_L_PU, BIT(25)), + PINCTRL_CONF_DESC(39, REG_GPIO_L_PU, BIT(26)), + PINCTRL_CONF_DESC(40, REG_GPIO_L_PU, BIT(27)), + PINCTRL_CONF_DESC(41, REG_GPIO_L_PU, BIT(28)), + PINCTRL_CONF_DESC(42, REG_GPIO_L_PU, BIT(29)), + PINCTRL_CONF_DESC(43, REG_GPIO_L_PU, BIT(30)), + PINCTRL_CONF_DESC(44, REG_GPIO_L_PU, BIT(31)), + PINCTRL_CONF_DESC(45, REG_GPIO_H_PU, BIT(0)), + PINCTRL_CONF_DESC(46, REG_GPIO_H_PU, BIT(1)), + PINCTRL_CONF_DESC(47, REG_GPIO_H_PU, BIT(2)), + PINCTRL_CONF_DESC(48, REG_GPIO_H_PU, BIT(3)), + PINCTRL_CONF_DESC(49, REG_GPIO_H_PU, BIT(4)), + PINCTRL_CONF_DESC(50, REG_GPIO_H_PU, BIT(5)), + PINCTRL_CONF_DESC(51, REG_GPIO_H_PU, BIT(6)), + PINCTRL_CONF_DESC(52, REG_GPIO_H_PU, BIT(7)), + PINCTRL_CONF_DESC(53, REG_GPIO_H_PU, BIT(8)), + PINCTRL_CONF_DESC(54, REG_GPIO_H_PU, BIT(9)), + PINCTRL_CONF_DESC(55, REG_GPIO_H_PU, BIT(10)), + PINCTRL_CONF_DESC(56, REG_GPIO_H_PU, BIT(11)), + PINCTRL_CONF_DESC(57, REG_GPIO_H_PU, BIT(12)), + PINCTRL_CONF_DESC(58, REG_GPIO_H_PU, BIT(13)), + PINCTRL_CONF_DESC(59, REG_GPIO_H_PU, BIT(14)), + PINCTRL_CONF_DESC(60, REG_I2C_SDA_PU, PCIE0_RESET_PU_MASK), + PINCTRL_CONF_DESC(61, REG_I2C_SDA_PU, PCIE1_RESET_PU_MASK), + PINCTRL_CONF_DESC(62, REG_I2C_SDA_PU, PCIE2_RESET_PU_MASK), +}; + +static const struct airoha_pinctrl_conf pinctrl_pulldown_conf[] = { + PINCTRL_CONF_DESC(0, REG_I2C_SDA_PD, UART1_TXD_PD_MASK), + PINCTRL_CONF_DESC(1, REG_I2C_SDA_PD, UART1_RXD_PD_MASK), + PINCTRL_CONF_DESC(2, REG_I2C_SDA_PD, I2C_SDA_PD_MASK), + PINCTRL_CONF_DESC(3, REG_I2C_SDA_PD, I2C_SCL_PD_MASK), + PINCTRL_CONF_DESC(4, REG_I2C_SDA_PD, SPI_CS0_PD_MASK), + PINCTRL_CONF_DESC(5, REG_I2C_SDA_PD, SPI_CLK_PD_MASK), + PINCTRL_CONF_DESC(6, REG_I2C_SDA_PD, SPI_MOSI_PD_MASK), + PINCTRL_CONF_DESC(7, REG_I2C_SDA_PD, SPI_MISO_PD_MASK), + PINCTRL_CONF_DESC(13, REG_GPIO_L_PD, BIT(0)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_PD, BIT(1)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_PD, BIT(2)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_PD, BIT(3)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_PD, BIT(4)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_PD, BIT(5)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_PD, BIT(6)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_PD, BIT(7)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_PD, BIT(8)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_PD, BIT(9)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_PD, BIT(10)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_PD, BIT(11)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_PD, BIT(12)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_PD, BIT(13)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_PD, BIT(14)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_PD, BIT(15)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_PD, BIT(16)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_PD, BIT(17)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_PD, BIT(18)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_PD, BIT(19)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_PD, BIT(20)), + PINCTRL_CONF_DESC(34, REG_GPIO_L_PD, BIT(21)), + PINCTRL_CONF_DESC(35, REG_GPIO_L_PD, BIT(22)), + PINCTRL_CONF_DESC(36, REG_GPIO_L_PD, BIT(23)), + PINCTRL_CONF_DESC(37, REG_GPIO_L_PD, BIT(24)), + PINCTRL_CONF_DESC(38, REG_GPIO_L_PD, BIT(25)), + PINCTRL_CONF_DESC(39, REG_GPIO_L_PD, BIT(26)), + PINCTRL_CONF_DESC(40, REG_GPIO_L_PD, BIT(27)), + PINCTRL_CONF_DESC(41, REG_GPIO_L_PD, BIT(28)), + PINCTRL_CONF_DESC(42, REG_GPIO_L_PD, BIT(29)), + PINCTRL_CONF_DESC(43, REG_GPIO_L_PD, BIT(30)), + PINCTRL_CONF_DESC(44, REG_GPIO_L_PD, BIT(31)), + PINCTRL_CONF_DESC(45, REG_GPIO_H_PD, BIT(0)), + PINCTRL_CONF_DESC(46, REG_GPIO_H_PD, BIT(1)), + PINCTRL_CONF_DESC(47, REG_GPIO_H_PD, BIT(2)), + PINCTRL_CONF_DESC(48, REG_GPIO_H_PD, BIT(3)), + PINCTRL_CONF_DESC(49, REG_GPIO_H_PD, BIT(4)), + PINCTRL_CONF_DESC(50, REG_GPIO_H_PD, BIT(5)), + PINCTRL_CONF_DESC(51, REG_GPIO_H_PD, BIT(6)), + PINCTRL_CONF_DESC(52, REG_GPIO_H_PD, BIT(7)), + PINCTRL_CONF_DESC(53, REG_GPIO_H_PD, BIT(8)), + PINCTRL_CONF_DESC(54, REG_GPIO_H_PD, BIT(9)), + PINCTRL_CONF_DESC(55, REG_GPIO_H_PD, BIT(10)), + PINCTRL_CONF_DESC(56, REG_GPIO_H_PD, BIT(11)), + PINCTRL_CONF_DESC(57, REG_GPIO_H_PD, BIT(12)), + PINCTRL_CONF_DESC(58, REG_GPIO_H_PD, BIT(13)), + PINCTRL_CONF_DESC(59, REG_GPIO_H_PD, BIT(14)), + PINCTRL_CONF_DESC(60, REG_I2C_SDA_PD, PCIE0_RESET_PD_MASK), + PINCTRL_CONF_DESC(61, REG_I2C_SDA_PD, PCIE1_RESET_PD_MASK), + PINCTRL_CONF_DESC(62, REG_I2C_SDA_PD, PCIE2_RESET_PD_MASK), +}; + +static const struct airoha_pinctrl_conf pinctrl_drive_e2_conf[] = { + PINCTRL_CONF_DESC(0, REG_I2C_SDA_E2, UART1_TXD_E2_MASK), + PINCTRL_CONF_DESC(1, REG_I2C_SDA_E2, UART1_RXD_E2_MASK), + PINCTRL_CONF_DESC(2, REG_I2C_SDA_E2, I2C_SDA_E2_MASK), + PINCTRL_CONF_DESC(3, REG_I2C_SDA_E2, I2C_SCL_E2_MASK), + PINCTRL_CONF_DESC(4, REG_I2C_SDA_E2, SPI_CS0_E2_MASK), + PINCTRL_CONF_DESC(5, REG_I2C_SDA_E2, SPI_CLK_E2_MASK), + PINCTRL_CONF_DESC(6, REG_I2C_SDA_E2, SPI_MOSI_E2_MASK), + PINCTRL_CONF_DESC(7, REG_I2C_SDA_E2, SPI_MISO_E2_MASK), + PINCTRL_CONF_DESC(13, REG_GPIO_L_E2, BIT(0)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_E2, BIT(1)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_E2, BIT(2)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_E2, BIT(3)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_E2, BIT(4)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_E2, BIT(5)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_E2, BIT(6)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_E2, BIT(7)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_E2, BIT(8)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_E2, BIT(9)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_E2, BIT(10)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_E2, BIT(11)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_E2, BIT(12)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_E2, BIT(13)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_E2, BIT(14)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_E2, BIT(15)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_E2, BIT(16)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_E2, BIT(17)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_E2, BIT(18)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_E2, BIT(19)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_E2, BIT(20)), + PINCTRL_CONF_DESC(34, REG_GPIO_L_E2, BIT(21)), + PINCTRL_CONF_DESC(35, REG_GPIO_L_E2, BIT(22)), + PINCTRL_CONF_DESC(36, REG_GPIO_L_E2, BIT(23)), + PINCTRL_CONF_DESC(37, REG_GPIO_L_E2, BIT(24)), + PINCTRL_CONF_DESC(38, REG_GPIO_L_E2, BIT(25)), + PINCTRL_CONF_DESC(39, REG_GPIO_L_E2, BIT(26)), + PINCTRL_CONF_DESC(40, REG_GPIO_L_E2, BIT(27)), + PINCTRL_CONF_DESC(41, REG_GPIO_L_E2, BIT(28)), + PINCTRL_CONF_DESC(42, REG_GPIO_L_E2, BIT(29)), + PINCTRL_CONF_DESC(43, REG_GPIO_L_E2, BIT(30)), + PINCTRL_CONF_DESC(44, REG_GPIO_L_E2, BIT(31)), + PINCTRL_CONF_DESC(45, REG_GPIO_H_E2, BIT(0)), + PINCTRL_CONF_DESC(46, REG_GPIO_H_E2, BIT(1)), + PINCTRL_CONF_DESC(47, REG_GPIO_H_E2, BIT(2)), + PINCTRL_CONF_DESC(48, REG_GPIO_H_E2, BIT(3)), + PINCTRL_CONF_DESC(49, REG_GPIO_H_E2, BIT(4)), + PINCTRL_CONF_DESC(50, REG_GPIO_H_E2, BIT(5)), + PINCTRL_CONF_DESC(51, REG_GPIO_H_E2, BIT(6)), + PINCTRL_CONF_DESC(52, REG_GPIO_H_E2, BIT(7)), + PINCTRL_CONF_DESC(53, REG_GPIO_H_E2, BIT(8)), + PINCTRL_CONF_DESC(54, REG_GPIO_H_E2, BIT(9)), + PINCTRL_CONF_DESC(55, REG_GPIO_H_E2, BIT(10)), + PINCTRL_CONF_DESC(56, REG_GPIO_H_E2, BIT(11)), + PINCTRL_CONF_DESC(57, REG_GPIO_H_E2, BIT(12)), + PINCTRL_CONF_DESC(58, REG_GPIO_H_E2, BIT(13)), + PINCTRL_CONF_DESC(59, REG_GPIO_H_E2, BIT(14)), + PINCTRL_CONF_DESC(60, REG_I2C_SDA_E2, PCIE0_RESET_E2_MASK), + PINCTRL_CONF_DESC(61, REG_I2C_SDA_E2, PCIE1_RESET_E2_MASK), + PINCTRL_CONF_DESC(62, REG_I2C_SDA_E2, PCIE2_RESET_E2_MASK), +}; + +static const struct airoha_pinctrl_conf pinctrl_drive_e4_conf[] = { + PINCTRL_CONF_DESC(0, REG_I2C_SDA_E4, UART1_TXD_E4_MASK), + PINCTRL_CONF_DESC(1, REG_I2C_SDA_E4, UART1_RXD_E4_MASK), + PINCTRL_CONF_DESC(2, REG_I2C_SDA_E4, I2C_SDA_E4_MASK), + PINCTRL_CONF_DESC(3, REG_I2C_SDA_E4, I2C_SCL_E4_MASK), + PINCTRL_CONF_DESC(4, REG_I2C_SDA_E4, SPI_CS0_E4_MASK), + PINCTRL_CONF_DESC(5, REG_I2C_SDA_E4, SPI_CLK_E4_MASK), + PINCTRL_CONF_DESC(6, REG_I2C_SDA_E4, SPI_MOSI_E4_MASK), + PINCTRL_CONF_DESC(7, REG_I2C_SDA_E4, SPI_MISO_E4_MASK), + PINCTRL_CONF_DESC(13, REG_GPIO_L_E4, BIT(0)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_E4, BIT(1)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_E4, BIT(2)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_E4, BIT(3)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_E4, BIT(4)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_E4, BIT(5)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_E4, BIT(6)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_E4, BIT(7)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_E4, BIT(8)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_E4, BIT(9)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_E4, BIT(10)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_E4, BIT(11)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_E4, BIT(12)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_E4, BIT(13)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_E4, BIT(14)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_E4, BIT(15)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_E4, BIT(16)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_E4, BIT(17)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_E4, BIT(18)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_E4, BIT(19)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_E4, BIT(20)), + PINCTRL_CONF_DESC(34, REG_GPIO_L_E4, BIT(21)), + PINCTRL_CONF_DESC(35, REG_GPIO_L_E4, BIT(22)), + PINCTRL_CONF_DESC(36, REG_GPIO_L_E4, BIT(23)), + PINCTRL_CONF_DESC(37, REG_GPIO_L_E4, BIT(24)), + PINCTRL_CONF_DESC(38, REG_GPIO_L_E4, BIT(25)), + PINCTRL_CONF_DESC(39, REG_GPIO_L_E4, BIT(26)), + PINCTRL_CONF_DESC(40, REG_GPIO_L_E4, BIT(27)), + PINCTRL_CONF_DESC(41, REG_GPIO_L_E4, BIT(28)), + PINCTRL_CONF_DESC(42, REG_GPIO_L_E4, BIT(29)), + PINCTRL_CONF_DESC(43, REG_GPIO_L_E4, BIT(30)), + PINCTRL_CONF_DESC(44, REG_GPIO_L_E4, BIT(31)), + PINCTRL_CONF_DESC(45, REG_GPIO_H_E4, BIT(0)), + PINCTRL_CONF_DESC(46, REG_GPIO_H_E4, BIT(1)), + PINCTRL_CONF_DESC(47, REG_GPIO_H_E4, BIT(2)), + PINCTRL_CONF_DESC(48, REG_GPIO_H_E4, BIT(3)), + PINCTRL_CONF_DESC(49, REG_GPIO_H_E4, BIT(4)), + PINCTRL_CONF_DESC(50, REG_GPIO_H_E4, BIT(5)), + PINCTRL_CONF_DESC(51, REG_GPIO_H_E4, BIT(6)), + PINCTRL_CONF_DESC(52, REG_GPIO_H_E4, BIT(7)), + PINCTRL_CONF_DESC(53, REG_GPIO_H_E4, BIT(8)), + PINCTRL_CONF_DESC(54, REG_GPIO_H_E4, BIT(9)), + PINCTRL_CONF_DESC(55, REG_GPIO_H_E4, BIT(10)), + PINCTRL_CONF_DESC(56, REG_GPIO_H_E4, BIT(11)), + PINCTRL_CONF_DESC(57, REG_GPIO_H_E4, BIT(12)), + PINCTRL_CONF_DESC(58, REG_GPIO_H_E4, BIT(13)), + PINCTRL_CONF_DESC(59, REG_GPIO_H_E4, BIT(14)), + PINCTRL_CONF_DESC(60, REG_I2C_SDA_E4, PCIE0_RESET_E4_MASK), + PINCTRL_CONF_DESC(61, REG_I2C_SDA_E4, PCIE1_RESET_E4_MASK), + PINCTRL_CONF_DESC(62, REG_I2C_SDA_E4, PCIE2_RESET_E4_MASK), +}; + +static const struct airoha_pinctrl_conf pinctrl_pcie_rst_od_conf[] = { + PINCTRL_CONF_DESC(60, REG_PCIE_RESET_OD, PCIE0_RESET_OD_MASK), + PINCTRL_CONF_DESC(61, REG_PCIE_RESET_OD, PCIE1_RESET_OD_MASK), + PINCTRL_CONF_DESC(62, REG_PCIE_RESET_OD, PCIE2_RESET_OD_MASK), +}; + +static const struct airoha_pinctrl_match_data pinctrl_match_data = { + .gpio_offs = 13, + .gpio_pin_cnt = 50, + .chip_scu_compatible = "airoha,en7581-chip-scu", + .pins = pinctrl_pins, + .num_pins = ARRAY_SIZE(pinctrl_pins), + .grps = pinctrl_groups, + .num_grps = ARRAY_SIZE(pinctrl_groups), + .funcs = pinctrl_funcs, + .num_funcs = ARRAY_SIZE(pinctrl_funcs), + .confs_info = { + [AIROHA_PINCTRL_CONFS_PULLUP] = { + .confs = pinctrl_pullup_conf, + .num_confs = ARRAY_SIZE(pinctrl_pullup_conf), + }, + [AIROHA_PINCTRL_CONFS_PULLDOWN] = { + .confs = pinctrl_pulldown_conf, + .num_confs = ARRAY_SIZE(pinctrl_pulldown_conf), + }, + [AIROHA_PINCTRL_CONFS_DRIVE_E2] = { + .confs = pinctrl_drive_e2_conf, + .num_confs = ARRAY_SIZE(pinctrl_drive_e2_conf), + }, + [AIROHA_PINCTRL_CONFS_DRIVE_E4] = { + .confs = pinctrl_drive_e4_conf, + .num_confs = ARRAY_SIZE(pinctrl_drive_e4_conf), + }, + [AIROHA_PINCTRL_CONFS_PCIE_RST_OD] = { + .confs = pinctrl_pcie_rst_od_conf, + .num_confs = ARRAY_SIZE(pinctrl_pcie_rst_od_conf), + }, + }, +}; + +static const struct udevice_id pinctrl_of_match[] = { + { .compatible = "airoha,en7581-pinctrl", + .data = (uintptr_t)&pinctrl_match_data }, + { .compatible = "airoha,an7581-pinctrl", + .data = (uintptr_t)&pinctrl_match_data }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(airoha_an7581_pinctrl) = { + .name = "airoha-an7581-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(pinctrl_of_match), + .probe = airoha_pinctrl_probe, + .bind = airoha_pinctrl_bind, + .priv_auto = sizeof(struct airoha_pinctrl), + .ops = &airoha_pinctrl_ops, +}; diff --git a/drivers/pinctrl/airoha/pinctrl-an7583.c b/drivers/pinctrl/airoha/pinctrl-an7583.c new file mode 100644 index 00000000000..2f6f3651ec8 --- /dev/null +++ b/drivers/pinctrl/airoha/pinctrl-an7583.c @@ -0,0 +1,1492 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Author: Lorenzo Bianconi <[email protected]> + * Author: Benjamin Larsson <[email protected]> + * Author: Markus Gothe <[email protected]> + */ + +#include "airoha-common.h" + +/* MUX */ +#define REG_SW_TOD_1PPS_MODE 0x0214 +#define GPIO_LAN3_LED1_MODE_MASK BIT(10) +#define GPIO_LAN3_LED0_MODE_MASK BIT(9) +#define GPIO_LAN2_LED1_MODE_MASK BIT(8) +#define GPIO_LAN2_LED0_MODE_MASK BIT(7) +#define GPIO_LAN1_LED1_MODE_MASK BIT(6) +#define GPIO_LAN1_LED0_MODE_MASK BIT(5) +#define GPIO_LAN0_LED1_MODE_MASK BIT(4) +#define GPIO_LAN0_LED0_MODE_MASK BIT(3) +#define PON_TOD_1PPS_MODE_MASK BIT(2) +#define GSW_TOD_1PPS_MODE_MASK BIT(1) + +#define REG_GPIO_SPI_CS1_MODE 0x0218 +#define GPIO_MDC_IO_MASTER_MODE_MASK BIT(22) +#define GPIO_PCM_SPI_CS4_MODE_MASK BIT(21) +#define GPIO_PCM_SPI_CS3_MODE_MASK BIT(20) +#define GPIO_PCM_SPI_CS2_MODE_MASK BIT(18) +#define GPIO_PCM_SPI_CS1_MODE_MASK BIT(17) +#define GPIO_PCM_SPI_MODE_MASK BIT(16) +#define GPIO_PCM2_MODE_MASK BIT(13) +#define GPIO_PCM1_MODE_MASK BIT(12) +#define GPIO_PCM_INT_MODE_MASK BIT(9) +#define GPIO_PCM_RESET_MODE_MASK BIT(8) +#define GPIO_SPI_QUAD_MODE_MASK BIT(4) +#define GPIO_SPI_CS4_MODE_MASK BIT(3) +#define GPIO_SPI_CS3_MODE_MASK BIT(2) +#define GPIO_SPI_CS2_MODE_MASK BIT(1) +#define GPIO_SPI_CS1_MODE_MASK BIT(0) + +#define REG_GPIO_PON_MODE 0x021c +#define GPIO_PON_ALT_MODE_MASK BIT(27) +#define MDIO_0_GPIO_MODE_MASK BIT(26) +#define MDC_0_GPIO_MODE_MASK BIT(25) +#define UART_RXD_GPIO_MODE_MASK BIT(24) +#define UART_TXD_GPIO_MODE_MASK BIT(23) +#define SPI_MISO_GPIO_MODE_MASK BIT(22) +#define SPI_MOSI_GPIO_MODE_MASK BIT(21) +#define SPI_CS_GPIO_MODE_MASK BIT(20) +#define SPI_CLK_GPIO_MODE_MASK BIT(19) +#define I2C1_SDA_GPIO_MODE_MASK BIT(18) +#define I2C1_SCL_GPIO_MODE_MASK BIT(17) +#define I2C0_SDA_GPIO_MODE_MASK BIT(16) +#define I2C0_SCL_GPIO_MODE_MASK BIT(15) +#define GPIO_PARALLEL_NAND_MODE_MASK BIT(14) +#define GPIO_SGMII_MDIO_MODE_MASK BIT(13) +#define GPIO_OLT_MODE_MASK BIT(12) +#define SIPO_RCLK_MODE_MASK BIT(11) +#define GPIO_PCIE_RESET1_MASK BIT(10) +#define GPIO_PCIE_RESET0_MASK BIT(9) +#define GPIO_UART5_MODE_MASK BIT(8) +#define GPIO_UART4_MODE_MASK BIT(7) +#define GPIO_HSUART_CTS_RTS_MODE_MASK BIT(6) +#define GPIO_HSUART_MODE_MASK BIT(5) +#define GPIO_UART2_CTS_RTS_MODE_MASK BIT(4) +#define GPIO_UART2_MODE_MASK BIT(3) +#define GPIO_SIPO_MODE_MASK BIT(2) +#define GPIO_EMMC_MODE_MASK BIT(1) +#define GPIO_PON_MODE_MASK BIT(0) + +#define REG_NPU_UART_EN 0x0224 +#define JTAG_UDI_EN_MASK BIT(4) +#define JTAG_DFD_EN_MASK BIT(3) +#define NPU_UART_EN_MASK BIT(2) + +#define REG_FORCE_GPIO_EN 0x0228 +#define FORCE_GPIO_EN(n) BIT(n) + +/* LED MAP */ +#define REG_LAN_LED0_MAPPING 0x027c +#define REG_LAN_LED1_MAPPING 0x0280 + +#define LAN4_LED_MAPPING_MASK GENMASK(18, 16) +#define LAN4_PHY_LED_MAP(_n) FIELD_PREP_CONST(LAN4_LED_MAPPING_MASK, (_n)) + +#define LAN3_LED_MAPPING_MASK GENMASK(14, 12) +#define LAN3_PHY_LED_MAP(_n) FIELD_PREP_CONST(LAN3_LED_MAPPING_MASK, (_n)) + +#define LAN2_LED_MAPPING_MASK GENMASK(10, 8) +#define LAN2_PHY_LED_MAP(_n) FIELD_PREP_CONST(LAN2_LED_MAPPING_MASK, (_n)) + +#define LAN1_LED_MAPPING_MASK GENMASK(6, 4) +#define LAN1_PHY_LED_MAP(_n) FIELD_PREP_CONST(LAN1_LED_MAPPING_MASK, (_n)) + +#define LAN0_LED_MAPPING_MASK GENMASK(2, 0) +#define LAN0_PHY_LED_MAP(_n) FIELD_PREP_CONST(LAN0_LED_MAPPING_MASK, (_n)) + +/* CONF */ +#define REG_I2C_SDA_E2 0x001c +#define I2C1_SCL_E2_MASK BIT(16) +#define I2C1_SDA_E2_MASK BIT(15) +#define SPI_MISO_E2_MASK BIT(14) +#define SPI_MOSI_E2_MASK BIT(13) +#define SPI_CLK_E2_MASK BIT(12) +#define SPI_CS0_E2_MASK BIT(11) +#define PCIE1_RESET_E2_MASK BIT(9) +#define PCIE0_RESET_E2_MASK BIT(8) +#define MDIO_0_E2_MASK BIT(5) +#define MDC_0_E2_MASK BIT(4) +#define UART1_RXD_E2_MASK BIT(3) +#define UART1_TXD_E2_MASK BIT(2) +#define I2C_SCL_E2_MASK BIT(1) +#define I2C_SDA_E2_MASK BIT(0) + +#define REG_I2C_SDA_E4 0x0020 +#define I2C1_SCL_E4_MASK BIT(16) +#define I2C1_SDA_E4_MASK BIT(15) +#define SPI_MISO_E4_MASK BIT(14) +#define SPI_MOSI_E4_MASK BIT(13) +#define SPI_CLK_E4_MASK BIT(12) +#define SPI_CS0_E4_MASK BIT(11) +#define PCIE1_RESET_E4_MASK BIT(9) +#define PCIE0_RESET_E4_MASK BIT(8) +#define MDIO_0_E4_MASK BIT(5) +#define MDC_0_E4_MASK BIT(4) +#define UART1_RXD_E4_MASK BIT(3) +#define UART1_TXD_E4_MASK BIT(2) +#define I2C_SCL_E4_MASK BIT(1) +#define I2C_SDA_E4_MASK BIT(0) + +#define REG_GPIO_L_E2 0x0024 +#define REG_GPIO_L_E4 0x0028 +#define REG_GPIO_H_E2 0x002c +#define REG_GPIO_H_E4 0x0030 + +#define REG_I2C_SDA_PU 0x0044 +#define I2C1_SCL_PU_MASK BIT(16) +#define I2C1_SDA_PU_MASK BIT(15) +#define SPI_MISO_PU_MASK BIT(14) +#define SPI_MOSI_PU_MASK BIT(13) +#define SPI_CLK_PU_MASK BIT(12) +#define SPI_CS0_PU_MASK BIT(11) +#define PCIE1_RESET_PU_MASK BIT(9) +#define PCIE0_RESET_PU_MASK BIT(8) +#define MDIO_0_PU_MASK BIT(5) +#define MDC_0_PU_MASK BIT(4) +#define UART1_RXD_PU_MASK BIT(3) +#define UART1_TXD_PU_MASK BIT(2) +#define I2C_SCL_PU_MASK BIT(1) +#define I2C_SDA_PU_MASK BIT(0) + +#define REG_I2C_SDA_PD 0x0048 +#define I2C1_SCL_PD_MASK BIT(16) +#define I2C1_SDA_PD_MASK BIT(15) +#define SPI_MISO_PD_MASK BIT(14) +#define SPI_MOSI_PD_MASK BIT(13) +#define SPI_CLK_PD_MASK BIT(12) +#define SPI_CS0_PD_MASK BIT(11) +#define PCIE1_RESET_PD_MASK BIT(9) +#define PCIE0_RESET_PD_MASK BIT(8) +#define MDIO_0_PD_MASK BIT(5) +#define MDC_0_PD_MASK BIT(4) +#define UART1_RXD_PD_MASK BIT(3) +#define UART1_TXD_PD_MASK BIT(2) +#define I2C_SCL_PD_MASK BIT(1) +#define I2C_SDA_PD_MASK BIT(0) + +#define REG_GPIO_L_PU 0x004c +#define REG_GPIO_L_PD 0x0050 +#define REG_GPIO_H_PU 0x0054 +#define REG_GPIO_H_PD 0x0058 + +#define REG_PCIE_RESET_OD 0x018c +#define PCIE1_RESET_OD_MASK BIT(1) +#define PCIE0_RESET_OD_MASK BIT(0) + +/* PWM MODE CONF */ +#define REG_GPIO_FLASH_MODE_CFG 0x0034 +#define GPIO15_FLASH_MODE_CFG BIT(15) +#define GPIO14_FLASH_MODE_CFG BIT(14) +#define GPIO13_FLASH_MODE_CFG BIT(13) +#define GPIO12_FLASH_MODE_CFG BIT(12) +#define GPIO11_FLASH_MODE_CFG BIT(11) +#define GPIO10_FLASH_MODE_CFG BIT(10) +#define GPIO9_FLASH_MODE_CFG BIT(9) +#define GPIO8_FLASH_MODE_CFG BIT(8) +#define GPIO7_FLASH_MODE_CFG BIT(7) +#define GPIO6_FLASH_MODE_CFG BIT(6) +#define GPIO5_FLASH_MODE_CFG BIT(5) +#define GPIO4_FLASH_MODE_CFG BIT(4) +#define GPIO3_FLASH_MODE_CFG BIT(3) +#define GPIO2_FLASH_MODE_CFG BIT(2) +#define GPIO1_FLASH_MODE_CFG BIT(1) +#define GPIO0_FLASH_MODE_CFG BIT(0) + +/* PWM MODE CONF EXT */ +#define REG_GPIO_FLASH_MODE_CFG_EXT 0x0068 +#define GPIO51_FLASH_MODE_CFG BIT(31) +#define GPIO50_FLASH_MODE_CFG BIT(30) +#define GPIO49_FLASH_MODE_CFG BIT(29) +#define GPIO48_FLASH_MODE_CFG BIT(28) +#define GPIO47_FLASH_MODE_CFG BIT(27) +#define GPIO46_FLASH_MODE_CFG BIT(26) +#define GPIO45_FLASH_MODE_CFG BIT(25) +#define GPIO44_FLASH_MODE_CFG BIT(24) +#define GPIO43_FLASH_MODE_CFG BIT(23) +#define GPIO42_FLASH_MODE_CFG BIT(22) +#define GPIO41_FLASH_MODE_CFG BIT(21) +#define GPIO40_FLASH_MODE_CFG BIT(20) +#define GPIO39_FLASH_MODE_CFG BIT(19) +#define GPIO38_FLASH_MODE_CFG BIT(18) +#define GPIO37_FLASH_MODE_CFG BIT(17) +#define GPIO36_FLASH_MODE_CFG BIT(16) +#define GPIO31_FLASH_MODE_CFG BIT(15) +#define GPIO30_FLASH_MODE_CFG BIT(14) +#define GPIO29_FLASH_MODE_CFG BIT(13) +#define GPIO28_FLASH_MODE_CFG BIT(12) +#define GPIO27_FLASH_MODE_CFG BIT(11) +#define GPIO26_FLASH_MODE_CFG BIT(10) +#define GPIO25_FLASH_MODE_CFG BIT(9) +#define GPIO24_FLASH_MODE_CFG BIT(8) +#define GPIO23_FLASH_MODE_CFG BIT(7) +#define GPIO22_FLASH_MODE_CFG BIT(6) +#define GPIO21_FLASH_MODE_CFG BIT(5) +#define GPIO20_FLASH_MODE_CFG BIT(4) +#define GPIO19_FLASH_MODE_CFG BIT(3) +#define GPIO18_FLASH_MODE_CFG BIT(2) +#define GPIO17_FLASH_MODE_CFG BIT(1) +#define GPIO16_FLASH_MODE_CFG BIT(0) + +#define AIROHA_PINCTRL_GPIO(gpio, mux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_PON_MODE, \ + (mux_val), \ + (mux_val) \ + }, \ + .regmap_size = 1, \ + } + +#define AIROHA_PINCTRL_GPIO_EXT(gpio, mux_val, smux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_PWM_EXT_MUX, \ + REG_GPIO_FLASH_MODE_CFG_EXT, \ + (mux_val), \ + 0 \ + }, \ + .regmap[1] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_PON_MODE, \ + (smux_val), \ + (smux_val) \ + }, \ + .regmap_size = 2, \ + } + +/* PWM */ +#define AIROHA_PINCTRL_PWM(gpio, mux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_PWM_MUX, \ + REG_GPIO_FLASH_MODE_CFG, \ + (mux_val), \ + (mux_val) \ + }, \ + .regmap_size = 1, \ + } + +#define AIROHA_PINCTRL_PWM_EXT(gpio, mux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_PWM_EXT_MUX, \ + REG_GPIO_FLASH_MODE_CFG_EXT, \ + (mux_val), \ + (mux_val) \ + }, \ + .regmap_size = 1, \ + } + +#define AIROHA_PINCTRL_PWM_EXT_SEC(gpio, mux_val, smux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_PWM_EXT_MUX, \ + REG_GPIO_FLASH_MODE_CFG_EXT, \ + (mux_val), \ + (mux_val) \ + }, \ + .regmap[1] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_PON_MODE, \ + (smux_val), \ + (smux_val) \ + }, \ + .regmap_size = 2, \ + } + +#define AIROHA_PINCTRL_PHY_LED0(gpio, mux_val, map_mask, map_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_MUX, \ + REG_SW_TOD_1PPS_MODE, \ + (mux_val), \ + (mux_val), \ + }, \ + .regmap[1] = { \ + AIROHA_FUNC_MUX, \ + REG_LAN_LED0_MAPPING, \ + (map_mask), \ + (map_val), \ + }, \ + .regmap_size = 2, \ + } + +#define AIROHA_PINCTRL_PHY_LED1(gpio, mux_val, map_mask, map_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_MUX, \ + REG_SW_TOD_1PPS_MODE, \ + (mux_val), \ + (mux_val), \ + }, \ + .regmap[1] = { \ + AIROHA_FUNC_MUX, \ + REG_LAN_LED1_MAPPING, \ + (map_mask), \ + (map_val), \ + }, \ + .regmap_size = 2, \ + } + +static struct pinctrl_pin_desc pinctrl_pins[] = { + PINCTRL_PIN(2, "gpio0"), + PINCTRL_PIN(3, "gpio1"), + PINCTRL_PIN(4, "gpio2"), + PINCTRL_PIN(5, "gpio3"), + PINCTRL_PIN(6, "gpio4"), + PINCTRL_PIN(7, "gpio5"), + PINCTRL_PIN(8, "gpio6"), + PINCTRL_PIN(9, "gpio7"), + PINCTRL_PIN(10, "gpio8"), + PINCTRL_PIN(11, "gpio9"), + PINCTRL_PIN(12, "gpio10"), + PINCTRL_PIN(13, "gpio11"), + PINCTRL_PIN(14, "gpio12"), + PINCTRL_PIN(15, "gpio13"), + PINCTRL_PIN(16, "gpio14"), + PINCTRL_PIN(17, "gpio15"), + PINCTRL_PIN(18, "gpio16"), + PINCTRL_PIN(19, "gpio17"), + PINCTRL_PIN(20, "gpio18"), + PINCTRL_PIN(21, "gpio19"), + PINCTRL_PIN(22, "gpio20"), + PINCTRL_PIN(23, "gpio21"), + PINCTRL_PIN(24, "gpio22"), + PINCTRL_PIN(25, "gpio23"), + PINCTRL_PIN(26, "gpio24"), + PINCTRL_PIN(27, "gpio25"), + PINCTRL_PIN(28, "gpio26"), + PINCTRL_PIN(29, "gpio27"), + PINCTRL_PIN(30, "gpio28"), + PINCTRL_PIN(31, "gpio29"), + PINCTRL_PIN(32, "gpio30"), + PINCTRL_PIN(33, "gpio31"), + PINCTRL_PIN(34, "gpio32"), + PINCTRL_PIN(35, "gpio33"), + PINCTRL_PIN(36, "gpio34"), + PINCTRL_PIN(37, "gpio35"), + PINCTRL_PIN(38, "gpio36"), + PINCTRL_PIN(39, "gpio37"), + PINCTRL_PIN(40, "gpio38"), + PINCTRL_PIN(41, "i2c0_scl"), + PINCTRL_PIN(42, "i2c0_sda"), + PINCTRL_PIN(43, "i2c1_scl"), + PINCTRL_PIN(44, "i2c1_sda"), + PINCTRL_PIN(45, "spi_clk"), + PINCTRL_PIN(46, "spi_cs"), + PINCTRL_PIN(47, "spi_mosi"), + PINCTRL_PIN(48, "spi_miso"), + PINCTRL_PIN(49, "uart_txd"), + PINCTRL_PIN(50, "uart_rxd"), + PINCTRL_PIN(51, "pcie_reset0"), + PINCTRL_PIN(52, "pcie_reset1"), + PINCTRL_PIN(53, "mdc_0"), + PINCTRL_PIN(54, "mdio_0"), +}; + +static const int pon_pins[] = { 15, 16, 17, 18, 19, 20 }; +static const int pon_alt_pins[] = { 36, 37, 38, 39, 40 }; +static const int olt_pins[] = { 36, 37, 38, 39, 40 }; +static const int pon_tod_1pps_pins[] = { 32 }; +static const int gsw_tod_1pps_pins[] = { 32 }; +static const int sipo_pins[] = { 34, 35 }; +static const int sipo_rclk_pins[] = { 34, 35, 33 }; +static const int mdio_pins[] = { 43, 44 }; +static const int uart2_pins[] = { 34, 35 }; +static const int uart2_cts_rts_pins[] = { 32, 33 }; +static const int hsuart_pins[] = { 30, 31 }; +static const int hsuart_cts_rts_pins[] = { 28, 29 }; +static const int npu_uart_pins[] = { 7, 8 }; +static const int uart4_pins[] = { 7, 8 }; +static const int uart5_pins[] = { 23, 24 }; +static const int i2c0_pins[] = { 41, 42 }; +static const int i2c1_pins[] = { 43, 44 }; +static const int jtag_udi_pins[] = { 23, 24, 22, 25, 26 }; +static const int jtag_dfd_pins[] = { 23, 24, 22, 25, 26 }; +static const int pcm1_pins[] = { 10, 11, 12, 13, 14 }; +static const int pcm2_pins[] = { 28, 29, 30, 31, 24 }; +static const int spi_pins[] = { 28, 29, 30, 31 }; +static const int spi_quad_pins[] = { 25, 26 }; +static const int spi_cs1_pins[] = { 27 }; +static const int pcm_spi_pins[] = { 28, 29, 30, 31, 10, 11, 12, 13 }; +static const int pcm_spi_rst_pins[] = { 14 }; +static const int pcm_spi_cs1_pins[] = { 24 }; +static const int emmc_pins[] = { + 7, 8, 9, 22, 23, 24, 25, 26, 45, 46, 47 +}; +static const int pnand_pins[] = { + 7, 8, 9, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 45, 46, 47, 48 +}; +static const int gpio0_pins[] = { 2 }; +static const int gpio1_pins[] = { 3 }; +static const int gpio2_pins[] = { 4 }; +static const int gpio3_pins[] = { 5 }; +static const int gpio4_pins[] = { 6 }; +static const int gpio5_pins[] = { 7 }; +static const int gpio6_pins[] = { 8 }; +static const int gpio7_pins[] = { 9 }; +static const int gpio8_pins[] = { 10 }; +static const int gpio9_pins[] = { 11 }; +static const int gpio10_pins[] = { 12 }; +static const int gpio11_pins[] = { 13 }; +static const int gpio12_pins[] = { 14 }; +static const int gpio13_pins[] = { 15 }; +static const int gpio14_pins[] = { 16 }; +static const int gpio15_pins[] = { 17 }; +static const int gpio16_pins[] = { 18 }; +static const int gpio17_pins[] = { 19 }; +static const int gpio18_pins[] = { 20 }; +static const int gpio19_pins[] = { 21 }; +static const int gpio20_pins[] = { 22 }; +static const int gpio21_pins[] = { 23 }; +static const int gpio22_pins[] = { 24 }; +static const int gpio23_pins[] = { 25 }; +static const int gpio24_pins[] = { 26 }; +static const int gpio25_pins[] = { 27 }; +static const int gpio26_pins[] = { 28 }; +static const int gpio27_pins[] = { 29 }; +static const int gpio28_pins[] = { 30 }; +static const int gpio29_pins[] = { 31 }; +static const int gpio30_pins[] = { 32 }; +static const int gpio31_pins[] = { 33 }; +static const int gpio32_pins[] = { 34 }; +static const int gpio33_pins[] = { 35 }; +static const int gpio34_pins[] = { 36 }; +static const int gpio35_pins[] = { 37 }; +static const int gpio36_pins[] = { 38 }; +static const int gpio37_pins[] = { 39 }; +static const int gpio38_pins[] = { 40 }; +static const int gpio39_pins[] = { 41 }; +static const int gpio40_pins[] = { 42 }; +static const int gpio41_pins[] = { 43 }; +static const int gpio42_pins[] = { 44 }; +static const int gpio43_pins[] = { 45 }; +static const int gpio44_pins[] = { 46 }; +static const int gpio45_pins[] = { 47 }; +static const int gpio46_pins[] = { 48 }; +static const int gpio47_pins[] = { 49 }; +static const int gpio48_pins[] = { 50 }; +static const int gpio49_pins[] = { 51 }; +static const int gpio50_pins[] = { 52 }; +static const int gpio51_pins[] = { 53 }; +static const int gpio52_pins[] = { 54 }; +static const int pcie_reset0_pins[] = { 51 }; +static const int pcie_reset1_pins[] = { 52 }; + +static const struct pingroup pinctrl_groups[] = { + PINCTRL_PIN_GROUP("pon", pon), + PINCTRL_PIN_GROUP("pon_alt", pon_alt), + PINCTRL_PIN_GROUP("olt", olt), + PINCTRL_PIN_GROUP("pon_tod_1pps", pon_tod_1pps), + PINCTRL_PIN_GROUP("gsw_tod_1pps", gsw_tod_1pps), + PINCTRL_PIN_GROUP("sipo", sipo), + PINCTRL_PIN_GROUP("sipo_rclk", sipo_rclk), + PINCTRL_PIN_GROUP("mdio", mdio), + PINCTRL_PIN_GROUP("uart2", uart2), + PINCTRL_PIN_GROUP("uart2_cts_rts", uart2_cts_rts), + PINCTRL_PIN_GROUP("hsuart", hsuart), + PINCTRL_PIN_GROUP("hsuart_cts_rts", hsuart_cts_rts), + PINCTRL_PIN_GROUP("npu_uart", npu_uart), + PINCTRL_PIN_GROUP("uart4", uart4), + PINCTRL_PIN_GROUP("uart5", uart5), + PINCTRL_PIN_GROUP("i2c0", i2c0), + PINCTRL_PIN_GROUP("i2c1", i2c1), + PINCTRL_PIN_GROUP("jtag_udi", jtag_udi), + PINCTRL_PIN_GROUP("jtag_dfd", jtag_dfd), + PINCTRL_PIN_GROUP("pcm1", pcm1), + PINCTRL_PIN_GROUP("pcm2", pcm2), + PINCTRL_PIN_GROUP("spi", spi), + PINCTRL_PIN_GROUP("spi_quad", spi_quad), + PINCTRL_PIN_GROUP("spi_cs1", spi_cs1), + PINCTRL_PIN_GROUP("pcm_spi", pcm_spi), + PINCTRL_PIN_GROUP("pcm_spi_rst", pcm_spi_rst), + PINCTRL_PIN_GROUP("pcm_spi_cs1", pcm_spi_cs1), + PINCTRL_PIN_GROUP("emmc", emmc), + PINCTRL_PIN_GROUP("pnand", pnand), + PINCTRL_PIN_GROUP("gpio0", gpio0), + PINCTRL_PIN_GROUP("gpio1", gpio1), + PINCTRL_PIN_GROUP("gpio2", gpio2), + PINCTRL_PIN_GROUP("gpio3", gpio3), + PINCTRL_PIN_GROUP("gpio4", gpio4), + PINCTRL_PIN_GROUP("gpio5", gpio5), + PINCTRL_PIN_GROUP("gpio6", gpio6), + PINCTRL_PIN_GROUP("gpio7", gpio7), + PINCTRL_PIN_GROUP("gpio8", gpio8), + PINCTRL_PIN_GROUP("gpio9", gpio9), + PINCTRL_PIN_GROUP("gpio10", gpio10), + PINCTRL_PIN_GROUP("gpio11", gpio11), + PINCTRL_PIN_GROUP("gpio12", gpio12), + PINCTRL_PIN_GROUP("gpio13", gpio13), + PINCTRL_PIN_GROUP("gpio14", gpio14), + PINCTRL_PIN_GROUP("gpio15", gpio15), + PINCTRL_PIN_GROUP("gpio16", gpio16), + PINCTRL_PIN_GROUP("gpio17", gpio17), + PINCTRL_PIN_GROUP("gpio18", gpio18), + PINCTRL_PIN_GROUP("gpio19", gpio19), + PINCTRL_PIN_GROUP("gpio20", gpio20), + PINCTRL_PIN_GROUP("gpio21", gpio21), + PINCTRL_PIN_GROUP("gpio22", gpio22), + PINCTRL_PIN_GROUP("gpio23", gpio23), + PINCTRL_PIN_GROUP("gpio24", gpio24), + PINCTRL_PIN_GROUP("gpio25", gpio25), + PINCTRL_PIN_GROUP("gpio26", gpio26), + PINCTRL_PIN_GROUP("gpio27", gpio27), + PINCTRL_PIN_GROUP("gpio28", gpio28), + PINCTRL_PIN_GROUP("gpio29", gpio29), + PINCTRL_PIN_GROUP("gpio30", gpio30), + PINCTRL_PIN_GROUP("gpio31", gpio31), + PINCTRL_PIN_GROUP("gpio32", gpio32), + PINCTRL_PIN_GROUP("gpio33", gpio33), + PINCTRL_PIN_GROUP("gpio34", gpio34), + PINCTRL_PIN_GROUP("gpio35", gpio35), + PINCTRL_PIN_GROUP("gpio36", gpio36), + PINCTRL_PIN_GROUP("gpio37", gpio37), + PINCTRL_PIN_GROUP("gpio38", gpio38), + PINCTRL_PIN_GROUP("gpio39", gpio39), + PINCTRL_PIN_GROUP("gpio40", gpio40), + PINCTRL_PIN_GROUP("gpio41", gpio41), + PINCTRL_PIN_GROUP("gpio42", gpio42), + PINCTRL_PIN_GROUP("gpio43", gpio43), + PINCTRL_PIN_GROUP("gpio44", gpio44), + PINCTRL_PIN_GROUP("gpio45", gpio45), + PINCTRL_PIN_GROUP("gpio46", gpio46), + PINCTRL_PIN_GROUP("gpio47", gpio47), + PINCTRL_PIN_GROUP("gpio48", gpio48), + PINCTRL_PIN_GROUP("gpio49", gpio49), + PINCTRL_PIN_GROUP("gpio50", gpio50), + PINCTRL_PIN_GROUP("gpio51", gpio51), + PINCTRL_PIN_GROUP("gpio52", gpio52), + PINCTRL_PIN_GROUP("pcie_reset0", pcie_reset0), + PINCTRL_PIN_GROUP("pcie_reset1", pcie_reset1), +}; + +static const char *const pon_groups[] = { "pon", "pon_alt" }; +static const char *const olt_groups[] = { "olt" }; +static const char *const tod_1pps_groups[] = { + "pon_tod_1pps", "gsw_tod_1pps" +}; +static const char *const sipo_groups[] = { "sipo", "sipo_rclk" }; +static const char *const mdio_groups[] = { "mdio" }; +static const char *const uart_groups[] = { + "uart2", "uart2_cts_rts", "hsuart", "hsuart_cts_rts", + "uart4", "uart5", "npu_uart" +}; +static const char *const jtag_groups[] = { "jtag_udi", "jtag_dfd" }; +static const char *const pcm_groups[] = { "pcm1", "pcm2" }; +static const char *const spi_groups[] = { "spi_quad", "spi_cs1" }; +static const char *const pcm_spi_groups[] = { + "pcm_spi", "pcm_spi_rst", "pcm_spi_cs1" +}; +static const char *const emmc_groups[] = { "emmc" }; +static const char *const pnand_groups[] = { "pnand" }; +static const char *const gpio_groups[] = { + "gpio39", "gpio40", "gpio41", "gpio42", "gpio43", + "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", + "gpio49", "gpio50", "gpio51", "gpio52" +}; +static const char *const pcie_reset_groups[] = { + "pcie_reset0", "pcie_reset1" +}; +static const char *const pwm_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", + "gpio6", "gpio7", "gpio8", "gpio9", "gpio10", "gpio11", + "gpio12", "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", + "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", "gpio23", + "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", + "gpio30", "gpio31", "gpio36", "gpio37", "gpio38", "gpio39", + "gpio40", "gpio41", "gpio42", "gpio43", "gpio44", "gpio45", + "gpio46", "gpio47", "gpio48", "gpio49", "gpio50", "gpio51" +}; +static const char *const phy1_led0_groups[] = { + "gpio1", "gpio2", "gpio3", "gpio4" +}; +static const char *const phy2_led0_groups[] = { + "gpio1", "gpio2", "gpio3", "gpio4" +}; +static const char *const phy3_led0_groups[] = { + "gpio1", "gpio2", "gpio3", "gpio4" +}; +static const char *const phy4_led0_groups[] = { + "gpio1", "gpio2", "gpio3", "gpio4" +}; +static const char *const phy1_led1_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio11" +}; +static const char *const phy2_led1_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio11" +}; +static const char *const phy3_led1_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio11" +}; +static const char *const phy4_led1_groups[] = { + "gpio8", "gpio9", "gpio10", "gpio11" +}; + +static const struct airoha_pinctrl_func_group pon_func_group[] = { + { + .name = "pon", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PON_MODE_MASK | GPIO_PON_ALT_MODE_MASK, + GPIO_PON_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pon_alt", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PON_MODE_MASK | GPIO_PON_ALT_MODE_MASK, + GPIO_PON_ALT_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group olt_func_group[] = { + { + .name = "olt", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_OLT_MODE_MASK, + GPIO_OLT_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group tod_1pps_func_group[] = { + { + .name = "pon_tod_1pps", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_SW_TOD_1PPS_MODE, + PON_TOD_1PPS_MODE_MASK, + PON_TOD_1PPS_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "gsw_tod_1pps", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_SW_TOD_1PPS_MODE, + GSW_TOD_1PPS_MODE_MASK, + GSW_TOD_1PPS_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group sipo_func_group[] = { + { + .name = "sipo", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK, + GPIO_SIPO_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "sipo_rclk", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK, + GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group mdio_func_group[] = { + { + .name = "mdio", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_SGMII_MDIO_MODE_MASK, + GPIO_SGMII_MDIO_MODE_MASK + }, + .regmap[1] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_MDC_IO_MASTER_MODE_MASK, + GPIO_MDC_IO_MASTER_MODE_MASK + }, + .regmap_size = 2, + }, +}; + +static const struct airoha_pinctrl_func_group uart_func_group[] = { + { + .name = "uart2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_UART2_MODE_MASK, + GPIO_UART2_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "uart2_cts_rts", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_UART2_MODE_MASK | GPIO_UART2_CTS_RTS_MODE_MASK, + GPIO_UART2_MODE_MASK | GPIO_UART2_CTS_RTS_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "hsuart", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK, + GPIO_HSUART_MODE_MASK + }, + .regmap_size = 1, + }, + { + .name = "hsuart_cts_rts", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK, + GPIO_HSUART_MODE_MASK | GPIO_HSUART_CTS_RTS_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "uart4", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_UART4_MODE_MASK, + GPIO_UART4_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "uart5", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_UART5_MODE_MASK, + GPIO_UART5_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "npu_uart", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_NPU_UART_EN, + NPU_UART_EN_MASK, + NPU_UART_EN_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group jtag_func_group[] = { + { + .name = "jtag_udi", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_NPU_UART_EN, + JTAG_UDI_EN_MASK, + JTAG_UDI_EN_MASK + }, + .regmap_size = 1, + }, { + .name = "jtag_dfd", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_NPU_UART_EN, + JTAG_DFD_EN_MASK, + JTAG_DFD_EN_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pcm_func_group[] = { + { + .name = "pcm1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM1_MODE_MASK, + GPIO_PCM1_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM2_MODE_MASK, + GPIO_PCM2_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group spi_func_group[] = { + { + .name = "spi_quad", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_QUAD_MODE_MASK, + GPIO_SPI_QUAD_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "spi_cs1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_CS1_MODE_MASK, + GPIO_SPI_CS1_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "spi_cs2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_CS2_MODE_MASK, + GPIO_SPI_CS2_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "spi_cs3", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_CS3_MODE_MASK, + GPIO_SPI_CS3_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "spi_cs4", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_CS4_MODE_MASK, + GPIO_SPI_CS4_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = { + { + .name = "pcm_spi", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_MODE_MASK, + GPIO_PCM_SPI_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_int", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_INT_MODE_MASK, + GPIO_PCM_INT_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_rst", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_RESET_MODE_MASK, + GPIO_PCM_RESET_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS1_MODE_MASK, + GPIO_PCM_SPI_CS1_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS2_MODE_MASK, + GPIO_PCM_SPI_CS2_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs3", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS3_MODE_MASK, + GPIO_PCM_SPI_CS3_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs4", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS4_MODE_MASK, + GPIO_PCM_SPI_CS4_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group emmc_func_group[] = { + { + .name = "emmc", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_EMMC_MODE_MASK, + GPIO_EMMC_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pnand_func_group[] = { + { + .name = "pnand", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PARALLEL_NAND_MODE_MASK, + GPIO_PARALLEL_NAND_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group gpio_func_group[] = { + AIROHA_PINCTRL_GPIO_EXT("gpio39", GPIO39_FLASH_MODE_CFG, + I2C0_SCL_GPIO_MODE_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio40", GPIO40_FLASH_MODE_CFG, + I2C0_SDA_GPIO_MODE_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio41", GPIO41_FLASH_MODE_CFG, + I2C1_SCL_GPIO_MODE_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio42", GPIO42_FLASH_MODE_CFG, + I2C1_SDA_GPIO_MODE_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio43", GPIO43_FLASH_MODE_CFG, + SPI_CLK_GPIO_MODE_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio44", GPIO44_FLASH_MODE_CFG, + SPI_CS_GPIO_MODE_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio45", GPIO45_FLASH_MODE_CFG, + SPI_MOSI_GPIO_MODE_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio46", GPIO46_FLASH_MODE_CFG, + SPI_MISO_GPIO_MODE_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio47", GPIO47_FLASH_MODE_CFG, + UART_TXD_GPIO_MODE_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio48", GPIO48_FLASH_MODE_CFG, + UART_RXD_GPIO_MODE_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio49", GPIO49_FLASH_MODE_CFG, + GPIO_PCIE_RESET0_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio50", GPIO50_FLASH_MODE_CFG, + GPIO_PCIE_RESET1_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio51", GPIO51_FLASH_MODE_CFG, + MDC_0_GPIO_MODE_MASK), + AIROHA_PINCTRL_GPIO("gpio52", MDIO_0_GPIO_MODE_MASK), +}; + +static const struct airoha_pinctrl_func_group pcie_reset_func_group[] = { + { + .name = "pcie_reset0", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PCIE_RESET0_MASK, + 0 + }, + .regmap_size = 1, + }, { + .name = "pcie_reset1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PCIE_RESET1_MASK, + 0 + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pwm_func_group[] = { + AIROHA_PINCTRL_PWM("gpio0", GPIO0_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio1", GPIO1_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio2", GPIO2_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio3", GPIO3_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio4", GPIO4_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio5", GPIO5_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio6", GPIO6_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio7", GPIO7_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio8", GPIO8_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio9", GPIO9_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio10", GPIO10_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio11", GPIO11_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio12", GPIO12_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio13", GPIO13_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio14", GPIO14_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio15", GPIO15_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio16", GPIO16_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio17", GPIO17_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio18", GPIO18_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio19", GPIO19_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio20", GPIO20_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio21", GPIO21_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio22", GPIO22_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio23", GPIO23_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio24", GPIO24_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio25", GPIO25_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio26", GPIO26_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio27", GPIO27_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio28", GPIO28_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio29", GPIO29_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio30", GPIO30_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio31", GPIO31_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio36", GPIO36_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio37", GPIO37_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio38", GPIO38_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio39", GPIO39_FLASH_MODE_CFG, + I2C0_SCL_GPIO_MODE_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio40", GPIO40_FLASH_MODE_CFG, + I2C0_SDA_GPIO_MODE_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio41", GPIO41_FLASH_MODE_CFG, + I2C1_SCL_GPIO_MODE_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio42", GPIO42_FLASH_MODE_CFG, + I2C1_SDA_GPIO_MODE_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio43", GPIO43_FLASH_MODE_CFG, + SPI_CLK_GPIO_MODE_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio44", GPIO44_FLASH_MODE_CFG, + SPI_CS_GPIO_MODE_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio45", GPIO45_FLASH_MODE_CFG, + SPI_MOSI_GPIO_MODE_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio46", GPIO46_FLASH_MODE_CFG, + SPI_MISO_GPIO_MODE_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio47", GPIO47_FLASH_MODE_CFG, + UART_TXD_GPIO_MODE_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio48", GPIO48_FLASH_MODE_CFG, + UART_RXD_GPIO_MODE_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio49", GPIO49_FLASH_MODE_CFG, + GPIO_PCIE_RESET0_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio50", GPIO50_FLASH_MODE_CFG, + GPIO_PCIE_RESET1_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio51", GPIO51_FLASH_MODE_CFG, + MDC_0_GPIO_MODE_MASK), +}; + +static const struct airoha_pinctrl_func_group phy1_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio1", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio2", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio3", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio4", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)), +}; + +static const struct airoha_pinctrl_func_group phy2_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio1", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio2", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio3", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio4", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)), +}; + +static const struct airoha_pinctrl_func_group phy3_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio1", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio2", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio3", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio4", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)), +}; + +static const struct airoha_pinctrl_func_group phy4_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio1", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio2", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio3", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio4", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)), +}; + +static const struct airoha_pinctrl_func_group phy1_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio8", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio9", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio10", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio11", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)), +}; + +static const struct airoha_pinctrl_func_group phy2_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio8", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio9", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio10", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio11", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)), +}; + +static const struct airoha_pinctrl_func_group phy3_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio8", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio9", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio10", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio11", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)), +}; + +static const struct airoha_pinctrl_func_group phy4_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio8", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED1("gpio9", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED1("gpio10", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED1("gpio11", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)), +}; + +static const struct airoha_pinctrl_func pinctrl_funcs[] = { + PINCTRL_FUNC_DESC("pon", pon), + PINCTRL_FUNC_DESC("olt", olt), + PINCTRL_FUNC_DESC("tod_1pps", tod_1pps), + PINCTRL_FUNC_DESC("sipo", sipo), + PINCTRL_FUNC_DESC("mdio", mdio), + PINCTRL_FUNC_DESC("uart", uart), + PINCTRL_FUNC_DESC("jtag", jtag), + PINCTRL_FUNC_DESC("pcm", pcm), + PINCTRL_FUNC_DESC("spi", spi), + PINCTRL_FUNC_DESC("pcm_spi", pcm_spi), + PINCTRL_FUNC_DESC("emmc", emmc), + PINCTRL_FUNC_DESC("pnand", pnand), + PINCTRL_FUNC_DESC("gpio", gpio), + PINCTRL_FUNC_DESC("pcie_reset", pcie_reset), + PINCTRL_FUNC_DESC("pwm", pwm), + PINCTRL_FUNC_DESC("phy1_led0", phy1_led0), + PINCTRL_FUNC_DESC("phy2_led0", phy2_led0), + PINCTRL_FUNC_DESC("phy3_led0", phy3_led0), + PINCTRL_FUNC_DESC("phy4_led0", phy4_led0), + PINCTRL_FUNC_DESC("phy1_led1", phy1_led1), + PINCTRL_FUNC_DESC("phy2_led1", phy2_led1), + PINCTRL_FUNC_DESC("phy3_led1", phy3_led1), + PINCTRL_FUNC_DESC("phy4_led1", phy4_led1), +}; + +static const struct airoha_pinctrl_conf pinctrl_pullup_conf[] = { + PINCTRL_CONF_DESC(2, REG_GPIO_L_PU, BIT(0)), + PINCTRL_CONF_DESC(3, REG_GPIO_L_PU, BIT(1)), + PINCTRL_CONF_DESC(4, REG_GPIO_L_PU, BIT(2)), + PINCTRL_CONF_DESC(5, REG_GPIO_L_PU, BIT(3)), + PINCTRL_CONF_DESC(6, REG_GPIO_L_PU, BIT(4)), + PINCTRL_CONF_DESC(7, REG_GPIO_L_PU, BIT(5)), + PINCTRL_CONF_DESC(8, REG_GPIO_L_PU, BIT(6)), + PINCTRL_CONF_DESC(9, REG_GPIO_L_PU, BIT(7)), + PINCTRL_CONF_DESC(10, REG_GPIO_L_PU, BIT(8)), + PINCTRL_CONF_DESC(11, REG_GPIO_L_PU, BIT(9)), + PINCTRL_CONF_DESC(12, REG_GPIO_L_PU, BIT(10)), + PINCTRL_CONF_DESC(13, REG_GPIO_L_PU, BIT(11)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_PU, BIT(12)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_PU, BIT(13)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_PU, BIT(14)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_PU, BIT(15)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_PU, BIT(16)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_PU, BIT(17)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_PU, BIT(18)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_PU, BIT(19)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_PU, BIT(20)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_PU, BIT(21)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_PU, BIT(22)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_PU, BIT(23)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_PU, BIT(24)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_PU, BIT(25)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_PU, BIT(26)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_PU, BIT(27)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_PU, BIT(28)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_PU, BIT(29)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_PU, BIT(30)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_PU, BIT(31)), + PINCTRL_CONF_DESC(34, REG_GPIO_H_PU, BIT(0)), + PINCTRL_CONF_DESC(35, REG_GPIO_H_PU, BIT(1)), + PINCTRL_CONF_DESC(36, REG_GPIO_H_PU, BIT(2)), + PINCTRL_CONF_DESC(37, REG_GPIO_H_PU, BIT(3)), + PINCTRL_CONF_DESC(38, REG_GPIO_H_PU, BIT(4)), + PINCTRL_CONF_DESC(39, REG_GPIO_H_PU, BIT(5)), + PINCTRL_CONF_DESC(40, REG_GPIO_H_PU, BIT(6)), + PINCTRL_CONF_DESC(41, REG_I2C_SDA_PU, I2C_SCL_PU_MASK), + PINCTRL_CONF_DESC(42, REG_I2C_SDA_PU, I2C_SDA_PU_MASK), + PINCTRL_CONF_DESC(43, REG_I2C_SDA_PU, I2C1_SCL_PU_MASK), + PINCTRL_CONF_DESC(44, REG_I2C_SDA_PU, I2C1_SDA_PU_MASK), + PINCTRL_CONF_DESC(45, REG_I2C_SDA_PU, SPI_CLK_PU_MASK), + PINCTRL_CONF_DESC(46, REG_I2C_SDA_PU, SPI_CS0_PU_MASK), + PINCTRL_CONF_DESC(47, REG_I2C_SDA_PU, SPI_MOSI_PU_MASK), + PINCTRL_CONF_DESC(48, REG_I2C_SDA_PU, SPI_MISO_PU_MASK), + PINCTRL_CONF_DESC(49, REG_I2C_SDA_PU, UART1_TXD_PU_MASK), + PINCTRL_CONF_DESC(50, REG_I2C_SDA_PU, UART1_RXD_PU_MASK), + PINCTRL_CONF_DESC(51, REG_I2C_SDA_PU, PCIE0_RESET_PU_MASK), + PINCTRL_CONF_DESC(52, REG_I2C_SDA_PU, PCIE1_RESET_PU_MASK), + PINCTRL_CONF_DESC(53, REG_I2C_SDA_PU, MDC_0_PU_MASK), + PINCTRL_CONF_DESC(54, REG_I2C_SDA_PU, MDIO_0_PU_MASK), +}; + +static const struct airoha_pinctrl_conf pinctrl_pulldown_conf[] = { + PINCTRL_CONF_DESC(2, REG_GPIO_L_PD, BIT(0)), + PINCTRL_CONF_DESC(3, REG_GPIO_L_PD, BIT(1)), + PINCTRL_CONF_DESC(4, REG_GPIO_L_PD, BIT(2)), + PINCTRL_CONF_DESC(5, REG_GPIO_L_PD, BIT(3)), + PINCTRL_CONF_DESC(6, REG_GPIO_L_PD, BIT(4)), + PINCTRL_CONF_DESC(7, REG_GPIO_L_PD, BIT(5)), + PINCTRL_CONF_DESC(8, REG_GPIO_L_PD, BIT(6)), + PINCTRL_CONF_DESC(9, REG_GPIO_L_PD, BIT(7)), + PINCTRL_CONF_DESC(10, REG_GPIO_L_PD, BIT(8)), + PINCTRL_CONF_DESC(11, REG_GPIO_L_PD, BIT(9)), + PINCTRL_CONF_DESC(12, REG_GPIO_L_PD, BIT(10)), + PINCTRL_CONF_DESC(13, REG_GPIO_L_PD, BIT(11)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_PD, BIT(12)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_PD, BIT(13)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_PD, BIT(14)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_PD, BIT(15)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_PD, BIT(16)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_PD, BIT(17)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_PD, BIT(18)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_PD, BIT(19)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_PD, BIT(20)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_PD, BIT(21)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_PD, BIT(22)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_PD, BIT(23)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_PD, BIT(24)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_PD, BIT(25)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_PD, BIT(26)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_PD, BIT(27)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_PD, BIT(28)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_PD, BIT(29)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_PD, BIT(30)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_PD, BIT(31)), + PINCTRL_CONF_DESC(34, REG_GPIO_H_PD, BIT(0)), + PINCTRL_CONF_DESC(35, REG_GPIO_H_PD, BIT(1)), + PINCTRL_CONF_DESC(36, REG_GPIO_H_PD, BIT(2)), + PINCTRL_CONF_DESC(37, REG_GPIO_H_PD, BIT(3)), + PINCTRL_CONF_DESC(38, REG_GPIO_H_PD, BIT(4)), + PINCTRL_CONF_DESC(39, REG_GPIO_H_PD, BIT(5)), + PINCTRL_CONF_DESC(40, REG_GPIO_H_PD, BIT(6)), + PINCTRL_CONF_DESC(41, REG_I2C_SDA_PD, I2C_SCL_PD_MASK), + PINCTRL_CONF_DESC(42, REG_I2C_SDA_PD, I2C_SDA_PD_MASK), + PINCTRL_CONF_DESC(43, REG_I2C_SDA_PD, I2C1_SCL_PD_MASK), + PINCTRL_CONF_DESC(44, REG_I2C_SDA_PD, I2C1_SDA_PD_MASK), + PINCTRL_CONF_DESC(45, REG_I2C_SDA_PD, SPI_CLK_PD_MASK), + PINCTRL_CONF_DESC(46, REG_I2C_SDA_PD, SPI_CS0_PD_MASK), + PINCTRL_CONF_DESC(47, REG_I2C_SDA_PD, SPI_MOSI_PD_MASK), + PINCTRL_CONF_DESC(48, REG_I2C_SDA_PD, SPI_MISO_PD_MASK), + PINCTRL_CONF_DESC(49, REG_I2C_SDA_PD, UART1_TXD_PD_MASK), + PINCTRL_CONF_DESC(50, REG_I2C_SDA_PD, UART1_RXD_PD_MASK), + PINCTRL_CONF_DESC(51, REG_I2C_SDA_PD, PCIE0_RESET_PD_MASK), + PINCTRL_CONF_DESC(52, REG_I2C_SDA_PD, PCIE1_RESET_PD_MASK), + PINCTRL_CONF_DESC(53, REG_I2C_SDA_PD, MDC_0_PD_MASK), + PINCTRL_CONF_DESC(54, REG_I2C_SDA_PD, MDIO_0_PD_MASK), +}; + +static const struct airoha_pinctrl_conf pinctrl_drive_e2_conf[] = { + PINCTRL_CONF_DESC(2, REG_GPIO_L_E2, BIT(0)), + PINCTRL_CONF_DESC(3, REG_GPIO_L_E2, BIT(1)), + PINCTRL_CONF_DESC(4, REG_GPIO_L_E2, BIT(2)), + PINCTRL_CONF_DESC(5, REG_GPIO_L_E2, BIT(3)), + PINCTRL_CONF_DESC(6, REG_GPIO_L_E2, BIT(4)), + PINCTRL_CONF_DESC(7, REG_GPIO_L_E2, BIT(5)), + PINCTRL_CONF_DESC(8, REG_GPIO_L_E2, BIT(6)), + PINCTRL_CONF_DESC(9, REG_GPIO_L_E2, BIT(7)), + PINCTRL_CONF_DESC(10, REG_GPIO_L_E2, BIT(8)), + PINCTRL_CONF_DESC(11, REG_GPIO_L_E2, BIT(9)), + PINCTRL_CONF_DESC(12, REG_GPIO_L_E2, BIT(10)), + PINCTRL_CONF_DESC(13, REG_GPIO_L_E2, BIT(11)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_E2, BIT(12)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_E2, BIT(13)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_E2, BIT(14)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_E2, BIT(15)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_E2, BIT(16)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_E2, BIT(17)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_E2, BIT(18)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_E2, BIT(19)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_E2, BIT(20)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_E2, BIT(21)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_E2, BIT(22)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_E2, BIT(23)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_E2, BIT(24)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_E2, BIT(25)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_E2, BIT(26)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_E2, BIT(27)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_E2, BIT(28)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_E2, BIT(29)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_E2, BIT(30)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_E2, BIT(31)), + PINCTRL_CONF_DESC(34, REG_GPIO_H_E2, BIT(0)), + PINCTRL_CONF_DESC(35, REG_GPIO_H_E2, BIT(1)), + PINCTRL_CONF_DESC(36, REG_GPIO_H_E2, BIT(2)), + PINCTRL_CONF_DESC(37, REG_GPIO_H_E2, BIT(3)), + PINCTRL_CONF_DESC(38, REG_GPIO_H_E2, BIT(4)), + PINCTRL_CONF_DESC(39, REG_GPIO_H_E2, BIT(5)), + PINCTRL_CONF_DESC(40, REG_GPIO_H_E2, BIT(6)), + PINCTRL_CONF_DESC(41, REG_I2C_SDA_E2, I2C_SCL_E2_MASK), + PINCTRL_CONF_DESC(42, REG_I2C_SDA_E2, I2C_SDA_E2_MASK), + PINCTRL_CONF_DESC(43, REG_I2C_SDA_E2, I2C1_SCL_E2_MASK), + PINCTRL_CONF_DESC(44, REG_I2C_SDA_E2, I2C1_SDA_E2_MASK), + PINCTRL_CONF_DESC(45, REG_I2C_SDA_E2, SPI_CLK_E2_MASK), + PINCTRL_CONF_DESC(46, REG_I2C_SDA_E2, SPI_CS0_E2_MASK), + PINCTRL_CONF_DESC(47, REG_I2C_SDA_E2, SPI_MOSI_E2_MASK), + PINCTRL_CONF_DESC(48, REG_I2C_SDA_E2, SPI_MISO_E2_MASK), + PINCTRL_CONF_DESC(49, REG_I2C_SDA_E2, UART1_TXD_E2_MASK), + PINCTRL_CONF_DESC(50, REG_I2C_SDA_E2, UART1_RXD_E2_MASK), + PINCTRL_CONF_DESC(51, REG_I2C_SDA_E2, PCIE0_RESET_E2_MASK), + PINCTRL_CONF_DESC(52, REG_I2C_SDA_E2, PCIE1_RESET_E2_MASK), + PINCTRL_CONF_DESC(53, REG_I2C_SDA_E2, MDC_0_E2_MASK), + PINCTRL_CONF_DESC(54, REG_I2C_SDA_E2, MDIO_0_E2_MASK), +}; + +static const struct airoha_pinctrl_conf pinctrl_drive_e4_conf[] = { + PINCTRL_CONF_DESC(2, REG_GPIO_L_E4, BIT(0)), + PINCTRL_CONF_DESC(3, REG_GPIO_L_E4, BIT(1)), + PINCTRL_CONF_DESC(4, REG_GPIO_L_E4, BIT(2)), + PINCTRL_CONF_DESC(5, REG_GPIO_L_E4, BIT(3)), + PINCTRL_CONF_DESC(6, REG_GPIO_L_E4, BIT(4)), + PINCTRL_CONF_DESC(7, REG_GPIO_L_E4, BIT(5)), + PINCTRL_CONF_DESC(8, REG_GPIO_L_E4, BIT(6)), + PINCTRL_CONF_DESC(9, REG_GPIO_L_E4, BIT(7)), + PINCTRL_CONF_DESC(10, REG_GPIO_L_E4, BIT(8)), + PINCTRL_CONF_DESC(11, REG_GPIO_L_E4, BIT(9)), + PINCTRL_CONF_DESC(12, REG_GPIO_L_E4, BIT(10)), + PINCTRL_CONF_DESC(13, REG_GPIO_L_E4, BIT(11)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_E4, BIT(12)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_E4, BIT(13)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_E4, BIT(14)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_E4, BIT(15)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_E4, BIT(16)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_E4, BIT(17)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_E4, BIT(18)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_E4, BIT(19)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_E4, BIT(20)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_E4, BIT(21)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_E4, BIT(22)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_E4, BIT(23)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_E4, BIT(24)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_E4, BIT(25)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_E4, BIT(26)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_E4, BIT(27)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_E4, BIT(28)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_E4, BIT(29)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_E4, BIT(30)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_E4, BIT(31)), + PINCTRL_CONF_DESC(34, REG_GPIO_H_E4, BIT(0)), + PINCTRL_CONF_DESC(35, REG_GPIO_H_E4, BIT(1)), + PINCTRL_CONF_DESC(36, REG_GPIO_H_E4, BIT(2)), + PINCTRL_CONF_DESC(37, REG_GPIO_H_E4, BIT(3)), + PINCTRL_CONF_DESC(38, REG_GPIO_H_E4, BIT(4)), + PINCTRL_CONF_DESC(39, REG_GPIO_H_E4, BIT(5)), + PINCTRL_CONF_DESC(40, REG_GPIO_H_E4, BIT(6)), + PINCTRL_CONF_DESC(41, REG_I2C_SDA_E4, I2C_SCL_E4_MASK), + PINCTRL_CONF_DESC(42, REG_I2C_SDA_E4, I2C_SDA_E4_MASK), + PINCTRL_CONF_DESC(43, REG_I2C_SDA_E4, I2C1_SCL_E4_MASK), + PINCTRL_CONF_DESC(44, REG_I2C_SDA_E4, I2C1_SDA_E4_MASK), + PINCTRL_CONF_DESC(45, REG_I2C_SDA_E4, SPI_CLK_E4_MASK), + PINCTRL_CONF_DESC(46, REG_I2C_SDA_E4, SPI_CS0_E4_MASK), + PINCTRL_CONF_DESC(47, REG_I2C_SDA_E4, SPI_MOSI_E4_MASK), + PINCTRL_CONF_DESC(48, REG_I2C_SDA_E4, SPI_MISO_E4_MASK), + PINCTRL_CONF_DESC(49, REG_I2C_SDA_E4, UART1_TXD_E4_MASK), + PINCTRL_CONF_DESC(50, REG_I2C_SDA_E4, UART1_RXD_E4_MASK), + PINCTRL_CONF_DESC(51, REG_I2C_SDA_E4, PCIE0_RESET_E4_MASK), + PINCTRL_CONF_DESC(52, REG_I2C_SDA_E4, PCIE1_RESET_E4_MASK), + PINCTRL_CONF_DESC(53, REG_I2C_SDA_E4, MDC_0_E4_MASK), + PINCTRL_CONF_DESC(54, REG_I2C_SDA_E4, MDIO_0_E4_MASK), +}; + +static const struct airoha_pinctrl_conf pinctrl_pcie_rst_od_conf[] = { + PINCTRL_CONF_DESC(51, REG_PCIE_RESET_OD, PCIE0_RESET_OD_MASK), + PINCTRL_CONF_DESC(52, REG_PCIE_RESET_OD, PCIE1_RESET_OD_MASK), +}; + +static const struct airoha_pinctrl_match_data pinctrl_match_data = { + .gpio_offs = 2, + .gpio_pin_cnt = 53, + .chip_scu_compatible = "airoha,en7581-chip-scu", + .pins = pinctrl_pins, + .num_pins = ARRAY_SIZE(pinctrl_pins), + .grps = pinctrl_groups, + .num_grps = ARRAY_SIZE(pinctrl_groups), + .funcs = pinctrl_funcs, + .num_funcs = ARRAY_SIZE(pinctrl_funcs), + .confs_info = { + [AIROHA_PINCTRL_CONFS_PULLUP] = { + .confs = pinctrl_pullup_conf, + .num_confs = ARRAY_SIZE(pinctrl_pullup_conf), + }, + [AIROHA_PINCTRL_CONFS_PULLDOWN] = { + .confs = pinctrl_pulldown_conf, + .num_confs = ARRAY_SIZE(pinctrl_pulldown_conf), + }, + [AIROHA_PINCTRL_CONFS_DRIVE_E2] = { + .confs = pinctrl_drive_e2_conf, + .num_confs = ARRAY_SIZE(pinctrl_drive_e2_conf), + }, + [AIROHA_PINCTRL_CONFS_DRIVE_E4] = { + .confs = pinctrl_drive_e4_conf, + .num_confs = ARRAY_SIZE(pinctrl_drive_e4_conf), + }, + [AIROHA_PINCTRL_CONFS_PCIE_RST_OD] = { + .confs = pinctrl_pcie_rst_od_conf, + .num_confs = ARRAY_SIZE(pinctrl_pcie_rst_od_conf), + }, + }, +}; + +static const struct udevice_id pinctrl_of_match[] = { + { .compatible = "airoha,an7583-pinctrl", + .data = (uintptr_t)&pinctrl_match_data }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(airoha_an7583_pinctrl) = { + .name = "airoha-an7583-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(pinctrl_of_match), + .probe = airoha_pinctrl_probe, + .bind = airoha_pinctrl_bind, + .priv_auto = sizeof(struct airoha_pinctrl), + .ops = &airoha_pinctrl_ops, +}; diff --git a/drivers/pinctrl/airoha/pinctrl-en7523.c b/drivers/pinctrl/airoha/pinctrl-en7523.c new file mode 100644 index 00000000000..958fcc8418f --- /dev/null +++ b/drivers/pinctrl/airoha/pinctrl-en7523.c @@ -0,0 +1,1118 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Author: Lorenzo Bianconi <[email protected]> + * Author: Benjamin Larsson <[email protected]> + * Author: Markus Gothe <[email protected]> + * Author: Matheus Sampaio Queiroga <[email protected]> + * Author: Mikhail Kshevetskiy <[email protected]> + */ +#include "airoha-common.h" + +/* MUX */ +#define REG_GPIO_2ND_I2C_MODE 0x0210 +#define GPIO_I2S_MODE_MASK BIT(12) +#define GPIO_I2C_SLAVE_MODE_MODE BIT(11) +#define GPIO_LAN3_LED1_MODE_MASK BIT(10) +#define GPIO_LAN3_LED0_MODE_MASK BIT(9) +#define GPIO_LAN2_LED1_MODE_MASK BIT(8) +#define GPIO_LAN2_LED0_MODE_MASK BIT(7) +#define GPIO_LAN1_LED1_MODE_MASK BIT(6) +#define GPIO_LAN1_LED0_MODE_MASK BIT(5) +#define GPIO_LAN0_LED1_MODE_MASK BIT(4) +#define GPIO_LAN0_LED0_MODE_MASK BIT(3) +#define PON_TOD_1PPS_MODE_MASK BIT(2) +#define GSW_TOD_1PPS_MODE_MASK BIT(1) +#define GPIO_2ND_I2C_MODE_MASK BIT(0) + +#define REG_GPIO_SPI_CS1_MODE 0x0214 +#define GPIO_PCM_SPI_CS4_MODE_MASK BIT(21) +#define GPIO_PCM_SPI_CS3_MODE_MASK BIT(20) +#define GPIO_PCM_SPI_CS2_MODE_P156_MASK BIT(19) +#define GPIO_PCM_SPI_CS2_MODE_P128_MASK BIT(18) +#define GPIO_PCM_SPI_CS1_MODE_MASK BIT(17) +#define GPIO_PCM_SPI_MODE_MASK BIT(16) +#define GPIO_PCM2_MODE_MASK BIT(13) +#define GPIO_PCM1_MODE_MASK BIT(12) +#define GPIO_PCM_INT_MODE_MASK BIT(9) +#define GPIO_PCM_RESET_MODE_MASK BIT(8) +#define GPIO_SPI_QUAD_MODE_MASK BIT(4) +#define GPIO_SPI_CS1_MODE_MASK BIT(0) + +#define REG_GPIO_PON_MODE 0x0218 +#define GPIO_SGMII_MDIO_MODE_MASK BIT(13) +#define SIPO_RCLK_MODE_MASK BIT(11) +#define GPIO_PCIE_RESET1_MASK BIT(10) +#define GPIO_PCIE_RESET0_MASK BIT(9) +#define GPIO_UART2_MODE_MASK BIT(3) +#define GPIO_SIPO_MODE_MASK BIT(2) +#define GPIO_PON_MODE_MASK BIT(0) + +#define REG_NPU_UART_EN 0x0220 +#define JTAG_UDI_EN_MASK BIT(4) +#define JTAG_DFD_EN_MASK BIT(3) +#define NPU_UART_EN_MASK BIT(2) + +#define REG_FORCE_GPIO_EN 0x0224 +#define FORCE_GPIO_EN(n) BIT(n) + +/* LED MAP */ +#define REG_LAN_LED0_MAPPING 0x0278 +#define REG_LAN_LED1_MAPPING 0x027c + +#define LAN3_LED_MAPPING_MASK GENMASK(14, 12) +#define LAN3_PHY_LED_MAP(_n) FIELD_PREP_CONST(LAN3_LED_MAPPING_MASK, (_n)) + +#define LAN2_LED_MAPPING_MASK GENMASK(10, 8) +#define LAN2_PHY_LED_MAP(_n) FIELD_PREP_CONST(LAN2_LED_MAPPING_MASK, (_n)) + +#define LAN1_LED_MAPPING_MASK GENMASK(6, 4) +#define LAN1_PHY_LED_MAP(_n) FIELD_PREP_CONST(LAN1_LED_MAPPING_MASK, (_n)) + +#define LAN0_LED_MAPPING_MASK GENMASK(2, 0) +#define LAN0_PHY_LED_MAP(_n) FIELD_PREP_CONST(LAN0_LED_MAPPING_MASK, (_n)) + +/* CONF */ +#define REG_I2C_SDA_E2 0x001c +#define SPI_MISO_E2_MASK BIT(13) +#define SPI_MOSI_E2_MASK BIT(12) +#define SPI_CLK_E2_MASK BIT(11) +#define SPI_CS0_E2_MASK BIT(10) +#define PCIE1_RESET_E2_MASK BIT(9) +#define PCIE0_RESET_E2_MASK BIT(8) +#define UART1_RXD_E2_MASK BIT(3) +#define UART1_TXD_E2_MASK BIT(2) +#define I2C_SCL_E2_MASK BIT(1) +#define I2C_SDA_E2_MASK BIT(0) + +#define REG_I2C_SDA_E4 0x0020 +#define SPI_MISO_E4_MASK BIT(13) +#define SPI_MOSI_E4_MASK BIT(12) +#define SPI_CLK_E4_MASK BIT(11) +#define SPI_CS0_E4_MASK BIT(10) +#define PCIE1_RESET_E4_MASK BIT(9) +#define PCIE0_RESET_E4_MASK BIT(8) +#define UART1_RXD_E4_MASK BIT(3) +#define UART1_TXD_E4_MASK BIT(2) +#define I2C_SCL_E4_MASK BIT(1) +#define I2C_SDA_E4_MASK BIT(0) + +#define REG_GPIO_L_E2 0x0024 +#define REG_GPIO_L_E4 0x0028 + +#define REG_I2C_SDA_PU 0x0044 +#define SPI_MISO_PU_MASK BIT(13) +#define SPI_MOSI_PU_MASK BIT(12) +#define SPI_CLK_PU_MASK BIT(11) +#define SPI_CS0_PU_MASK BIT(10) +#define PCIE1_RESET_PU_MASK BIT(9) +#define PCIE0_RESET_PU_MASK BIT(8) +#define UART1_RXD_PU_MASK BIT(3) +#define UART1_TXD_PU_MASK BIT(2) +#define I2C_SCL_PU_MASK BIT(1) +#define I2C_SDA_PU_MASK BIT(0) + +#define REG_I2C_SDA_PD 0x0048 +#define SPI_MISO_PD_MASK BIT(13) +#define SPI_MOSI_PD_MASK BIT(12) +#define SPI_CLK_PD_MASK BIT(11) +#define SPI_CS0_PD_MASK BIT(10) +#define PCIE1_RESET_PD_MASK BIT(9) +#define PCIE0_RESET_PD_MASK BIT(8) +#define UART1_RXD_PD_MASK BIT(3) +#define UART1_TXD_PD_MASK BIT(2) +#define I2C_SCL_PD_MASK BIT(1) +#define I2C_SDA_PD_MASK BIT(0) + +#define REG_GPIO_L_PU 0x004c +#define REG_GPIO_L_PD 0x0050 + +/* PWM MODE CONF */ +#define REG_GPIO_FLASH_MODE_CFG 0x0034 +#define GPIO15_FLASH_MODE_CFG BIT(15) +#define GPIO14_FLASH_MODE_CFG BIT(14) +#define GPIO13_FLASH_MODE_CFG BIT(13) +#define GPIO12_FLASH_MODE_CFG BIT(12) +#define GPIO11_FLASH_MODE_CFG BIT(11) +#define GPIO10_FLASH_MODE_CFG BIT(10) +#define GPIO9_FLASH_MODE_CFG BIT(9) +#define GPIO8_FLASH_MODE_CFG BIT(8) +#define GPIO7_FLASH_MODE_CFG BIT(7) +#define GPIO6_FLASH_MODE_CFG BIT(6) +#define GPIO5_FLASH_MODE_CFG BIT(5) +#define GPIO4_FLASH_MODE_CFG BIT(4) +#define GPIO3_FLASH_MODE_CFG BIT(3) +#define GPIO2_FLASH_MODE_CFG BIT(2) +#define GPIO1_FLASH_MODE_CFG BIT(1) +#define GPIO0_FLASH_MODE_CFG BIT(0) + +/* PWM MODE CONF EXT */ +#define REG_GPIO_FLASH_MODE_CFG_EXT 0x0068 +#define GPIO51_FLASH_MODE_CFG BIT(31) +#define GPIO50_FLASH_MODE_CFG BIT(30) +#define GPIO49_FLASH_MODE_CFG BIT(29) +#define GPIO48_FLASH_MODE_CFG BIT(28) +#define GPIO47_FLASH_MODE_CFG BIT(27) +#define GPIO46_FLASH_MODE_CFG BIT(26) +#define GPIO45_FLASH_MODE_CFG BIT(25) +#define GPIO44_FLASH_MODE_CFG BIT(24) +#define GPIO43_FLASH_MODE_CFG BIT(23) +#define GPIO42_FLASH_MODE_CFG BIT(22) +#define GPIO41_FLASH_MODE_CFG BIT(21) +#define GPIO40_FLASH_MODE_CFG BIT(20) +#define GPIO39_FLASH_MODE_CFG BIT(19) +#define GPIO38_FLASH_MODE_CFG BIT(18) +#define GPIO37_FLASH_MODE_CFG BIT(17) +#define GPIO36_FLASH_MODE_CFG BIT(16) +#define GPIO31_FLASH_MODE_CFG BIT(15) +#define GPIO30_FLASH_MODE_CFG BIT(14) +#define GPIO29_FLASH_MODE_CFG BIT(13) +#define GPIO28_FLASH_MODE_CFG BIT(12) +#define GPIO27_FLASH_MODE_CFG BIT(11) +#define GPIO26_FLASH_MODE_CFG BIT(10) +#define GPIO25_FLASH_MODE_CFG BIT(9) +#define GPIO24_FLASH_MODE_CFG BIT(8) +#define GPIO23_FLASH_MODE_CFG BIT(7) +#define GPIO22_FLASH_MODE_CFG BIT(6) +#define GPIO21_FLASH_MODE_CFG BIT(5) +#define GPIO20_FLASH_MODE_CFG BIT(4) +#define GPIO19_FLASH_MODE_CFG BIT(3) +#define GPIO18_FLASH_MODE_CFG BIT(2) +#define GPIO17_FLASH_MODE_CFG BIT(1) +#define GPIO16_FLASH_MODE_CFG BIT(0) + +#define AIROHA_PINCTRL_GPIO(gpio, mux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_PON_MODE, \ + (mux_val), \ + (mux_val) \ + }, \ + .regmap_size = 1, \ + } + +#define AIROHA_PINCTRL_GPIO_EXT(gpio, mux_val, smux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_PWM_EXT_MUX, \ + REG_GPIO_FLASH_MODE_CFG_EXT, \ + (mux_val), \ + 0 \ + }, \ + .regmap[1] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_PON_MODE, \ + (smux_val), \ + (smux_val) \ + }, \ + .regmap_size = 2, \ + } + +/* PWM */ +#define AIROHA_PINCTRL_PWM(gpio, mux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_PWM_MUX, \ + REG_GPIO_FLASH_MODE_CFG, \ + (mux_val), \ + (mux_val) \ + }, \ + .regmap_size = 1, \ + } + +#define AIROHA_PINCTRL_PWM_EXT(gpio, mux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_PWM_EXT_MUX, \ + REG_GPIO_FLASH_MODE_CFG_EXT, \ + (mux_val), \ + (mux_val) \ + }, \ + .regmap_size = 1, \ + } + +#define AIROHA_PINCTRL_PWM_EXT_SEC(gpio, mux_val, smux_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_PWM_EXT_MUX, \ + REG_GPIO_FLASH_MODE_CFG_EXT, \ + (mux_val), \ + (mux_val) \ + }, \ + .regmap[1] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_PON_MODE, \ + (smux_val), \ + (smux_val) \ + }, \ + .regmap_size = 2, \ + } + +#define AIROHA_PINCTRL_PHY_LED0(gpio, mux_val, map_mask, map_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_2ND_I2C_MODE, \ + (mux_val), \ + (mux_val), \ + }, \ + .regmap[1] = { \ + AIROHA_FUNC_MUX, \ + REG_LAN_LED0_MAPPING, \ + (map_mask), \ + (map_val), \ + }, \ + .regmap_size = 2, \ + } + +#define AIROHA_PINCTRL_PHY_LED1(gpio, mux_val, map_mask, map_val) \ + { \ + .name = (gpio), \ + .regmap[0] = { \ + AIROHA_FUNC_MUX, \ + REG_GPIO_2ND_I2C_MODE, \ + (mux_val), \ + (mux_val), \ + }, \ + .regmap[1] = { \ + AIROHA_FUNC_MUX, \ + REG_LAN_LED1_MAPPING, \ + (map_mask), \ + (map_val), \ + }, \ + .regmap_size = 2, \ + } + +static struct pinctrl_pin_desc pinctrl_pins[] = { + PINCTRL_PIN(2, "i2c_sda"), + PINCTRL_PIN(3, "i2c_scl"), + PINCTRL_PIN(4, "spi_cs0"), + PINCTRL_PIN(5, "spi_clk"), + PINCTRL_PIN(6, "spi_mosi"), + PINCTRL_PIN(7, "spi_miso"), + PINCTRL_PIN(8, "uart1_txd"), + PINCTRL_PIN(9, "uart1_rxd"), + PINCTRL_PIN(12, "gpio0"), + PINCTRL_PIN(13, "gpio1"), + PINCTRL_PIN(14, "gpio2"), + PINCTRL_PIN(15, "gpio3"), + PINCTRL_PIN(16, "gpio4"), + PINCTRL_PIN(17, "gpio5"), + PINCTRL_PIN(18, "gpio6"), + PINCTRL_PIN(19, "gpio7"), + PINCTRL_PIN(20, "gpio8"), + PINCTRL_PIN(21, "gpio9"), + PINCTRL_PIN(22, "gpio10"), + PINCTRL_PIN(23, "gpio11"), + PINCTRL_PIN(24, "gpio12"), + PINCTRL_PIN(25, "gpio13"), + PINCTRL_PIN(26, "gpio14"), + PINCTRL_PIN(27, "gpio15"), + PINCTRL_PIN(28, "gpio16"), + PINCTRL_PIN(29, "gpio17"), + PINCTRL_PIN(30, "gpio18"), + PINCTRL_PIN(31, "gpio19"), + PINCTRL_PIN(32, "gpio20"), + PINCTRL_PIN(33, "gpio21"), + PINCTRL_PIN(34, "gpio22"), + PINCTRL_PIN(35, "gpio23"), + PINCTRL_PIN(36, "gpio24"), + PINCTRL_PIN(37, "gpio25"), + PINCTRL_PIN(38, "gpio26"), + PINCTRL_PIN(39, "gpio27"), + PINCTRL_PIN(40, "pcie_reset0"), + PINCTRL_PIN(41, "pcie_reset1"), +}; + +static const int pon_pins[] = { 28, 29, 30, 31, 32, 33 }; +static const int pon_tod_1pps_pins[] = { 21 }; +static const int gsw_tod_1pps_pins[] = { 21 }; +static const int sipo_pins[] = { 13, 38 }; +static const int sipo_rclk_pins[] = { 13, 30, 38 }; +static const int mdio_pins[] = { 20, 21 }; +static const int uart2_pins[] = { 20, 21 }; +static const int npu_uart_pins[] = { 13, 38 }; +static const int i2c0_pins[] = { 2, 3 }; +static const int i2c1_pins[] = { 14, 15 }; +static const int jtag_udi_pins[] = { 34, 35, 36, 37, 38 }; +static const int jtag_dfd_pins[] = { 34, 35, 36, 37, 38 }; +static const int i2s_pins[] = { 16, 17, 18, 19 }; +static const int pcm1_pins[] = { 24, 25, 26, 27 }; +static const int pcm2_pins[] = { 16, 17, 18, 19 }; +static const int spi_pins[] = { 4, 5, 6, 7 }; +static const int spi_quad_pins[] = { 14, 15 }; +static const int spi_cs1_pins[] = { 21 }; +static const int pcm_spi_pins[] = { 16, 17, 18, 19, 24, 25, 26, 27 }; +static const int pcm_spi_int_pins[] = { 15 }; +static const int pcm_spi_rst_pins[] = { 14 }; +static const int pcm_spi_cs1_pins[] = { 22 }; +static const int pcm_spi_cs2_p128_pins[] = { 39 }; +static const int pcm_spi_cs2_p156_pins[] = { 39 }; +static const int pcm_spi_cs3_pins[] = { 20 }; +static const int pcm_spi_cs4_pins[] = { 23 }; +static const int gpio0_pins[] = { 12 }; +static const int gpio1_pins[] = { 13 }; +static const int gpio2_pins[] = { 14 }; +static const int gpio3_pins[] = { 15 }; +static const int gpio4_pins[] = { 16 }; +static const int gpio5_pins[] = { 17 }; +static const int gpio6_pins[] = { 18 }; +static const int gpio7_pins[] = { 19 }; +static const int gpio8_pins[] = { 20 }; +static const int gpio9_pins[] = { 21 }; +static const int gpio10_pins[] = { 22 }; +static const int gpio11_pins[] = { 23 }; +static const int gpio12_pins[] = { 24 }; +static const int gpio13_pins[] = { 25 }; +static const int gpio14_pins[] = { 26 }; +static const int gpio15_pins[] = { 27 }; +static const int gpio16_pins[] = { 28 }; +static const int gpio17_pins[] = { 29 }; +static const int gpio18_pins[] = { 30 }; +static const int gpio19_pins[] = { 31 }; +static const int gpio20_pins[] = { 32 }; +static const int gpio21_pins[] = { 33 }; +static const int gpio22_pins[] = { 34 }; +static const int gpio23_pins[] = { 35 }; +static const int gpio24_pins[] = { 36 }; +static const int gpio25_pins[] = { 37 }; +static const int gpio26_pins[] = { 38 }; +static const int gpio27_pins[] = { 39 }; +static const int gpio28_pins[] = { 40 }; +static const int gpio29_pins[] = { 41 }; +static const int pcie_reset0_pins[] = { 40 }; +static const int pcie_reset1_pins[] = { 41 }; + +static const struct pingroup pinctrl_groups[] = { + PINCTRL_PIN_GROUP("pon", pon), + PINCTRL_PIN_GROUP("pon_tod_1pps", pon_tod_1pps), + PINCTRL_PIN_GROUP("gsw_tod_1pps", gsw_tod_1pps), + PINCTRL_PIN_GROUP("sipo", sipo), + PINCTRL_PIN_GROUP("sipo_rclk", sipo_rclk), + PINCTRL_PIN_GROUP("mdio", mdio), + PINCTRL_PIN_GROUP("uart2", uart2), + PINCTRL_PIN_GROUP("npu_uart", npu_uart), + PINCTRL_PIN_GROUP("i2c0", i2c0), + PINCTRL_PIN_GROUP("i2c1", i2c1), + PINCTRL_PIN_GROUP("jtag_udi", jtag_udi), + PINCTRL_PIN_GROUP("jtag_dfd", jtag_dfd), + PINCTRL_PIN_GROUP("i2s", i2s), + PINCTRL_PIN_GROUP("pcm1", pcm1), + PINCTRL_PIN_GROUP("pcm2", pcm2), + PINCTRL_PIN_GROUP("spi", spi), + PINCTRL_PIN_GROUP("spi_quad", spi_quad), + PINCTRL_PIN_GROUP("spi_cs1", spi_cs1), + PINCTRL_PIN_GROUP("pcm_spi", pcm_spi), + PINCTRL_PIN_GROUP("pcm_spi_int", pcm_spi_int), + PINCTRL_PIN_GROUP("pcm_spi_rst", pcm_spi_rst), + PINCTRL_PIN_GROUP("pcm_spi_cs1", pcm_spi_cs1), + PINCTRL_PIN_GROUP("pcm_spi_cs2_p128", pcm_spi_cs2_p128), + PINCTRL_PIN_GROUP("pcm_spi_cs2_p156", pcm_spi_cs2_p156), + PINCTRL_PIN_GROUP("pcm_spi_cs3", pcm_spi_cs3), + PINCTRL_PIN_GROUP("pcm_spi_cs4", pcm_spi_cs4), + PINCTRL_PIN_GROUP("gpio0", gpio0), + PINCTRL_PIN_GROUP("gpio1", gpio1), + PINCTRL_PIN_GROUP("gpio2", gpio2), + PINCTRL_PIN_GROUP("gpio3", gpio3), + PINCTRL_PIN_GROUP("gpio4", gpio4), + PINCTRL_PIN_GROUP("gpio5", gpio5), + PINCTRL_PIN_GROUP("gpio6", gpio6), + PINCTRL_PIN_GROUP("gpio7", gpio7), + PINCTRL_PIN_GROUP("gpio8", gpio8), + PINCTRL_PIN_GROUP("gpio9", gpio9), + PINCTRL_PIN_GROUP("gpio10", gpio10), + PINCTRL_PIN_GROUP("gpio11", gpio11), + PINCTRL_PIN_GROUP("gpio12", gpio12), + PINCTRL_PIN_GROUP("gpio13", gpio13), + PINCTRL_PIN_GROUP("gpio14", gpio14), + PINCTRL_PIN_GROUP("gpio15", gpio15), + PINCTRL_PIN_GROUP("gpio16", gpio16), + PINCTRL_PIN_GROUP("gpio17", gpio17), + PINCTRL_PIN_GROUP("gpio18", gpio18), + PINCTRL_PIN_GROUP("gpio19", gpio19), + PINCTRL_PIN_GROUP("gpio20", gpio20), + PINCTRL_PIN_GROUP("gpio21", gpio21), + PINCTRL_PIN_GROUP("gpio22", gpio22), + PINCTRL_PIN_GROUP("gpio23", gpio23), + PINCTRL_PIN_GROUP("gpio24", gpio24), + PINCTRL_PIN_GROUP("gpio25", gpio25), + PINCTRL_PIN_GROUP("gpio26", gpio26), + PINCTRL_PIN_GROUP("gpio27", gpio27), + PINCTRL_PIN_GROUP("gpio28", gpio28), + PINCTRL_PIN_GROUP("gpio29", gpio29), + PINCTRL_PIN_GROUP("pcie_reset0", pcie_reset0), + PINCTRL_PIN_GROUP("pcie_reset1", pcie_reset1), +}; + +static const char *const pon_groups[] = { "pon" }; +static const char *const tod_1pps_groups[] = { + "pon_tod_1pps", "gsw_tod_1pps" +}; +static const char *const sipo_groups[] = { "sipo", "sipo_rclk" }; +static const char *const mdio_groups[] = { "mdio" }; +static const char *const uart_groups[] = { "uart2", "npu_uart" }; +static const char *const i2c_groups[] = { "i2c1" }; +static const char *const jtag_groups[] = { "jtag_udi", "jtag_dfd" }; +static const char *const pcm_groups[] = { "pcm1", "pcm2" }; +static const char *const spi_groups[] = { "spi_quad", "spi_cs1" }; +static const char *const pcm_spi_groups[] = { + "pcm_spi", "pcm_spi_int", "pcm_spi_rst", "pcm_spi_cs1", + "pcm_spi_cs2_p156", "pcm_spi_cs2_p128", "pcm_spi_cs3", "pcm_spi_cs4" +}; +static const char *const i2s_groups[] = { "i2s" }; +static const char *const gpio_groups[] = { "gpio28", "gpio29" }; +static const char *const pcie_reset_groups[] = { + "pcie_reset0", "pcie_reset1" +}; +static const char *const pwm_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", + "gpio6", "gpio7", "gpio8", "gpio9", "gpio10", "gpio11", + "gpio12", "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", + "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", "gpio23", + "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29" +}; +static const char *const phy1_led0_groups[] = { + "gpio22", "gpio23", "gpio24", "gpio25" +}; +static const char *const phy2_led0_groups[] = { + "gpio22", "gpio23", "gpio24", "gpio25" +}; +static const char *const phy3_led0_groups[] = { + "gpio22", "gpio23", "gpio24", "gpio25" +}; +static const char *const phy4_led0_groups[] = { + "gpio22", "gpio23", "gpio24", "gpio25" +}; +static const char *const phy1_led1_groups[] = { + "gpio7", "gpio6", "gpio5", "gpio4" +}; +static const char *const phy2_led1_groups[] = { + "gpio7", "gpio6", "gpio5", "gpio4" +}; +static const char *const phy3_led1_groups[] = { + "gpio7", "gpio6", "gpio5", "gpio4" +}; +static const char *const phy4_led1_groups[] = { + "gpio7", "gpio6", "gpio5", "gpio4" +}; + +static const struct airoha_pinctrl_func_group pon_func_group[] = { + { + .name = "pon", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PON_MODE_MASK, + GPIO_PON_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group tod_1pps_func_group[] = { + { + .name = "pon_tod_1pps", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + PON_TOD_1PPS_MODE_MASK, + PON_TOD_1PPS_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "gsw_tod_1pps", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GSW_TOD_1PPS_MODE_MASK, + GSW_TOD_1PPS_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group sipo_func_group[] = { + { + .name = "sipo", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK, + GPIO_SIPO_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "sipo_rclk", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK, + GPIO_SIPO_MODE_MASK | SIPO_RCLK_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group mdio_func_group[] = { + { + .name = "mdio", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_SGMII_MDIO_MODE_MASK, + GPIO_SGMII_MDIO_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group uart_func_group[] = { + { + .name = "uart2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_UART2_MODE_MASK, + GPIO_UART2_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "npu_uart", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_NPU_UART_EN, + NPU_UART_EN_MASK, + NPU_UART_EN_MASK + }, + .regmap_size = 1, + } +}; + +static const struct airoha_pinctrl_func_group i2c_func_group[] = { + { + .name = "i2c1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_2ND_I2C_MODE_MASK, + GPIO_2ND_I2C_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group jtag_func_group[] = { + { + .name = "jtag_udi", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_NPU_UART_EN, + JTAG_UDI_EN_MASK, + JTAG_UDI_EN_MASK + }, + .regmap_size = 1, + }, { + .name = "jtag_dfd", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_NPU_UART_EN, + JTAG_DFD_EN_MASK, + JTAG_DFD_EN_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pcm_func_group[] = { + { + .name = "pcm1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM1_MODE_MASK, + GPIO_PCM1_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm2", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM2_MODE_MASK, + GPIO_PCM2_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group spi_func_group[] = { + { + .name = "spi_quad", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_QUAD_MODE_MASK, + GPIO_SPI_QUAD_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "spi_cs1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_SPI_CS1_MODE_MASK, + GPIO_SPI_CS1_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pcm_spi_func_group[] = { + { + .name = "pcm_spi", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_MODE_MASK, + GPIO_PCM_SPI_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_int", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_INT_MODE_MASK, + GPIO_PCM_INT_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_rst", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_RESET_MODE_MASK, + GPIO_PCM_RESET_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS1_MODE_MASK, + GPIO_PCM_SPI_CS1_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs2_p128", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS2_MODE_P128_MASK, + GPIO_PCM_SPI_CS2_MODE_P128_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs2_p156", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS2_MODE_P156_MASK, + GPIO_PCM_SPI_CS2_MODE_P156_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs3", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS3_MODE_MASK, + GPIO_PCM_SPI_CS3_MODE_MASK + }, + .regmap_size = 1, + }, { + .name = "pcm_spi_cs4", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_SPI_CS1_MODE, + GPIO_PCM_SPI_CS4_MODE_MASK, + GPIO_PCM_SPI_CS4_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group i2s_func_group[] = { + { + .name = "i2s", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_2ND_I2C_MODE, + GPIO_I2S_MODE_MASK, + GPIO_I2S_MODE_MASK + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group gpio_func_group[] = { + AIROHA_PINCTRL_GPIO_EXT("gpio28", GPIO28_FLASH_MODE_CFG, + GPIO_PCIE_RESET0_MASK), + AIROHA_PINCTRL_GPIO_EXT("gpio29", GPIO29_FLASH_MODE_CFG, + GPIO_PCIE_RESET1_MASK), +}; + +static const struct airoha_pinctrl_func_group pcie_reset_func_group[] = { + { + .name = "pcie_reset0", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PCIE_RESET0_MASK, + 0 + }, + .regmap_size = 1, + }, { + .name = "pcie_reset1", + .regmap[0] = { + AIROHA_FUNC_MUX, + REG_GPIO_PON_MODE, + GPIO_PCIE_RESET1_MASK, + 0 + }, + .regmap_size = 1, + }, +}; + +static const struct airoha_pinctrl_func_group pwm_func_group[] = { + AIROHA_PINCTRL_PWM("gpio0", GPIO0_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio1", GPIO1_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio2", GPIO2_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio3", GPIO3_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio4", GPIO4_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio5", GPIO5_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio6", GPIO6_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio7", GPIO7_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio8", GPIO8_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio9", GPIO9_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio10", GPIO10_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio11", GPIO11_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio12", GPIO12_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio13", GPIO13_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio14", GPIO14_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM("gpio15", GPIO15_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio16", GPIO16_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio17", GPIO17_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio18", GPIO18_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio19", GPIO19_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio20", GPIO20_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio21", GPIO21_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio22", GPIO22_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio23", GPIO23_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio24", GPIO24_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio25", GPIO25_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio26", GPIO26_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT("gpio27", GPIO27_FLASH_MODE_CFG), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio28", GPIO28_FLASH_MODE_CFG, + GPIO_PCIE_RESET0_MASK), + AIROHA_PINCTRL_PWM_EXT_SEC("gpio29", GPIO29_FLASH_MODE_CFG, + GPIO_PCIE_RESET1_MASK), +}; + +static const struct airoha_pinctrl_func_group phy1_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio22", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio23", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio24", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED0("gpio25", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)), +}; + +static const struct airoha_pinctrl_func_group phy2_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio22", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio23", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio24", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED0("gpio25", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)), +}; + +static const struct airoha_pinctrl_func_group phy3_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio22", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio23", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio24", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED0("gpio25", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)), +}; + +static const struct airoha_pinctrl_func_group phy4_led0_func_group[] = { + AIROHA_PINCTRL_PHY_LED0("gpio22", GPIO_LAN0_LED0_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio23", GPIO_LAN1_LED0_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio24", GPIO_LAN2_LED0_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED0("gpio25", GPIO_LAN3_LED0_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)), +}; + +static const struct airoha_pinctrl_func_group phy1_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio7", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio6", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio5", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(0)), + AIROHA_PINCTRL_PHY_LED1("gpio4", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(0)), +}; + +static const struct airoha_pinctrl_func_group phy2_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio7", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio6", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio5", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(1)), + AIROHA_PINCTRL_PHY_LED1("gpio4", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(1)), +}; + +static const struct airoha_pinctrl_func_group phy3_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio7", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio6", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio5", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(2)), + AIROHA_PINCTRL_PHY_LED1("gpio4", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(2)), +}; + +static const struct airoha_pinctrl_func_group phy4_led1_func_group[] = { + AIROHA_PINCTRL_PHY_LED1("gpio7", GPIO_LAN0_LED1_MODE_MASK, + LAN0_LED_MAPPING_MASK, LAN0_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED1("gpio6", GPIO_LAN1_LED1_MODE_MASK, + LAN1_LED_MAPPING_MASK, LAN1_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED1("gpio5", GPIO_LAN2_LED1_MODE_MASK, + LAN2_LED_MAPPING_MASK, LAN2_PHY_LED_MAP(3)), + AIROHA_PINCTRL_PHY_LED1("gpio4", GPIO_LAN3_LED1_MODE_MASK, + LAN3_LED_MAPPING_MASK, LAN3_PHY_LED_MAP(3)), +}; + +static const struct airoha_pinctrl_func pinctrl_funcs[] = { + PINCTRL_FUNC_DESC("pon", pon), + PINCTRL_FUNC_DESC("tod_1pps", tod_1pps), + PINCTRL_FUNC_DESC("sipo", sipo), + PINCTRL_FUNC_DESC("mdio", mdio), + PINCTRL_FUNC_DESC("uart", uart), + PINCTRL_FUNC_DESC("i2c", i2c), + PINCTRL_FUNC_DESC("jtag", jtag), + PINCTRL_FUNC_DESC("pcm", pcm), + PINCTRL_FUNC_DESC("spi", spi), + PINCTRL_FUNC_DESC("pcm_spi", pcm_spi), + PINCTRL_FUNC_DESC("i2s", i2s), + PINCTRL_FUNC_DESC("gpio", gpio), + PINCTRL_FUNC_DESC("pcie_reset", pcie_reset), + PINCTRL_FUNC_DESC("pwm", pwm), + PINCTRL_FUNC_DESC("phy1_led0", phy1_led0), + PINCTRL_FUNC_DESC("phy2_led0", phy2_led0), + PINCTRL_FUNC_DESC("phy3_led0", phy3_led0), + PINCTRL_FUNC_DESC("phy4_led0", phy4_led0), + PINCTRL_FUNC_DESC("phy1_led1", phy1_led1), + PINCTRL_FUNC_DESC("phy2_led1", phy2_led1), + PINCTRL_FUNC_DESC("phy3_led1", phy3_led1), + PINCTRL_FUNC_DESC("phy4_led1", phy4_led1), +}; + +static const struct airoha_pinctrl_conf pinctrl_pullup_conf[] = { + PINCTRL_CONF_DESC(12, REG_GPIO_L_PU, BIT(0)), + PINCTRL_CONF_DESC(13, REG_GPIO_L_PU, BIT(1)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_PU, BIT(2)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_PU, BIT(3)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_PU, BIT(4)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_PU, BIT(5)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_PU, BIT(6)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_PU, BIT(7)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_PU, BIT(8)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_PU, BIT(9)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_PU, BIT(10)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_PU, BIT(11)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_PU, BIT(12)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_PU, BIT(13)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_PU, BIT(14)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_PU, BIT(15)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_PU, BIT(16)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_PU, BIT(17)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_PU, BIT(18)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_PU, BIT(19)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_PU, BIT(20)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_PU, BIT(21)), + PINCTRL_CONF_DESC(34, REG_GPIO_L_PU, BIT(22)), + PINCTRL_CONF_DESC(35, REG_GPIO_L_PU, BIT(23)), + PINCTRL_CONF_DESC(36, REG_GPIO_L_PU, BIT(24)), + PINCTRL_CONF_DESC(37, REG_GPIO_L_PU, BIT(25)), + PINCTRL_CONF_DESC(38, REG_GPIO_L_PU, BIT(26)), + PINCTRL_CONF_DESC(39, REG_GPIO_L_PU, BIT(27)), + PINCTRL_CONF_DESC(40, REG_GPIO_L_PU, BIT(28)), + PINCTRL_CONF_DESC(41, REG_GPIO_L_PU, BIT(29)), +}; + +static const struct airoha_pinctrl_conf pinctrl_pulldown_conf[] = { + PINCTRL_CONF_DESC(12, REG_GPIO_L_PD, BIT(0)), + PINCTRL_CONF_DESC(13, REG_GPIO_L_PD, BIT(1)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_PD, BIT(2)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_PD, BIT(3)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_PD, BIT(4)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_PD, BIT(5)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_PD, BIT(6)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_PD, BIT(7)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_PD, BIT(8)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_PD, BIT(9)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_PD, BIT(10)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_PD, BIT(11)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_PD, BIT(12)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_PD, BIT(13)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_PD, BIT(14)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_PD, BIT(15)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_PD, BIT(16)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_PD, BIT(17)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_PD, BIT(18)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_PD, BIT(19)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_PD, BIT(20)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_PD, BIT(21)), + PINCTRL_CONF_DESC(34, REG_GPIO_L_PD, BIT(22)), + PINCTRL_CONF_DESC(35, REG_GPIO_L_PD, BIT(23)), + PINCTRL_CONF_DESC(36, REG_GPIO_L_PD, BIT(24)), + PINCTRL_CONF_DESC(37, REG_GPIO_L_PD, BIT(25)), + PINCTRL_CONF_DESC(38, REG_GPIO_L_PD, BIT(26)), + PINCTRL_CONF_DESC(39, REG_GPIO_L_PD, BIT(27)), + PINCTRL_CONF_DESC(40, REG_GPIO_L_PD, BIT(28)), + PINCTRL_CONF_DESC(41, REG_GPIO_L_PD, BIT(29)), +}; + +static const struct airoha_pinctrl_conf pinctrl_drive_e2_conf[] = { + PINCTRL_CONF_DESC(12, REG_GPIO_L_E2, BIT(0)), + PINCTRL_CONF_DESC(13, REG_GPIO_L_E2, BIT(1)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_E2, BIT(2)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_E2, BIT(3)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_E2, BIT(4)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_E2, BIT(5)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_E2, BIT(6)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_E2, BIT(7)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_E2, BIT(8)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_E2, BIT(9)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_E2, BIT(10)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_E2, BIT(11)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_E2, BIT(12)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_E2, BIT(13)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_E2, BIT(14)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_E2, BIT(15)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_E2, BIT(16)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_E2, BIT(17)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_E2, BIT(18)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_E2, BIT(19)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_E2, BIT(20)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_E2, BIT(21)), + PINCTRL_CONF_DESC(34, REG_GPIO_L_E2, BIT(22)), + PINCTRL_CONF_DESC(35, REG_GPIO_L_E2, BIT(23)), + PINCTRL_CONF_DESC(36, REG_GPIO_L_E2, BIT(24)), + PINCTRL_CONF_DESC(37, REG_GPIO_L_E2, BIT(25)), + PINCTRL_CONF_DESC(38, REG_GPIO_L_E2, BIT(26)), + PINCTRL_CONF_DESC(39, REG_GPIO_L_E2, BIT(27)), + PINCTRL_CONF_DESC(40, REG_GPIO_L_E2, BIT(28)), + PINCTRL_CONF_DESC(41, REG_GPIO_L_E2, BIT(29)), +}; + +static const struct airoha_pinctrl_conf pinctrl_drive_e4_conf[] = { + PINCTRL_CONF_DESC(12, REG_GPIO_L_E4, BIT(0)), + PINCTRL_CONF_DESC(13, REG_GPIO_L_E4, BIT(1)), + PINCTRL_CONF_DESC(14, REG_GPIO_L_E4, BIT(2)), + PINCTRL_CONF_DESC(15, REG_GPIO_L_E4, BIT(3)), + PINCTRL_CONF_DESC(16, REG_GPIO_L_E4, BIT(4)), + PINCTRL_CONF_DESC(17, REG_GPIO_L_E4, BIT(5)), + PINCTRL_CONF_DESC(18, REG_GPIO_L_E4, BIT(6)), + PINCTRL_CONF_DESC(19, REG_GPIO_L_E4, BIT(7)), + PINCTRL_CONF_DESC(20, REG_GPIO_L_E4, BIT(8)), + PINCTRL_CONF_DESC(21, REG_GPIO_L_E4, BIT(9)), + PINCTRL_CONF_DESC(22, REG_GPIO_L_E4, BIT(10)), + PINCTRL_CONF_DESC(23, REG_GPIO_L_E4, BIT(11)), + PINCTRL_CONF_DESC(24, REG_GPIO_L_E4, BIT(12)), + PINCTRL_CONF_DESC(25, REG_GPIO_L_E4, BIT(13)), + PINCTRL_CONF_DESC(26, REG_GPIO_L_E4, BIT(14)), + PINCTRL_CONF_DESC(27, REG_GPIO_L_E4, BIT(15)), + PINCTRL_CONF_DESC(28, REG_GPIO_L_E4, BIT(16)), + PINCTRL_CONF_DESC(29, REG_GPIO_L_E4, BIT(17)), + PINCTRL_CONF_DESC(30, REG_GPIO_L_E4, BIT(18)), + PINCTRL_CONF_DESC(31, REG_GPIO_L_E4, BIT(19)), + PINCTRL_CONF_DESC(32, REG_GPIO_L_E4, BIT(20)), + PINCTRL_CONF_DESC(33, REG_GPIO_L_E4, BIT(21)), + PINCTRL_CONF_DESC(34, REG_GPIO_L_E4, BIT(22)), + PINCTRL_CONF_DESC(35, REG_GPIO_L_E4, BIT(23)), + PINCTRL_CONF_DESC(36, REG_GPIO_L_E4, BIT(24)), + PINCTRL_CONF_DESC(37, REG_GPIO_L_E4, BIT(25)), + PINCTRL_CONF_DESC(38, REG_GPIO_L_E4, BIT(26)), + PINCTRL_CONF_DESC(39, REG_GPIO_L_E4, BIT(27)), + PINCTRL_CONF_DESC(40, REG_GPIO_L_E4, BIT(28)), + PINCTRL_CONF_DESC(41, REG_GPIO_L_E4, BIT(29)), +}; + +static const struct airoha_pinctrl_match_data pinctrl_match_data = { + .gpio_offs = 12, + .gpio_pin_cnt = 30, + .chip_scu_compatible = "airoha,en7523-chip-scu", + .pins = pinctrl_pins, + .num_pins = ARRAY_SIZE(pinctrl_pins), + .grps = pinctrl_groups, + .num_grps = ARRAY_SIZE(pinctrl_groups), + .funcs = pinctrl_funcs, + .num_funcs = ARRAY_SIZE(pinctrl_funcs), + .confs_info = { + [AIROHA_PINCTRL_CONFS_PULLUP] = { + .confs = pinctrl_pullup_conf, + .num_confs = ARRAY_SIZE(pinctrl_pullup_conf), + }, + [AIROHA_PINCTRL_CONFS_PULLDOWN] = { + .confs = pinctrl_pulldown_conf, + .num_confs = ARRAY_SIZE(pinctrl_pulldown_conf), + }, + [AIROHA_PINCTRL_CONFS_DRIVE_E2] = { + .confs = pinctrl_drive_e2_conf, + .num_confs = ARRAY_SIZE(pinctrl_drive_e2_conf), + }, + [AIROHA_PINCTRL_CONFS_DRIVE_E4] = { + .confs = pinctrl_drive_e4_conf, + .num_confs = ARRAY_SIZE(pinctrl_drive_e4_conf), + }, + }, +}; + +static const struct udevice_id pinctrl_of_match[] = { + { .compatible = "airoha,en7523-pinctrl", + .data = (uintptr_t)&pinctrl_match_data }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(airoha_en7523_pinctrl) = { + .name = "airoha-en7523-pinctrl", + .id = UCLASS_PINCTRL, + .of_match = of_match_ptr(pinctrl_of_match), + .probe = airoha_pinctrl_probe, + .bind = airoha_pinctrl_bind, + .priv_auto = sizeof(struct airoha_pinctrl), + .ops = &airoha_pinctrl_ops, +}; diff --git a/drivers/pinctrl/aspeed/Makefile b/drivers/pinctrl/aspeed/Makefile index a3e01ed1ca9..33b23fce629 100644 --- a/drivers/pinctrl/aspeed/Makefile +++ b/drivers/pinctrl/aspeed/Makefile @@ -1,2 +1,4 @@ obj-$(CONFIG_ASPEED_AST2500_PINCTRL) += pinctrl_ast2500.o obj-$(CONFIG_ASPEED_AST2600_PINCTRL) += pinctrl_ast2600.o +obj-$(CONFIG_ASPEED_AST2700_SOC0_PINCTRL) += pinctrl_ast2700_soc0.o +obj-$(CONFIG_ASPEED_AST2700_SOC1_PINCTRL) += pinctrl_ast2700_soc1.o diff --git a/drivers/pinctrl/aspeed/pinctrl_ast2700_soc0.c b/drivers/pinctrl/aspeed/pinctrl_ast2700_soc0.c new file mode 100644 index 00000000000..b5111d7ee15 --- /dev/null +++ b/drivers/pinctrl/aspeed/pinctrl_ast2700_soc0.c @@ -0,0 +1,623 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 ASPEED Technology Inc. + */ + +#include <asm/io.h> +#include <dm.h> +#include <dm/pinctrl.h> +#include <errno.h> +#include <vsprintf.h> +#include <linux/bitops.h> +#include <linux/kernel.h> +#include <linux/string.h> + +#define SCU010 0x010 +#define SCU200 0x200 +#define SCU400 0x400 +#define SCU404 0x404 +#define SCU408 0x408 +#define SCU410 0x410 +/* One IO control register per ball, GPIO18A0..GPIO18B3 */ +#define SCU480 0x480 + +/* Indexes into ast2700_soc0_pins[], in GPIO18A0..GPIO18B3 order */ +enum { + AC14, + AE15, + AD14, + AE14, + AF14, + AB13, + AB14, + AF15, + AF13, + AC13, + AD13, + AE13, +}; + +#define USB_PORTA_ROUTE BIT(9) +#define USB_PORTB_ROUTE BIT(10) + +#define PORTA_U3_MODE GENMASK(1, 0) +#define PORTA_U2_MODE GENMASK(3, 2) +#define PORTB_U3_MODE GENMASK(5, 4) +#define PORTB_U2_MODE GENMASK(7, 6) +#define PORTA_MODE GENMASK(25, 24) +#define PORTB_MODE GENMASK(29, 28) + +#define PINMUX(_function, _group, _offset, _mask, _val) \ + { \ + .function = _function, \ + .group = _group, \ + .offset = _offset, \ + .mask = _mask, \ + .val = _val, \ + } + +struct ast2700_soc0_pinmux { + const char *function; + const char *group; + u32 offset; + u32 mask; + u32 val; +}; + +struct ast2700_soc0_sig { + u32 offset; + u32 mask; + const char *name; +}; + +struct ast2700_soc0_pin { + const char *name; + const struct ast2700_soc0_sig *sigs; + unsigned int nsigs; +}; + +struct ast2700_soc0_pinctrl_priv { + void __iomem *base; +}; + +struct ast2700_soc0_group { + const char *name; + const u8 *pins; + unsigned int npins; +}; + +static const u8 ast2700_soc0_emmcg1_pins[] = { AC14, AE15, AD14 }; +static const u8 ast2700_soc0_emmcg4_pins[] = { + AC14, AE15, AD14, AE14, AF14, AB13, +}; + +static const u8 ast2700_soc0_emmcg8_pins[] = { + AC14, AE15, AD14, AE14, AF14, AB13, AF13, AC13, AD13, AE13, +}; + +static const u8 ast2700_soc0_emmcwpn_pins[] = { AF15 }; +static const u8 ast2700_soc0_emmccdn_pins[] = { AB14 }; +static const u8 ast2700_soc0_vgaddc_pins[] = { AD13, AE13 }; +static const u8 ast2700_soc0_vb1_pins[] = { AC14, AE15, AD14, AE14 }; +static const u8 ast2700_soc0_vb0_pins[] = { AF15, AB14, AF13, AC13 }; +static const u8 ast2700_soc0_tsprstn_pins[] = { AF13 }; +static const u8 ast2700_soc0_ufsclki_pins[] = { AC13 }; + +#define AST2700_SOC0_GROUP(_name, _pins) \ + { \ + .name = _name, \ + .pins = _pins, \ + .npins = ARRAY_SIZE(_pins), \ + } + +/* + * The USB, JTAG and PCIe RC groups control internal routing only; they + * have no package balls, hence no group pins to configure. + */ +static const struct ast2700_soc0_group ast2700_soc0_groups[] = { + AST2700_SOC0_GROUP("EMMCG1", ast2700_soc0_emmcg1_pins), + AST2700_SOC0_GROUP("EMMCG4", ast2700_soc0_emmcg4_pins), + AST2700_SOC0_GROUP("EMMCG8", ast2700_soc0_emmcg8_pins), + AST2700_SOC0_GROUP("EMMCWPN", ast2700_soc0_emmcwpn_pins), + AST2700_SOC0_GROUP("EMMCCDN", ast2700_soc0_emmccdn_pins), + AST2700_SOC0_GROUP("VGADDC", ast2700_soc0_vgaddc_pins), + AST2700_SOC0_GROUP("VB1", ast2700_soc0_vb1_pins), + AST2700_SOC0_GROUP("VB0", ast2700_soc0_vb0_pins), + AST2700_SOC0_GROUP("TSPRSTN", ast2700_soc0_tsprstn_pins), + AST2700_SOC0_GROUP("UFSCLKI", ast2700_soc0_ufsclki_pins), + { "USB3A" }, + { "USB3AAP" }, + { "USB3ABP" }, + { "USB3B" }, + { "USB3BAP" }, + { "USB3BBP" }, + { "USB2A" }, + { "USB2AAP" }, + { "USB2ABP" }, + { "USB2ADAP" }, + { "USB2AH" }, + { "USB2AHAP" }, + { "USB2B" }, + { "USB2BBP" }, + { "USB2BAP" }, + { "USB2BDBP" }, + { "USB2BH" }, + { "USB2BHBP" }, + { "JTAG0" }, + { "PCIERC0PERST" }, + { "PCIERC1PERST" }, +}; + +static const char * const ast2700_soc0_functions[] = { + "EMMC", + "VB", + "TSPRSTN", + "UFSCLKI", + "VGADDC", + "USB3AXHD", + "USB3AXHPD", + "USB3AXH", + "USB3AXHP", + "USB3AXH2B", + "USB3AXHP2B", + "USB3BXHD", + "USB3BXHPD", + "USB3BXH", + "USB3BXHP", + "USB3BXH2A", + "USB3BXHP2A", + "USB2AXHD1", + "USB2AXHPD1", + "USB2AXH", + "USB2AXHP", + "USB2AXH2B", + "USB2AXHP2B", + "USB2AD1", + "USB2AHPD0", + "USB2AH", + "USB2AHP", + "USB2AD0", + "USB2BXHD1", + "USB2BXHPD1", + "USB2BXH", + "USB2BXHP", + "USB2BXH2A", + "USB2BXHP2A", + "USB2BD1", + "USB2BHPD0", + "USB2BH", + "USB2BHP", + "USB2BD0", + "JTAGPSP", + "JTAGSSP", + "JTAGTSP", + "JTAGDDR", + "JTAGUSB3A", + "JTAGUSB3B", + "JTAGPCIEA", + "JTAGPCIEB", + "JTAGM0", + "PCIERC0PERST", + "PCIERC1PERST", +}; + +static const struct ast2700_soc0_pinmux ast2700_soc0_pinmuxes[] = { + PINMUX("EMMC", "EMMCG1", SCU400, GENMASK(2, 0), GENMASK(2, 0)), + PINMUX("EMMC", "EMMCG4", SCU400, GENMASK(5, 0), GENMASK(5, 0)), + PINMUX("EMMC", "EMMCG8", SCU400, + GENMASK(5, 0) | GENMASK(11, 8), + GENMASK(5, 0) | GENMASK(11, 8)), + PINMUX("EMMC", "EMMCWPN", SCU400, BIT(7), BIT(7)), + PINMUX("EMMC", "EMMCCDN", SCU400, BIT(6), BIT(6)), + PINMUX("VB", "VB1", SCU404, GENMASK(3, 0), GENMASK(3, 0)), + PINMUX("VB", "VB0", SCU010, BIT(17), BIT(17)), + PINMUX("TSPRSTN", "TSPRSTN", SCU010, BIT(9), BIT(9)), + PINMUX("UFSCLKI", "UFSCLKI", SCU010, BIT(19), BIT(19)), + PINMUX("VGADDC", "VGADDC", SCU404, GENMASK(11, 10), + GENMASK(11, 10)), + + /* + * The Linux driver models the USB2/USB3 routing with additional + * virtual PHY pins (PORTA/PORTB_U2_PHY, PORTA/PORTB_U3_PHY) purely + * to reject conflicting cross-coupled selections; they carry no + * register writes. U-Boot applies the states given by the device + * tree without strict conflict checking, so only the real selector + * fields are programmed here while the group names stay identical. + */ + PINMUX("USB3AXHD", "USB3A", SCU410, + PORTA_U3_MODE | USB_PORTA_ROUTE, USB_PORTA_ROUTE), + PINMUX("USB3AXHPD", "USB3A", SCU410, + PORTA_U3_MODE | USB_PORTA_ROUTE, 0), + PINMUX("USB3AXH", "USB3AAP", SCU410, + PORTA_U3_MODE | USB_PORTA_ROUTE, (2 << 0) | USB_PORTA_ROUTE), + PINMUX("USB3AXHP", "USB3AAP", SCU410, + PORTA_U3_MODE | USB_PORTA_ROUTE, 2 << 0), + PINMUX("USB3AXH2B", "USB3ABP", SCU410, + PORTA_U3_MODE | USB_PORTA_ROUTE, (3 << 0) | USB_PORTA_ROUTE), + PINMUX("USB3AXHP2B", "USB3ABP", SCU410, + PORTA_U3_MODE | USB_PORTA_ROUTE, 3 << 0), + + PINMUX("USB3BXHD", "USB3B", SCU410, + PORTB_U3_MODE | USB_PORTB_ROUTE, USB_PORTB_ROUTE), + PINMUX("USB3BXHPD", "USB3B", SCU410, + PORTB_U3_MODE | USB_PORTB_ROUTE, 0), + PINMUX("USB3BXH", "USB3BBP", SCU410, + PORTB_U3_MODE | USB_PORTB_ROUTE, (2 << 4) | USB_PORTB_ROUTE), + PINMUX("USB3BXHP", "USB3BBP", SCU410, + PORTB_U3_MODE | USB_PORTB_ROUTE, 2 << 4), + PINMUX("USB3BXH2A", "USB3BAP", SCU410, + PORTB_U3_MODE | USB_PORTB_ROUTE, (3 << 4) | USB_PORTB_ROUTE), + PINMUX("USB3BXHP2A", "USB3BAP", SCU410, + PORTB_U3_MODE | USB_PORTB_ROUTE, 3 << 4), + + PINMUX("USB2AXHD1", "USB2A", SCU410, + PORTA_U2_MODE | USB_PORTA_ROUTE, USB_PORTA_ROUTE), + PINMUX("USB2AXHPD1", "USB2A", SCU410, + PORTA_U2_MODE | USB_PORTA_ROUTE, 0), + PINMUX("USB2AXH", "USB2AAP", SCU410, + PORTA_U2_MODE | USB_PORTA_ROUTE, (2 << 2) | USB_PORTA_ROUTE), + PINMUX("USB2AXHP", "USB2AAP", SCU410, + PORTA_U2_MODE | USB_PORTA_ROUTE, 2 << 2), + PINMUX("USB2AXH2B", "USB2ABP", SCU410, + PORTA_U2_MODE | USB_PORTA_ROUTE, (3 << 2) | USB_PORTA_ROUTE), + PINMUX("USB2AXHP2B", "USB2ABP", SCU410, + PORTA_U2_MODE | USB_PORTA_ROUTE, 3 << 2), + PINMUX("USB2AD1", "USB2ADAP", SCU410, PORTA_U2_MODE, 1 << 2), + PINMUX("USB2AHPD0", "USB2AH", SCU410, PORTA_MODE, 0), + PINMUX("USB2AH", "USB2AHAP", SCU410, PORTA_MODE, 2 << 24), + PINMUX("USB2AHP", "USB2AHAP", SCU410, PORTA_MODE, 3 << 24), + PINMUX("USB2AD0", "USB2AHAP", SCU410, PORTA_MODE, 1 << 24), + + PINMUX("USB2BXHD1", "USB2B", SCU410, + PORTB_U2_MODE | USB_PORTB_ROUTE, USB_PORTB_ROUTE), + PINMUX("USB2BXHPD1", "USB2B", SCU410, + PORTB_U2_MODE | USB_PORTB_ROUTE, 0), + PINMUX("USB2BXH", "USB2BBP", SCU410, + PORTB_U2_MODE | USB_PORTB_ROUTE, (2 << 6) | USB_PORTB_ROUTE), + PINMUX("USB2BXHP", "USB2BBP", SCU410, + PORTB_U2_MODE | USB_PORTB_ROUTE, 2 << 6), + PINMUX("USB2BXH2A", "USB2BAP", SCU410, + PORTB_U2_MODE | USB_PORTB_ROUTE, (3 << 6) | USB_PORTB_ROUTE), + PINMUX("USB2BXHP2A", "USB2BAP", SCU410, + PORTB_U2_MODE | USB_PORTB_ROUTE, 3 << 6), + PINMUX("USB2BD1", "USB2BDBP", SCU410, PORTB_U2_MODE, 1 << 6), + PINMUX("USB2BHPD0", "USB2BH", SCU410, PORTB_MODE, 0), + PINMUX("USB2BH", "USB2BHBP", SCU410, PORTB_MODE, 2 << 28), + PINMUX("USB2BHP", "USB2BHBP", SCU410, PORTB_MODE, 3 << 28), + PINMUX("USB2BD0", "USB2BHBP", SCU410, PORTB_MODE, 1 << 28), + + PINMUX("JTAGPSP", "JTAG0", SCU408, GENMASK(12, 5), 0x00 << 5), + PINMUX("JTAGSSP", "JTAG0", SCU408, GENMASK(12, 5), 0x41 << 5), + PINMUX("JTAGTSP", "JTAG0", SCU408, GENMASK(12, 5), 0x42 << 5), + PINMUX("JTAGDDR", "JTAG0", SCU408, GENMASK(12, 5), 0x43 << 5), + PINMUX("JTAGUSB3A", "JTAG0", SCU408, GENMASK(12, 5), 0x44 << 5), + PINMUX("JTAGUSB3B", "JTAG0", SCU408, GENMASK(12, 5), 0x45 << 5), + PINMUX("JTAGPCIEA", "JTAG0", SCU408, GENMASK(12, 5), 0x46 << 5), + PINMUX("JTAGPCIEB", "JTAG0", SCU408, GENMASK(12, 5), 0x47 << 5), + PINMUX("JTAGM0", "JTAG0", SCU408, GENMASK(12, 5), 0x08 << 5), + PINMUX("PCIERC0PERST", "PCIERC0PERST", SCU200, BIT(21), BIT(21)), + PINMUX("PCIERC1PERST", "PCIERC1PERST", SCU200, BIT(19), BIT(19)), +}; + +/* + * Signals muxable on each package ball, strongest first. A pin acts as + * GPIO when none of its signal enable bits are set; gpio_request_enable + * clears them all. The pin order follows the GPIO18A0..GPIO18B3 numbering + * used by the gpio-ranges of the SoC0 GPIO controller. + */ +static const struct ast2700_soc0_sig ast2700_soc0_ac14_sigs[] = { + { SCU400, BIT(0), "EMMCCLK" }, + { SCU404, BIT(0), "VB1CS" }, +}; + +static const struct ast2700_soc0_sig ast2700_soc0_ae15_sigs[] = { + { SCU400, BIT(1), "EMMCCMD" }, + { SCU404, BIT(1), "VB1CK" }, +}; + +static const struct ast2700_soc0_sig ast2700_soc0_ad14_sigs[] = { + { SCU400, BIT(2), "EMMCDAT0" }, + { SCU404, BIT(2), "VB1MOSI" }, +}; + +static const struct ast2700_soc0_sig ast2700_soc0_ae14_sigs[] = { + { SCU400, BIT(3), "EMMCDAT1" }, + { SCU404, BIT(3), "VB1MISO" }, +}; + +static const struct ast2700_soc0_sig ast2700_soc0_af14_sigs[] = { + { SCU400, BIT(4), "EMMCDAT2" }, +}; + +static const struct ast2700_soc0_sig ast2700_soc0_ab13_sigs[] = { + { SCU400, BIT(5), "EMMCDAT3" }, +}; + +static const struct ast2700_soc0_sig ast2700_soc0_ab14_sigs[] = { + { SCU400, BIT(6), "EMMCCDN" }, + { SCU010, BIT(17), "VB0CS" }, +}; + +static const struct ast2700_soc0_sig ast2700_soc0_af15_sigs[] = { + { SCU400, BIT(7), "EMMCWPN" }, + { SCU010, BIT(17), "VB0CK" }, +}; + +static const struct ast2700_soc0_sig ast2700_soc0_af13_sigs[] = { + { SCU010, BIT(9), "TSPRSTN" }, + { SCU400, BIT(8), "EMMCDAT4" }, + { SCU010, BIT(17), "VB0MOSI" }, +}; + +static const struct ast2700_soc0_sig ast2700_soc0_ac13_sigs[] = { + { SCU010, BIT(19), "UFSCLKI" }, + { SCU400, BIT(9), "EMMCDAT5" }, + { SCU010, BIT(17), "VB0MISO" }, +}; + +static const struct ast2700_soc0_sig ast2700_soc0_ad13_sigs[] = { + { SCU400, BIT(10), "EMMCDAT6" }, + { SCU404, BIT(10), "DDCCLK" }, +}; + +static const struct ast2700_soc0_sig ast2700_soc0_ae13_sigs[] = { + { SCU400, BIT(11), "EMMCDAT7" }, + { SCU404, BIT(11), "DDCDAT" }, +}; + +#define AST2700_SOC0_PIN(_name, _sigs) \ + { \ + .name = _name, \ + .sigs = _sigs, \ + .nsigs = ARRAY_SIZE(_sigs), \ + } + +static const struct ast2700_soc0_pin ast2700_soc0_pins[] = { + AST2700_SOC0_PIN("AC14", ast2700_soc0_ac14_sigs), + AST2700_SOC0_PIN("AE15", ast2700_soc0_ae15_sigs), + AST2700_SOC0_PIN("AD14", ast2700_soc0_ad14_sigs), + AST2700_SOC0_PIN("AE14", ast2700_soc0_ae14_sigs), + AST2700_SOC0_PIN("AF14", ast2700_soc0_af14_sigs), + AST2700_SOC0_PIN("AB13", ast2700_soc0_ab13_sigs), + AST2700_SOC0_PIN("AB14", ast2700_soc0_ab14_sigs), + AST2700_SOC0_PIN("AF15", ast2700_soc0_af15_sigs), + AST2700_SOC0_PIN("AF13", ast2700_soc0_af13_sigs), + AST2700_SOC0_PIN("AC13", ast2700_soc0_ac13_sigs), + AST2700_SOC0_PIN("AD13", ast2700_soc0_ad13_sigs), + AST2700_SOC0_PIN("AE13", ast2700_soc0_ae13_sigs), +}; + +static int ast2700_soc0_pinctrl_probe(struct udevice *dev) +{ + struct ast2700_soc0_pinctrl_priv *priv = dev_get_priv(dev); + + priv->base = dev_remap_addr(dev->parent); + if (!priv->base) + return -ENOMEM; + + return 0; +} + +static int ast2700_soc0_pinctrl_get_groups_count(struct udevice *dev) +{ + return ARRAY_SIZE(ast2700_soc0_groups); +} + +static const char *ast2700_soc0_pinctrl_get_group_name(struct udevice *dev, + unsigned int selector) +{ + return ast2700_soc0_groups[selector].name; +} + +static int ast2700_soc0_pinctrl_get_functions_count(struct udevice *dev) +{ + return ARRAY_SIZE(ast2700_soc0_functions); +} + +static const char *ast2700_soc0_pinctrl_get_function_name(struct udevice *dev, + unsigned int selector) +{ + return ast2700_soc0_functions[selector]; +} + +static int ast2700_soc0_pinctrl_group_set(struct udevice *dev, + unsigned int group_selector, + unsigned int func_selector) +{ + struct ast2700_soc0_pinctrl_priv *priv = dev_get_priv(dev); + const struct ast2700_soc0_pinmux *pinmux; + const char *function; + const char *group; + u32 i; + + if (group_selector >= ARRAY_SIZE(ast2700_soc0_groups) || + func_selector >= ARRAY_SIZE(ast2700_soc0_functions)) + return -EINVAL; + + function = ast2700_soc0_functions[func_selector]; + group = ast2700_soc0_groups[group_selector].name; + + for (i = 0; i < ARRAY_SIZE(ast2700_soc0_pinmuxes); i++) { + pinmux = &ast2700_soc0_pinmuxes[i]; + if (strcmp(pinmux->function, function) || + strcmp(pinmux->group, group)) + continue; + + clrsetbits_le32(priv->base + pinmux->offset, pinmux->mask, + pinmux->val); + return 0; + } + + return -EINVAL; +} + +static int ast2700_soc0_pinctrl_gpio_request_enable(struct udevice *dev, + unsigned int selector) +{ + struct ast2700_soc0_pinctrl_priv *priv = dev_get_priv(dev); + const struct ast2700_soc0_pin *pin; + u32 i; + + if (selector >= ARRAY_SIZE(ast2700_soc0_pins)) + return -EINVAL; + + pin = &ast2700_soc0_pins[selector]; + for (i = 0; i < pin->nsigs; i++) + clrbits_le32(priv->base + pin->sigs[i].offset, + pin->sigs[i].mask); + + return 0; +} + +static int ast2700_soc0_pinctrl_get_pins_count(struct udevice *dev) +{ + return ARRAY_SIZE(ast2700_soc0_pins); +} + +static const char *ast2700_soc0_pinctrl_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + if (selector >= ARRAY_SIZE(ast2700_soc0_pins)) + return NULL; + + return ast2700_soc0_pins[selector].name; +} + +static int ast2700_soc0_pinctrl_get_pin_muxing(struct udevice *dev, + unsigned int selector, + char *buf, int size) +{ + struct ast2700_soc0_pinctrl_priv *priv = dev_get_priv(dev); + const struct ast2700_soc0_pin *pin; + const struct ast2700_soc0_sig *sig; + u32 i; + + if (selector >= ARRAY_SIZE(ast2700_soc0_pins)) + return -EINVAL; + + pin = &ast2700_soc0_pins[selector]; + for (i = 0; i < pin->nsigs; i++) { + sig = &pin->sigs[i]; + if ((readl(priv->base + sig->offset) & sig->mask) == + sig->mask) { + snprintf(buf, size, "%s", sig->name); + return 0; + } + } + + snprintf(buf, size, "GPIO"); + + return 0; +} + +/* Drive strength in mA selectable by the IO control register [3:0] */ +static const u8 ast2700_soc0_drv_ma[] = { + 3, 6, 8, 11, 16, 18, 20, 23, 30, 32, 33, 35, 37, 38, 39, 41, +}; + +static const struct pinconf_param ast2700_soc0_pinconf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 0 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, +}; + +static int ast2700_soc0_pinctrl_pinconf_set(struct udevice *dev, + unsigned int selector, + unsigned int param, + unsigned int arg) +{ + struct ast2700_soc0_pinctrl_priv *priv = dev_get_priv(dev); + u32 mask, val, i; + + if (selector >= ARRAY_SIZE(ast2700_soc0_pins)) + return -EINVAL; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + mask = BIT(5); + val = 0; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + mask = GENMASK(5, 4); + val = 2 << 4; + break; + case PIN_CONFIG_BIAS_PULL_UP: + mask = GENMASK(5, 4); + val = 3 << 4; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + for (i = 0; i < ARRAY_SIZE(ast2700_soc0_drv_ma); i++) { + if (ast2700_soc0_drv_ma[i] == arg) + break; + } + if (i == ARRAY_SIZE(ast2700_soc0_drv_ma)) + return -EINVAL; + mask = GENMASK(3, 0); + val = i; + break; + default: + return -ENOTSUPP; + } + + clrsetbits_le32(priv->base + SCU480 + selector * 4, mask, val); + + return 0; +} + +static int ast2700_soc0_pinctrl_pinconf_group_set(struct udevice *dev, + unsigned int selector, + unsigned int param, + unsigned int arg) +{ + const struct ast2700_soc0_group *group; + u32 i; + int ret; + + if (selector >= ARRAY_SIZE(ast2700_soc0_groups)) + return -EINVAL; + + group = &ast2700_soc0_groups[selector]; + if (!group->npins) + return -ENOTSUPP; + + for (i = 0; i < group->npins; i++) { + ret = ast2700_soc0_pinctrl_pinconf_set(dev, group->pins[i], + param, arg); + if (ret) + return ret; + } + + return 0; +} + +static const struct pinctrl_ops ast2700_soc0_pinctrl_ops = { + .set_state = pinctrl_generic_set_state, + .get_pins_count = ast2700_soc0_pinctrl_get_pins_count, + .get_pin_name = ast2700_soc0_pinctrl_get_pin_name, + .get_pin_muxing = ast2700_soc0_pinctrl_get_pin_muxing, + .get_groups_count = ast2700_soc0_pinctrl_get_groups_count, + .get_group_name = ast2700_soc0_pinctrl_get_group_name, + .get_functions_count = ast2700_soc0_pinctrl_get_functions_count, + .get_function_name = ast2700_soc0_pinctrl_get_function_name, + .pinmux_group_set = ast2700_soc0_pinctrl_group_set, + .gpio_request_enable = ast2700_soc0_pinctrl_gpio_request_enable, + .pinconf_num_params = ARRAY_SIZE(ast2700_soc0_pinconf_params), + .pinconf_params = ast2700_soc0_pinconf_params, + .pinconf_set = ast2700_soc0_pinctrl_pinconf_set, + .pinconf_group_set = ast2700_soc0_pinctrl_pinconf_group_set, +}; + +static const struct udevice_id ast2700_soc0_pinctrl_ids[] = { + { .compatible = "aspeed,ast2700-soc0-pinctrl" }, + { } +}; + +U_BOOT_DRIVER(pinctrl_ast2700_soc0) = { + .name = "aspeed_ast2700_soc0_pinctrl", + .id = UCLASS_PINCTRL, + .of_match = ast2700_soc0_pinctrl_ids, + .priv_auto = sizeof(struct ast2700_soc0_pinctrl_priv), + .ops = &ast2700_soc0_pinctrl_ops, + .probe = ast2700_soc0_pinctrl_probe, +}; diff --git a/drivers/pinctrl/aspeed/pinctrl_ast2700_soc1.c b/drivers/pinctrl/aspeed/pinctrl_ast2700_soc1.c new file mode 100644 index 00000000000..05656c38ad2 --- /dev/null +++ b/drivers/pinctrl/aspeed/pinctrl_ast2700_soc1.c @@ -0,0 +1,1642 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 ASPEED Technology Inc. + */ + +#include <asm/io.h> +#include <dm.h> +#include <dm/pinctrl.h> +#include <errno.h> +#include <vsprintf.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/types.h> + +#define AST2700_SOC1_MUX_BASE 0x400 +#define AST2700_SOC1_PCIE_REG 0x908 +#define AST2700_SOC1_USB_MODE_REG 0x3b0 +#define AST2700_SOC1_SGMII_REG 0x47c +#define AST2700_SOC1_MUX_MASK 0x7 +#define AST2700_SOC1_MUX_BITS_PER_PIN 4 +#define AST2700_SOC1_MUX_PINS_PER_REG 8 + +#define AST2700_SOC1_BIAS_BASE 0x480 +#define AST2700_SOC1_BIAS_PINS_PER_REG 32 + +#define AST2700_SOC1_DRV_BASE 0x4c0 +#define AST2700_SOC1_DRV_MASK 0x3 +#define AST2700_SOC1_DRV_BITS_PER_PIN 2 +#define AST2700_SOC1_DRV_PINS_PER_REG 16 +#define AST2700_SOC1_DRV_STEP_MA 4 +#define AST2700_SOC1_DRV_MIN_MA 4 +#define AST2700_SOC1_DRV_MAX_MA 16 + +enum { + C16, + C14, + C11, + D9, + F14, + D10, + C12, + C13, + AC26, + AA25, + AB23, + U22, + V21, + N26, + P25, + N25, + V23, + W22, + AB26, + AD26, + P26, + AE26, + AF26, + AF25, + AE25, + AD25, + AF23, + AF20, + AF21, + AE21, + AE23, + AD22, + AF17, + AA16, + Y16, + V17, + J13, + AB16, + AC16, + AF16, + AA15, + AB15, + AC15, + AD15, + Y15, + AA14, + W16, + V16, + AB18, + AC18, + K13, + AA17, + AB17, + AD16, + AC17, + AD17, + AE16, + AE17, + AB24, + W26, + HOLE0, + HOLE1, + HOLE2, + HOLE3, + W25, + Y23, + Y24, + W21, + AA23, + AC22, + AB22, + Y21, + AE20, + AF19, + Y22, + AA20, + AA22, + AB20, + AF18, + AE19, + AD20, + AC20, + AA21, + AB21, + AC19, + AE18, + AD19, + AD18, + U25, + U26, + Y26, + AA24, + R25, + AA26, + R26, + Y25, + B16, + D14, + B15, + B14, + C17, + B13, + E14, + C15, + D24, + B23, + B22, + C23, + B18, + B21, + M15, + B19, + B26, + A25, + A24, + B24, + E26, + A21, + A19, + A18, + D26, + C26, + A23, + A22, + B25, + F26, + A26, + A14, + E10, + E13, + D12, + F10, + E11, + F11, + F13, + N15, + C20, + C19, + A8, + R14, + A7, + P14, + D20, + A6, + B6, + N14, + B7, + B8, + B9, + M14, + J11, + E7, + D19, + B11, + D15, + B12, + B10, + P13, + C18, + C6, + C7, + D7, + N13, + C8, + C9, + C10, + M16, + A15, + G11, + H7, + H8, + H9, + H10, + H11, + J9, + J10, + E9, + F9, + F8, + M13, + F7, + D8, + E8, + L12, + F12, + E12, + J12, + G7, + G8, + G9, + G10, + K12, + W17, + V18, + W18, + Y17, + AA18, + AA13, + Y18, + AA12, + W20, + V20, + Y11, + V14, + V19, + W14, + Y20, + AB19, + U21, + T24, + V24, + V22, + T23, + AC25, + AB25, + AC24, + PCIERC2_PERST, + PORTC_MODE, + PORTD_MODE, + SGMII0, +}; + +struct ast2700_soc1_field { + u32 reg; + u32 shift; + u32 mask; +}; + +struct ast2700_soc1_group { + const char *name; + const unsigned int *pins; + unsigned int npins; +}; + +struct ast2700_soc1_function { + const char *name; + const char *const *groups; + const u8 *muxvals; + unsigned int ngroups; +}; + +struct ast2700_soc1_pinctrl_priv { + void __iomem *scu; +}; + +#define PIN(n) \ + [n] = #n + +static const char *const ast2700_soc1_pin_names[] = { + PIN(C16), + PIN(C14), + PIN(C11), + PIN(D9), + PIN(F14), + PIN(D10), + PIN(C12), + PIN(C13), + PIN(AC26), + PIN(AA25), + PIN(AB23), + PIN(U22), + PIN(V21), + PIN(N26), + PIN(P25), + PIN(N25), + PIN(V23), + PIN(W22), + PIN(AB26), + PIN(AD26), + PIN(P26), + PIN(AE26), + PIN(AF26), + PIN(AF25), + PIN(AE25), + PIN(AD25), + PIN(AF23), + PIN(AF20), + PIN(AF21), + PIN(AE21), + PIN(AE23), + PIN(AD22), + PIN(AF17), + PIN(AA16), + PIN(Y16), + PIN(V17), + PIN(J13), + PIN(AB16), + PIN(AC16), + PIN(AF16), + PIN(AA15), + PIN(AB15), + PIN(AC15), + PIN(AD15), + PIN(Y15), + PIN(AA14), + PIN(W16), + PIN(V16), + PIN(AB18), + PIN(AC18), + PIN(K13), + PIN(AA17), + PIN(AB17), + PIN(AD16), + PIN(AC17), + PIN(AD17), + PIN(AE16), + PIN(AE17), + PIN(AB24), + PIN(W26), + PIN(HOLE0), + PIN(HOLE1), + PIN(HOLE2), + PIN(HOLE3), + PIN(W25), + PIN(Y23), + PIN(Y24), + PIN(W21), + PIN(AA23), + PIN(AC22), + PIN(AB22), + PIN(Y21), + PIN(AE20), + PIN(AF19), + PIN(Y22), + PIN(AA20), + PIN(AA22), + PIN(AB20), + PIN(AF18), + PIN(AE19), + PIN(AD20), + PIN(AC20), + PIN(AA21), + PIN(AB21), + PIN(AC19), + PIN(AE18), + PIN(AD19), + PIN(AD18), + PIN(U25), + PIN(U26), + PIN(Y26), + PIN(AA24), + PIN(R25), + PIN(AA26), + PIN(R26), + PIN(Y25), + PIN(B16), + PIN(D14), + PIN(B15), + PIN(B14), + PIN(C17), + PIN(B13), + PIN(E14), + PIN(C15), + PIN(D24), + PIN(B23), + PIN(B22), + PIN(C23), + PIN(B18), + PIN(B21), + PIN(M15), + PIN(B19), + PIN(B26), + PIN(A25), + PIN(A24), + PIN(B24), + PIN(E26), + PIN(A21), + PIN(A19), + PIN(A18), + PIN(D26), + PIN(C26), + PIN(A23), + PIN(A22), + PIN(B25), + PIN(F26), + PIN(A26), + PIN(A14), + PIN(E10), + PIN(E13), + PIN(D12), + PIN(F10), + PIN(E11), + PIN(F11), + PIN(F13), + PIN(N15), + PIN(C20), + PIN(C19), + PIN(A8), + PIN(R14), + PIN(A7), + PIN(P14), + PIN(D20), + PIN(A6), + PIN(B6), + PIN(N14), + PIN(B7), + PIN(B8), + PIN(B9), + PIN(M14), + PIN(J11), + PIN(E7), + PIN(D19), + PIN(B11), + PIN(D15), + PIN(B12), + PIN(B10), + PIN(P13), + PIN(C18), + PIN(C6), + PIN(C7), + PIN(D7), + PIN(N13), + PIN(C8), + PIN(C9), + PIN(C10), + PIN(M16), + PIN(A15), + PIN(G11), + PIN(H7), + PIN(H8), + PIN(H9), + PIN(H10), + PIN(H11), + PIN(J9), + PIN(J10), + PIN(E9), + PIN(F9), + PIN(F8), + PIN(M13), + PIN(F7), + PIN(D8), + PIN(E8), + PIN(L12), + PIN(F12), + PIN(E12), + PIN(J12), + PIN(G7), + PIN(G8), + PIN(G9), + PIN(G10), + PIN(K12), + PIN(W17), + PIN(V18), + PIN(W18), + PIN(Y17), + PIN(AA18), + PIN(AA13), + PIN(Y18), + PIN(AA12), + PIN(W20), + PIN(V20), + PIN(Y11), + PIN(V14), + PIN(V19), + PIN(W14), + PIN(Y20), + PIN(AB19), + PIN(U21), + PIN(T24), + PIN(V24), + PIN(V22), + PIN(T23), + PIN(AC25), + PIN(AB25), + PIN(AC24), + PIN(PCIERC2_PERST), + PIN(PORTC_MODE), + PIN(PORTD_MODE), + PIN(SGMII0), +}; + +#define PIN_GROUP(name, ...) \ + static const unsigned int name##_pins[] = { __VA_ARGS__ } + +/* Pin groups and functions */ +PIN_GROUP(ADC0, W17); +PIN_GROUP(ADC1, V18); +PIN_GROUP(ADC10, Y11); +PIN_GROUP(ADC11, V14); +PIN_GROUP(ADC12, V19); +PIN_GROUP(ADC13, W14); +PIN_GROUP(ADC14, Y20); +PIN_GROUP(ADC15, AB19); +PIN_GROUP(ADC2, W18); +PIN_GROUP(ADC3, Y17); +PIN_GROUP(ADC4, AA18); +PIN_GROUP(ADC5, AA13); +PIN_GROUP(ADC6, Y18); +PIN_GROUP(ADC7, AA12); +PIN_GROUP(ADC8, W20); +PIN_GROUP(ADC9, V20); +PIN_GROUP(AUXPWRGOOD0, W14); +PIN_GROUP(AUXPWRGOOD1, Y20); +PIN_GROUP(CANBUS, G7, G8, G9); +PIN_GROUP(DI2C0, C16, D9); +PIN_GROUP(DI2C1, C14, F14); +PIN_GROUP(DI2C10, R25, AA26); +PIN_GROUP(DI2C11, R26, Y25); +PIN_GROUP(DI2C12, W25, Y23); +PIN_GROUP(DI2C13, Y24, W21); +PIN_GROUP(DI2C14, AA23, AC22); +PIN_GROUP(DI2C15, AB22, Y21); +PIN_GROUP(DI2C2, D10, C12); +PIN_GROUP(DI2C3, C11, C13); +PIN_GROUP(DI2C8, U25, U26); +PIN_GROUP(DI2C9, Y26, AA24); +PIN_GROUP(DSGPM0, D19, B10, C7, D7); +PIN_GROUP(ESPI0, B16, D14, B15, B14, C17, B13, E14, C15); +PIN_GROUP(ESPI1, C16, C14, C11, D9, F14, D10, C12, C13); +PIN_GROUP(FSI0, AD20, AC20); +PIN_GROUP(FSI1, AA21, AB21); +PIN_GROUP(FSI2, AC19, AE18); +PIN_GROUP(FSI3, AD19, AD18); +PIN_GROUP(FWQSPI, M16, A15); +PIN_GROUP(FWSPIABR, A14); +PIN_GROUP(FWWPN, N15); +PIN_GROUP(HBLED, V24); +PIN_GROUP(HVI3C0, U25, U26); +PIN_GROUP(HVI3C1, Y26, AA24); +PIN_GROUP(HVI3C12, W25, Y23); +PIN_GROUP(HVI3C13, Y24, W21); +PIN_GROUP(HVI3C14, AA23, AC22); +PIN_GROUP(HVI3C15, AB22, Y21); +PIN_GROUP(HVI3C2, R25, AA26); +PIN_GROUP(HVI3C3, R26, Y25); +PIN_GROUP(I2C0, G11, H7); +PIN_GROUP(I2C1, H8, H9); +PIN_GROUP(I2C10, G8, G9); +PIN_GROUP(I2C11, G10, K12); +PIN_GROUP(I2C12, AC18, AA17); +PIN_GROUP(I2C13, AB17, AD16); +PIN_GROUP(I2C14, AC17, AD17); +PIN_GROUP(I2C15, AE16, AE17); +PIN_GROUP(I2C2, H10, H11); +PIN_GROUP(I2C3, J9, J10); +PIN_GROUP(I2C4, E9, F9); +PIN_GROUP(I2C5, F8, M13); +PIN_GROUP(I2C6, F7, D8); +PIN_GROUP(I2C7, E8, L12); +PIN_GROUP(I2C8, F12, E12); +PIN_GROUP(I2C9, J12, G7); +PIN_GROUP(I2CF0, F12, E12, J12, G7); +PIN_GROUP(I2CF1, E9, F9, F8, M13); +PIN_GROUP(I2CF2, F7, D8, E8, L12); +PIN_GROUP(I3C10, AC19, AE18); +PIN_GROUP(I3C11, AD19, AD18); +PIN_GROUP(I3C4, AE20, AF19); +PIN_GROUP(I3C5, Y22, AA20); +PIN_GROUP(I3C6, AA22, AB20); +PIN_GROUP(I3C7, AF18, AE19); +PIN_GROUP(I3C8, AD20, AC20); +PIN_GROUP(I3C9, AA21, AB21); +PIN_GROUP(JTAGM1, D12, F10, E11, F11, F13); +PIN_GROUP(LPC0, AF26, AF25, B16, D14, B15, B14, C17, B13, E14, C15); +PIN_GROUP(LPC1, C16, C14, C11, D9, F14, D10, C12, C13, AE16, AE17); +PIN_GROUP(LTPI, U25, U26, Y26, AA24); +PIN_GROUP(LTPI_PS_I2C0, G11, H7); +PIN_GROUP(LTPI_PS_I2C1, H8, H9); +PIN_GROUP(LTPI_PS_I2C2, H10, H11); +PIN_GROUP(LTPI_PS_I2C3, J9, J10); +PIN_GROUP(MACLINK0, U21); +PIN_GROUP(MACLINK1, AC24); +PIN_GROUP(MACLINK2, T24); +PIN_GROUP(MDIO0, B9, M14); +PIN_GROUP(MDIO1, C9, C10); +PIN_GROUP(MDIO2, E10, E13); +PIN_GROUP(NCTS0, AF17); +PIN_GROUP(NCTS1, AA15); +PIN_GROUP(NCTS5, V21); +PIN_GROUP(NCTS6, AB26); +PIN_GROUP(NDCD0, AA16); +PIN_GROUP(NDCD1, AB15); +PIN_GROUP(NDCD5, N26); +PIN_GROUP(NDCD6, AD26); +PIN_GROUP(NDSR0, Y16); +PIN_GROUP(NDSR1, AC15); +PIN_GROUP(NDSR5, P25); +PIN_GROUP(NDSR6, P26); +PIN_GROUP(NDTR0, J13); +PIN_GROUP(NDTR1, Y15); +PIN_GROUP(NDTR5, V23); +PIN_GROUP(NDTR6, AF26); +PIN_GROUP(NRI0, V17); +PIN_GROUP(NRI1, AD15); +PIN_GROUP(NRI5, N25); +PIN_GROUP(NRI6, AE26); +PIN_GROUP(NRTS0, AB16); +PIN_GROUP(NRTS1, AA14); +PIN_GROUP(NRTS5, W22); +PIN_GROUP(NRTS6, AF25); +PIN_GROUP(OSCCLK, C17); +PIN_GROUP(PE2SGRSTN, E10, PCIERC2_PERST); +PIN_GROUP(PWM0, AE25); +PIN_GROUP(PWM1, AD25); +PIN_GROUP(PWM10, AB17); +PIN_GROUP(PWM11, AD16); +PIN_GROUP(PWM12, AC17); +PIN_GROUP(PWM13, AD17); +PIN_GROUP(PWM14, AE16); +PIN_GROUP(PWM15, AE17); +PIN_GROUP(PWM2, AF23); +PIN_GROUP(PWM3, AF20); +PIN_GROUP(PWM4, AF21); +PIN_GROUP(PWM5, AE21); +PIN_GROUP(PWM6, AE23); +PIN_GROUP(PWM7, AD22); +PIN_GROUP(PWM8, K13); +PIN_GROUP(PWM9, AA17); +PIN_GROUP(QSPI0, C23, B18); +PIN_GROUP(QSPI1, B24, E26); +PIN_GROUP(QSPI2, B25, F26); +PIN_GROUP(RGMII0, C20, C19, A8, R14, A7, P14, D20, A6, B6, N14, B7, B8); +PIN_GROUP(RGMII1, D19, B11, D15, B12, B10, P13, C18, C6, C7, D7, N13, C8); +PIN_GROUP(RMII0, C20, A8, R14, A7, P14, A6, B6, N14); +PIN_GROUP(RMII0RCLKO, D20); +PIN_GROUP(RMII1, D19, D15, B12, B10, P13, C6, C7, D7); +PIN_GROUP(RMII1RCLKO, C18); +PIN_GROUP(SALT0, AC17); +PIN_GROUP(SALT1, AD17); +PIN_GROUP(SALT10, Y18); +PIN_GROUP(SALT11, AA12); +PIN_GROUP(SALT12, AB26); +PIN_GROUP(SALT13, AD26); +PIN_GROUP(SALT14, P26); +PIN_GROUP(SALT15, AE26); +PIN_GROUP(SALT2, AC15); +PIN_GROUP(SALT3, AD15); +PIN_GROUP(SALT4, W17); +PIN_GROUP(SALT5, V18); +PIN_GROUP(SALT6, W18); +PIN_GROUP(SALT7, Y17); +PIN_GROUP(SALT8, AA18); +PIN_GROUP(SALT9, AA13); +PIN_GROUP(SD, C16, C14, C11, D9, F14, D10, C12, C13); +PIN_GROUP(SGMII, SGMII0); +PIN_GROUP(SGPM0, U21, T24, V22, T23); +PIN_GROUP(SGPM1, AC25, AB25, AB24, W26); +PIN_GROUP(SGPS, B11, C18, N13, C8); +PIN_GROUP(SIOONCTRLN0, AE23); +PIN_GROUP(SIOONCTRLN1, AA15); +PIN_GROUP(SIOPBIN0, AD25); +PIN_GROUP(SIOPBIN1, AA16); +PIN_GROUP(SIOPBON0, AE25); +PIN_GROUP(SIOPBON1, AF17); +PIN_GROUP(SIOPWREQN0, AE21); +PIN_GROUP(SIOPWREQN1, AB16); +PIN_GROUP(SIOPWRGD1, AB15); +PIN_GROUP(SIOS3N0, AF20); +PIN_GROUP(SIOS3N1, V17); +PIN_GROUP(SIOS5N0, AF21); +PIN_GROUP(SIOS5N1, J13); +PIN_GROUP(SIOSCIN0, AF23); +PIN_GROUP(SIOSCIN1, Y16); +PIN_GROUP(SMON0, U21, T24, V22, T23); +PIN_GROUP(SMON1, W26, AC25, AB25); +PIN_GROUP(SPI0, D24, B23, B22); +PIN_GROUP(SPI0ABR, M15); +PIN_GROUP(SPI0CS1, B21); +PIN_GROUP(SPI0WPN, B19); +PIN_GROUP(SPI1, B26, A25, A24); +PIN_GROUP(SPI1ABR, A19); +PIN_GROUP(SPI1CS1, A21); +PIN_GROUP(SPI1WPN, A18); +PIN_GROUP(SPI2, D26, C26, A23, A22); +PIN_GROUP(SPI2CS1, A26); +PIN_GROUP(TACH0, AC26); +PIN_GROUP(TACH1, AA25); +PIN_GROUP(TACH10, AB26); +PIN_GROUP(TACH11, AD26); +PIN_GROUP(TACH12, P26); +PIN_GROUP(TACH13, AE26); +PIN_GROUP(TACH14, AF26); +PIN_GROUP(TACH15, AF25); +PIN_GROUP(TACH2, AB23); +PIN_GROUP(TACH3, U22); +PIN_GROUP(TACH4, V21); +PIN_GROUP(TACH5, N26); +PIN_GROUP(TACH6, P25); +PIN_GROUP(TACH7, N25); +PIN_GROUP(TACH8, V23); +PIN_GROUP(TACH9, W22); +PIN_GROUP(THRU0, AC26, AA25); +PIN_GROUP(THRU1, AB23, U22); +PIN_GROUP(THRU2, A19, A18); +PIN_GROUP(THRU3, B25, F26); +PIN_GROUP(UART0, AC16, AF16); +PIN_GROUP(UART1, W16, V16); +PIN_GROUP(UART2, AB18, AC18); +PIN_GROUP(UART3, K13, AA17); +PIN_GROUP(UART5, AB17, AD16); +PIN_GROUP(UART6, AC17, AD17); +PIN_GROUP(UART7, AE16, AE17); +PIN_GROUP(UART8, M15, B19); +PIN_GROUP(UART9, B26, A25); +PIN_GROUP(UART10, A24, B24); +PIN_GROUP(UART11, E26, A21); +PIN_GROUP(USB2CD, PORTC_MODE); +PIN_GROUP(USB2CH, PORTC_MODE); +PIN_GROUP(USB2CU, PORTC_MODE); +PIN_GROUP(USB2CUD, PORTC_MODE); +PIN_GROUP(USB2DD, PORTD_MODE); +PIN_GROUP(USB2DH, PORTD_MODE); +PIN_GROUP(USBUART, G10, K12); +PIN_GROUP(VGA, J11, E7); +PIN_GROUP(VPI, C16, C14, C11, D9, F14, D10, AC26, AA25, AB23, U22, V21, N26, + P25, N25, V23, W22, AB26, AD26, P26, AE26, AF26, AF25, AE25, AD25, + AF23, AF20, AF21, AE21); +PIN_GROUP(WDTRST0N, K13); +PIN_GROUP(WDTRST1N, AA17); +PIN_GROUP(WDTRST2N, AB17); +PIN_GROUP(WDTRST3N, AD16); +PIN_GROUP(WDTRST4N, AC25); +PIN_GROUP(WDTRST5N, AB25); +PIN_GROUP(WDTRST6N, AC24); +PIN_GROUP(WDTRST7N, AB24); + +#define GROUP(n) \ + { .name = #n, .pins = n##_pins, .npins = ARRAY_SIZE(n##_pins) } + +static const struct ast2700_soc1_group ast2700_soc1_groups[] = { + GROUP(ADC0), + GROUP(ADC1), + GROUP(ADC10), + GROUP(ADC11), + GROUP(ADC12), + GROUP(ADC13), + GROUP(ADC14), + GROUP(ADC15), + GROUP(ADC2), + GROUP(ADC3), + GROUP(ADC4), + GROUP(ADC5), + GROUP(ADC6), + GROUP(ADC7), + GROUP(ADC8), + GROUP(ADC9), + GROUP(AUXPWRGOOD0), + GROUP(AUXPWRGOOD1), + GROUP(CANBUS), + GROUP(DI2C0), + GROUP(DI2C1), + GROUP(DI2C10), + GROUP(DI2C11), + GROUP(DI2C12), + GROUP(DI2C13), + GROUP(DI2C14), + GROUP(DI2C15), + GROUP(DI2C2), + GROUP(DI2C3), + GROUP(DI2C8), + GROUP(DI2C9), + GROUP(DSGPM0), + GROUP(ESPI0), + GROUP(ESPI1), + GROUP(FSI0), + GROUP(FSI1), + GROUP(FSI2), + GROUP(FSI3), + GROUP(FWQSPI), + GROUP(FWSPIABR), + GROUP(FWWPN), + GROUP(HBLED), + GROUP(HVI3C0), + GROUP(HVI3C1), + GROUP(HVI3C12), + GROUP(HVI3C13), + GROUP(HVI3C14), + GROUP(HVI3C15), + GROUP(HVI3C2), + GROUP(HVI3C3), + GROUP(I2C0), + GROUP(I2C1), + GROUP(I2C10), + GROUP(I2C11), + GROUP(I2C12), + GROUP(I2C13), + GROUP(I2C14), + GROUP(I2C15), + GROUP(I2C2), + GROUP(I2C3), + GROUP(I2C4), + GROUP(I2C5), + GROUP(I2C6), + GROUP(I2C7), + GROUP(I2C8), + GROUP(I2C9), + GROUP(I2CF0), + GROUP(I2CF1), + GROUP(I2CF2), + GROUP(I3C10), + GROUP(I3C11), + GROUP(I3C4), + GROUP(I3C5), + GROUP(I3C6), + GROUP(I3C7), + GROUP(I3C8), + GROUP(I3C9), + GROUP(JTAGM1), + GROUP(LPC0), + GROUP(LPC1), + GROUP(LTPI), + GROUP(LTPI_PS_I2C0), + GROUP(LTPI_PS_I2C1), + GROUP(LTPI_PS_I2C2), + GROUP(LTPI_PS_I2C3), + GROUP(MACLINK0), + GROUP(MACLINK1), + GROUP(MACLINK2), + GROUP(MDIO0), + GROUP(MDIO1), + GROUP(MDIO2), + GROUP(NCTS0), + GROUP(NCTS1), + GROUP(NCTS5), + GROUP(NCTS6), + GROUP(NDCD0), + GROUP(NDCD1), + GROUP(NDCD5), + GROUP(NDCD6), + GROUP(NDSR0), + GROUP(NDSR1), + GROUP(NDSR5), + GROUP(NDSR6), + GROUP(NDTR0), + GROUP(NDTR1), + GROUP(NDTR5), + GROUP(NDTR6), + GROUP(NRI0), + GROUP(NRI1), + GROUP(NRI5), + GROUP(NRI6), + GROUP(NRTS0), + GROUP(NRTS1), + GROUP(NRTS5), + GROUP(NRTS6), + GROUP(OSCCLK), + GROUP(PE2SGRSTN), + GROUP(PWM0), + GROUP(PWM1), + GROUP(PWM10), + GROUP(PWM11), + GROUP(PWM12), + GROUP(PWM13), + GROUP(PWM14), + GROUP(PWM15), + GROUP(PWM2), + GROUP(PWM3), + GROUP(PWM4), + GROUP(PWM5), + GROUP(PWM6), + GROUP(PWM7), + GROUP(PWM8), + GROUP(PWM9), + GROUP(QSPI0), + GROUP(QSPI1), + GROUP(QSPI2), + GROUP(RGMII0), + GROUP(RGMII1), + GROUP(RMII0), + GROUP(RMII0RCLKO), + GROUP(RMII1), + GROUP(RMII1RCLKO), + GROUP(SALT0), + GROUP(SALT1), + GROUP(SALT10), + GROUP(SALT11), + GROUP(SALT12), + GROUP(SALT13), + GROUP(SALT14), + GROUP(SALT15), + GROUP(SALT2), + GROUP(SALT3), + GROUP(SALT4), + GROUP(SALT5), + GROUP(SALT6), + GROUP(SALT7), + GROUP(SALT8), + GROUP(SALT9), + GROUP(SD), + GROUP(SGMII), + GROUP(SGPM0), + GROUP(SGPM1), + GROUP(SGPS), + GROUP(SIOONCTRLN0), + GROUP(SIOONCTRLN1), + GROUP(SIOPBIN0), + GROUP(SIOPBIN1), + GROUP(SIOPBON0), + GROUP(SIOPBON1), + GROUP(SIOPWREQN0), + GROUP(SIOPWREQN1), + GROUP(SIOPWRGD1), + GROUP(SIOS3N0), + GROUP(SIOS3N1), + GROUP(SIOS5N0), + GROUP(SIOS5N1), + GROUP(SIOSCIN0), + GROUP(SIOSCIN1), + GROUP(SMON0), + GROUP(SMON1), + GROUP(SPI0), + GROUP(SPI0ABR), + GROUP(SPI0CS1), + GROUP(SPI0WPN), + GROUP(SPI1), + GROUP(SPI1ABR), + GROUP(SPI1CS1), + GROUP(SPI1WPN), + GROUP(SPI2), + GROUP(SPI2CS1), + GROUP(TACH0), + GROUP(TACH1), + GROUP(TACH10), + GROUP(TACH11), + GROUP(TACH12), + GROUP(TACH13), + GROUP(TACH14), + GROUP(TACH15), + GROUP(TACH2), + GROUP(TACH3), + GROUP(TACH4), + GROUP(TACH5), + GROUP(TACH6), + GROUP(TACH7), + GROUP(TACH8), + GROUP(TACH9), + GROUP(THRU0), + GROUP(THRU1), + GROUP(THRU2), + GROUP(THRU3), + GROUP(UART0), + GROUP(UART1), + GROUP(UART10), + GROUP(UART11), + GROUP(UART2), + GROUP(UART3), + GROUP(UART5), + GROUP(UART6), + GROUP(UART7), + GROUP(UART8), + GROUP(UART9), + GROUP(USB2CD), + GROUP(USB2CH), + GROUP(USB2CU), + GROUP(USB2CUD), + GROUP(USB2DD), + GROUP(USB2DH), + GROUP(USBUART), + GROUP(VGA), + GROUP(VPI), + GROUP(WDTRST0N), + GROUP(WDTRST1N), + GROUP(WDTRST2N), + GROUP(WDTRST3N), + GROUP(WDTRST4N), + GROUP(WDTRST5N), + GROUP(WDTRST6N), + GROUP(WDTRST7N), +}; + +/** + * VM() - Helper macro to unwrap a parenthesized list of arguments. + * @...: The parenthesized list to be unwrapped. + * + * Since the C preprocessor treats commas inside braces {} as argument + * separators for macros, wrap mux value lists in parentheses and strip + * them here when initializing the compound literal. + */ +#define VM(...) __VA_ARGS__ + +/** + * FUNC() - Initialize an ast2700_soc1_function entry. + * @n: Name of the pin function. + * @m: Parenthesized list of mux values mapped 1:1 to the groups list. + * @...: Variable list of pin group names associated with this function. + */ +#define FUNC(n, m, ...) \ + { \ + .name = #n, \ + .groups = (const char *const[]){ __VA_ARGS__ }, \ + .muxvals = (const u8[]){ VM m }, \ + .ngroups = sizeof((const char *const[]){ __VA_ARGS__ }) / \ + sizeof(char *), \ + } + +static const struct ast2700_soc1_function ast2700_soc1_functions[] = { + FUNC(ADC0, (0), "ADC0"), + FUNC(ADC1, (0), "ADC1"), + FUNC(ADC10, (0), "ADC10"), + FUNC(ADC11, (0), "ADC11"), + FUNC(ADC12, (0), "ADC12"), + FUNC(ADC13, (0), "ADC13"), + FUNC(ADC14, (0), "ADC14"), + FUNC(ADC15, (0), "ADC15"), + FUNC(ADC2, (0), "ADC2"), + FUNC(ADC3, (0), "ADC3"), + FUNC(ADC4, (0), "ADC4"), + FUNC(ADC5, (0), "ADC5"), + FUNC(ADC6, (0), "ADC6"), + FUNC(ADC7, (0), "ADC7"), + FUNC(ADC8, (0), "ADC8"), + FUNC(ADC9, (0), "ADC9"), + FUNC(AUXPWRGOOD0, (2), "AUXPWRGOOD0"), + FUNC(AUXPWRGOOD1, (2), "AUXPWRGOOD1"), + FUNC(CANBUS, (2), "CANBUS"), + FUNC(ESPI0, (1), "ESPI0"), + FUNC(ESPI1, (1), "ESPI1"), + FUNC(FSI0, (2), "FSI0"), + FUNC(FSI1, (2), "FSI1"), + FUNC(FSI2, (2), "FSI2"), + FUNC(FSI3, (2), "FSI3"), + FUNC(FWQSPI, (1), "FWQSPI"), + FUNC(FWSPIABR, (1), "FWSPIABR"), + FUNC(FWWPN, (1), "FWWPN"), + FUNC(HBLED, (2), "HBLED"), + FUNC(I2C0, (1, 2, 4), "I2C0", "LTPI_PS_I2C0", "DI2C0"), + FUNC(I2C1, (1, 2, 4), "I2C1", "LTPI_PS_I2C1", "DI2C1"), + FUNC(I2C10, (1, 2), "I2C10", "DI2C10"), + FUNC(I2C11, (1, 2), "I2C11", "DI2C11"), + FUNC(I2C12, (4, 2), "I2C12", "DI2C12"), + FUNC(I2C13, (4, 2), "I2C13", "DI2C13"), + FUNC(I2C14, (4, 2), "I2C14", "DI2C14"), + FUNC(I2C15, (2, 2), "I2C15", "DI2C15"), + FUNC(I2C2, (1, 2, 4), "I2C2", "LTPI_PS_I2C2", "DI2C2"), + FUNC(I2C3, (1, 2, 4), "I2C3", "LTPI_PS_I2C3", "DI2C3"), + FUNC(I2C4, (1), "I2C4"), + FUNC(I2C5, (1), "I2C5"), + FUNC(I2C6, (1), "I2C6"), + FUNC(I2C7, (1), "I2C7"), + FUNC(I2C8, (1, 2), "I2C8", "DI2C8"), + FUNC(I2C9, (1, 2), "I2C9", "DI2C9"), + FUNC(I2CF0, (5), "I2CF0"), + FUNC(I2CF1, (5), "I2CF1"), + FUNC(I2CF2, (5), "I2CF2"), + FUNC(I3C0, (1), "HVI3C0"), + FUNC(I3C1, (1), "HVI3C1"), + FUNC(I3C10, (1), "I3C10"), + FUNC(I3C11, (1), "I3C11"), + FUNC(I3C12, (1), "HVI3C12"), + FUNC(I3C13, (1), "HVI3C13"), + FUNC(I3C14, (1), "HVI3C14"), + FUNC(I3C15, (1), "HVI3C15"), + FUNC(I3C2, (1), "HVI3C2"), + FUNC(I3C3, (1), "HVI3C3"), + FUNC(I3C4, (1), "I3C4"), + FUNC(I3C5, (1), "I3C5"), + FUNC(I3C6, (1), "I3C6"), + FUNC(I3C7, (1), "I3C7"), + FUNC(I3C8, (1), "I3C8"), + FUNC(I3C9, (1), "I3C9"), + FUNC(JTAGM1, (1), "JTAGM1"), + FUNC(LPC0, (2), "LPC0"), + FUNC(LPC1, (2), "LPC1"), + FUNC(LTPI, (2), "LTPI"), + FUNC(MACLINK0, (4), "MACLINK0"), + FUNC(MACLINK1, (3), "MACLINK1"), + FUNC(MACLINK2, (4), "MACLINK2"), + FUNC(MDIO0, (1), "MDIO0"), + FUNC(MDIO1, (1), "MDIO1"), + FUNC(MDIO2, (1), "MDIO2"), + FUNC(NCTS0, (1), "NCTS0"), + FUNC(NCTS1, (1), "NCTS1"), + FUNC(NCTS5, (4), "NCTS5"), + FUNC(NCTS6, (4), "NCTS6"), + FUNC(NDCD0, (1), "NDCD0"), + FUNC(NDCD1, (1), "NDCD1"), + FUNC(NDCD5, (4), "NDCD5"), + FUNC(NDCD6, (4), "NDCD6"), + FUNC(NDSR0, (1), "NDSR0"), + FUNC(NDSR1, (1), "NDSR1"), + FUNC(NDSR5, (4), "NDSR5"), + FUNC(NDSR6, (4), "NDSR6"), + FUNC(NDTR0, (1), "NDTR0"), + FUNC(NDTR1, (1), "NDTR1"), + FUNC(NDTR5, (4), "NDTR5"), + FUNC(NDTR6, (4), "NDTR6"), + FUNC(NRI0, (1), "NRI0"), + FUNC(NRI1, (1), "NRI1"), + FUNC(NRI5, (4), "NRI5"), + FUNC(NRI6, (4), "NRI6"), + FUNC(NRTS0, (1), "NRTS0"), + FUNC(NRTS1, (1), "NRTS1"), + FUNC(NRTS5, (4), "NRTS5"), + FUNC(NRTS6, (4), "NRTS6"), + FUNC(OSCCLK, (3), "OSCCLK"), + FUNC(PCIERC, (2), "PE2SGRSTN"), + FUNC(PWM0, (1), "PWM0"), + FUNC(PWM1, (1), "PWM1"), + FUNC(PWM10, (3), "PWM10"), + FUNC(PWM11, (3), "PWM11"), + FUNC(PWM12, (3), "PWM12"), + FUNC(PWM13, (3), "PWM13"), + FUNC(PWM14, (3), "PWM14"), + FUNC(PWM15, (3), "PWM15"), + FUNC(PWM2, (1), "PWM2"), + FUNC(PWM3, (1), "PWM3"), + FUNC(PWM4, (1), "PWM4"), + FUNC(PWM5, (1), "PWM5"), + FUNC(PWM6, (1), "PWM6"), + FUNC(PWM7, (1), "PWM7"), + FUNC(PWM8, (3), "PWM8"), + FUNC(PWM9, (3), "PWM9"), + FUNC(QSPI0, (1), "QSPI0"), + FUNC(QSPI1, (1), "QSPI1"), + FUNC(QSPI2, (1), "QSPI2"), + FUNC(RGMII0, (1), "RGMII0"), + FUNC(RGMII1, (1), "RGMII1"), + FUNC(RMII0, (2), "RMII0"), + FUNC(RMII0RCLKO, (2), "RMII0RCLKO"), + FUNC(RMII1, (2), "RMII1"), + FUNC(RMII1RCLKO, (2), "RMII1RCLKO"), + FUNC(SALT0, (2), "SALT0"), + FUNC(SALT1, (2), "SALT1"), + FUNC(SALT10, (2), "SALT10"), + FUNC(SALT11, (2), "SALT11"), + FUNC(SALT12, (2), "SALT12"), + FUNC(SALT13, (2), "SALT13"), + FUNC(SALT14, (2), "SALT14"), + FUNC(SALT15, (2), "SALT15"), + FUNC(SALT2, (2), "SALT2"), + FUNC(SALT3, (2), "SALT3"), + FUNC(SALT4, (2), "SALT4"), + FUNC(SALT5, (2), "SALT5"), + FUNC(SALT6, (2), "SALT6"), + FUNC(SALT7, (2), "SALT7"), + FUNC(SALT8, (2), "SALT8"), + FUNC(SALT9, (2), "SALT9"), + FUNC(SD, (3), "SD"), + FUNC(SGMII, (1), "SGMII"), + FUNC(SGPM0, (1, 4), "SGPM0", "DSGPM0"), + FUNC(SGPM1, (1), "SGPM1"), + FUNC(SGPS, (5), "SGPS"), + FUNC(SIOONCTRLN0, (2), "SIOONCTRLN0"), + FUNC(SIOONCTRLN1, (2), "SIOONCTRLN1"), + FUNC(SIOPBIN0, (2), "SIOPBIN0"), + FUNC(SIOPBIN1, (2), "SIOPBIN1"), + FUNC(SIOPBON0, (2), "SIOPBON0"), + FUNC(SIOPBON1, (2), "SIOPBON1"), + FUNC(SIOPWREQN0, (2), "SIOPWREQN0"), + FUNC(SIOPWREQN1, (2), "SIOPWREQN1"), + FUNC(SIOPWRGD1, (2), "SIOPWRGD1"), + FUNC(SIOS3N0, (2), "SIOS3N0"), + FUNC(SIOS3N1, (2), "SIOS3N1"), + FUNC(SIOS5N0, (2), "SIOS5N0"), + FUNC(SIOS5N1, (2), "SIOS5N1"), + FUNC(SIOSCIN0, (2), "SIOSCIN0"), + FUNC(SIOSCIN1, (2), "SIOSCIN1"), + FUNC(SMON0, (2), "SMON0"), + FUNC(SMON1, (4), "SMON1"), + FUNC(SPI0, (1), "SPI0"), + FUNC(SPI0ABR, (1), "SPI0ABR"), + FUNC(SPI0CS1, (1), "SPI0CS1"), + FUNC(SPI0WPN, (1), "SPI0WPN"), + FUNC(SPI1, (1), "SPI1"), + FUNC(SPI1ABR, (1), "SPI1ABR"), + FUNC(SPI1CS1, (1), "SPI1CS1"), + FUNC(SPI1WPN, (1), "SPI1WPN"), + FUNC(SPI2, (1), "SPI2"), + FUNC(SPI2CS1, (1), "SPI2CS1"), + FUNC(TACH0, (1), "TACH0"), + FUNC(TACH1, (1), "TACH1"), + FUNC(TACH10, (1), "TACH10"), + FUNC(TACH11, (1), "TACH11"), + FUNC(TACH12, (1), "TACH12"), + FUNC(TACH13, (1), "TACH13"), + FUNC(TACH14, (1), "TACH14"), + FUNC(TACH15, (1), "TACH15"), + FUNC(TACH2, (1), "TACH2"), + FUNC(TACH3, (1), "TACH3"), + FUNC(TACH4, (1), "TACH4"), + FUNC(TACH5, (1), "TACH5"), + FUNC(TACH6, (1), "TACH6"), + FUNC(TACH7, (1), "TACH7"), + FUNC(TACH8, (1), "TACH8"), + FUNC(TACH9, (1), "TACH9"), + FUNC(THRU0, (2), "THRU0"), + FUNC(THRU1, (2), "THRU1"), + FUNC(THRU2, (4), "THRU2"), + FUNC(THRU3, (4), "THRU3"), + FUNC(UART0, (1), "UART0"), + FUNC(UART1, (1), "UART1"), + FUNC(UART10, (3), "UART10"), + FUNC(UART11, (3), "UART11"), + FUNC(UART2, (1), "UART2"), + FUNC(UART3, (1), "UART3"), + FUNC(UART5, (1), "UART5"), + FUNC(UART6, (1), "UART6"), + FUNC(UART7, (1), "UART7"), + FUNC(UART8, (3), "UART8"), + FUNC(UART9, (3), "UART9"), + FUNC(USB2C, (0, 1, 2, 3), "USB2CUD", "USB2CD", "USB2CH", "USB2CU"), + FUNC(USB2D, (1, 2), "USB2DD", "USB2DH"), + FUNC(USBUART, (2), "USBUART"), + FUNC(VGA, (1), "VGA"), + FUNC(VPI, (5), "VPI"), + FUNC(WDTRST0N, (2), "WDTRST0N"), + FUNC(WDTRST1N, (2), "WDTRST1N"), + FUNC(WDTRST2N, (2), "WDTRST2N"), + FUNC(WDTRST3N, (2), "WDTRST3N"), + FUNC(WDTRST4N, (2), "WDTRST4N"), + FUNC(WDTRST5N, (2), "WDTRST5N"), + FUNC(WDTRST6N, (2), "WDTRST6N"), + FUNC(WDTRST7N, (2), "WDTRST7N"), +}; + +static struct ast2700_soc1_field +ast2700_soc1_pinmux_field_from_pin(unsigned int pin) +{ + return (struct ast2700_soc1_field){ + .reg = AST2700_SOC1_MUX_BASE + + (pin / AST2700_SOC1_MUX_PINS_PER_REG) * sizeof(u32), + .shift = (pin % AST2700_SOC1_MUX_PINS_PER_REG) * + AST2700_SOC1_MUX_BITS_PER_PIN, + .mask = AST2700_SOC1_MUX_MASK, + }; +} + +static void __iomem *ast2700_soc1_reg(struct ast2700_soc1_pinctrl_priv *priv, + unsigned int offset) +{ + return (u8 __iomem *)priv->scu + offset; +} + +static struct ast2700_soc1_field +ast2700_soc1_field_from_pin(unsigned int pin) +{ + switch (pin) { + case PCIERC2_PERST: + return (struct ast2700_soc1_field){ + .reg = AST2700_SOC1_PCIE_REG, + .shift = 0, + .mask = 0x1, + }; + case PORTC_MODE: + return (struct ast2700_soc1_field){ + .reg = AST2700_SOC1_USB_MODE_REG, + .shift = 0, + .mask = 0x3, + }; + case PORTD_MODE: + return (struct ast2700_soc1_field){ + .reg = AST2700_SOC1_USB_MODE_REG, + .shift = 2, + .mask = 0x3, + }; + case SGMII0: + return (struct ast2700_soc1_field){ + .reg = AST2700_SOC1_SGMII_REG, + .shift = 0, + .mask = 0x1, + }; + default: + return ast2700_soc1_pinmux_field_from_pin(pin); + } +} + +static void +ast2700_soc1_set_muxval(struct ast2700_soc1_pinctrl_priv *priv, + unsigned int pin, unsigned int muxval) +{ + struct ast2700_soc1_field field = ast2700_soc1_field_from_pin(pin); + + /* + * PCIERC2_PERST is controlled by a 1-bit enable instead of the + * function mux value. + */ + if (pin == PCIERC2_PERST) + muxval = 1; + + clrsetbits_le32(ast2700_soc1_reg(priv, field.reg), + field.mask << field.shift, + (muxval & field.mask) << field.shift); +} + +static int ast2700_soc1_pinctrl_get_pins_count(struct udevice *dev) +{ + return ARRAY_SIZE(ast2700_soc1_pin_names); +} + +static const char * +ast2700_soc1_pinctrl_get_pin_name(struct udevice *dev, unsigned int selector) +{ + if (selector >= ARRAY_SIZE(ast2700_soc1_pin_names)) + return NULL; + + return ast2700_soc1_pin_names[selector]; +} + +static const struct ast2700_soc1_group * +ast2700_soc1_find_group(const char *name) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ast2700_soc1_groups); i++) { + if (!strcmp(ast2700_soc1_groups[i].name, name)) + return &ast2700_soc1_groups[i]; + } + + return NULL; +} + +static int ast2700_soc1_pinctrl_get_pin_muxing(struct udevice *dev, + unsigned int selector, + char *buf, int size) +{ + struct ast2700_soc1_pinctrl_priv *priv = dev_get_priv(dev); + const struct ast2700_soc1_function *func; + const struct ast2700_soc1_group *group; + struct ast2700_soc1_field field; + unsigned int muxval, want, f, g, i; + bool adc_pin; + + if (selector >= ARRAY_SIZE(ast2700_soc1_pin_names)) + return -EINVAL; + + field = ast2700_soc1_field_from_pin(selector); + muxval = (readl(ast2700_soc1_reg(priv, field.reg)) >> field.shift) & + field.mask; + + /* Mux value 0 selects GPIO, except on the ADC balls where it is 1 */ + adc_pin = selector >= W17 && selector <= AB19; + if (selector <= AC24 && muxval == (adc_pin ? 1 : 0)) { + snprintf(buf, size, "GPIO"); + return 0; + } + + for (f = 0; f < ARRAY_SIZE(ast2700_soc1_functions); f++) { + func = &ast2700_soc1_functions[f]; + for (g = 0; g < func->ngroups; g++) { + want = func->muxvals[g]; + /* PCIERC2_PERST is a 1-bit enable, not a mux value */ + if (selector == PCIERC2_PERST) + want = 1; + if (want != muxval) + continue; + group = ast2700_soc1_find_group(func->groups[g]); + if (!group) + continue; + for (i = 0; i < group->npins; i++) { + if (group->pins[i] != selector) + continue; + snprintf(buf, size, "%s (%s)", func->name, + group->name); + return 0; + } + } + } + + snprintf(buf, size, "unknown (mux 0x%x)", muxval); + + return 0; +} + +static int ast2700_soc1_pinctrl_get_groups_count(struct udevice *dev) +{ + return ARRAY_SIZE(ast2700_soc1_groups); +} + +static const char * +ast2700_soc1_pinctrl_get_group_name(struct udevice *dev, + unsigned int selector) +{ + if (selector >= ARRAY_SIZE(ast2700_soc1_groups)) + return NULL; + + return ast2700_soc1_groups[selector].name; +} + +static int ast2700_soc1_pinctrl_get_functions_count(struct udevice *dev) +{ + return ARRAY_SIZE(ast2700_soc1_functions); +} + +static const char * +ast2700_soc1_pinctrl_get_function_name(struct udevice *dev, + unsigned int selector) +{ + if (selector >= ARRAY_SIZE(ast2700_soc1_functions)) + return NULL; + + return ast2700_soc1_functions[selector].name; +} + +static int +ast2700_soc1_pinctrl_group_set(struct udevice *dev, + unsigned int group_selector, + unsigned int func_selector) +{ + struct ast2700_soc1_pinctrl_priv *priv = dev_get_priv(dev); + const struct ast2700_soc1_function *func; + const struct ast2700_soc1_group *group; + unsigned int muxval = 0; + unsigned int i; + + if (group_selector >= ARRAY_SIZE(ast2700_soc1_groups) || + func_selector >= ARRAY_SIZE(ast2700_soc1_functions)) + return -EINVAL; + + group = &ast2700_soc1_groups[group_selector]; + func = &ast2700_soc1_functions[func_selector]; + + for (i = 0; i < func->ngroups; i++) { + if (!strcmp(group->name, func->groups[i])) { + muxval = func->muxvals[i]; + break; + } + } + + if (i == func->ngroups) + return -EINVAL; + + for (i = 0; i < group->npins; i++) + ast2700_soc1_set_muxval(priv, group->pins[i], muxval); + + return 0; +} + +static int +ast2700_soc1_pinctrl_gpio_request_enable(struct udevice *dev, + unsigned int selector) +{ + struct ast2700_soc1_pinctrl_priv *priv = dev_get_priv(dev); + unsigned int muxval = 0; + + if (selector > AC24) + return -ENOTSUPP; + + if (selector >= W17 && selector <= AB19) + muxval = 1; + + ast2700_soc1_set_muxval(priv, selector, muxval); + + return 0; +} + +/* + * Drive strength is controlled by 2-bit fields in the registers at + * DRV_BASE, but the mapping from pins to fields is sparse and + * non-linear: only a subset of the pins supports drive strength + * selection. The table stores (field index + 1) so that the implicit + * zero initialization marks the unsupported pins. + */ +static const u8 ast2700_soc1_drv_map[] = { + [C16] = 1, [C14] = 2, [C11] = 3, [D9] = 4, [F14] = 5, + [D10] = 6, [C12] = 7, [C13] = 8, [W25] = 9, [Y23] = 10, + [Y24] = 11, [W21] = 12, [AA23] = 13, [AC22] = 14, [AB22] = 15, + [Y21] = 16, [AE20] = 17, [AF19] = 18, [Y22] = 19, [AA20] = 20, + [AA22] = 21, [AB20] = 22, [AF18] = 23, [AE19] = 24, [AD20] = 25, + [AC20] = 26, [AA21] = 27, [AB21] = 28, [AC19] = 29, [AE18] = 30, + [AD19] = 31, [AD18] = 32, [U25] = 33, [U26] = 34, [Y26] = 35, + [AA24] = 36, [R25] = 37, [AA26] = 38, [R26] = 39, [Y25] = 40, + [B16] = 41, [D14] = 42, [B15] = 43, [B14] = 44, [C17] = 45, + [B13] = 46, [E14] = 47, [C15] = 48, [D24] = 49, [B23] = 50, + [B22] = 51, [C23] = 52, [B18] = 53, [B21] = 54, [M15] = 55, + [B19] = 56, [B26] = 57, [A25] = 58, [A24] = 59, [B24] = 60, + [E26] = 61, [A21] = 62, [A19] = 63, [A18] = 64, [D26] = 65, + [C26] = 66, [A23] = 67, [A22] = 68, [B25] = 69, [F26] = 70, + [A26] = 71, [A14] = 72, [E10] = 73, [E13] = 74, [D12] = 75, + [F10] = 76, [E11] = 77, [F11] = 78, [F13] = 79, [N15] = 80, + [C20] = 81, [C19] = 82, [A8] = 83, [R14] = 84, [A7] = 85, + [P14] = 86, [D20] = 87, [A6] = 88, [B6] = 89, [N14] = 90, + [B7] = 91, [B8] = 92, [B9] = 93, [M14] = 94, [J11] = 95, + [E7] = 96, [D19] = 97, [B11] = 98, [D15] = 99, [B12] = 100, + [B10] = 101, [P13] = 102, [C18] = 103, [C6] = 104, [C7] = 105, + [D7] = 106, [N13] = 107, [C8] = 108, [C9] = 109, [C10] = 110, + [M16] = 111, [A15] = 112, [E9] = 113, [F9] = 114, [F8] = 115, + [M13] = 116, [F7] = 117, [D8] = 118, [E8] = 119, [L12] = 120, +}; + +static struct ast2700_soc1_field +ast2700_soc1_bias_field_from_pin(unsigned int pin) +{ + return (struct ast2700_soc1_field){ + .reg = AST2700_SOC1_BIAS_BASE + + (pin / AST2700_SOC1_BIAS_PINS_PER_REG) * sizeof(u32), + .shift = pin % AST2700_SOC1_BIAS_PINS_PER_REG, + .mask = 0x1, + }; +} + +static struct ast2700_soc1_field +ast2700_soc1_drv_field_from_idx(unsigned int idx) +{ + return (struct ast2700_soc1_field){ + .reg = AST2700_SOC1_DRV_BASE + + (idx / AST2700_SOC1_DRV_PINS_PER_REG) * sizeof(u32), + .shift = (idx % AST2700_SOC1_DRV_PINS_PER_REG) * + AST2700_SOC1_DRV_BITS_PER_PIN, + .mask = AST2700_SOC1_DRV_MASK, + }; +} + +static const struct pinconf_param ast2700_soc1_pinconf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 0 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 0 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, +}; + +static int ast2700_soc1_pinctrl_pinconf_set(struct udevice *dev, + unsigned int selector, + unsigned int param, + unsigned int arg) +{ + struct ast2700_soc1_pinctrl_priv *priv = dev_get_priv(dev); + struct ast2700_soc1_field field; + unsigned int val, idx; + + if (selector > AC24) + return -EINVAL; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_UP: + /* + * One bias enable bit per pin; the pull direction is fixed + * in silicon. Setting the bit disables the bias. + */ + field = ast2700_soc1_bias_field_from_pin(selector); + val = param == PIN_CONFIG_BIAS_DISABLE ? 1 : 0; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + if (selector >= ARRAY_SIZE(ast2700_soc1_drv_map) || + !ast2700_soc1_drv_map[selector]) + return -ENOTSUPP; + if (arg < AST2700_SOC1_DRV_MIN_MA || + arg > AST2700_SOC1_DRV_MAX_MA || + arg % AST2700_SOC1_DRV_STEP_MA) + return -EINVAL; + idx = ast2700_soc1_drv_map[selector] - 1; + field = ast2700_soc1_drv_field_from_idx(idx); + val = arg / AST2700_SOC1_DRV_STEP_MA - 1; + break; + default: + return -ENOTSUPP; + } + + clrsetbits_le32(ast2700_soc1_reg(priv, field.reg), + field.mask << field.shift, val << field.shift); + + return 0; +} + +static int ast2700_soc1_pinctrl_pinconf_group_set(struct udevice *dev, + unsigned int selector, + unsigned int param, + unsigned int arg) +{ + const struct ast2700_soc1_group *group; + unsigned int i; + int ret; + + if (selector >= ARRAY_SIZE(ast2700_soc1_groups)) + return -EINVAL; + + group = &ast2700_soc1_groups[selector]; + for (i = 0; i < group->npins; i++) { + ret = ast2700_soc1_pinctrl_pinconf_set(dev, group->pins[i], + param, arg); + if (ret) + return ret; + } + + return 0; +} + +static int ast2700_soc1_pinctrl_probe(struct udevice *dev) +{ + struct ast2700_soc1_pinctrl_priv *priv = dev_get_priv(dev); + + priv->scu = dev_remap_addr(dev->parent); + if (!priv->scu) + return -ENOMEM; + + return 0; +} + +static const struct pinctrl_ops ast2700_soc1_pinctrl_ops = { + .set_state = pinctrl_generic_set_state, + .get_pins_count = ast2700_soc1_pinctrl_get_pins_count, + .get_pin_name = ast2700_soc1_pinctrl_get_pin_name, + .get_pin_muxing = ast2700_soc1_pinctrl_get_pin_muxing, + .get_groups_count = ast2700_soc1_pinctrl_get_groups_count, + .get_group_name = ast2700_soc1_pinctrl_get_group_name, + .get_functions_count = ast2700_soc1_pinctrl_get_functions_count, + .get_function_name = ast2700_soc1_pinctrl_get_function_name, + .pinmux_group_set = ast2700_soc1_pinctrl_group_set, + .gpio_request_enable = ast2700_soc1_pinctrl_gpio_request_enable, + .pinconf_num_params = ARRAY_SIZE(ast2700_soc1_pinconf_params), + .pinconf_params = ast2700_soc1_pinconf_params, + .pinconf_set = ast2700_soc1_pinctrl_pinconf_set, + .pinconf_group_set = ast2700_soc1_pinctrl_pinconf_group_set, +}; + +static const struct udevice_id ast2700_soc1_pinctrl_ids[] = { + { .compatible = "aspeed,ast2700-soc1-pinctrl" }, + { } +}; + +U_BOOT_DRIVER(pinctrl_ast2700_soc1) = { + .name = "aspeed_ast2700_soc1_pinctrl", + .id = UCLASS_PINCTRL, + .of_match = ast2700_soc1_pinctrl_ids, + .priv_auto = sizeof(struct ast2700_soc1_pinctrl_priv), + .ops = &ast2700_soc1_pinctrl_ops, + .probe = ast2700_soc1_pinctrl_probe, +}; diff --git a/drivers/pinctrl/broadcom/Kconfig b/drivers/pinctrl/broadcom/Kconfig index b01b725583a..d7cf3855928 100644 --- a/drivers/pinctrl/broadcom/Kconfig +++ b/drivers/pinctrl/broadcom/Kconfig @@ -3,13 +3,13 @@ config PINCTRL_BCM283X default y bool "Broadcom 283x family pin control driver" help - Support pin multiplexing and pin configuration control on - Broadcom's 283x family of SoCs. + Support pin multiplexing and pin configuration control on + Broadcom's 283x family of SoCs. config PINCTRL_BCM6838 depends on ARCH_BMIPS && PINCTRL_FULL && OF_CONTROL default y bool "Broadcom 6838 family pin control driver" help - Support pin multiplexing and pin configuration control on - Broadcom's 6838 family of SoCs. + Support pin multiplexing and pin configuration control on + Broadcom's 6838 family of SoCs. diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig index cf72a7df62c..5a90d74a9e1 100644 --- a/drivers/pinctrl/mediatek/Kconfig +++ b/drivers/pinctrl/mediatek/Kconfig @@ -59,7 +59,7 @@ config PINCTRL_MT8516 select PINCTRL_MTK config PINCTRL_MT8518 - bool "MT8518 SoC pinctrl driver" + bool "MT8518 SoC pinctrl driver" select PINCTRL_MTK endif diff --git a/drivers/pinctrl/mediatek/pinctrl-mt7981.c b/drivers/pinctrl/mediatek/pinctrl-mt7981.c index 8875c276f36..5219b147797 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt7981.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt7981.c @@ -106,7 +106,7 @@ static const struct mtk_pin_field_calc mt7981_pin_ies_range[] = { PIN_FIELD_BASE(9, 9, 5, 0x20, 0x10, 9, 1), PIN_FIELD_BASE(10, 10, 5, 0x20, 0x10, 8, 1), - PIN_FIELD_BASE(11, 11, 5, 0x40, 0x10, 10, 1), + PIN_FIELD_BASE(11, 11, 5, 0x20, 0x10, 10, 1), PIN_FIELD_BASE(12, 12, 5, 0x20, 0x10, 7, 1), PIN_FIELD_BASE(13, 13, 5, 0x20, 0x10, 11, 1), @@ -215,7 +215,7 @@ static const struct mtk_pin_field_calc mt7981_pin_smt_range[] = { PIN_FIELD_BASE(41, 41, 7, 0x70, 0x10, 0, 1), PIN_FIELD_BASE(42, 42, 7, 0x70, 0x10, 9, 1), PIN_FIELD_BASE(43, 43, 7, 0x70, 0x10, 7, 1), - PIN_FIELD_BASE(44, 44, 7, 0x30, 0x10, 8, 1), + PIN_FIELD_BASE(44, 44, 7, 0x70, 0x10, 8, 1), PIN_FIELD_BASE(45, 45, 7, 0x70, 0x10, 3, 1), PIN_FIELD_BASE(46, 46, 7, 0x70, 0x10, 4, 1), PIN_FIELD_BASE(47, 47, 7, 0x70, 0x10, 5, 1), @@ -279,8 +279,8 @@ static const struct mtk_pin_field_calc mt7981_pin_drv_range[] = { PIN_FIELD_BASE(2, 2, 5, 0x00, 0x10, 18, 3), - PIN_FIELD_BASE(3, 3, 4, 0x00, 0x10, 18, 1), - PIN_FIELD_BASE(4, 4, 4, 0x00, 0x10, 6, 1), + PIN_FIELD_BASE(3, 3, 4, 0x00, 0x10, 18, 3), + PIN_FIELD_BASE(4, 4, 4, 0x00, 0x10, 6, 3), PIN_FIELD_BASE(5, 5, 4, 0x00, 0x10, 3, 3), PIN_FIELD_BASE(6, 6, 4, 0x00, 0x10, 9, 3), PIN_FIELD_BASE(7, 7, 4, 0x00, 0x10, 0, 3), @@ -288,9 +288,9 @@ static const struct mtk_pin_field_calc mt7981_pin_drv_range[] = { PIN_FIELD_BASE(9, 9, 5, 0x00, 0x10, 27, 3), PIN_FIELD_BASE(10, 10, 5, 0x00, 0x10, 24, 3), - PIN_FIELD_BASE(11, 11, 5, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(11, 11, 5, 0x10, 0x10, 0, 3), PIN_FIELD_BASE(12, 12, 5, 0x00, 0x10, 21, 3), - PIN_FIELD_BASE(13, 13, 5, 0x00, 0x10, 3, 3), + PIN_FIELD_BASE(13, 13, 5, 0x10, 0x10, 3, 3), PIN_FIELD_BASE(14, 14, 4, 0x00, 0x10, 27, 3), @@ -302,7 +302,7 @@ static const struct mtk_pin_field_calc mt7981_pin_drv_range[] = { PIN_FIELD_BASE(20, 20, 2, 0x00, 0x10, 9, 3), PIN_FIELD_BASE(21, 21, 2, 0x00, 0x10, 18, 3), PIN_FIELD_BASE(22, 22, 2, 0x00, 0x10, 21, 3), - PIN_FIELD_BASE(23, 23, 2, 0x00, 0x10, 0, 3), + PIN_FIELD_BASE(23, 23, 2, 0x10, 0x10, 0, 3), PIN_FIELD_BASE(24, 24, 2, 0x00, 0x10, 27, 3), PIN_FIELD_BASE(25, 25, 2, 0x00, 0x10, 24, 3), @@ -368,7 +368,7 @@ static const struct mtk_pin_field_calc mt7981_pin_pupd_range[] = { PIN_FIELD_BASE(17, 17, 2, 0x30, 0x10, 5, 1), PIN_FIELD_BASE(18, 18, 2, 0x30, 0x10, 4, 1), PIN_FIELD_BASE(19, 19, 2, 0x30, 0x10, 2, 1), - PIN_FIELD_BASE(20, 20, 2, 0x90, 0x10, 3, 1), + PIN_FIELD_BASE(20, 20, 2, 0x30, 0x10, 3, 1), PIN_FIELD_BASE(21, 21, 2, 0x30, 0x10, 6, 1), PIN_FIELD_BASE(22, 22, 2, 0x30, 0x10, 7, 1), PIN_FIELD_BASE(23, 23, 2, 0x30, 0x10, 10, 1), diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index cfffbaeef84..01f67f09407 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -251,7 +251,7 @@ static int mtk_pinconf_get(struct udevice *dev, u32 pin, char *buf, size_t size) if (mtk_get_pin_io_type(dev, pin, &io_type)) return 0; - pos = snprintf(buf, size, " (%s)", io_type.name); + pos = scnprintf(buf, size, " (%s)", io_type.name); if (pos >= size) return pos; @@ -306,7 +306,7 @@ static int mtk_get_pin_muxing(struct udevice *dev, unsigned int selector, if (err) return err; - pos = snprintf(buf, size, "Aux Func.%d", val); + pos = scnprintf(buf, size, "Aux Func.%d", val); if (pos >= size) return 0; @@ -721,7 +721,7 @@ int mtk_pinconf_get_pu_pd(struct udevice *dev, u32 pin, char *buf, size_t size) if (err) return err; - return snprintf(buf, size, " PU:%d PD:%d", pu, pd); + return scnprintf(buf, size, " PU:%d PD:%d", pu, pd); } int mtk_pinconf_get_pupd_r1_r0(struct udevice *dev, u32 pin, char *buf, size_t size) @@ -740,7 +740,7 @@ int mtk_pinconf_get_pupd_r1_r0(struct udevice *dev, u32 pin, char *buf, size_t s if (err) return err; - return snprintf(buf, size, " PUPD:%d R1:%d R0:%d", pupd, r1, r0); + return scnprintf(buf, size, " PUPD:%d R1:%d R0:%d", pupd, r1, r0); } int mtk_pinconf_get_pu_pd_rsel(struct udevice *dev, u32 pin, char *buf, size_t size) @@ -755,7 +755,7 @@ int mtk_pinconf_get_pu_pd_rsel(struct udevice *dev, u32 pin, char *buf, size_t s if (err) return err; - return pos + snprintf(buf + pos, size - pos, " RSEL:%d", rsel); + return pos + scnprintf(buf + pos, size - pos, " RSEL:%d", rsel); } #endif diff --git a/drivers/pinctrl/mscc/Kconfig b/drivers/pinctrl/mscc/Kconfig index 567c93f404c..285787c4467 100644 --- a/drivers/pinctrl/mscc/Kconfig +++ b/drivers/pinctrl/mscc/Kconfig @@ -10,8 +10,8 @@ config PINCTRL_MSCC_OCELOT default y bool "Microsemi ocelot family pin control driver" help - Support pin multiplexing and pin configuration control on - Microsemi ocelot SoCs. + Support pin multiplexing and pin configuration control on + Microsemi ocelot SoCs. config PINCTRL_MSCC_LUTON depends on SOC_LUTON && PINCTRL_FULL && OF_CONTROL @@ -19,8 +19,8 @@ config PINCTRL_MSCC_LUTON default y bool "Microsemi luton family pin control driver" help - Support pin multiplexing and pin configuration control on - Microsemi luton SoCs. + Support pin multiplexing and pin configuration control on + Microsemi luton SoCs. config PINCTRL_MSCC_JR2 depends on SOC_JR2 && PINCTRL_FULL && OF_CONTROL @@ -28,8 +28,8 @@ config PINCTRL_MSCC_JR2 default y bool "Microsemi jr2 family pin control driver" help - Support pin multiplexing and pin configuration control on - Microsemi jr2 SoCs. + Support pin multiplexing and pin configuration control on + Microsemi jr2 SoCs. config PINCTRL_MSCC_SERVALT depends on SOC_SERVALT && PINCTRL_FULL && OF_CONTROL @@ -37,8 +37,8 @@ config PINCTRL_MSCC_SERVALT default y bool "Microsemi servalt family pin control driver" help - Support pin multiplexing and pin configuration control on - Microsemi servalt SoCs. + Support pin multiplexing and pin configuration control on + Microsemi servalt SoCs. config PINCTRL_MSCC_SERVAL depends on SOC_SERVAL && PINCTRL_FULL && OF_CONTROL @@ -46,6 +46,6 @@ config PINCTRL_MSCC_SERVAL default y bool "Microsemi serval family pin control driver" help - Support pin multiplexing and pin configuration control on - Microsemi serval SoCs. + Support pin multiplexing and pin configuration control on + Microsemi serval SoCs. diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig index 10ba440f246..72b97a7935d 100644 --- a/drivers/pinctrl/mvebu/Kconfig +++ b/drivers/pinctrl/mvebu/Kconfig @@ -4,22 +4,22 @@ config PINCTRL_ARMADA_38X depends on ARMADA_38X && PINCTRL_FULL bool "Armada 38x pin control driver" help - Support pin multiplexing and pin configuration control on - Marvell's Armada-38x SoC. + Support pin multiplexing and pin configuration control on + Marvell's Armada-38x SoC. config PINCTRL_ARMADA_37XX depends on ARMADA_3700 && PINCTRL_FULL select DEVRES bool "Armada 37xx pin control driver" help - Support pin multiplexing and pin configuration control on - Marvell's Armada-37xx SoC. + Support pin multiplexing and pin configuration control on + Marvell's Armada-37xx SoC. config PINCTRL_ARMADA_8K depends on (ARMADA_8K || ALLEYCAT_5) && PINCTRL_FULL bool "Armada 7k/8k pin control driver" help - Support pin multiplexing and pin configuration control on - Marvell's Armada-8K SoC. + Support pin multiplexing and pin configuration control on + Marvell's Armada-8K SoC. endif diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c index 78184d2860a..c18afe958dc 100644 --- a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c @@ -550,7 +550,7 @@ static int armada_38x_pinctrl_probe(struct udevice *dev) return 0; } -struct pinctrl_ops armada_37xx_pinctrl_ops = { +static const struct pinctrl_ops armada_37xx_pinctrl_ops = { .get_pins_count = armada_38x_pinctrl_get_pins_count, .get_pin_name = armada_38x_pinctrl_get_pin_name, .get_functions_count = armada_38x_pinctrl_get_functions_count, diff --git a/drivers/pinctrl/nexell/pinctrl-nexell.c b/drivers/pinctrl/nexell/pinctrl-nexell.c index af1acd91649..bd89e779864 100644 --- a/drivers/pinctrl/nexell/pinctrl-nexell.c +++ b/drivers/pinctrl/nexell/pinctrl-nexell.c @@ -49,7 +49,7 @@ int nexell_pinctrl_probe(struct udevice *dev) if (!priv) return -EINVAL; - base = devfdt_get_addr(dev); + base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/pinctrl/pinctrl-apple.c b/drivers/pinctrl/pinctrl-apple.c index f373afde58e..083ea6d6cd5 100644 --- a/drivers/pinctrl/pinctrl-apple.c +++ b/drivers/pinctrl/pinctrl-apple.c @@ -192,6 +192,7 @@ static struct pinctrl_ops apple_pinctrl_ops = { }; static const struct udevice_id apple_pinctrl_ids[] = { + { .compatible = "apple,t8103-pinctrl" }, { .compatible = "apple,pinctrl" }, { /* sentinel */ } }; diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 2938635ed95..50a130d700f 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -527,7 +527,7 @@ static int at91_pinctrl_probe(struct udevice *dev) if (list_empty(&dev->child_head)) { for (index = 0; index < MAX_GPIO_BANKS; index++) { - addr_base = devfdt_get_addr_index(dev, index); + addr_base = dev_read_addr_index(dev, index); if (addr_base == FDT_ADDR_T_NONE) break; diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 580308621b1..0bea461fcc3 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -54,6 +54,14 @@ config PINCTRL_QCOM_IPQ9574 Say Y here to enable support for pinctrl on the IPQ9574 SoC, as well as the associated GPIO driver. +config PINCTRL_QCOM_MILOS + bool "Qualcomm Milos Pinctrl" + default y if PINCTRL_QCOM_GENERIC + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the Snapdragon Milos SoC, + as well as the associated GPIO driver. + config PINCTRL_QCOM_QCM2290 bool "Qualcomm QCM2290 Pinctrl" default y if PINCTRL_QCOM_GENERIC @@ -71,12 +79,12 @@ config PINCTRL_QCOM_QCS404 as well as the associated GPIO driver. config PINCTRL_QCOM_QCS615 - bool "Qualcomm QCS615 Pinctrl" + bool "Qualcomm QCS615 Pinctrl" default y if PINCTRL_QCOM_GENERIC - select PINCTRL_QCOM - help - Say Y here to enable support for pinctrl on the Snapdragon QCS615 SoC, - as well as the associated GPIO driver. + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the Snapdragon QCS615 SoC, + as well as the associated GPIO driver. config PINCTRL_QCOM_SA8775P bool "Qualcomm SA8775P Pinctrl" @@ -125,6 +133,14 @@ 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_SM6125 + bool "Qualcomm SM6125 Pinctrl" + default y if PINCTRL_QCOM_GENERIC + select PINCTRL_QCOM + help + Say Y here to enable support for pinctrl on the Snapdragon SM6125 SoC, + as well as the associated GPIO driver. + config PINCTRL_QCOM_SM6350 bool "Qualcomm SM6350 Pinctrl" default y if PINCTRL_QCOM_GENERIC diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index b5a111605ed..87cb128c4d4 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_PINCTRL_QCOM_IPQ4019) += pinctrl-ipq4019.o obj-$(CONFIG_PINCTRL_QCOM_IPQ5424) += pinctrl-ipq5424.o obj-$(CONFIG_PINCTRL_QCOM_IPQ9574) += pinctrl-ipq9574.o obj-$(CONFIG_PINCTRL_QCOM_APQ8096) += pinctrl-apq8096.o +obj-$(CONFIG_PINCTRL_QCOM_MILOS) += pinctrl-milos.o obj-$(CONFIG_PINCTRL_QCOM_QCM2290) += pinctrl-qcm2290.o obj-$(CONFIG_PINCTRL_QCOM_QCS404) += pinctrl-qcs404.o obj-$(CONFIG_PINCTRL_QCOM_QCS615) += pinctrl-qcs615.o @@ -17,6 +18,7 @@ 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_SM6125) += pinctrl-sm6125.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 diff --git a/drivers/pinctrl/qcom/pinctrl-milos.c b/drivers/pinctrl/qcom/pinctrl-milos.c new file mode 100644 index 00000000000..4f958fbfbf3 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-milos.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Qualcomm Milos pinctrl + * + * (C) Copyright 2024 Linaro Ltd. + * (C) Copyright 2026 Luca Weiss <[email protected]> + * + */ + +#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[] = { + {"qup0_se5", 1}, + {"sdc2_clk", 1}, + {"sdc2_cmd", 1}, + {"sdc2_data", 1}, + {"gpio", 0}, +}; + +#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, ctl, io) \ + { \ + .name = pg_name, \ + .ctl_reg = ctl, \ + .io_reg = io, \ + .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", 0xb4004, 0xb5000), + [1] = SDC_QDSD_PINGROUP("sdc2_clk", 0xab000, 0, 6), + [2] = SDC_QDSD_PINGROUP("sdc2_cmd", 0xab000, 12, 3), + [3] = SDC_QDSD_PINGROUP("sdc2_data", 0xab000, 9, 0), +}; + +static const char *milos_get_function_name(struct udevice *dev, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].name; +} + +static const char *milos_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + if (selector >= 167 && selector <= 170) + snprintf(pin_name, MAX_PIN_NAME_LEN, + msm_special_pins_data[selector - 167].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + + return pin_name; +} + +static int milos_get_function_mux(__maybe_unused unsigned int pin, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].val; +} + +static struct msm_pinctrl_data milos_data = { + .pin_data = { + .pin_count = 171, + .special_pins_start = 167, + .special_pins_data = msm_special_pins_data, + }, + .functions_count = ARRAY_SIZE(msm_pinctrl_functions), + .get_function_name = milos_get_function_name, + .get_function_mux = milos_get_function_mux, + .get_pin_name = milos_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,milos-tlmm", .data = (ulong)&milos_data }, + { /* Sentinel */ } +}; + +U_BOOT_DRIVER(pinctrl_milos) = { + .name = "pinctrl_milos", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops = &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, +}; diff --git a/drivers/pinctrl/qcom/pinctrl-sc7280.c b/drivers/pinctrl/qcom/pinctrl-sc7280.c index d62b2cc6fb6..d0242fc1c17 100644 --- a/drivers/pinctrl/qcom/pinctrl-sc7280.c +++ b/drivers/pinctrl/qcom/pinctrl-sc7280.c @@ -13,11 +13,22 @@ #define MAX_PIN_NAME_LEN 32 static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); -static const struct pinctrl_function msm_pinctrl_functions[] = { - { "qup05", 1 }, - { "gpio", 0 }, - { "pcie1_clkreqn", 3}, -}; +typedef unsigned int msm_pin_function[10]; + +#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9)\ + { \ + msm_mux_gpio, /* gpio mode */ \ + msm_mux_##f1, \ + msm_mux_##f2, \ + msm_mux_##f3, \ + msm_mux_##f4, \ + msm_mux_##f5, \ + msm_mux_##f6, \ + msm_mux_##f7, \ + msm_mux_##f8, \ + msm_mux_##f9 \ + } + #define SDC_PINGROUP(pg_name, ctl, pull, drv) \ { \ .name = pg_name, \ @@ -42,6 +53,492 @@ static const struct pinctrl_function msm_pinctrl_functions[] = { .out_bit = 0, \ } +enum sc7280_functions { + msm_mux_atest_char, + msm_mux_atest_char0, + msm_mux_atest_char1, + msm_mux_atest_char2, + msm_mux_atest_char3, + msm_mux_atest_usb0, + msm_mux_atest_usb00, + msm_mux_atest_usb01, + msm_mux_atest_usb02, + msm_mux_atest_usb03, + msm_mux_atest_usb1, + msm_mux_atest_usb10, + msm_mux_atest_usb11, + msm_mux_atest_usb12, + msm_mux_atest_usb13, + msm_mux_audio_ref, + msm_mux_cam_mclk, + msm_mux_cci_async, + msm_mux_cci_i2c, + msm_mux_cci_timer0, + msm_mux_cci_timer1, + msm_mux_cci_timer2, + msm_mux_cci_timer3, + msm_mux_cci_timer4, + msm_mux_cmu_rng0, + msm_mux_cmu_rng1, + msm_mux_cmu_rng2, + msm_mux_cmu_rng3, + msm_mux_coex_uart1, + msm_mux_cri_trng, + msm_mux_cri_trng0, + msm_mux_cri_trng1, + msm_mux_dbg_out, + msm_mux_ddr_bist, + msm_mux_ddr_pxi0, + msm_mux_ddr_pxi1, + msm_mux_dp_hot, + msm_mux_dp_lcd, + msm_mux_edp_hot, + msm_mux_edp_lcd, + msm_mux_egpio, + msm_mux_gcc_gp1, + msm_mux_gcc_gp2, + msm_mux_gcc_gp3, + msm_mux_gpio, + msm_mux_host2wlan_sol, + msm_mux_ibi_i3c, + msm_mux_jitter_bist, + msm_mux_lpass_slimbus, + msm_mux_mdp_vsync, + msm_mux_mdp_vsync0, + msm_mux_mdp_vsync1, + msm_mux_mdp_vsync2, + msm_mux_mdp_vsync3, + msm_mux_mdp_vsync4, + msm_mux_mdp_vsync5, + msm_mux_mi2s0_data0, + msm_mux_mi2s0_data1, + msm_mux_mi2s0_sck, + msm_mux_mi2s0_ws, + msm_mux_mi2s1_data0, + msm_mux_mi2s1_data1, + msm_mux_mi2s1_sck, + msm_mux_mi2s1_ws, + msm_mux_mi2s2_data0, + msm_mux_mi2s2_data1, + msm_mux_mi2s2_sck, + msm_mux_mi2s2_ws, + msm_mux_mss_grfc0, + msm_mux_mss_grfc1, + msm_mux_mss_grfc10, + msm_mux_mss_grfc11, + msm_mux_mss_grfc12, + msm_mux_mss_grfc2, + msm_mux_mss_grfc3, + msm_mux_mss_grfc4, + msm_mux_mss_grfc5, + msm_mux_mss_grfc6, + msm_mux_mss_grfc7, + msm_mux_mss_grfc8, + msm_mux_mss_grfc9, + msm_mux_nav_gpio0, + msm_mux_nav_gpio1, + msm_mux_nav_gpio2, + msm_mux_pa_indicator, + msm_mux_pcie0_clkreqn, + msm_mux_pcie1_clkreqn, + msm_mux_phase_flag, + msm_mux_pll_bist, + msm_mux_pll_bypassnl, + msm_mux_pll_clk, + msm_mux_pll_reset, + msm_mux_pri_mi2s, + msm_mux_prng_rosc, + msm_mux_qdss, + msm_mux_qdss_cti, + msm_mux_qlink0_enable, + msm_mux_qlink0_request, + msm_mux_qlink0_wmss, + msm_mux_qlink1_enable, + msm_mux_qlink1_request, + msm_mux_qlink1_wmss, + msm_mux_qspi_clk, + msm_mux_qspi_cs, + msm_mux_qspi_data, + msm_mux_qup00, + msm_mux_qup01, + msm_mux_qup02, + msm_mux_qup03, + msm_mux_qup04, + msm_mux_qup05, + msm_mux_qup06, + msm_mux_qup07, + msm_mux_qup10, + msm_mux_qup11, + msm_mux_qup12, + msm_mux_qup13, + msm_mux_qup14, + msm_mux_qup15, + msm_mux_qup16, + msm_mux_qup17, + msm_mux_sd_write, + msm_mux_sdc40, + msm_mux_sdc41, + msm_mux_sdc42, + msm_mux_sdc43, + msm_mux_sdc4_clk, + msm_mux_sdc4_cmd, + msm_mux_sec_mi2s, + msm_mux_tb_trig, + msm_mux_tgu_ch0, + msm_mux_tgu_ch1, + msm_mux_tsense_pwm1, + msm_mux_tsense_pwm2, + msm_mux_uim0_clk, + msm_mux_uim0_data, + msm_mux_uim0_present, + msm_mux_uim0_reset, + msm_mux_uim1_clk, + msm_mux_uim1_data, + msm_mux_uim1_present, + msm_mux_uim1_reset, + msm_mux_usb2phy_ac, + msm_mux_usb_phy, + msm_mux_vfr_0, + msm_mux_vfr_1, + msm_mux_vsense_trigger, + msm_mux__, +}; + +#define MSM_PIN_FUNCTION(fname) \ + [msm_mux_##fname] = {#fname, msm_mux_##fname} + +static const struct pinctrl_function msm_pinctrl_functions[] = { + MSM_PIN_FUNCTION(atest_char), + MSM_PIN_FUNCTION(atest_char0), + MSM_PIN_FUNCTION(atest_char1), + MSM_PIN_FUNCTION(atest_char2), + MSM_PIN_FUNCTION(atest_char3), + MSM_PIN_FUNCTION(atest_usb0), + MSM_PIN_FUNCTION(atest_usb00), + MSM_PIN_FUNCTION(atest_usb01), + MSM_PIN_FUNCTION(atest_usb02), + MSM_PIN_FUNCTION(atest_usb03), + MSM_PIN_FUNCTION(atest_usb1), + MSM_PIN_FUNCTION(atest_usb10), + MSM_PIN_FUNCTION(atest_usb11), + MSM_PIN_FUNCTION(atest_usb12), + MSM_PIN_FUNCTION(atest_usb13), + MSM_PIN_FUNCTION(audio_ref), + MSM_PIN_FUNCTION(cam_mclk), + MSM_PIN_FUNCTION(cci_async), + MSM_PIN_FUNCTION(cci_i2c), + MSM_PIN_FUNCTION(cci_timer0), + MSM_PIN_FUNCTION(cci_timer1), + MSM_PIN_FUNCTION(cci_timer2), + MSM_PIN_FUNCTION(cci_timer3), + MSM_PIN_FUNCTION(cci_timer4), + MSM_PIN_FUNCTION(cmu_rng0), + MSM_PIN_FUNCTION(cmu_rng1), + MSM_PIN_FUNCTION(cmu_rng2), + MSM_PIN_FUNCTION(cmu_rng3), + MSM_PIN_FUNCTION(coex_uart1), + MSM_PIN_FUNCTION(cri_trng), + MSM_PIN_FUNCTION(cri_trng0), + MSM_PIN_FUNCTION(cri_trng1), + MSM_PIN_FUNCTION(dbg_out), + MSM_PIN_FUNCTION(ddr_bist), + MSM_PIN_FUNCTION(ddr_pxi0), + MSM_PIN_FUNCTION(ddr_pxi1), + MSM_PIN_FUNCTION(dp_hot), + MSM_PIN_FUNCTION(dp_lcd), + MSM_PIN_FUNCTION(edp_hot), + MSM_PIN_FUNCTION(edp_lcd), + MSM_PIN_FUNCTION(egpio), + MSM_PIN_FUNCTION(gcc_gp1), + MSM_PIN_FUNCTION(gcc_gp2), + MSM_PIN_FUNCTION(gcc_gp3), + MSM_PIN_FUNCTION(gpio), + MSM_PIN_FUNCTION(host2wlan_sol), + MSM_PIN_FUNCTION(ibi_i3c), + MSM_PIN_FUNCTION(jitter_bist), + MSM_PIN_FUNCTION(lpass_slimbus), + MSM_PIN_FUNCTION(mdp_vsync), + MSM_PIN_FUNCTION(mdp_vsync0), + MSM_PIN_FUNCTION(mdp_vsync1), + MSM_PIN_FUNCTION(mdp_vsync2), + MSM_PIN_FUNCTION(mdp_vsync3), + MSM_PIN_FUNCTION(mdp_vsync4), + MSM_PIN_FUNCTION(mdp_vsync5), + MSM_PIN_FUNCTION(mi2s0_data0), + MSM_PIN_FUNCTION(mi2s0_data1), + MSM_PIN_FUNCTION(mi2s0_sck), + MSM_PIN_FUNCTION(mi2s0_ws), + MSM_PIN_FUNCTION(mi2s1_data0), + MSM_PIN_FUNCTION(mi2s1_data1), + MSM_PIN_FUNCTION(mi2s1_sck), + MSM_PIN_FUNCTION(mi2s1_ws), + MSM_PIN_FUNCTION(mi2s2_data0), + MSM_PIN_FUNCTION(mi2s2_data1), + MSM_PIN_FUNCTION(mi2s2_sck), + MSM_PIN_FUNCTION(mi2s2_ws), + MSM_PIN_FUNCTION(mss_grfc0), + MSM_PIN_FUNCTION(mss_grfc1), + MSM_PIN_FUNCTION(mss_grfc10), + MSM_PIN_FUNCTION(mss_grfc11), + MSM_PIN_FUNCTION(mss_grfc12), + MSM_PIN_FUNCTION(mss_grfc2), + MSM_PIN_FUNCTION(mss_grfc3), + MSM_PIN_FUNCTION(mss_grfc4), + MSM_PIN_FUNCTION(mss_grfc5), + MSM_PIN_FUNCTION(mss_grfc6), + MSM_PIN_FUNCTION(mss_grfc7), + MSM_PIN_FUNCTION(mss_grfc8), + MSM_PIN_FUNCTION(mss_grfc9), + MSM_PIN_FUNCTION(nav_gpio0), + MSM_PIN_FUNCTION(nav_gpio1), + MSM_PIN_FUNCTION(nav_gpio2), + MSM_PIN_FUNCTION(pa_indicator), + MSM_PIN_FUNCTION(pcie0_clkreqn), + MSM_PIN_FUNCTION(pcie1_clkreqn), + MSM_PIN_FUNCTION(phase_flag), + MSM_PIN_FUNCTION(pll_bist), + MSM_PIN_FUNCTION(pll_bypassnl), + MSM_PIN_FUNCTION(pll_clk), + MSM_PIN_FUNCTION(pll_reset), + MSM_PIN_FUNCTION(pri_mi2s), + MSM_PIN_FUNCTION(prng_rosc), + MSM_PIN_FUNCTION(qdss), + MSM_PIN_FUNCTION(qdss_cti), + MSM_PIN_FUNCTION(qlink0_enable), + MSM_PIN_FUNCTION(qlink0_request), + MSM_PIN_FUNCTION(qlink0_wmss), + MSM_PIN_FUNCTION(qlink1_enable), + MSM_PIN_FUNCTION(qlink1_request), + MSM_PIN_FUNCTION(qlink1_wmss), + MSM_PIN_FUNCTION(qspi_clk), + MSM_PIN_FUNCTION(qspi_cs), + MSM_PIN_FUNCTION(qspi_data), + MSM_PIN_FUNCTION(qup00), + MSM_PIN_FUNCTION(qup01), + MSM_PIN_FUNCTION(qup02), + MSM_PIN_FUNCTION(qup03), + MSM_PIN_FUNCTION(qup04), + MSM_PIN_FUNCTION(qup05), + MSM_PIN_FUNCTION(qup06), + MSM_PIN_FUNCTION(qup07), + MSM_PIN_FUNCTION(qup10), + MSM_PIN_FUNCTION(qup11), + MSM_PIN_FUNCTION(qup12), + MSM_PIN_FUNCTION(qup13), + MSM_PIN_FUNCTION(qup14), + MSM_PIN_FUNCTION(qup15), + MSM_PIN_FUNCTION(qup16), + MSM_PIN_FUNCTION(qup17), + MSM_PIN_FUNCTION(sd_write), + MSM_PIN_FUNCTION(sdc40), + MSM_PIN_FUNCTION(sdc41), + MSM_PIN_FUNCTION(sdc42), + MSM_PIN_FUNCTION(sdc43), + MSM_PIN_FUNCTION(sdc4_clk), + MSM_PIN_FUNCTION(sdc4_cmd), + MSM_PIN_FUNCTION(sec_mi2s), + MSM_PIN_FUNCTION(tb_trig), + MSM_PIN_FUNCTION(tgu_ch0), + MSM_PIN_FUNCTION(tgu_ch1), + MSM_PIN_FUNCTION(tsense_pwm1), + MSM_PIN_FUNCTION(tsense_pwm2), + MSM_PIN_FUNCTION(uim0_clk), + MSM_PIN_FUNCTION(uim0_data), + MSM_PIN_FUNCTION(uim0_present), + MSM_PIN_FUNCTION(uim0_reset), + MSM_PIN_FUNCTION(uim1_clk), + MSM_PIN_FUNCTION(uim1_data), + MSM_PIN_FUNCTION(uim1_present), + MSM_PIN_FUNCTION(uim1_reset), + MSM_PIN_FUNCTION(usb2phy_ac), + MSM_PIN_FUNCTION(usb_phy), + MSM_PIN_FUNCTION(vfr_0), + MSM_PIN_FUNCTION(vfr_1), + MSM_PIN_FUNCTION(vsense_trigger), +}; + +static const msm_pin_function sc7280_pin_functions[] = { + [0] = PINGROUP(0, qup00, ibi_i3c, _, _, _, _, _, _, _), + [1] = PINGROUP(1, qup00, ibi_i3c, _, _, _, _, _, _, _), + [2] = PINGROUP(2, qup00, qup07, _, qdss, _, _, _, _, _), + [3] = PINGROUP(3, qup00, qup07, _, qdss, _, _, _, _, _), + [4] = PINGROUP(4, qup01, ibi_i3c, _, _, _, _, _, _, _), + [5] = PINGROUP(5, qup01, ibi_i3c, _, _, _, _, _, _, _), + [6] = PINGROUP(6, qup01, qup07, _, _, _, _, _, _, _), + [7] = PINGROUP(7, qup01, _, _, _, _, _, _, _, _), + [8] = PINGROUP(8, qup02, _, qdss, _, _, _, _, _, _), + [9] = PINGROUP(9, qup02, _, qdss, _, _, _, _, _, _), + [10] = PINGROUP(10, qup02, _, qdss, _, _, _, _, _, _), + [11] = PINGROUP(11, qup02, _, qdss, _, _, _, _, _, _), + [12] = PINGROUP(12, qup03, qspi_data, sdc40, tb_trig, phase_flag, qdss, ddr_pxi1, _, _), + [13] = PINGROUP(13, qup03, qspi_data, sdc41, tb_trig, phase_flag, qdss, ddr_pxi1, _, _), + [14] = PINGROUP(14, qup03, qspi_clk, sdc4_clk, mdp_vsync, phase_flag, ddr_pxi0, _, _, _), + [15] = PINGROUP(15, qup03, qspi_cs, tb_trig, phase_flag, qdss_cti, ddr_pxi0, _, _, _), + [16] = PINGROUP(16, qup04, qspi_data, sdc42, mdp_vsync, phase_flag, qdss_cti, _, _, _), + [17] = PINGROUP(17, qup04, qspi_data, sdc43, _, phase_flag, _, _, _, _), + [18] = PINGROUP(18, qup04, _, phase_flag, qdss_cti, _, _, _, _, _), + [19] = PINGROUP(19, qup04, qspi_cs, sdc4_cmd, _, phase_flag, qdss_cti, _, _, _), + [20] = PINGROUP(20, qup05, cci_timer0, _, qdss, _, _, _, _, _), + [21] = PINGROUP(21, qup05, cci_timer1, _, qdss, _, _, _, _, _), + [22] = PINGROUP(22, qup05, _, qdss, _, _, _, _, _, _), + [23] = PINGROUP(23, qup05, _, qdss, _, _, _, _, _, _), + [24] = PINGROUP(24, qup06, _, qdss, _, _, _, _, _, _), + [25] = PINGROUP(25, qup06, _, qdss, _, _, _, _, _, _), + [26] = PINGROUP(26, qup06, host2wlan_sol, _, qdss, _, _, _, _, _), + [27] = PINGROUP(27, qup06, _, qdss, _, _, _, _, _, _), + [28] = PINGROUP(28, qup07, _, qdss, _, _, _, _, _, _), + [29] = PINGROUP(29, qup07, qdss, _, _, _, _, _, _, _), + [30] = PINGROUP(30, qup07, _, _, _, _, _, _, _, _), + [31] = PINGROUP(31, qup07, _, _, _, _, _, _, _, _), + [32] = PINGROUP(32, qup10, _, _, _, _, _, _, _, _), + [33] = PINGROUP(33, qup10, _, _, _, _, _, _, _, _), + [34] = PINGROUP(34, qup10, _, _, _, _, _, _, _, _), + [35] = PINGROUP(35, qup10, _, _, _, _, _, _, _, _), + [36] = PINGROUP(36, qup11, ibi_i3c, _, _, _, _, _, _, _), + [37] = PINGROUP(37, qup11, ibi_i3c, _, _, _, _, _, _, _), + [38] = PINGROUP(38, qup11, qup14, dbg_out, _, _, _, _, _, _), + [39] = PINGROUP(39, qup11, _, _, _, _, _, _, _, _), + [40] = PINGROUP(40, qup12, _, _, _, _, _, _, _, _), + [41] = PINGROUP(41, qup12, _, _, _, _, _, _, _, _), + [42] = PINGROUP(42, qup12, _, _, _, _, _, _, _, _), + [43] = PINGROUP(43, qup12, _, _, _, _, _, _, _, _), + [44] = PINGROUP(44, qup13, _, _, _, _, _, _, _, _), + [45] = PINGROUP(45, qup13, _, _, _, _, _, _, _, _), + [46] = PINGROUP(46, qup13, edp_lcd, _, _, _, _, _, _, _), + [47] = PINGROUP(47, qup13, dp_hot, _, _, _, _, _, _, _), + [48] = PINGROUP(48, qup14, _, _, _, _, _, _, _, _), + [49] = PINGROUP(49, qup14, _, _, _, _, _, _, _, _), + [50] = PINGROUP(50, qup14, qup16, _, _, _, _, _, _, _), + [51] = PINGROUP(51, qup14, _, _, _, _, _, _, _, _), + [52] = PINGROUP(52, qup15, _, _, _, _, _, _, _, _), + [53] = PINGROUP(53, qup15, _, _, _, _, _, _, _, _), + [54] = PINGROUP(54, qup15, qup14, _, _, _, _, _, _, _), + [55] = PINGROUP(55, qup15, qup14, _, _, _, _, _, _, _), + [56] = PINGROUP(56, qup16, ddr_bist, phase_flag, _, _, _, _, _, _), + [57] = PINGROUP(57, qup16, ddr_bist, phase_flag, _, _, _, _, _, _), + [58] = PINGROUP(58, qup16, ddr_bist, phase_flag, qdss, _, _, _, _, _), + [59] = PINGROUP(59, qup16, ddr_bist, phase_flag, qdss, _, _, _, _, _), + [60] = PINGROUP(60, qup17, edp_hot, _, phase_flag, _, _, _, _, _), + [61] = PINGROUP(61, qup17, sd_write, phase_flag, tsense_pwm1, tsense_pwm2, _, _, _, _), + [62] = PINGROUP(62, qup17, qup16, phase_flag, _, _, _, _, _, _), + [63] = PINGROUP(63, qup17, qup16, phase_flag, _, _, _, _, _, _), + [64] = PINGROUP(64, cam_mclk, _, _, _, _, _, _, _, _), + [65] = PINGROUP(65, cam_mclk, tgu_ch0, _, _, _, _, _, _, _), + [66] = PINGROUP(66, cam_mclk, pll_bypassnl, tgu_ch1, _, _, _, _, _, _), + [67] = PINGROUP(67, cam_mclk, pll_reset, _, _, _, _, _, _, _), + [68] = PINGROUP(68, cam_mclk, _, _, _, _, _, _, _, _), + [69] = PINGROUP(69, cci_i2c, _, _, _, _, _, _, _, _), + [70] = PINGROUP(70, cci_i2c, _, _, _, _, _, _, _, _), + [71] = PINGROUP(71, cci_i2c, _, _, _, _, _, _, _, _), + [72] = PINGROUP(72, cci_i2c, _, _, _, _, _, _, _, _), + [73] = PINGROUP(73, cci_i2c, _, _, _, _, _, _, _, _), + [74] = PINGROUP(74, cci_i2c, _, _, _, _, _, _, _, _), + [75] = PINGROUP(75, cci_i2c, _, _, _, _, _, _, _, _), + [76] = PINGROUP(76, cci_i2c, gcc_gp1, _, _, _, _, _, _, _), + [77] = PINGROUP(77, cci_timer2, gcc_gp2, _, atest_usb13, atest_char0, _, _, _, _), + [78] = PINGROUP(78, cci_timer3, cci_async, gcc_gp3, _, atest_usb12, atest_char1, _, _, _), + [79] = PINGROUP(79, cci_timer4, cci_async, pcie1_clkreqn, mdp_vsync, jitter_bist, + atest_usb11, atest_char2, _, _), + [80] = PINGROUP(80, mdp_vsync, vfr_0, mdp_vsync0, mdp_vsync1, mdp_vsync4, pll_bist, + atest_usb10, atest_char3, _), + [81] = PINGROUP(81, mdp_vsync, dp_lcd, mdp_vsync2, mdp_vsync3, mdp_vsync5, atest_usb1, + atest_char, _, _), + [82] = PINGROUP(82, _, _, _, _, _, _, _, _, _), + [83] = PINGROUP(83, _, _, _, _, _, _, _, _, _), + [84] = PINGROUP(84, usb2phy_ac, _, _, _, _, _, _, _, _), + [85] = PINGROUP(85, usb2phy_ac, _, _, _, _, _, _, _, _), + [86] = PINGROUP(86, _, _, _, _, _, _, _, _, _), + [87] = PINGROUP(87, _, _, _, _, _, _, _, _, _), + [88] = PINGROUP(88, pcie0_clkreqn, _, _, _, _, _, _, _, _), + [89] = PINGROUP(89, _, _, _, _, _, _, _, _, _), + [90] = PINGROUP(90, _, _, _, _, _, _, _, _, _), + [91] = PINGROUP(91, _, _, _, _, _, _, _, _, _), + [92] = PINGROUP(92, _, _, _, _, _, _, _, _, _), + [93] = PINGROUP(93, cam_mclk, cci_async, _, _, _, _, _, _, _), + [94] = PINGROUP(94, lpass_slimbus, _, _, _, _, _, _, _, _), + [95] = PINGROUP(95, lpass_slimbus, _, _, _, _, _, _, _, _), + [96] = PINGROUP(96, pri_mi2s, _, _, _, _, _, _, _, _), + [97] = PINGROUP(97, mi2s0_sck, _, _, _, _, _, _, _, _), + [98] = PINGROUP(98, mi2s0_data0, _, _, _, _, _, _, _, _), + [99] = PINGROUP(99, mi2s0_data1, _, _, _, _, _, _, _, _), + [100] = PINGROUP(100, mi2s0_ws, _, vsense_trigger, _, _, _, _, _, _), + [101] = PINGROUP(101, mi2s2_sck, _, qdss, _, _, _, _, _, _), + [102] = PINGROUP(102, mi2s2_data0, _, _, qdss, _, _, _, _, _), + [103] = PINGROUP(103, mi2s2_ws, vfr_1, _, _, qdss, _, atest_usb03, _, _), + [104] = PINGROUP(104, mi2s2_data1, _, _, qdss, _, atest_usb02, _, _, _), + [105] = PINGROUP(105, sec_mi2s, mi2s1_data1, audio_ref, gcc_gp1, _, qdss, + atest_usb01, _, _), + [106] = PINGROUP(106, mi2s1_sck, gcc_gp2, _, qdss, atest_usb00, _, _, _, _), + [107] = PINGROUP(107, mi2s1_data0, gcc_gp3, _, qdss, atest_usb0, _, _, _, _), + [108] = PINGROUP(108, mi2s1_ws, _, qdss, _, _, _, _, _, _), + [109] = PINGROUP(109, uim1_data, _, _, _, _, _, _, _, _), + [110] = PINGROUP(110, uim1_clk, _, _, _, _, _, _, _, _), + [111] = PINGROUP(111, uim1_reset, _, _, _, _, _, _, _, _), + [112] = PINGROUP(112, uim1_present, _, _, _, _, _, _, _, _), + [113] = PINGROUP(113, uim0_data, _, _, _, _, _, _, _, _), + [114] = PINGROUP(114, uim0_clk, _, _, _, _, _, _, _, _), + [115] = PINGROUP(115, uim0_reset, _, _, _, _, _, _, _, _), + [116] = PINGROUP(116, uim0_present, _, _, _, _, _, _, _, _), + [117] = PINGROUP(117, _, mss_grfc0, cmu_rng3, phase_flag, _, _, _, _, _), + [118] = PINGROUP(118, _, mss_grfc1, cmu_rng2, phase_flag, _, _, _, _, _), + [119] = PINGROUP(119, _, mss_grfc2, cmu_rng1, phase_flag, _, _, _, _, _), + [120] = PINGROUP(120, _, mss_grfc3, cmu_rng0, phase_flag, _, _, _, _, _), + [121] = PINGROUP(121, _, mss_grfc4, cri_trng0, phase_flag, _, _, _, _, _), + [122] = PINGROUP(122, _, mss_grfc5, cri_trng1, phase_flag, _, _, _, _, _), + [123] = PINGROUP(123, _, mss_grfc6, prng_rosc, phase_flag, _, _, _, _, _), + [124] = PINGROUP(124, _, mss_grfc7, cri_trng, phase_flag, _, _, _, _, _), + [125] = PINGROUP(125, _, mss_grfc8, phase_flag, _, _, _, _, _, _), + [126] = PINGROUP(126, _, mss_grfc9, phase_flag, _, _, _, _, _, _), + [127] = PINGROUP(127, coex_uart1, mss_grfc10, phase_flag, _, _, _, _, _, _), + [128] = PINGROUP(128, coex_uart1, mss_grfc11, phase_flag, _, _, _, _, _, _), + [129] = PINGROUP(129, nav_gpio0, phase_flag, _, _, _, _, _, _, _), + [130] = PINGROUP(130, nav_gpio1, phase_flag, _, _, _, _, _, _, _), + [131] = PINGROUP(131, mss_grfc12, nav_gpio2, pa_indicator, phase_flag, _, _, _, _, _), + [132] = PINGROUP(132, mss_grfc0, phase_flag, _, _, _, _, _, _, _), + [133] = PINGROUP(133, qlink0_request, _, _, _, _, _, _, _, _), + [134] = PINGROUP(134, qlink0_enable, _, _, _, _, _, _, _, _), + [135] = PINGROUP(135, qlink0_wmss, _, _, _, _, _, _, _, _), + [136] = PINGROUP(136, qlink1_request, _, _, _, _, _, _, _, _), + [137] = PINGROUP(137, qlink1_enable, _, _, _, _, _, _, _, _), + [138] = PINGROUP(138, qlink1_wmss, _, _, _, _, _, _, _, _), + [139] = PINGROUP(139, _, _, _, _, _, _, _, _, _), + [140] = PINGROUP(140, usb_phy, pll_clk, _, _, _, _, _, _, _), + [141] = PINGROUP(141, _, _, _, _, _, _, _, _, _), + [142] = PINGROUP(142, _, _, _, _, _, _, _, _, _), + [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _), + [144] = PINGROUP(144, _, _, _, _, _, _, _, _, egpio), + [145] = PINGROUP(145, _, _, _, _, _, _, _, _, egpio), + [146] = PINGROUP(146, _, _, _, _, _, _, _, _, egpio), + [147] = PINGROUP(147, _, _, _, _, _, _, _, _, egpio), + [148] = PINGROUP(148, _, _, _, _, _, _, _, _, egpio), + [149] = PINGROUP(149, _, _, _, _, _, _, _, _, egpio), + [150] = PINGROUP(150, qdss, _, _, _, _, _, _, _, egpio), + [151] = PINGROUP(151, qdss, _, _, _, _, _, _, _, egpio), + [152] = PINGROUP(152, qdss, _, _, _, _, _, _, _, egpio), + [153] = PINGROUP(153, qdss, _, _, _, _, _, _, _, egpio), + [154] = PINGROUP(154, _, _, _, _, _, _, _, _, egpio), + [155] = PINGROUP(155, _, _, _, _, _, _, _, _, egpio), + [156] = PINGROUP(156, qdss_cti, _, _, _, _, _, _, _, egpio), + [157] = PINGROUP(157, qdss_cti, _, _, _, _, _, _, _, egpio), + [158] = PINGROUP(158, _, _, _, _, _, _, _, _, egpio), + [159] = PINGROUP(159, _, _, _, _, _, _, _, _, egpio), + [160] = PINGROUP(160, _, _, _, _, _, _, _, _, egpio), + [161] = PINGROUP(161, _, _, _, _, _, _, _, _, egpio), + [162] = PINGROUP(162, _, _, _, _, _, _, _, _, egpio), + [163] = PINGROUP(163, _, _, _, _, _, _, _, _, egpio), + [164] = PINGROUP(164, _, _, _, _, _, _, _, _, egpio), + [165] = PINGROUP(165, qdss_cti, _, _, _, _, _, _, _, egpio), + [166] = PINGROUP(166, qdss_cti, _, _, _, _, _, _, _, egpio), + [167] = PINGROUP(167, _, _, _, _, _, _, _, _, egpio), + [168] = PINGROUP(168, _, _, _, _, _, _, _, _, egpio), + [169] = PINGROUP(169, _, _, _, _, _, _, _, _, egpio), + [170] = PINGROUP(170, _, _, _, _, _, _, _, _, egpio), + [171] = PINGROUP(171, qdss, _, _, _, _, _, _, _, egpio), + [172] = PINGROUP(172, qdss, _, _, _, _, _, _, _, egpio), + [173] = PINGROUP(173, qdss, _, _, _, _, _, _, _, egpio), + [174] = PINGROUP(174, qdss, _, _, _, _, _, _, _, egpio), +}; + static const struct msm_special_pin_data sc7280_special_pins_data[] = { [0] = UFS_RESET("ufs_reset", 0xbe000), [1] = SDC_PINGROUP("sdc1_rclk", 0xb3004, 0, 6), @@ -71,7 +568,20 @@ static const char *sc7280_get_pin_name(struct udevice *dev, unsigned int selecto static int sc7280_get_function_mux(__maybe_unused unsigned int pin, unsigned int selector) { - return msm_pinctrl_functions[selector].val; + unsigned int i; + const msm_pin_function *func = NULL; + + if (pin >= ARRAY_SIZE(sc7280_pin_functions)) + return -EINVAL; + + func = sc7280_pin_functions + pin; + for (i = 0; i < 10; i++) + if ((*func)[i] == selector) + return i; + + pr_err("Can't find requested function for pin %u pin\n", pin); + + return -EINVAL; } static struct msm_pinctrl_data sc7280_data = { diff --git a/drivers/pinctrl/qcom/pinctrl-sm6125.c b/drivers/pinctrl/qcom/pinctrl-sm6125.c new file mode 100644 index 00000000000..82f8972ff5b --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sm6125.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Pinctrl driver for Qualcomm SM6125 + * + * (C) Copyright 2026 Biswapriyo Nath <[email protected]> + * + * Based on Linux Kernel driver + */ + +#include <dm.h> + +#include "pinctrl-qcom.h" + +#define TLMM_BASE 0x00500000 +#define WEST (0x00500000 - TLMM_BASE) /* 0x0 */ +#define SOUTH (0x00900000 - TLMM_BASE) /* 0x400000 */ +#define EAST (0x00d00000 - TLMM_BASE) /* 0x800000 */ + +#define MAX_PIN_NAME_LEN 32 +static char pin_name[MAX_PIN_NAME_LEN] __section(".data"); + +static const struct pinctrl_function msm_pinctrl_functions[] = { + { "qup04", 1 }, + { "gpio", 0 }, +}; + +#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", 0x190000), + [1] = SDC_QDSD_PINGROUP("sdc1_rclk", WEST + 0x18d000, 15, 0), + [2] = SDC_QDSD_PINGROUP("sdc1_clk", WEST + 0x18d000, 13, 6), + [3] = SDC_QDSD_PINGROUP("sdc1_cmd", WEST + 0x18d000, 11, 3), + [4] = SDC_QDSD_PINGROUP("sdc1_data", WEST + 0x18d000, 9, 0), + [5] = SDC_QDSD_PINGROUP("sdc2_clk", SOUTH + 0x58b000, 14, 6), + [6] = SDC_QDSD_PINGROUP("sdc2_cmd", SOUTH + 0x58b000, 11, 3), + [7] = SDC_QDSD_PINGROUP("sdc2_data", SOUTH + 0x58b000, 9, 0), +}; + +static const unsigned int sm6125_pin_offsets[] = { + [0] = WEST, [1] = WEST, [2] = WEST, [3] = WEST, + [4] = WEST, [5] = WEST, [6] = WEST, [7] = WEST, + [8] = WEST, [9] = WEST, [10] = EAST, [11] = EAST, + [12] = EAST, [13] = EAST, [14] = WEST, [15] = WEST, + [16] = WEST, [17] = WEST, [18] = EAST, [19] = EAST, + [20] = EAST, [21] = EAST, [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] = SOUTH, [35] = SOUTH, + [36] = SOUTH, [37] = SOUTH, [38] = EAST, [39] = EAST, + [40] = EAST, [41] = EAST, [42] = EAST, [43] = EAST, + [44] = SOUTH, [45] = SOUTH, [46] = SOUTH, [47] = SOUTH, + [48] = SOUTH, [49] = SOUTH, [50] = SOUTH, [51] = SOUTH, + [52] = SOUTH, [53] = SOUTH, [54] = SOUTH, [55] = SOUTH, + [56] = SOUTH, [57] = SOUTH, [58] = SOUTH, [59] = SOUTH, + [60] = SOUTH, [61] = SOUTH, [62] = SOUTH, [63] = SOUTH, + [64] = SOUTH, [65] = SOUTH, [66] = SOUTH, [67] = SOUTH, + [68] = SOUTH, [69] = SOUTH, [70] = SOUTH, [71] = SOUTH, + [72] = SOUTH, [73] = SOUTH, [74] = SOUTH, [75] = SOUTH, + [76] = SOUTH, [77] = SOUTH, [78] = SOUTH, [79] = SOUTH, + [80] = SOUTH, [81] = SOUTH, [82] = SOUTH, [83] = SOUTH, + [84] = SOUTH, [85] = SOUTH, [86] = SOUTH, [87] = WEST, + [88] = WEST, [89] = WEST, [90] = WEST, [91] = WEST, + [92] = WEST, [93] = WEST, [94] = SOUTH, [95] = SOUTH, + [96] = SOUTH, [97] = SOUTH, [98] = SOUTH, [99] = SOUTH, + [100] = SOUTH, [101] = SOUTH, [102] = SOUTH, [103] = SOUTH, + [104] = EAST, [105] = EAST, [106] = EAST, [107] = EAST, + [108] = EAST, [109] = EAST, [110] = EAST, [111] = EAST, + [112] = EAST, [113] = EAST, [114] = EAST, [115] = EAST, + [116] = EAST, [117] = SOUTH, [118] = SOUTH, [119] = SOUTH, + [120] = SOUTH, [121] = EAST, [122] = EAST, [123] = EAST, + [124] = EAST, [125] = EAST, [126] = EAST, [127] = EAST, + [128] = EAST, [129] = SOUTH, [130] = SOUTH, [131] = SOUTH, + [132] = SOUTH, +}; + +static const char *sm6125_get_function_name(struct udevice *dev, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].name; +} + +static const char *sm6125_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + if (selector >= 133 && selector <= 140) + snprintf(pin_name, MAX_PIN_NAME_LEN, + msm_special_pins_data[selector - 133].name); + else + snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector); + + return pin_name; +} + +static int sm6125_get_function_mux(__maybe_unused unsigned int pin, + unsigned int selector) +{ + return msm_pinctrl_functions[selector].val; +} + +static struct msm_pinctrl_data sm6125_data = { + .pin_data = { + .pin_offsets = sm6125_pin_offsets, + .pin_count = 141, + .special_pins_start = 133, + .special_pins_data = msm_special_pins_data, + }, + .functions_count = ARRAY_SIZE(msm_pinctrl_functions), + .get_function_name = sm6125_get_function_name, + .get_function_mux = sm6125_get_function_mux, + .get_pin_name = sm6125_get_pin_name, +}; + +static const struct udevice_id msm_pinctrl_ids[] = { + { .compatible = "qcom,sm6125-tlmm", .data = (ulong)&sm6125_data }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(pinctrl_sm6125) = { + .name = "pinctrl_sm6125", + .id = UCLASS_NOP, + .of_match = msm_pinctrl_ids, + .ops = &msm_pinctrl_ops, + .bind = msm_pinctrl_bind, +}; diff --git a/drivers/pinctrl/spacemit/Kconfig b/drivers/pinctrl/spacemit/Kconfig new file mode 100644 index 00000000000..6aab89e160c --- /dev/null +++ b/drivers/pinctrl/spacemit/Kconfig @@ -0,0 +1,9 @@ +config PINCTRL_SPACEMIT_K1 + bool "Spacemit K1 SoC pinctrl driver" + depends on PINCTRL_GENERIC && DM + help + Supports pin multiplexing control on Spacemit K1 SoCs. + + The driver is controlled by a device tree node which contains both + the GPIO definitions and pin control functions for each available + multiplex function. diff --git a/drivers/pinctrl/spacemit/Makefile b/drivers/pinctrl/spacemit/Makefile new file mode 100644 index 00000000000..0dc43c72cb1 --- /dev/null +++ b/drivers/pinctrl/spacemit/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-y += pinctrl-k1.o diff --git a/drivers/pinctrl/spacemit/pinctrl-k1.c b/drivers/pinctrl/spacemit/pinctrl-k1.c new file mode 100644 index 00000000000..a6a22eacac7 --- /dev/null +++ b/drivers/pinctrl/spacemit/pinctrl-k1.c @@ -0,0 +1,550 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Yixun Lan <[email protected]> + * Copyright (c) 2025-2026 RISCstar Ltd. + */ + +#include <clk.h> +#include <dm/device.h> +#include <dm/device_compat.h> +#include <dm/pinctrl.h> +#include <dm/read.h> +#include <linux/bitops.h> +#include <linux/errno.h> +#include <linux/io.h> + +/* + * +---------+----------+-----------+--------+--------+----------+--------+ + * | pull | drive | schmitter | slew | edge | strong | mux | + * | up/down | strength | trigger | rate | detect | pull | mode | + * +---------+----------+-----------+--------+--------+----------+--------+ + * 3 bits 3 bits 2 bits 1 bit 3 bits 1 bit 3 bits + */ + +#define PAD_MUX GENMASK(2, 0) +#define PAD_STRONG_PULL BIT(3) +#define PAD_EDGE_RISE BIT(4) +#define PAD_EDGE_FALL BIT(5) +#define PAD_EDGE_CLEAR BIT(6) +#define PAD_SLEW_RATE GENMASK(12, 11) +#define PAD_SLEW_RATE_EN BIT(7) +#define PAD_SCHMITT GENMASK(9, 8) +#define PAD_DRIVE GENMASK(12, 10) +#define PAD_PULLDOWN BIT(13) +#define PAD_PULLUP BIT(14) +#define PAD_PULL_EN BIT(15) + +#define PIN_POWER_STATE_1V8 1800 +#define PIN_POWER_STATE_3V3 3300 + +enum spacemit_pin_io_type { + IO_TYPE_NONE = 0, + IO_TYPE_1V8, + IO_TYPE_3V3, + IO_TYPE_EXTERNAL, +}; + +struct spacemit_pin_io { + unsigned int pin : 12; // 0~4095 + unsigned int io_type : 4; // 0~15 + unsigned int ds : 8; // 0~255 + unsigned int reserved : 8; +}; + +struct spacemit_pinctrl_data { + struct spacemit_pin_io *io_pins; + int nr_io_pins; + + void __iomem * (*pin_to_reg)(struct udevice *dev, unsigned int pin); + int (*get_gpio_mux)(struct udevice *dev, unsigned int pin); + int (*get_pins)(struct udevice *dev); + int (*get_functions)(struct udevice *dev); + int (*get_io_type)(struct udevice *dev, unsigned int pin); +}; + +struct spacemit_pinctrl_priv { + void __iomem *regs; + struct spacemit_pin_io *io_pins; + int nr_io_pins; +}; + +struct spacemit_pin_mux_config { + const struct spacemit_pin *pin; + u32 config; +}; + +struct spacemit_pin_drv_strength { + unsigned int val : 8; + unsigned int ma : 16; + unsigned int reserved : 8; +}; + +static char pin_name[PINNAME_SIZE]; + +/* External: IO voltage via external source, can be 1.8V or 3.3V */ +static struct spacemit_pin_io k1_io_pins[] = { + { 47, IO_TYPE_EXTERNAL, 0, }, + { 48, IO_TYPE_EXTERNAL, 0, }, + { 49, IO_TYPE_EXTERNAL, 0, }, + { 50, IO_TYPE_EXTERNAL, 0, }, + { 51, IO_TYPE_EXTERNAL, 0, }, + { 52, IO_TYPE_EXTERNAL, 0, }, + { 75, IO_TYPE_EXTERNAL, 0, }, + { 76, IO_TYPE_EXTERNAL, 0, }, + { 77, IO_TYPE_EXTERNAL, 0, }, + { 78, IO_TYPE_EXTERNAL, 0, }, + { 79, IO_TYPE_EXTERNAL, 0, }, + { 80, IO_TYPE_EXTERNAL, 0, }, + { 98, IO_TYPE_EXTERNAL, 0, }, + { 99, IO_TYPE_EXTERNAL, 0, }, + { 100, IO_TYPE_EXTERNAL, 0, }, + { 101, IO_TYPE_EXTERNAL, 0, }, + { 102, IO_TYPE_EXTERNAL, 0, }, + { 103, IO_TYPE_EXTERNAL, 0, }, + { 104, IO_TYPE_EXTERNAL, 0, }, + { 105, IO_TYPE_EXTERNAL, 0, }, + { 106, IO_TYPE_EXTERNAL, 0, }, + { 107, IO_TYPE_EXTERNAL, 0, }, + { 108, IO_TYPE_EXTERNAL, 0, }, + { 109, IO_TYPE_EXTERNAL, 0, }, +}; + +static inline int k1_get_pins(struct udevice *dev) +{ + return 128; +} + +static inline int k1_get_functions(struct udevice *dev) +{ + return 7; +} + +// The pin number equals to the gpio number. +static void __iomem *k1_pin_to_reg(struct udevice *dev, unsigned int pin) +{ + struct spacemit_pinctrl_priv *priv = dev_get_priv(dev); + unsigned int offset = 1; + + if (pin < 86) { + offset += pin; + } else if (pin < 93) { + offset += pin + 36; + } else if (pin < 98) { + offset += pin + 23; + } else if (pin == 98) { // QSPI_DAT3 + offset += 92; + } else if (pin == 99) { // QSPI_DAT2 + offset += 91; + } else if (pin == 100) { // QSPI_DAT1 + offset += 90; + } else if (pin == 101) { // QSPI_DAT0 + offset += 89; + } else if (pin == 102) { // QSPI_CLK + offset += 94; + } else if (pin == 103) { // QSPI_CS1 + offset += 93; + } else if (pin < 111) { + offset += pin + 5; + } else if (pin < 128) { + offset += pin + 19; + } else { + dev_err(dev, "Invalid pin (%u)\n", pin); + return NULL; + } + return priv->regs + (offset << 2); +} + +static int k1_get_gpio_mux(struct udevice *dev, unsigned int selector) +{ + u32 mux = 0; + + if (selector < 70) { + mux = 0; + } else if (selector < 74) { + mux = 1; + } else if (selector < 93) { + mux = 0; + } else if (selector < 104) { + mux = 1; + } else if (selector < 110) { + mux = 4; + } else if (selector < 128) { + mux = 0; + } else { + dev_err(dev, "Invalid pin (%u)\n", selector); + return -EINVAL; + } + return mux; +} + +static int k1_get_io_type(struct udevice *dev, unsigned int selector) +{ + if (selector < 47) + return IO_TYPE_1V8; + else if (selector < 53) + return IO_TYPE_EXTERNAL; + else if (selector < 75) + return IO_TYPE_1V8; + else if (selector < 81) + return IO_TYPE_EXTERNAL; + else if (selector < 98) + return IO_TYPE_1V8; + else if (selector < 110) + return IO_TYPE_EXTERNAL; + else if (selector < 128) + return IO_TYPE_1V8; + return -EINVAL; +} + +/* use IO high level output current as the table */ +static struct spacemit_pin_drv_strength spacemit_ds_1v8_tbl[4] = { + { 0, 11 }, + { 2, 21 }, + { 4, 32 }, + { 6, 42 }, +}; + +static struct spacemit_pin_drv_strength spacemit_ds_3v3_tbl[8] = { + { 0, 7 }, + { 2, 10 }, + { 4, 13 }, + { 6, 16 }, + { 1, 19 }, + { 3, 23 }, + { 5, 26 }, + { 7, 29 }, +}; + +static inline u8 spacemit_get_ds_value(struct spacemit_pin_drv_strength *tbl, + u32 num, u32 ma) +{ + int i; + + for (i = 0; i < num; i++) + if (ma <= tbl[i].ma) + return tbl[i].val; + + return tbl[num - 1].val; +} + +static inline u32 spacemit_get_ds_ma(struct spacemit_pin_drv_strength *tbl, + u32 num, u32 val) +{ + int i; + + for (i = 0; i < num; i++) + if (val == tbl[i].val) + return tbl[i].ma; + + return 0; +} + +static inline u8 spacemit_get_drive_strength(enum spacemit_pin_io_type type, + u32 ma) +{ + switch (type) { + case IO_TYPE_1V8: + return spacemit_get_ds_value(spacemit_ds_1v8_tbl, + ARRAY_SIZE(spacemit_ds_1v8_tbl), + ma); + case IO_TYPE_3V3: + return spacemit_get_ds_value(spacemit_ds_3v3_tbl, + ARRAY_SIZE(spacemit_ds_3v3_tbl), + ma); + default: + return 0; + } +} + +static inline u32 spacemit_get_drive_strength_ma(enum spacemit_pin_io_type type, + u32 value) +{ + switch (type) { + case IO_TYPE_1V8: + return spacemit_get_ds_ma(spacemit_ds_1v8_tbl, + ARRAY_SIZE(spacemit_ds_1v8_tbl), + value & 0x6); + case IO_TYPE_3V3: + return spacemit_get_ds_ma(spacemit_ds_3v3_tbl, + ARRAY_SIZE(spacemit_ds_3v3_tbl), + value); + default: + return 0; + } +} + +static inline u16 spacemit_dt_get_pin(u32 value) +{ + return value >> 16; +} + +static inline u16 spacemit_dt_get_pin_mux(u32 value) +{ + return value & GENMASK(15, 0); +} + +static int spacemit_get_pins_count(struct udevice *dev) +{ + struct spacemit_pinctrl_data *data; + + data = (struct spacemit_pinctrl_data *)dev_get_driver_data(dev); + if (!data || !data->get_pins) + return -EINVAL; + return data->get_pins(dev); +} + +static const char *spacemit_get_pin_name(struct udevice *dev, + unsigned int selector) +{ + struct spacemit_pinctrl_data *data; + unsigned int npins; + + data = (struct spacemit_pinctrl_data *)dev_get_driver_data(dev); + if (!data || !data->get_pins) + return NULL; + npins = data->get_pins(dev); + + if (selector >= npins) + snprintf(pin_name, PINNAME_SIZE, "Error"); + else + snprintf(pin_name, PINNAME_SIZE, "PIN%u", selector); + + return pin_name; +} + +static int spacemit_get_functions_count(struct udevice *dev) +{ + struct spacemit_pinctrl_data *data; + + data = (struct spacemit_pinctrl_data *)dev_get_driver_data(dev); + if (!data || !data->get_functions) + return -EINVAL; + return data->get_functions(dev); +} + +static int spacemit_get_pin_muxing(struct udevice *dev, unsigned int pin, + char *buf, int size) +{ + struct spacemit_pinctrl_data *data; + void __iomem *addr; + u32 mux, val; + + data = (struct spacemit_pinctrl_data *)dev_get_driver_data(dev); + if (!data || !data->pin_to_reg) + return -EINVAL; + + addr = data->pin_to_reg(dev, pin); + if (!addr) + return -EINVAL; + + val = readl(addr); + mux = val & PAD_MUX; + snprintf(buf, size, "[%p] 0x%08x MUX%d", addr, val, mux); + return 0; +} + +static int spacemit_pinctrl_request_gpio(struct udevice *dev, + unsigned int selector) +{ + struct spacemit_pinctrl_data *data; + void __iomem *addr; + int mux; + + data = (struct spacemit_pinctrl_data *)dev_get_driver_data(dev); + if (!data || !data->pin_to_reg || !data->get_gpio_mux) + return -EINVAL; + addr = data->pin_to_reg(dev, selector); + mux = data->get_gpio_mux(dev, selector); + if (mux < 0) { + dev_err(dev, "Invalid pin (%d)\n", selector); + return -EINVAL; + } + clrsetbits_le32(addr, PAD_MUX, mux & PAD_MUX); + return 0; +} + +static int spacemit_pinctrl_free_gpio(struct udevice *dev, + unsigned int selector) +{ + return 0; +} + +static int spacemit_pinmux_set(struct udevice *dev, unsigned int pin, + unsigned int mux) +{ + struct spacemit_pinctrl_data *data; + void __iomem *addr; + + data = (struct spacemit_pinctrl_data *)dev_get_driver_data(dev); + if (!data || !data->pin_to_reg) + return -EINVAL; + addr = data->pin_to_reg(dev, pin); + clrsetbits_le32(addr, PAD_MUX, mux & PAD_MUX); + return 0; +} + +static int spacemit_pinmux_property_set(struct udevice *dev, u32 pinmux_group) +{ + u32 pin, mux; + + pin = spacemit_dt_get_pin(pinmux_group); + mux = spacemit_dt_get_pin_mux(pinmux_group); + return spacemit_pinmux_set(dev, pin, mux); +} + +static const struct pinconf_param spacemit_pinconf_params[] = { + { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, + { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 }, + { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 }, + { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, U32_MAX }, + { "power-source", PIN_CONFIG_POWER_SOURCE, U32_MAX }, +}; + +static int spacemit_pinconf_set(struct udevice *dev, unsigned int pin_selector, + unsigned int param, unsigned int argument) +{ + struct spacemit_pinctrl_data *data; + struct spacemit_pinctrl_priv *priv = dev_get_priv(dev); + void __iomem *addr; + u32 mask = 0; + unsigned int io_type; + u8 ds; + bool found; + int i; + + data = (struct spacemit_pinctrl_data *)dev_get_driver_data(dev); + if (!data || !data->pin_to_reg) + return -EINVAL; + addr = data->pin_to_reg(dev, pin_selector); + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + clrbits_le32(addr, PAD_PULLUP | PAD_PULLDOWN | PAD_PULL_EN); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + mask = PAD_PULLDOWN | PAD_PULLUP | PAD_PULL_EN; + clrsetbits_le32(addr, mask, PAD_PULLDOWN | PAD_PULL_EN); + break; + case PIN_CONFIG_BIAS_PULL_UP: + mask = PAD_PULLDOWN | PAD_PULLUP | PAD_PULL_EN; + clrsetbits_le32(addr, mask, PAD_PULLUP | PAD_PULL_EN); + break; + case PIN_CONFIG_DRIVE_STRENGTH: + io_type = IO_TYPE_1V8; + for (i = 0; i < priv->nr_io_pins; i++) { + if (priv->io_pins[i].pin != pin_selector) + continue; + io_type = priv->io_pins[i].io_type; + break; + } + if (io_type != IO_TYPE_3V3 && io_type != IO_TYPE_1V8) { + dev_err(dev, "Invalid IO type (%d)\n", io_type); + return -EINVAL; + } + ds = spacemit_get_drive_strength(io_type, argument); + clrsetbits_le32(addr, PAD_DRIVE, ds); + break; + case PIN_CONFIG_POWER_SOURCE: + for (i = 0, found = false; i < priv->nr_io_pins; i++) { + if (priv->io_pins[i].pin != pin_selector) + continue; + if (argument == PIN_POWER_STATE_3V3) { + priv->io_pins[i].io_type = IO_TYPE_3V3; + found = true; + } else if (argument == PIN_POWER_STATE_1V8) { + priv->io_pins[i].io_type = IO_TYPE_1V8; + found = true; + } + break; + } + if (!found && argument != PIN_POWER_STATE_1V8) { + dev_err(dev, "Invalid power source (%d)\n", argument); + return -EINVAL; + } + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +static int spacemit_pinctrl_probe(struct udevice *dev) +{ + struct spacemit_pinctrl_data *data; + struct spacemit_pinctrl_priv *priv; + struct clk_bulk clks; + size_t size; + int ret; + + data = (struct spacemit_pinctrl_data *)dev_get_driver_data(dev); + priv = dev_get_priv(dev); + priv->regs = dev_read_addr_ptr(dev); + if (!priv->regs) { + dev_err(dev, "Fail to get base address\n"); + return -EINVAL; + } + priv->nr_io_pins = data->nr_io_pins; + size = priv->nr_io_pins * sizeof(struct spacemit_pin_io); + priv->io_pins = (struct spacemit_pin_io *)memdup(data->io_pins, size); + if (!priv->io_pins) { + dev_err(dev, "Fail to allocate memory\n"); + return -ENOMEM; + } + + ret = clk_get_bulk(dev, &clks); + if (ret) { + dev_err(dev, "Fail to get bulk clks\n"); + goto out_get_clk; + } + ret = clk_enable_bulk(&clks); + if (ret) { + dev_err(dev, "Fail to enable bulk clks\n"); + goto out_clks; + } + return 0; +out_clks: + clk_release_bulk(&clks); +out_get_clk: + free(priv->io_pins); + return ret; +} + +static const struct spacemit_pinctrl_data k1_pinctrl_data = { + .io_pins = k1_io_pins, + .nr_io_pins = ARRAY_SIZE(k1_io_pins), + .pin_to_reg = k1_pin_to_reg, + .get_gpio_mux = k1_get_gpio_mux, + .get_pins = k1_get_pins, + .get_functions = k1_get_functions, + .get_io_type = k1_get_io_type, +}; + +static const struct udevice_id spacemit_pinctrl_ids[] = { + { + .compatible = "spacemit,k1-pinctrl", + .data = (uintptr_t)&k1_pinctrl_data, + }, { /* sentinel */ } +}; + +static const struct pinctrl_ops spacemit_pinctrl_ops = { + .get_pins_count = spacemit_get_pins_count, + .get_pin_name = spacemit_get_pin_name, + .get_functions_count = spacemit_get_functions_count, + .get_pin_muxing = spacemit_get_pin_muxing, + .set_state = pinctrl_generic_set_state, + .gpio_request_enable = spacemit_pinctrl_request_gpio, + .gpio_disable_free = spacemit_pinctrl_free_gpio, + .pinmux_set = spacemit_pinmux_set, + .pinmux_property_set = spacemit_pinmux_property_set, + .pinconf_num_params = ARRAY_SIZE(spacemit_pinconf_params), + .pinconf_params = spacemit_pinconf_params, + .pinconf_set = spacemit_pinconf_set, +}; + +U_BOOT_DRIVER(spacemit_pinctrl) = { + .name = "spacemit_pinctrl", + .id = UCLASS_PINCTRL, + .of_match = spacemit_pinctrl_ids, + .ops = &spacemit_pinctrl_ops, + .priv_auto = sizeof(struct spacemit_pinctrl_priv), + .probe = spacemit_pinctrl_probe, +}; diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index fd357ab0d4e..a8632aeaf8f 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -603,6 +603,7 @@ static const struct sunxi_pinctrl_function sun20i_d1_pinctrl_functions[] = { { "gpio_in", 0 }, { "gpio_out", 1 }, { "i2c0", 4 }, /* PB10-PB11 */ + { "i2c3", 3 }, /* PG10-PG11 */ { "mmc0", 2 }, /* PF0-PF5 */ { "mmc1", 2 }, /* PG0-PG5 */ { "mmc2", 3 }, /* PC2-PC7 */ diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 1b06d8a66c7..66c389d073b 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -1,7 +1,7 @@ menuconfig POWER - bool "Power" - default y - help + bool "Power" + default y + help Enable support for power control in U-Boot. This includes support for PMICs (Power-management Integrated Circuits) and some of the features provided by PMICs. In particular, voltage regulators can @@ -63,98 +63,98 @@ choice config SUNXI_NO_PMIC bool "board without a pmic" - ---help--- - Select this for boards which do not use a PMIC. + help + Select this for boards which do not use a PMIC. config AXP152_POWER bool "axp152 pmic support" depends on MACH_SUN5I select AXP_PMIC_BUS select CMD_POWEROFF - ---help--- - Select this to enable support for the axp152 pmic found on most - A10s boards. + help + Select this to enable support for the axp152 pmic found on most + A10s boards. config AXP209_POWER bool "axp209 pmic support" depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || MACH_SUN8I_V3S select AXP_PMIC_BUS select CMD_POWEROFF - ---help--- - Select this to enable support for the axp209 pmic found on most - A10, A13 and A20 boards. + help + Select this to enable support for the axp209 pmic found on most + A10, A13 and A20 boards. config AXP221_POWER bool "axp221 / axp223 pmic support" depends on MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33 || MACH_SUN8I_R40 select AXP_PMIC_BUS select CMD_POWEROFF - ---help--- - Select this to enable support for the axp221/axp223 pmic found on most - A23 and A31 boards. + help + Select this to enable support for the axp221/axp223 pmic found on most + A23 and A31 boards. config AXP305_POWER bool "axp305 pmic support" depends on MACH_SUN50I_H616 select AXP_PMIC_BUS select CMD_POWEROFF - ---help--- - Select this to enable support for the axp305 pmic found on most - H616 boards. + help + Select this to enable support for the axp305 pmic found on most + H616 boards. config AXP313_POWER bool "axp313 pmic support" depends on MACH_SUN50I_H616 select AXP_PMIC_BUS select CMD_POWEROFF - ---help--- - Select this to enable support for the AXP313 PMIC found on some - H616 boards. + help + Select this to enable support for the AXP313 PMIC found on some + H616 boards. config AXP717_POWER bool "axp717 pmic support" select AXP_PMIC_BUS select CMD_POWEROFF - ---help--- - Select this to enable support for the AXP717 PMIC found on some boards. + help + Select this to enable support for the AXP717 PMIC found on some boards. config AXP803_POWER bool "AXP803 PMIC support" select AXP_PMIC_BUS - ---help--- - Select this to enable support for the AXP803 PMIC found on some boards. + help + Select this to enable support for the AXP803 PMIC found on some boards. config AXP809_POWER bool "axp809 pmic support" depends on MACH_SUN9I select AXP_PMIC_BUS select CMD_POWEROFF - ---help--- - Say y here to enable support for the axp809 pmic found on A80 boards. + help + Say y here to enable support for the axp809 pmic found on A80 boards. config AXP818_POWER bool "axp818 pmic support" depends on MACH_SUN8I_A83T select AXP_PMIC_BUS select CMD_POWEROFF - ---help--- - Say y here to enable support for the axp818 pmic found on - A83T dev board. + help + Say y here to enable support for the axp818 pmic found on + A83T dev board. config AXP318W_POWER bool "axp318w pmic support" select AXP_PMIC_BUS select CMD_POWEROFF - ---help--- - Select this to enable support for the AXP318W PMIC found on some - A733 boards. + help + Select this to enable support for the AXP318W PMIC found on some + A733 boards. config SY8106A_POWER bool "SY8106A pmic support" depends on MACH_SUNXI_H3_H5 - ---help--- - Select this to enable support for the SY8106A pmic found on some - H3 boards. + help + Select this to enable support for the SY8106A pmic found on some + H3 boards. endchoice @@ -166,22 +166,22 @@ config AXP_I2C_ADDRESS default 0x36 if AXP318W_POWER default 0x30 if AXP152_POWER default 0x34 - ---help--- - I2C address of the AXP PMIC, used for the SPL only. + help + I2C address of the AXP PMIC, used for the SPL only. config AXP_DCDC1_VOLT int "axp pmic dcdc1 voltage" depends on AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP803_POWER default 3300 if AXP818_POWER || MACH_SUN8I_R40 || AXP803_POWER default 3000 if MACH_SUN6I || MACH_SUN8I || MACH_SUN9I - ---help--- - Set the voltage (mV) to program the axp pmic dcdc1 at, set to 0 to - disable dcdc1. On A23 / A31 / A33 (axp221) boards dcdc1 is used for - generic 3.3V IO voltage for external devices like the lcd-panal and - sdcard interfaces, etc. On most boards dcdc1 is undervolted to 3.0V to - save battery. On A31 devices dcdc1 is also used for VCC-IO. On A83T - dcdc1 is used for VCC-IO, nand, usb0, sd , etc. On A80 dcdc1 normally - powers some of the pingroups, NAND/eMMC, SD/MMC, and USB OTG. + help + Set the voltage (mV) to program the axp pmic dcdc1 at, set to 0 to + disable dcdc1. On A23 / A31 / A33 (axp221) boards dcdc1 is used for + generic 3.3V IO voltage for external devices like the lcd-panal and + sdcard interfaces, etc. On most boards dcdc1 is undervolted to 3.0V to + save battery. On A31 devices dcdc1 is also used for VCC-IO. On A83T + dcdc1 is used for VCC-IO, nand, usb0, sd , etc. On A80 dcdc1 normally + powers some of the pingroups, NAND/eMMC, SD/MMC, and USB OTG. config AXP_DCDC2_VOLT int "axp pmic dcdc2 voltage" @@ -194,16 +194,16 @@ config AXP_DCDC2_VOLT default 1200 if MACH_SUN6I default 1100 if MACH_SUN8I default 0 if MACH_SUN9I - ---help--- - Set the voltage (mV) to program the axp pmic dcdc2 at, set to 0 to - disable dcdc2. - On A10(s) / A13 / A20 boards dcdc2 is VDD-CPU and should be 1.4V. - On A31 boards dcdc2 is used for VDD-GPU and should be 1.2V. - On A23/A33 boards dcdc2 is used for VDD-SYS and should be 1.1V. - On A80 boards dcdc2 powers the GPU and can be left off. - On A83T boards dcdc2 is used for VDD-CPUA(cluster 0) and should be 0.9V. - On R40 boards dcdc2 is VDD-CPU and should be 1.1V - On boards using the AXP313 or AXP717 it's often VDD-CPU. + help + Set the voltage (mV) to program the axp pmic dcdc2 at, set to 0 to + disable dcdc2. + On A10(s) / A13 / A20 boards dcdc2 is VDD-CPU and should be 1.4V. + On A31 boards dcdc2 is used for VDD-GPU and should be 1.2V. + On A23/A33 boards dcdc2 is used for VDD-SYS and should be 1.1V. + On A80 boards dcdc2 powers the GPU and can be left off. + On A83T boards dcdc2 is used for VDD-CPUA(cluster 0) and should be 0.9V. + On R40 boards dcdc2 is VDD-CPU and should be 1.1V + On boards using the AXP313 or AXP717 it's often VDD-CPU. config AXP_DCDC3_VOLT int "axp pmic dcdc3 voltage" @@ -214,18 +214,18 @@ config AXP_DCDC3_VOLT default 1100 if AXP313_POWER default 1100 if MACH_SUN8I_R40 default 1200 if MACH_SUN6I || MACH_SUN8I - ---help--- - Set the voltage (mV) to program the axp pmic dcdc3 at, set to 0 to - disable dcdc3. - On A10(s) / A13 / A20 boards with an axp209 dcdc3 is VDD-INT-DLL and - should be 1.25V. - On A10s boards with an axp152 dcdc3 is VCC-DRAM and should be 1.5V. - On A23 / A31 / A33 boards dcdc3 is VDD-CPU and should be 1.2V. - On A80 boards dcdc3 is used for VDD-CPUA(cluster 0) and should be 0.9V. - On A83T boards dcdc3 is used for VDD-CPUB(cluster 1) and should be 0.9V. - On R40 boards dcdc3 is VDD-SYS and VDD-GPU and should be 1.1V. - On boards using the AXP313 or AXP717 it's often VDD-DRAM and should - be 1.1V for LPDDR4. + help + Set the voltage (mV) to program the axp pmic dcdc3 at, set to 0 to + disable dcdc3. + On A10(s) / A13 / A20 boards with an axp209 dcdc3 is VDD-INT-DLL and + should be 1.25V. + On A10s boards with an axp152 dcdc3 is VCC-DRAM and should be 1.5V. + On A23 / A31 / A33 boards dcdc3 is VDD-CPU and should be 1.2V. + On A80 boards dcdc3 is used for VDD-CPUA(cluster 0) and should be 0.9V. + On A83T boards dcdc3 is used for VDD-CPUB(cluster 1) and should be 0.9V. + On R40 boards dcdc3 is VDD-SYS and VDD-GPU and should be 1.1V. + On boards using the AXP313 or AXP717 it's often VDD-DRAM and should + be 1.1V for LPDDR4. config AXP_DCDC4_VOLT int "axp pmic dcdc4 voltage" @@ -235,25 +235,25 @@ config AXP_DCDC4_VOLT default 0 if MACH_SUN8I default 900 if MACH_SUN9I default 1500 if AXP305_POWER - ---help--- - Set the voltage (mV) to program the axp pmic dcdc4 at, set to 0 to - disable dcdc4. - On A10s boards with an axp152 dcdc4 is VDD-INT-DLL and should be 1.25V. - On A31 boards dcdc4 is used for VDD-SYS and should be 1.2V. - On A23 / A33 boards dcdc4 is unused and should be disabled. - On A80 boards dcdc4 powers VDD-SYS, HDMI, USB OTG and should be 0.9V. - On A83T boards dcdc4 is used for VDD-GPU. - On H616 boards dcdcd is used for VCC-DRAM. + help + Set the voltage (mV) to program the axp pmic dcdc4 at, set to 0 to + disable dcdc4. + On A10s boards with an axp152 dcdc4 is VDD-INT-DLL and should be 1.25V. + On A31 boards dcdc4 is used for VDD-SYS and should be 1.2V. + On A23 / A33 boards dcdc4 is unused and should be disabled. + On A80 boards dcdc4 powers VDD-SYS, HDMI, USB OTG and should be 0.9V. + On A83T boards dcdc4 is used for VDD-GPU. + On H616 boards dcdcd is used for VCC-DRAM. config AXP_DCDC5_VOLT int "axp pmic dcdc5 voltage" depends on AXP221_POWER || AXP809_POWER || AXP818_POWER || AXP803_POWER default 1500 if MACH_SUN6I || MACH_SUN8I || MACH_SUN9I - ---help--- - Set the voltage (mV) to program the axp pmic dcdc5 at, set to 0 to - disable dcdc5. - On A23 / A31 / A33 / A80 / A83T / R40 boards dcdc5 is VCC-DRAM and - should be 1.5V, 1.35V if DDR3L is used. + help + Set the voltage (mV) to program the axp pmic dcdc5 at, set to 0 to + disable dcdc5. + On A23 / A31 / A33 / A80 / A83T / R40 boards dcdc5 is VCC-DRAM and + should be 1.5V, 1.35V if DDR3L is used. config AXP_ALDO1_VOLT int "axp pmic (a)ldo1 voltage" @@ -261,14 +261,14 @@ config AXP_ALDO1_VOLT default 0 if MACH_SUN6I || MACH_SUN8I_R40 default 1800 if MACH_SUN8I_A83T default 3000 if MACH_SUN8I || MACH_SUN9I - ---help--- - Set the voltage (mV) to program the axp pmic aldo1 at, set to 0 to - disable aldo1. - On A31 boards aldo1 is often used to power the wifi module. - On A23 / A33 boards aldo1 is used for VCC-IO and should be 3.0V. - On A80 boards aldo1 powers the USB hosts and should be 3.0V. - On A83T / H8 boards aldo1 is used for MIPI CSI, DSI, HDMI, EFUSE, and - should be 1.8V. + help + Set the voltage (mV) to program the axp pmic aldo1 at, set to 0 to + disable aldo1. + On A31 boards aldo1 is often used to power the wifi module. + On A23 / A33 boards aldo1 is used for VCC-IO and should be 3.0V. + On A80 boards aldo1 powers the USB hosts and should be 3.0V. + On A83T / H8 boards aldo1 is used for MIPI CSI, DSI, HDMI, EFUSE, and + should be 1.8V. config AXP_ALDO2_VOLT int "axp pmic (a)ldo2 voltage" @@ -277,188 +277,188 @@ config AXP_ALDO2_VOLT default 0 if MACH_SUN6I || MACH_SUN9I default 1800 if MACH_SUN8I_A83T default 2500 if MACH_SUN8I - ---help--- - Set the voltage (mV) to program the axp pmic aldo2 at, set to 0 to - disable aldo2. - On A10(s) / A13 / A20 boards aldo2 is AVCC and should be 3.0V. - On A31 boards aldo2 is typically unused and should be disabled. - On A31 boards aldo2 may be used for LPDDR2 then it should be 1.8V. - On A23 / A33 boards aldo2 is used for VDD-DLL and should be 2.5V. - On A80 boards aldo2 powers PB pingroup and camera IO and can be left off. - On A83T / H8 boards aldo2 powers VDD-DLL, VCC18-PLL, CPVDD, VDD18-ADC, - LPDDR2, and the codec. It should be 1.8V. + help + Set the voltage (mV) to program the axp pmic aldo2 at, set to 0 to + disable aldo2. + On A10(s) / A13 / A20 boards aldo2 is AVCC and should be 3.0V. + On A31 boards aldo2 is typically unused and should be disabled. + On A31 boards aldo2 may be used for LPDDR2 then it should be 1.8V. + On A23 / A33 boards aldo2 is used for VDD-DLL and should be 2.5V. + On A80 boards aldo2 powers PB pingroup and camera IO and can be left off. + On A83T / H8 boards aldo2 powers VDD-DLL, VCC18-PLL, CPVDD, VDD18-ADC, + LPDDR2, and the codec. It should be 1.8V. config AXP_ALDO3_VOLT int "axp pmic (a)ldo3 voltage" depends on AXP209_POWER || AXP221_POWER || AXP809_POWER || AXP818_POWER default 0 if AXP209_POWER || MACH_SUN9I default 3000 if MACH_SUN6I || MACH_SUN8I - ---help--- - Set the voltage (mV) to program the axp pmic aldo3 at, set to 0 to - disable aldo3. - On A10(s) / A13 / A20 boards aldo3 should be 2.8V. - On A23 / A31 / A33 / R40 boards aldo3 is VCC-PLL and AVCC and should - be 3.0V. - On A80 boards aldo3 is normally not used. - On A83T / H8 boards aldo3 is AVCC, VCC-PL, and VCC-LED, and should be - 3.0V. + help + Set the voltage (mV) to program the axp pmic aldo3 at, set to 0 to + disable aldo3. + On A10(s) / A13 / A20 boards aldo3 should be 2.8V. + On A23 / A31 / A33 / R40 boards aldo3 is VCC-PLL and AVCC and should + be 3.0V. + On A80 boards aldo3 is normally not used. + On A83T / H8 boards aldo3 is AVCC, VCC-PL, and VCC-LED, and should be + 3.0V. choice prompt "axp pmic (a)ldo3 voltage rate control" depends on AXP209_POWER default AXP_ALDO3_VOLT_SLOPE_NONE - ---help--- - The AXP can slowly ramp up voltage to reduce the inrush current when - changing voltages. - Note, this does not apply when enabling/disabling LDO3. See - "axp pmic (a)ldo3 inrush quirk" below to enable a slew rate to limit - inrush current on broken board designs. + help + The AXP can slowly ramp up voltage to reduce the inrush current when + changing voltages. + Note, this does not apply when enabling/disabling LDO3. See + "axp pmic (a)ldo3 inrush quirk" below to enable a slew rate to limit + inrush current on broken board designs. config AXP_ALDO3_VOLT_SLOPE_NONE bool "No voltage slope" - ---help--- - Tries to reach the next voltage setting near instantaneously. Measurements - indicate that this is about 0.0167 V/uS. + help + Tries to reach the next voltage setting near instantaneously. Measurements + indicate that this is about 0.0167 V/uS. config AXP_ALDO3_VOLT_SLOPE_16 bool "1.6 mV per uS" - ---help--- - Increases the voltage by 1.6 mV per uS until the final voltage has - been reached. Note that the scaling is in 25 mV steps and thus - the slew rate in reality is about 25 mV/31.250 uS. + help + Increases the voltage by 1.6 mV per uS until the final voltage has + been reached. Note that the scaling is in 25 mV steps and thus + the slew rate in reality is about 25 mV/31.250 uS. config AXP_ALDO3_VOLT_SLOPE_08 bool "0.8 mV per uS" - ---help--- - Increases the voltage by 0.8 mV per uS until the final voltage has - been reached. Note that the scaling is in 25 mV steps however and thus - the slew rate in reality is about 25 mV/15.625 uS. - This is the slowest supported rate. + help + Increases the voltage by 0.8 mV per uS until the final voltage has + been reached. Note that the scaling is in 25 mV steps however and thus + the slew rate in reality is about 25 mV/15.625 uS. + This is the slowest supported rate. endchoice config AXP_ALDO3_INRUSH_QUIRK bool "axp pmic (a)ldo3 inrush quirk" depends on AXP209_POWER - ---help--- - The reference design denotes a value of 4.7 uF for the output capacitor - of LDO3. Some boards have too high capacitance causing an inrush current - and resulting an AXP209 shutdown. + help + The reference design denotes a value of 4.7 uF for the output capacitor + of LDO3. Some boards have too high capacitance causing an inrush current + and resulting an AXP209 shutdown. config AXP_ALDO4_VOLT int "axp pmic (a)ldo4 voltage" depends on AXP209_POWER default 0 if AXP209_POWER - ---help--- - Set the voltage (mV) to program the axp pmic aldo4 at, set to 0 to - disable aldo4. - On A10(s) / A13 / A20 boards aldo4 should be 2.8V. + help + Set the voltage (mV) to program the axp pmic aldo4 at, set to 0 to + disable aldo4. + On A10(s) / A13 / A20 boards aldo4 should be 2.8V. config AXP_DLDO1_VOLT int "axp pmic dldo1 voltage" depends on AXP221_POWER || AXP809_POWER || AXP818_POWER default 0 - ---help--- - Set the voltage (mV) to program the axp pmic dldo1 at, set to 0 to - disable dldo1. On sun6i (A31) boards with ethernet dldo1 is often used - to power the ethernet phy. On A23, A33 and A80 boards this is often - used to power the wifi. + help + Set the voltage (mV) to program the axp pmic dldo1 at, set to 0 to + disable dldo1. On sun6i (A31) boards with ethernet dldo1 is often used + to power the ethernet phy. On A23, A33 and A80 boards this is often + used to power the wifi. config AXP_DLDO2_VOLT int "axp pmic dldo2 voltage" depends on AXP221_POWER || AXP809_POWER || AXP818_POWER default 3000 if MACH_SUN9I default 0 - ---help--- - Set the voltage (mV) to program the axp pmic dldo2 at, set to 0 to - disable dldo2. - On A80 boards dldo2 normally powers the PL pins and should be 3.0V. + help + Set the voltage (mV) to program the axp pmic dldo2 at, set to 0 to + disable dldo2. + On A80 boards dldo2 normally powers the PL pins and should be 3.0V. config AXP_DLDO3_VOLT int "axp pmic dldo3 voltage" depends on AXP221_POWER || AXP818_POWER default 0 - ---help--- - Set the voltage (mV) to program the axp pmic dldo3 at, set to 0 to - disable dldo3. + help + Set the voltage (mV) to program the axp pmic dldo3 at, set to 0 to + disable dldo3. config AXP_DLDO4_VOLT int "axp pmic dldo4 voltage" depends on AXP221_POWER || AXP818_POWER default 0 - ---help--- - Set the voltage (mV) to program the axp pmic dldo4 at, set to 0 to - disable dldo4. + help + Set the voltage (mV) to program the axp pmic dldo4 at, set to 0 to + disable dldo4. config AXP_ELDO1_VOLT int "axp pmic eldo1 voltage" depends on AXP221_POWER || AXP809_POWER || AXP818_POWER default 0 - ---help--- - Set the voltage (mV) to program the axp pmic eldo1 at, set to 0 to - disable eldo1. + help + Set the voltage (mV) to program the axp pmic eldo1 at, set to 0 to + disable eldo1. config AXP_ELDO2_VOLT int "axp pmic eldo2 voltage" depends on AXP221_POWER || AXP809_POWER || AXP818_POWER default 0 - ---help--- - Set the voltage (mV) to program the axp pmic eldo2 at, set to 0 to - disable eldo2. + help + Set the voltage (mV) to program the axp pmic eldo2 at, set to 0 to + disable eldo2. config AXP_ELDO3_VOLT int "axp pmic eldo3 voltage" depends on AXP221_POWER || AXP809_POWER || AXP818_POWER default 3000 if MACH_SUN9I default 0 - ---help--- - Set the voltage (mV) to program the axp pmic eldo3 at, set to 0 to - disable eldo3. On some A31(s) tablets it might be used to supply - 1.2V for the SSD2828 chip (converter of parallel LCD interface - into MIPI DSI). - On A80 boards it powers the PM pingroup and should be 3.0V. + help + Set the voltage (mV) to program the axp pmic eldo3 at, set to 0 to + disable eldo3. On some A31(s) tablets it might be used to supply + 1.2V for the SSD2828 chip (converter of parallel LCD interface + into MIPI DSI). + On A80 boards it powers the PM pingroup and should be 3.0V. config AXP_FLDO1_VOLT int "axp pmic fldo1 voltage" depends on AXP818_POWER default 0 if MACH_SUN8I_A83T - ---help--- - Set the voltage (mV) to program the axp pmic fldo1 at, set to 0 to - disable fldo1. - On A83T / H8 boards fldo1 is VCC-HSIC and should be 1.2V if HSIC is - used. + help + Set the voltage (mV) to program the axp pmic fldo1 at, set to 0 to + disable fldo1. + On A83T / H8 boards fldo1 is VCC-HSIC and should be 1.2V if HSIC is + used. config AXP_FLDO2_VOLT int "axp pmic fldo2 voltage" depends on AXP818_POWER default 900 if MACH_SUN8I_A83T - ---help--- - Set the voltage (mV) to program the axp pmic fldo2 at, set to 0 to - disable fldo2. - On A83T / H8 boards fldo2 is VCC-CPUS and should be 0.9V. + help + Set the voltage (mV) to program the axp pmic fldo2 at, set to 0 to + disable fldo2. + On A83T / H8 boards fldo2 is VCC-CPUS and should be 0.9V. config AXP_FLDO3_VOLT int "axp pmic fldo3 voltage" depends on AXP818_POWER default 0 - ---help--- - Set the voltage (mV) to program the axp pmic fldo3 at, set to 0 to - disable fldo3. + help + Set the voltage (mV) to program the axp pmic fldo3 at, set to 0 to + disable fldo3. config AXP_SW_ON bool "axp pmic sw on" depends on AXP809_POWER || AXP818_POWER - ---help--- - Enable to turn on axp pmic sw. + help + Enable to turn on axp pmic sw. config SY8106A_VOUT1_VOLT int "SY8106A pmic VOUT1 voltage" depends on SY8106A_POWER default 1200 - ---help--- - Set the voltage (mV) to program the SY8106A pmic VOUT1. This - is typically used to power the VDD-CPU and should be 1200mV. - Values can range from 680mV till 1950mV. + help + Set the voltage (mV) to program the SY8106A pmic VOUT1. This + is typically used to power the VDD-CPU and should be 1200mV. + Values can range from 680mV till 1950mV. config TPS6586X_POWER bool "Enable legacy driver for TI TPS6586x power management chip" @@ -467,9 +467,9 @@ config TWL4030_POWER depends on OMAP34XX bool "Enable driver for TI TWL4030 power management chip" imply CMD_POWEROFF - ---help--- - The TWL4030 in a combination audio CODEC/power management with - GPIO and it is commonly used with the OMAP3 family of processors + help + The TWL4030 in a combination audio CODEC/power management with + GPIO and it is commonly used with the OMAP3 family of processors config POWER_MT6323 bool "Poweroff driver for mediatek mt6323" diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig index 2f63a8e54e5..bb9c52155d2 100644 --- a/drivers/power/domain/Kconfig +++ b/drivers/power/domain/Kconfig @@ -35,10 +35,10 @@ config BCM6328_POWER_DOMAIN config IMX8_POWER_DOMAIN bool "Enable i.MX8 power domain driver" - depends on ARCH_IMX8 - help - Enable support for manipulating NXP i.MX8 on-SoC power domains via IPC - requests to the SCU. + depends on ARCH_IMX8 + help + Enable support for manipulating NXP i.MX8 on-SoC power domains via IPC + requests to the SCU. config IMX8M_POWER_DOMAIN bool "Enable i.MX8M power domain driver" @@ -90,6 +90,22 @@ config MESON_SECURE_POWER_DOMAIN Enable support for manipulating Amlogic Meson Secure power domains. Support for Amlogic A1 series. +config QCOM_RPMH_POWER_DOMAIN + bool "Enable the QCOM RPMH Power domain driver" + depends on POWER_DOMAIN && ARCH_SNAPDRAGON + help + Generic RPMH power domain implementation for QCOM devices. + The RPMH power domain driver is responsible for managing power + domains on Qualcomm SoCs. + +config RENESAS_R8A78000_POWER_DOMAIN + bool "Enable the Renesas R-Car MDLC Power domain and reset driver" + depends on POWER_DOMAIN && ARCH_RENESAS + help + Enable support for Renesas R-Car R8A78000 X5H MDLC Power domain + and reset driver. The MDLC is responsible for managing both + power domains and resets on R-Car R8A78000 X5H SoC. + config SANDBOX_POWER_DOMAIN bool "Enable the sandbox power domain test driver" depends on POWER_DOMAIN && SANDBOX diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile index b2c0bd8a61a..110153d5cf8 100644 --- a/drivers/power/domain/Makefile +++ b/drivers/power/domain/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_MTK_POWER_DOMAIN) += mtk-power-domain.o obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o obj-$(CONFIG_MESON_EE_POWER_DOMAIN) += meson-ee-pwrc.o obj-$(CONFIG_MESON_SECURE_POWER_DOMAIN) += meson-secure-pwrc.o +obj-$(CONFIG_RENESAS_R8A78000_POWER_DOMAIN) += renesas-r8a78000-power-domain.o obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o obj-$(CONFIG_SCMI_POWER_DOMAIN) += scmi-power-domain.o @@ -23,3 +24,4 @@ obj-$(CONFIG_TI_SCI_POWER_DOMAIN) += ti-sci-power-domain.o obj-$(CONFIG_TI_POWER_DOMAIN) += ti-power-domain.o obj-$(CONFIG_TI_OMAP_PRM_POWER_DOMAIN) += ti-omap-prm.o obj-$(CONFIG_ZYNQMP_POWER_DOMAIN) += zynqmp-power-domain.o +obj-$(CONFIG_QCOM_RPMH_POWER_DOMAIN) += qcom-rpmhpd.o diff --git a/drivers/power/domain/apple-pmgr.c b/drivers/power/domain/apple-pmgr.c index bf9940621ee..9873d3cd8db 100644 --- a/drivers/power/domain/apple-pmgr.c +++ b/drivers/power/domain/apple-pmgr.c @@ -67,7 +67,7 @@ static int apple_reset_deassert(struct reset_ctl *reset_ctl) return 0; } -struct reset_ops apple_reset_ops = { +static const struct reset_ops apple_reset_ops = { .of_xlate = apple_reset_of_xlate, .rst_assert = apple_reset_assert, .rst_deassert = apple_reset_deassert, @@ -110,6 +110,7 @@ static int apple_pmgr_of_xlate(struct power_domain *power_domain, } static const struct udevice_id apple_pmgr_ids[] = { + { .compatible = "apple,t8103-pmgr-pwrstate" }, { .compatible = "apple,pmgr-pwrstate" }, { /* sentinel */ } }; @@ -138,7 +139,7 @@ static int apple_pmgr_probe(struct udevice *dev) return 0; } -struct power_domain_ops apple_pmgr_ops = { +static const struct power_domain_ops apple_pmgr_ops = { .on = apple_pmgr_on, .of_xlate = apple_pmgr_of_xlate, }; diff --git a/drivers/power/domain/bcm6328-power-domain.c b/drivers/power/domain/bcm6328-power-domain.c index 36b5a933748..5b449f4c29d 100644 --- a/drivers/power/domain/bcm6328-power-domain.c +++ b/drivers/power/domain/bcm6328-power-domain.c @@ -57,7 +57,7 @@ static const struct udevice_id bcm6328_power_domain_ids[] = { { /* sentinel */ } }; -struct power_domain_ops bcm6328_power_domain_ops = { +static const struct power_domain_ops bcm6328_power_domain_ops = { .off = bcm6328_power_domain_off, .on = bcm6328_power_domain_on, .request = bcm6328_power_domain_request, diff --git a/drivers/power/domain/imx8-power-domain-legacy.c b/drivers/power/domain/imx8-power-domain-legacy.c index 713a51d7807..a646f667039 100644 --- a/drivers/power/domain/imx8-power-domain-legacy.c +++ b/drivers/power/domain/imx8-power-domain-legacy.c @@ -347,7 +347,7 @@ static const struct udevice_id imx8_power_domain_ids[] = { { } }; -struct power_domain_ops imx8_power_domain_ops = { +static const struct power_domain_ops imx8_power_domain_ops = { .on = imx8_power_domain_on, .off = imx8_power_domain_off, .of_xlate = imx8_power_domain_of_xlate, diff --git a/drivers/power/domain/imx8-power-domain.c b/drivers/power/domain/imx8-power-domain.c index e8dcc057fee..5740cd686db 100644 --- a/drivers/power/domain/imx8-power-domain.c +++ b/drivers/power/domain/imx8-power-domain.c @@ -51,7 +51,7 @@ static const struct udevice_id imx8_power_domain_ids[] = { { } }; -struct power_domain_ops imx8_power_domain_ops_v2 = { +static const struct power_domain_ops imx8_power_domain_ops_v2 = { .on = imx8_power_domain_on, .off = imx8_power_domain_off, }; diff --git a/drivers/power/domain/imx8m-power-domain.c b/drivers/power/domain/imx8m-power-domain.c index 1c731b897cc..a3ef49aa67c 100644 --- a/drivers/power/domain/imx8m-power-domain.c +++ b/drivers/power/domain/imx8m-power-domain.c @@ -476,7 +476,7 @@ static int imx8m_power_domain_bind(struct udevice *dev) const char *name; int ret = 0; - ofnode_for_each_subnode(subnode, dev_ofnode(dev)) { + dev_for_each_subnode(subnode, dev) { /* Bind the subnode to this driver */ name = ofnode_get_name(subnode); @@ -531,7 +531,7 @@ static int imx8m_power_domain_of_to_plat(struct udevice *dev) struct imx_pgc_domain_data *domain_data = (struct imx_pgc_domain_data *)dev_get_driver_data(dev); - pdata->resource_id = ofnode_read_u32_default(dev_ofnode(dev), "reg", -1); + pdata->resource_id = dev_read_u32_default(dev, "reg", -1); pdata->domain = &domain_data->domains[pdata->resource_id]; pdata->regs = domain_data->pgc_regs; pdata->base = dev_read_addr_ptr(dev->parent); @@ -558,7 +558,7 @@ static const struct udevice_id imx8m_power_domain_ids[] = { { } }; -struct power_domain_ops imx8m_power_domain_ops = { +static const struct power_domain_ops imx8m_power_domain_ops = { .on = imx8m_power_domain_on, .off = imx8m_power_domain_off, .of_xlate = imx8m_power_domain_of_xlate, diff --git a/drivers/power/domain/imx8mp-mediamix.c b/drivers/power/domain/imx8mp-mediamix.c index 504c22f7d36..66ea5d8e60c 100644 --- a/drivers/power/domain/imx8mp-mediamix.c +++ b/drivers/power/domain/imx8mp-mediamix.c @@ -194,7 +194,7 @@ static const struct udevice_id imx8mp_mediamix_ids[] = { { } }; -struct power_domain_ops imx8mp_mediamix_ops = { +static const struct power_domain_ops imx8mp_mediamix_ops = { .on = imx8mp_mediamix_on, .off = imx8mp_mediamix_off, .of_xlate = imx8mp_mediamix_of_xlate, diff --git a/drivers/power/domain/meson-ee-pwrc.c b/drivers/power/domain/meson-ee-pwrc.c index 4d9f3bba644..882238f2937 100644 --- a/drivers/power/domain/meson-ee-pwrc.c +++ b/drivers/power/domain/meson-ee-pwrc.c @@ -386,7 +386,7 @@ static int meson_ee_pwrc_of_xlate(struct power_domain *power_domain, return 0; } -struct power_domain_ops meson_ee_pwrc_ops = { +static const struct power_domain_ops meson_ee_pwrc_ops = { .off = meson_ee_pwrc_off, .on = meson_ee_pwrc_on, .of_xlate = meson_ee_pwrc_of_xlate, @@ -435,8 +435,7 @@ static const struct udevice_id meson_ee_pwrc_ids[] = { static int meson_ee_pwrc_probe(struct udevice *dev) { struct meson_ee_pwrc_priv *priv = dev_get_priv(dev); - u32 ao_phandle; - ofnode ao_node; + struct ofnode_phandle_args args; int ret; priv->data = (void *)dev_get_driver_data(dev); @@ -447,16 +446,12 @@ static int meson_ee_pwrc_probe(struct udevice *dev) if (IS_ERR(priv->regmap_hhi)) return PTR_ERR(priv->regmap_hhi); - ret = ofnode_read_u32(dev_ofnode(dev), "amlogic,ao-sysctrl", - &ao_phandle); + ret = dev_read_phandle_with_args(dev, "amlogic,ao-sysctrl", NULL, 0, 0, + &args); if (ret) return ret; - ao_node = ofnode_get_by_phandle(ao_phandle); - if (!ofnode_valid(ao_node)) - return -EINVAL; - - priv->regmap_ao = syscon_node_to_regmap(ao_node); + priv->regmap_ao = syscon_node_to_regmap(args.node); if (IS_ERR(priv->regmap_ao)) return PTR_ERR(priv->regmap_ao); diff --git a/drivers/power/domain/meson-gx-pwrc-vpu.c b/drivers/power/domain/meson-gx-pwrc-vpu.c index 1c56e8508c3..e08c0fac49a 100644 --- a/drivers/power/domain/meson-gx-pwrc-vpu.c +++ b/drivers/power/domain/meson-gx-pwrc-vpu.c @@ -262,7 +262,7 @@ static int meson_pwrc_vpu_of_xlate(struct power_domain *power_domain, return 0; } -struct power_domain_ops meson_gx_pwrc_vpu_ops = { +static const struct power_domain_ops meson_gx_pwrc_vpu_ops = { .off = meson_pwrc_vpu_off, .on = meson_pwrc_vpu_on, .of_xlate = meson_pwrc_vpu_of_xlate, @@ -283,24 +283,19 @@ static const struct udevice_id meson_gx_pwrc_vpu_ids[] = { static int meson_gx_pwrc_vpu_probe(struct udevice *dev) { struct meson_gx_pwrc_vpu_priv *priv = dev_get_priv(dev); - u32 hhi_phandle; - ofnode hhi_node; + struct ofnode_phandle_args args; int ret; priv->regmap_ao = syscon_node_to_regmap(dev_ofnode(dev_get_parent(dev))); if (IS_ERR(priv->regmap_ao)) return PTR_ERR(priv->regmap_ao); - ret = ofnode_read_u32(dev_ofnode(dev), "amlogic,hhi-sysctrl", - &hhi_phandle); + ret = dev_read_phandle_with_args(dev, "amlogic,hhi-sysctrl", NULL, 0, 0, + &args); if (ret) return ret; - hhi_node = ofnode_get_by_phandle(hhi_phandle); - if (!ofnode_valid(hhi_node)) - return -EINVAL; - - priv->regmap_hhi = syscon_node_to_regmap(hhi_node); + priv->regmap_hhi = syscon_node_to_regmap(args.node); if (IS_ERR(priv->regmap_hhi)) return PTR_ERR(priv->regmap_hhi); diff --git a/drivers/power/domain/meson-secure-pwrc.c b/drivers/power/domain/meson-secure-pwrc.c index f70f8e02423..1b82b58f3e5 100644 --- a/drivers/power/domain/meson-secure-pwrc.c +++ b/drivers/power/domain/meson-secure-pwrc.c @@ -120,7 +120,7 @@ static struct meson_secure_pwrc_domain_desc a1_pwrc_domains[] = { SEC_PD(RSA), }; -struct power_domain_ops meson_secure_pwrc_ops = { +static const struct power_domain_ops meson_secure_pwrc_ops = { .on = meson_secure_pwrc_on, .off = meson_secure_pwrc_off, .of_xlate = meson_secure_pwrc_of_xlate, diff --git a/drivers/power/domain/mtk-power-domain.c b/drivers/power/domain/mtk-power-domain.c index 2d1ba1855a5..24dd540897d 100644 --- a/drivers/power/domain/mtk-power-domain.c +++ b/drivers/power/domain/mtk-power-domain.c @@ -392,7 +392,7 @@ static const struct udevice_id mtk_power_domain_ids[] = { { /* sentinel */ } }; -struct power_domain_ops mtk_power_domain_ops = { +static const struct power_domain_ops mtk_power_domain_ops = { .off = scpsys_power_off, .on = scpsys_power_on, .request = scpsys_power_request, diff --git a/drivers/power/domain/power-domain-uclass.c b/drivers/power/domain/power-domain-uclass.c index cea68945cbd..b4cda5f6c16 100644 --- a/drivers/power/domain/power-domain-uclass.c +++ b/drivers/power/domain/power-domain-uclass.c @@ -10,6 +10,7 @@ #include <malloc.h> #include <power-domain.h> #include <power-domain-uclass.h> +#include <dm/device_compat.h> #include <dm/device-internal.h> struct power_domain_priv { @@ -187,6 +188,12 @@ static int dev_power_domain_ctrl(struct udevice *dev, bool on) "#power-domain-cells", 0); for (i = 0; i < count; i++) { ret = power_domain_get_by_index(dev, &pd, i); + + if (ret == -ENODEV) { + dev_warn(dev, "power-domain driver not found\n"); + return 0; + } + if (ret) return ret; if (on) diff --git a/drivers/power/domain/qcom-rpmhpd.c b/drivers/power/domain/qcom-rpmhpd.c new file mode 100644 index 00000000000..f51bc9a4bbb --- /dev/null +++ b/drivers/power/domain/qcom-rpmhpd.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018, The Linux Foundation. All rights reserved. +// Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + +#include <dm.h> +#include <dm/lists.h> +#include <power-domain.h> +#include <asm/io.h> +#include <linux/errno.h> + +#include <power-domain-uclass.h> +#include <soc/qcom/cmd-db.h> +#include <soc/qcom/rpmh.h> +#include <dt-bindings/power/qcom-rpmpd.h> +#include <dm/device_compat.h> + +#define RPMH_ARC_MAX_LEVELS 16 + +/** + * struct rpmhpd - top level RPMh power domain resource data structure + * @dev: rpmh power domain controller device + * @pd: generic_pm_domain corresponding to the power domain + * @parent: generic_pm_domain corresponding to the parent's power domain + * @enable_corner: lowest non-zero corner + * @level: An array of level (vlvl) to corner (hlvl) mappings + * derived from cmd-db + * @level_count: Number of levels supported by the power domain. max + * being 16 (0 - 15) + * @enabled: true if the power domain is enabled + * @res_name: Resource name used for cmd-db lookup + * @addr: Resource address as looped up using resource name from + * @skip_retention_level: Indicate that retention level should not be used for the power domain + */ +struct rpmhpd { + struct udevice *dev; + struct power_domain pd; + struct power_domain *parent; + unsigned int enable_corner; + u32 level[RPMH_ARC_MAX_LEVELS]; + size_t level_count; + bool enabled; + const char *res_name; + u32 addr; + bool skip_retention_level; +}; + +struct rpmhpd_desc { + struct rpmhpd **rpmhpds; + size_t num_pds; +}; + +/* RPMH powerdomains */ +static struct rpmhpd mmcx_ao; +static struct rpmhpd mmcx = { + .res_name = "mmcx.lvl", +}; + +static struct rpmhpd mmcx_ao = { + .res_name = "mmcx.lvl", +}; + +/* SA8775P RPMH power domains */ +static struct rpmhpd *sa8775p_rpmhpds[] = { + [SA8775P_MMCX] = &mmcx, + [SA8775P_MMCX_AO] = &mmcx_ao, +}; + +static const struct rpmhpd_desc sa8775p_desc = { + .rpmhpds = sa8775p_rpmhpds, + .num_pds = ARRAY_SIZE(sa8775p_rpmhpds), +}; + +/* stub RPMH power domains mapped for unsupported platforms */ +static struct rpmhpd *stub_rpmhpds[] = {}; + +static const struct rpmhpd_desc stub_desc = { + .rpmhpds = stub_rpmhpds, + .num_pds = ARRAY_SIZE(stub_rpmhpds), +}; + +static const struct udevice_id rpmhpd_match_table[] = { + { .compatible = "qcom,sa8775p-rpmhpd", .data = (ulong)&sa8775p_desc }, + { .compatible = "qcom,qcs615-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,qcs8300-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,qdu1000-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sa8155p-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sa8540p-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sar2130p-rpmhpd", .data = (ulong)&stub_desc}, + { .compatible = "qcom,sc7180-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sc7280-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sc8180x-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sc8280xp-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sdm670-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sdm845-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sdx55-rpmhpd", .data = (ulong)&stub_desc}, + { .compatible = "qcom,sdx65-rpmhpd", .data = (ulong)&stub_desc}, + { .compatible = "qcom,sdx75-rpmhpd", .data = (ulong)&stub_desc}, + { .compatible = "qcom,sm4450-rpmhpd", .data = (ulong)&stub_desc}, + { .compatible = "qcom,sm6350-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sm7150-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sm8150-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sm8250-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sm8350-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sm8450-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sm8550-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sm8650-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,sm8750-rpmhpd", .data = (ulong)&stub_desc }, + { .compatible = "qcom,x1e80100-rpmhpd", .data = (ulong)&stub_desc }, + { } +}; + +static int rpmhpd_send_corner(struct rpmhpd *pd, int state, + unsigned int corner, bool sync) +{ + struct tcs_cmd cmd = { + .addr = pd->addr, + .data = corner, + }; + + return rpmh_write(pd->dev, state, &cmd, 1); +} + +static int rpmhpd_power_on(struct power_domain *pd) +{ + int ret; + unsigned int corner; + struct rpmhpd **rpmhpds; + const struct rpmhpd_desc *desc; + struct rpmhpd *curr_rpmhpd; + + desc = (const struct rpmhpd_desc *)dev_get_driver_data(pd->dev); + if (!desc) + return -EINVAL; + + rpmhpds = desc->rpmhpds; + curr_rpmhpd = rpmhpds[pd->id]; + + /* Do nothing for undefined power domains */ + if (!curr_rpmhpd) { + log_warning("Power domain id (%ld) not supported\n", + pd->id); + return 0; + } + + corner = curr_rpmhpd->enable_corner; + + ret = rpmhpd_send_corner(curr_rpmhpd, RPMH_ACTIVE_ONLY_STATE, corner, + false); + if (!ret) + curr_rpmhpd->enabled = true; + + return ret; +} + +static int rpmhpd_power_off(struct power_domain *pd) +{ + int ret; + unsigned int corner; + struct rpmhpd **rpmhpds; + const struct rpmhpd_desc *desc; + struct rpmhpd *curr_rpmhpd; + + desc = (const struct rpmhpd_desc *)dev_get_driver_data(pd->dev); + if (!desc) + return -EINVAL; + + rpmhpds = desc->rpmhpds; + curr_rpmhpd = rpmhpds[pd->id]; + + /* Do nothing for undefined power domains */ + if (!curr_rpmhpd) { + log_warning("Power domain id (%ld) not supported\n", + pd->id); + return 0; + } + + corner = 0; + + ret = rpmhpd_send_corner(curr_rpmhpd, RPMH_ACTIVE_ONLY_STATE, corner, + false); + if (!ret) + curr_rpmhpd->enabled = false; + + return ret; +} + +static int rpmhpd_update_level_mapping(struct rpmhpd *rpmhpd) +{ + int i; + const u16 *buf; + + buf = cmd_db_read_aux_data(rpmhpd->res_name, &rpmhpd->level_count); + if (IS_ERR(buf)) + return PTR_ERR(buf); + + /* 2 bytes used for each command DB aux data entry */ + rpmhpd->level_count >>= 1; + + if (rpmhpd->level_count > RPMH_ARC_MAX_LEVELS) + return -EINVAL; + + for (i = 0; i < rpmhpd->level_count; i++) { + if (rpmhpd->skip_retention_level && buf[i] == RPMH_REGULATOR_LEVEL_RETENTION) + continue; + + rpmhpd->level[i] = buf[i]; + + /* Remember the first corner with non-zero level */ + if (!rpmhpd->level[rpmhpd->enable_corner] && rpmhpd->level[i]) + rpmhpd->enable_corner = i; + + /* + * The AUX data may be zero padded. These 0 valued entries at + * the end of the map must be ignored. + */ + if (i > 0 && rpmhpd->level[i] == 0) { + rpmhpd->level_count = i; + break; + } + debug("%s: ARC hlvl=%2d --> vlvl=%4u\n", rpmhpd->res_name, i, + rpmhpd->level[i]); + } + + return 0; +} + +static int rpmhpd_probe(struct udevice *dev) +{ + int i, ret = 0; + struct rpmhpd **rpmhpds; + struct rpmhpd *priv; + const struct rpmhpd_desc *desc; + + desc = (const struct rpmhpd_desc *)dev_get_driver_data(dev); + if (!desc) + return -EINVAL; + + rpmhpds = desc->rpmhpds; + + for (i = 0; i < desc->num_pds; i++) { + if (!rpmhpds[i]) + continue; + + priv = rpmhpds[i]; + priv->dev = dev; + priv->addr = cmd_db_read_addr(priv->res_name); + if (!priv->addr) { + dev_err(dev, "Could not find RPMh address for resource %s\n", + priv->res_name); + return -ENODEV; + } + + ret = cmd_db_read_slave_id(priv->res_name); + if (ret != CMD_DB_HW_ARC) { + dev_err(dev, "RPMh slave ID mismatch\n"); + return -EINVAL; + } + + ret = rpmhpd_update_level_mapping(priv); + if (ret) + return ret; + } + + return ret; +} + +static const struct power_domain_ops qcom_rpmhpd_power_ops = { + .on = rpmhpd_power_on, + .off = rpmhpd_power_off, +}; + +U_BOOT_DRIVER(qcom_rpmhpd_drv) = { + .name = "qcom_rpmhpd_drv", + .id = UCLASS_POWER_DOMAIN, + .of_match = rpmhpd_match_table, + .probe = rpmhpd_probe, + .ops = &qcom_rpmhpd_power_ops, +}; diff --git a/drivers/power/domain/renesas-r8a78000-power-domain.c b/drivers/power/domain/renesas-r8a78000-power-domain.c new file mode 100644 index 00000000000..57b3b56b2d9 --- /dev/null +++ b/drivers/power/domain/renesas-r8a78000-power-domain.c @@ -0,0 +1,425 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car Gen5 MDLC driver + * + * Copyright (C) 2026 Marek Vasut <[email protected]> + */ + +#include <dm.h> +#include <dm/device_compat.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/bitfield.h> +#include <power-domain-uclass.h> +#include <reset-uclass.h> + +#include <scmi_agent.h> +#include <scmi_agent-uclass.h> +#include <scmi_protocols.h> + +#include <dt-bindings/power/r8a78000-power-scmi.h> +#include <dt-bindings/reset/r8a78000-reset-scmi.h> + +#define PKC_PROT_LOCK 0xa5a5a500 +#define PKC_PROT_UNLOCK 0xa5a5a501 + +#define MDLC_MSRESS_STANDBY 0 +#define MDLC_MSRESS_RESET 1 +#define MDLC_MSRESS_STOP 2 +#define MDLC_MSRESS_RUN 3 + +#define MDLC_MSRES00 0x900 +#define MDLC_MSRESS00 0x960 +#define MDLC_PKCPROT1 0xcf4 + +struct gen5_mdlc_priv { +#if IS_ENABLED(CONFIG_SCMI_POWER_DOMAIN) + struct udevice *pd; +#endif +#if IS_ENABLED(CONFIG_RESET_SCMI) + struct udevice *rst; +#endif +#if IS_ENABLED(CONFIG_SCMI_POWER_DOMAIN) || IS_ENABLED(CONFIG_RESET_SCMI) + u32 basever; +#endif +#if !IS_ENABLED(CONFIG_SCMI_POWER_DOMAIN) && !IS_ENABLED(CONFIG_RESET_SCMI) + void __iomem *base; +#endif +}; + +static int gen5_pd_of_xlate(struct power_domain *power_domain, + struct ofnode_phandle_args *args) +{ + /* Perform direct remap until the bindings stabilize. */ + power_domain->id = args->args[0]; + + return 0; +} + +#if IS_ENABLED(CONFIG_SCMI_POWER_DOMAIN) +static int gen5_pd_on(struct power_domain *power_domain) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(power_domain->dev->parent); + struct power_domain_ops *ops = (struct power_domain_ops *)priv->pd->driver->ops; + struct power_domain scmi = { + .dev = priv->pd, + .id = power_domain->id + }; + + return ops->on(&scmi); +} + +static int gen5_pd_off(struct power_domain *power_domain) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(power_domain->dev->parent); + struct power_domain_ops *ops = (struct power_domain_ops *)priv->pd->driver->ops; + struct power_domain scmi = { + .dev = priv->pd, + .id = power_domain->id + }; + + return ops->off(&scmi); +} + +static const struct power_domain_ops pd_gen5_ops = { + .on = gen5_pd_on, + .off = gen5_pd_off, + .of_xlate = gen5_pd_of_xlate, +}; + +static int gen5_pd_probe(struct udevice *dev) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(dev->parent); + struct udevice *agent; + int ret; + + if (!priv->basever) { + ret = uclass_get_device(UCLASS_SCMI_AGENT, 0, &agent); + if (ret) + return ret; + + if (!agent) + return -ENODEV; + + priv->basever = scmi_impl_version(agent); + } + + return uclass_get_device_by_driver(UCLASS_POWER_DOMAIN, + DM_DRIVER_GET(scmi_power_domain), + &priv->pd); +} + +U_BOOT_DRIVER(pd_gen5) = { + .name = "pd_gen5", + .id = UCLASS_POWER_DOMAIN, + .ops = &pd_gen5_ops, + .probe = gen5_pd_probe, + .flags = DM_FLAG_OS_PREPARE | DM_FLAG_VITAL, +}; +#else +static const struct power_domain_ops pd_gen5_ops = { + .of_xlate = gen5_pd_of_xlate, +}; + +U_BOOT_DRIVER(pd_gen5) = { + .name = "pd_gen5", + .id = UCLASS_POWER_DOMAIN, + .ops = &pd_gen5_ops, + .flags = DM_FLAG_OS_PREPARE | DM_FLAG_VITAL, +}; +#endif + +#if IS_ENABLED(CONFIG_RESET_SCMI) +static int gen5_reset_assert(struct reset_ctl *reset_ctl) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(reset_ctl->dev->parent); + struct reset_ops *ops = (struct reset_ops *)priv->rst->driver->ops; + struct reset_ctl scmi = { + .dev = priv->rst, + .id = reset_ctl->id + }; + + return ops->rst_assert(&scmi); +} + +static int gen5_reset_deassert(struct reset_ctl *reset_ctl) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(reset_ctl->dev->parent); + struct reset_ops *ops = (struct reset_ops *)priv->rst->driver->ops; + struct reset_ctl scmi = { + .dev = priv->rst, + .id = reset_ctl->id + }; + + return ops->rst_deassert(&scmi); +} + +struct rst_map_in { + u16 dt_id; /* DT binding clock ID */ + u16 fw_id; /* SCMI firmware clock ID */ +}; + +#define GEN5_SCMI_SDK_4_28 0x010a0000 +#define GEN5_SCMI_SDK_4_29 0x010b0000 +#define GEN5_SCMI_SDK_4_30 0x010c0000 +#define GEN5_SCMI_SDK_4_31 0x010d0000 +#define GEN5_SCMI_SDK_4_32 0x010e0000 + +static const struct rst_map_in gen5_rst_map_dt_sdk_4_28[] = { + { SCP_RESET_DOMAIN_ID_UFS0, 202 }, + { SCP_RESET_DOMAIN_ID_UFS1, 203 }, + { SCP_RESET_DOMAIN_ID_XPCS0, 316 }, + { SCP_RESET_DOMAIN_ID_XPCS1, 317 }, + { SCP_RESET_DOMAIN_ID_XPCS2, 318 }, + { SCP_RESET_DOMAIN_ID_XPCS3, 319 }, + { SCP_RESET_DOMAIN_ID_XPCS4, 320 }, + { SCP_RESET_DOMAIN_ID_XPCS5, 321 }, + { SCP_RESET_DOMAIN_ID_XPCS6, 322 }, + { SCP_RESET_DOMAIN_ID_XPCS7, 323 }, + { SCP_RESET_DOMAIN_ID_MPPHY01, 344 }, + { SCP_RESET_DOMAIN_ID_MPPHY11, 345 }, + { SCP_RESET_DOMAIN_ID_MPPHY21, 346 }, + { SCP_RESET_DOMAIN_ID_MPPHY31, 347 }, + { SCP_RESET_DOMAIN_ID_MPPHY02, 348 }, +}; + +static const struct rst_map_in gen5_rst_map_dt_sdk_4_31[] = { + { SCP_RESET_DOMAIN_ID_UFS0, 198 }, + { SCP_RESET_DOMAIN_ID_UFS1, 199 }, + { SCP_RESET_DOMAIN_ID_XPCS0, 312 }, + { SCP_RESET_DOMAIN_ID_XPCS1, 313 }, + { SCP_RESET_DOMAIN_ID_XPCS2, 314 }, + { SCP_RESET_DOMAIN_ID_XPCS3, 315 }, + { SCP_RESET_DOMAIN_ID_XPCS4, 316 }, + { SCP_RESET_DOMAIN_ID_XPCS5, 317 }, + { SCP_RESET_DOMAIN_ID_XPCS6, 318 }, + { SCP_RESET_DOMAIN_ID_XPCS7, 319 }, + { SCP_RESET_DOMAIN_ID_MPPHY01, 340 }, + { SCP_RESET_DOMAIN_ID_MPPHY11, 341 }, + { SCP_RESET_DOMAIN_ID_MPPHY21, 342 }, + { SCP_RESET_DOMAIN_ID_MPPHY31, 343 }, + { SCP_RESET_DOMAIN_ID_MPPHY02, 344 }, +}; + +static int gen5_reset_of_xlate(struct reset_ctl *reset_ctl, + struct ofnode_phandle_args *args) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(reset_ctl->dev->parent); + const struct rst_map_in *map; + unsigned int map_size; + int i; + + if (args->args_count != 1) { + debug("Invalid args_count: %d\n", args->args_count); + return -EINVAL; + } + + if (priv->basever == GEN5_SCMI_SDK_4_28) { + map = gen5_rst_map_dt_sdk_4_28; + map_size = ARRAY_SIZE(gen5_rst_map_dt_sdk_4_28); + } else if (priv->basever == GEN5_SCMI_SDK_4_31 || + priv->basever == GEN5_SCMI_SDK_4_32) { + map = gen5_rst_map_dt_sdk_4_31; + map_size = ARRAY_SIZE(gen5_rst_map_dt_sdk_4_31); + } else { + printf("Unsupported SCMI base protocol version %x\n", priv->basever); + return -EINVAL; + } + + reset_ctl->id = -1; + for (i = 0; i < map_size; i++) { + if (map[i].dt_id != args->args[0]) + continue; + reset_ctl->id = map[i].fw_id; + break; + } + + return 0; +} + +static const struct reset_ops rst_gen5_ops = { + .rst_assert = gen5_reset_assert, + .rst_deassert = gen5_reset_deassert, + .of_xlate = gen5_reset_of_xlate, +}; + +static int gen5_rst_probe(struct udevice *dev) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(dev->parent); + struct udevice *agent; + int ret = 0; + + if (!priv->basever) { + ret = uclass_get_device(UCLASS_SCMI_AGENT, 0, &agent); + if (ret) + return ret; + + if (!agent) + return -ENODEV; + + priv->basever = scmi_impl_version(agent); + } + + return uclass_get_device_by_driver(UCLASS_RESET, + DM_DRIVER_GET(scmi_reset_domain), + &priv->rst); +} +#else +static int mdlc_wait_for_reset(struct reset_ctl *reset_ctl) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(reset_ctl->dev->parent); + const u32 offset = (reset_ctl->id / 16) * 4; + void __iomem *res = priv->base + MDLC_MSRES00 + offset; + void __iomem *stat = priv->base + MDLC_MSRESS00 + offset; + u32 val; + int ret; + + /* Wait 100ms for reset controller to synchronize. */ + ret = readl_poll_timeout(res, val, val == readl(stat), 100000); + if (ret < 0) + dev_err(reset_ctl->dev, "Reset controller out of sync!\n"); + + return ret; +} + +static void mdlc_rmw_msres(struct reset_ctl *reset_ctl, const int val) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(reset_ctl->dev->parent); + const u32 offset = (reset_ctl->id / 16) * 4; + const u32 mask = 3 << ((reset_ctl->id % 16) * 2); + void __iomem *prot = priv->base + MDLC_PKCPROT1; + void __iomem *res = priv->base + MDLC_MSRES00 + offset; + u32 reg; + + reg = readl(res); + reg &= ~mask; + reg |= field_prep(mask, val); + + writel(PKC_PROT_UNLOCK, prot); + writel(reg, res); + writel(PKC_PROT_LOCK, prot); +} + +static int gen5_reset_toggle(struct reset_ctl *reset_ctl, const u8 step1, + const u8 step2, const u8 step3, const u8 step4) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(reset_ctl->dev->parent); + const u32 offset = (reset_ctl->id / 16) * 4; + const u32 mask = 3 << ((reset_ctl->id % 16) * 2); + void __iomem *stat = priv->base + MDLC_MSRESS00 + offset; + u32 status; + int ret; + + ret = mdlc_wait_for_reset(reset_ctl); + if (ret) + return ret; + + status = field_get(mask, readl(stat)); + if (status == step1) { + mdlc_rmw_msres(reset_ctl, step2); + ret = mdlc_wait_for_reset(reset_ctl); + if (ret) + return ret; + status = field_get(mask, readl(stat)); + } + + if (status == step2 || status == step3) { + mdlc_rmw_msres(reset_ctl, step4); + ret = mdlc_wait_for_reset(reset_ctl); + if (ret) + return ret; + } + + return 0; +} + +static int gen5_reset_assert(struct reset_ctl *reset_ctl) +{ + return gen5_reset_toggle(reset_ctl, + MDLC_MSRESS_STOP, MDLC_MSRESS_STANDBY, + MDLC_MSRESS_RUN, MDLC_MSRESS_RESET); +} + +static int gen5_reset_deassert(struct reset_ctl *reset_ctl) +{ + return gen5_reset_toggle(reset_ctl, + MDLC_MSRESS_STANDBY, MDLC_MSRESS_RESET, + MDLC_MSRESS_STOP, MDLC_MSRESS_RUN); +} + +static int gen5_reset_of_xlate(struct reset_ctl *reset_ctl, + struct ofnode_phandle_args *args) +{ + /* Perform direct remap until the bindings stabilize. */ + reset_ctl->id = args->args[0]; + + return 0; +} + +static const struct reset_ops rst_gen5_ops = { + .rst_assert = gen5_reset_assert, + .rst_deassert = gen5_reset_deassert, + .of_xlate = gen5_reset_of_xlate, +}; + +static int gen5_rst_probe(struct udevice *dev) +{ + struct gen5_mdlc_priv *priv = dev_get_priv(dev->parent); + + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -EINVAL; + + return 0; +} +#endif + +U_BOOT_DRIVER(rst_gen5) = { + .name = "rst_gen5", + .id = UCLASS_RESET, + .ops = &rst_gen5_ops, + .probe = gen5_rst_probe, + .flags = DM_FLAG_OS_PREPARE | DM_FLAG_VITAL, +}; + +int gen5_mdlc_bind(struct udevice *parent) +{ + struct udevice *pdev, *rdev; + struct driver *pdrv, *rdrv; + int ret; + + pdrv = lists_driver_lookup_name("pd_gen5"); + if (!pdrv) + return -ENOENT; + + rdrv = lists_driver_lookup_name("rst_gen5"); + if (!rdrv) + return -ENOENT; + + ret = device_bind_with_driver_data(parent, pdrv, "pd_gen5", 0, + dev_ofnode(parent), &pdev); + if (ret) + return ret; + + ret = device_bind_with_driver_data(parent, rdrv, "rst_gen5", (ulong)pdev, + dev_ofnode(parent), &rdev); + if (ret) + device_unbind(pdev); + + return ret; +} + +static const struct udevice_id r8a78000_mdlc_ids[] = { + { .compatible = "renesas,r8a78000-mdlc", }, + { } +}; + +U_BOOT_DRIVER(mdlc_gen5) = { + .name = "mdlc_gen5", + .id = UCLASS_NOP, + .of_match = r8a78000_mdlc_ids, + .bind = gen5_mdlc_bind, + .priv_auto = sizeof(struct gen5_mdlc_priv), +}; diff --git a/drivers/power/domain/sandbox-power-domain.c b/drivers/power/domain/sandbox-power-domain.c index a8031657638..a30826a3b4d 100644 --- a/drivers/power/domain/sandbox-power-domain.c +++ b/drivers/power/domain/sandbox-power-domain.c @@ -78,7 +78,7 @@ static const struct udevice_id sandbox_power_domain_ids[] = { { } }; -struct power_domain_ops sandbox_power_domain_ops = { +static const struct power_domain_ops sandbox_power_domain_ops = { .request = sandbox_power_domain_request, .rfree = sandbox_power_domain_free, .on = sandbox_power_domain_on, diff --git a/drivers/power/domain/scmi-power-domain.c b/drivers/power/domain/scmi-power-domain.c index e8c0ba8878e..a369fe52f2f 100644 --- a/drivers/power/domain/scmi-power-domain.c +++ b/drivers/power/domain/scmi-power-domain.c @@ -165,21 +165,15 @@ static int scmi_power_domain_probe(struct udevice *dev) for (i = 0; i < priv->num_pwdoms; i++) { ret = scmi_pwd_attrs(dev, i, &priv->prop[i].attributes, &priv->prop[i].name); - if (ret) { + if (ret) dev_err(dev, "failed to get attributes pwd:%d (%d)\n", i, ret); - for (i--; i >= 0; i--) - free(priv->prop[i].name); - free(priv->prop); - - return ret; - } } return 0; } -struct power_domain_ops scmi_power_domain_ops = { +static const struct power_domain_ops scmi_power_domain_ops = { .on = scmi_power_domain_on, .off = scmi_power_domain_off, }; diff --git a/drivers/power/domain/tegra186-power-domain.c b/drivers/power/domain/tegra186-power-domain.c index 334c460c805..3865cd4cf47 100644 --- a/drivers/power/domain/tegra186-power-domain.c +++ b/drivers/power/domain/tegra186-power-domain.c @@ -55,7 +55,7 @@ static int tegra186_power_domain_off(struct power_domain *power_domain) return tegra186_power_domain_common(power_domain, false); } -struct power_domain_ops tegra186_power_domain_ops = { +static const struct power_domain_ops tegra186_power_domain_ops = { .on = tegra186_power_domain_on, .off = tegra186_power_domain_off, }; diff --git a/drivers/power/domain/zynqmp-power-domain.c b/drivers/power/domain/zynqmp-power-domain.c index a54de5c1439..0acfc54e787 100644 --- a/drivers/power/domain/zynqmp-power-domain.c +++ b/drivers/power/domain/zynqmp-power-domain.c @@ -57,7 +57,7 @@ static int zynqmp_power_domain_off(struct power_domain *power_domain) return 0; } -struct power_domain_ops zynqmp_power_domain_ops = { +static const struct power_domain_ops zynqmp_power_domain_ops = { .request = zynqmp_power_domain_request, .rfree = zynqmp_power_domain_free, .on = zynqmp_power_domain_on, diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index 5bc14842e66..d45869cb30f 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -1,14 +1,14 @@ config DM_PMIC bool "Enable Driver Model for PMIC drivers (UCLASS_PMIC)" depends on DM - ---help--- - This config enables the driver-model PMIC support. - UCLASS_PMIC - designed to provide an I/O interface for PMIC devices. - For the multi-function PMIC devices, this can be used as parent I/O - device for each IC's interface. Then, each children uses its parent - for read/write. For detailed description, please refer to the files: - - 'drivers/power/pmic/pmic-uclass.c' - - 'include/power/pmic.h' + help + This config enables the driver-model PMIC support. + UCLASS_PMIC - designed to provide an I/O interface for PMIC devices. + For the multi-function PMIC devices, this can be used as parent I/O + device for each IC's interface. Then, each children uses its parent + for read/write. For detailed description, please refer to the files: + - 'drivers/power/pmic/pmic-uclass.c' + - 'include/power/pmic.h' if DM_PMIC @@ -16,34 +16,34 @@ config SPL_DM_PMIC bool "Enable Driver Model for PMIC drivers (UCLASS_PMIC) in SPL" depends on SPL_DM default y - ---help--- - This config enables the driver-model PMIC support in SPL. - UCLASS_PMIC - designed to provide an I/O interface for PMIC devices. - For the multi-function PMIC devices, this can be used as parent I/O - device for each IC's interface. Then, each children uses its parent - for read/write. For detailed description, please refer to the files: - - 'drivers/power/pmic/pmic-uclass.c' - - 'include/power/pmic.h' + help + This config enables the driver-model PMIC support in SPL. + UCLASS_PMIC - designed to provide an I/O interface for PMIC devices. + For the multi-function PMIC devices, this can be used as parent I/O + device for each IC's interface. Then, each children uses its parent + for read/write. For detailed description, please refer to the files: + - 'drivers/power/pmic/pmic-uclass.c' + - 'include/power/pmic.h' config PMIC_CHILDREN bool "Allow child devices for PMICs" default y - ---help--- - This allows PMICs to support child devices (such as regulators) in - SPL. This adds quite a bit of code so if you are not using this - feature you can turn it off. Most likely you should turn it on for - U-Boot proper. + help + This allows PMICs to support child devices (such as regulators) in + SPL. This adds quite a bit of code so if you are not using this + feature you can turn it off. Most likely you should turn it on for + U-Boot proper. config SPL_PMIC_CHILDREN bool "Allow child devices for PMICs in SPL" depends on SPL_DM_PMIC default y - ---help--- - This allows PMICs to support child devices (such as regulators) in - SPL. This adds quite a bit of code so if you are not using this - feature you can turn it off. In this case you may need a 'back door' - to call your regulator code (e.g. see rk8xx.c for direct functions - for use in SPL). + help + This allows PMICs to support child devices (such as regulators) in + SPL. This adds quite a bit of code so if you are not using this + feature you can turn it off. In this case you may need a 'back door' + to call your regulator code (e.g. see rk8xx.c for direct functions + for use in SPL). config PMIC_AB8500 bool "Enable driver for ST-Ericsson AB8500 PMIC via PRCMU" @@ -57,11 +57,11 @@ config PMIC_AB8500 config PMIC_ACT8846 bool "Enable support for the active-semi 8846 PMIC" depends on DM_I2C - ---help--- - This PMIC includes 4 DC/DC step-down buck regulators and 8 low-dropout - regulators (LDOs). It also provides some GPIO, reset and battery - functions. It uses an I2C interface and is designed for use with - tablets and smartphones. + help + This PMIC includes 4 DC/DC step-down buck regulators and 8 low-dropout + regulators (LDOs). It also provides some GPIO, reset and battery + functions. It uses an I2C interface and is designed for use with + tablets and smartphones. config PMIC_AXP bool "Enable Driver Model for X-Powers AXP PMICs" @@ -101,8 +101,8 @@ config PMIC_AS3722 required for a tablets or laptop. config DM_PMIC_BD71837 - bool "Enable Driver Model for PMIC BD71837" - help + bool "Enable Driver Model for PMIC BD71837" + help This config enables implementation of driver-model pmic uclass features for PMIC BD71837. The driver implements read/write operations. @@ -173,257 +173,257 @@ config SPL_DM_PMIC_PCA9450 config DM_PMIC_PFUZE100 bool "Enable Driver Model for PMIC PFUZE100" - ---help--- - This config enables implementation of driver-model pmic uclass features - for PMIC PFUZE100. The driver implements read/write operations. + help + This config enables implementation of driver-model pmic uclass features + for PMIC PFUZE100. The driver implements read/write operations. config SPL_DM_PMIC_PFUZE100 bool "Enable Driver Model for PMIC PFUZE100 in SPL" depends on SPL_DM_PMIC - ---help--- - This config enables implementation of driver-model pmic uclass features - for PMIC PFUZE100 in SPL. The driver implements read/write operations. + help + This config enables implementation of driver-model pmic uclass features + for PMIC PFUZE100 in SPL. The driver implements read/write operations. config DM_PMIC_MAX8907 bool "Enable Driver Model for PMIC MAX8907" - ---help--- - This config enables implementation of driver-model pmic uclass features - for PMIC MAX8907. The driver implements read/write operations. - This is a Power Management IC with a decent set of peripherals from which - 3 DC-to-DC Step-Down (SD) Regulators, 20 Low-Dropout Linear (LDO) Regulators, - Real-Time Clock (RTC) and more with I2C Compatible Interface. + help + This config enables implementation of driver-model pmic uclass features + for PMIC MAX8907. The driver implements read/write operations. + This is a Power Management IC with a decent set of peripherals from which + 3 DC-to-DC Step-Down (SD) Regulators, 20 Low-Dropout Linear (LDO) Regulators, + Real-Time Clock (RTC) and more with I2C Compatible Interface. config DM_PMIC_MAX77663 bool "Enable Driver Model for PMIC MAX77663" - ---help--- - This config enables implementation of driver-model pmic uclass features - for PMIC MAX77663. The driver implements read/write operations. - This is a Power Management IC with a decent set of peripherals from which - 4 DC-to-DC Step-Down (SD) Regulators, 9 Low-Dropout Linear (LDO) Regulators, - 8 GPIOs, Real-Time Clock (RTC) and more with I2C Compatible Interface. + help + This config enables implementation of driver-model pmic uclass features + for PMIC MAX77663. The driver implements read/write operations. + This is a Power Management IC with a decent set of peripherals from which + 4 DC-to-DC Step-Down (SD) Regulators, 9 Low-Dropout Linear (LDO) Regulators, + 8 GPIOs, Real-Time Clock (RTC) and more with I2C Compatible Interface. config DM_PMIC_MAX77686 bool "Enable Driver Model for PMIC MAX77686" - ---help--- - This config enables implementation of driver-model pmic uclass features - for PMIC MAX77686. The driver implements read/write operations. + help + This config enables implementation of driver-model pmic uclass features + for PMIC MAX77686. The driver implements read/write operations. config DM_PMIC_MAX8998 bool "Enable Driver Model for PMIC MAX8998" - ---help--- - This config enables implementation of driver-model pmic uclass features - for PMIC MAX8998. The driver implements read/write operations. + help + This config enables implementation of driver-model pmic uclass features + for PMIC MAX8998. The driver implements read/write operations. config DM_PMIC_MC34708 bool "Enable Driver Model for PMIC MC34708" help - This config enables implementation of driver-model pmic uclass features - for PMIC MC34708. The driver implements read/write operations. + This config enables implementation of driver-model pmic uclass features + for PMIC MC34708. The driver implements read/write operations. config PMIC_MAX8997 bool "Enable Driver Model for PMIC MAX8997" - ---help--- - This config enables implementation of driver-model pmic uclass features - for PMIC MAX8997. The driver implements read/write operations. - This is a Power Management IC with RTC, Fuel Gauge, MUIC control on Chip. - - 21x LDOs - - 12x GPIOs - - Haptic motor driver - - RTC with two alarms - - Fuel Gauge and one backup battery charger - - MUIC - - Others + help + This config enables implementation of driver-model pmic uclass features + for PMIC MAX8997. The driver implements read/write operations. + This is a Power Management IC with RTC, Fuel Gauge, MUIC control on Chip. + - 21x LDOs + - 12x GPIOs + - Haptic motor driver + - RTC with two alarms + - Fuel Gauge and one backup battery charger + - MUIC + - Others config PMIC_QCOM bool "Enable Driver Model for Qualcomm generic PMIC" - ---help--- - The Qcom PMIC is connected to one (or several) processors - with SPMI bus. It has 2 slaves with several peripherals: - - 18x LDO - - 4x GPIO - - Power and Reset buttons - - Watchdog - - RTC - - Vibrator drivers - - Others + help + The Qcom PMIC is connected to one (or several) processors + with SPMI bus. It has 2 slaves with several peripherals: + - 18x LDO + - 4x GPIO + - Power and Reset buttons + - Watchdog + - RTC + - Vibrator drivers + - Others - Driver binding info: doc/device-tree-bindings/pmic/qcom,spmi-pmic.txt + Driver binding info: doc/device-tree-bindings/pmic/qcom,spmi-pmic.txt config PMIC_RK8XX bool "Enable support for Rockchip PMIC RK8XX" select SYSRESET_CMD_POWEROFF if SYSRESET && CMD_POWEROFF - ---help--- - The Rockchip RK808 PMIC provides four buck DC-DC convertors, 8 LDOs, - an RTC and two low Rds (resistance (drain to source)) switches. It is - accessed via an I2C interface. The device is used with Rockchip SoCs. - This driver implements register read/write operations. + help + The Rockchip RK808 PMIC provides four buck DC-DC convertors, 8 LDOs, + an RTC and two low Rds (resistance (drain to source)) switches. It is + accessed via an I2C interface. The device is used with Rockchip SoCs. + This driver implements register read/write operations. config SPL_PMIC_RK8XX bool "Enable support for Rockchip PMIC RK8XX in SPL" depends on SPL_DM_PMIC - ---help--- - The Rockchip RK808 PMIC provides four buck DC-DC convertors, 8 LDOs, - an RTC and two low Rds (resistance (drain to source)) switches. It is - accessed via an I2C interface. The device is used with Rockchip SoCs. - This driver implements register read/write operations. + help + The Rockchip RK808 PMIC provides four buck DC-DC convertors, 8 LDOs, + an RTC and two low Rds (resistance (drain to source)) switches. It is + accessed via an I2C interface. The device is used with Rockchip SoCs. + This driver implements register read/write operations. config PMIC_S2MPS11 bool "Enable Driver Model for PMIC Samsung S2MPS11" - ---help--- - The Samsung S2MPS11 PMIC provides: - - 38 adjustable LDO regulators - - 9 High-Efficiency Buck Converters - - 1 BuckBoost Converter - - RTC with two alarms - - Backup battery charger - - I2C Configuration Interface - This driver provides access to I/O interface only. - Binding info: doc/device-tree-bindings/pmic/s2mps11.txt + help + The Samsung S2MPS11 PMIC provides: + - 38 adjustable LDO regulators + - 9 High-Efficiency Buck Converters + - 1 BuckBoost Converter + - RTC with two alarms + - Backup battery charger + - I2C Configuration Interface + This driver provides access to I/O interface only. + Binding info: doc/device-tree-bindings/pmic/s2mps11.txt config DM_PMIC_SANDBOX bool "Enable Driver Model for emulated Sandbox PMIC" - ---help--- - Enable the driver for Sandbox PMIC emulation. The emulated PMIC device - depends on two drivers: - - sandbox PMIC I/O driver - implements dm pmic operations - - sandbox PMIC i2c emul driver - emulates the PMIC's I2C transmission + help + Enable the driver for Sandbox PMIC emulation. The emulated PMIC device + depends on two drivers: + - sandbox PMIC I/O driver - implements dm pmic operations + - sandbox PMIC i2c emul driver - emulates the PMIC's I2C transmission - A detailed information can be found in header: '<power/sandbox_pmic.h>' + A detailed information can be found in header: '<power/sandbox_pmic.h>' - The Sandbox PMIC info: - * I/O interface: - - I2C chip address: 0x40 - - first register address: 0x0 - - register count: 0x10 - * Adjustable outputs: - - 2x LDO - - 2x BUCK - - Each, with a different operating conditions (header). - * Reset values: - - set by i2c emul driver's probe() (defaults in header) + The Sandbox PMIC info: + * I/O interface: + - I2C chip address: 0x40 + - first register address: 0x0 + - register count: 0x10 + * Adjustable outputs: + - 2x LDO + - 2x BUCK + - Each, with a different operating conditions (header). + * Reset values: + - set by i2c emul driver's probe() (defaults in header) - Driver binding info: doc/device-tree-bindings/pmic/sandbox.txt + Driver binding info: doc/device-tree-bindings/pmic/sandbox.txt config DM_PMIC_CPCAP bool "Enable Driver Model for Motorola CPCAP" help - The CPCAP is a Motorola/ST-Ericsson creation, a multifunctional IC - whose main purpose is power control. It was used in a wide variety of - Motorola products, both Tegra and OMAP based. The most notable devices - using this PMIC are the Motorola Droid 4, Atrix 4G, and Droid X2. - Unlike most PMICs, this one is not I2C based; it uses the SPI bus. The - core driver provides both read and write access to the device registers. + The CPCAP is a Motorola/ST-Ericsson creation, a multifunctional IC + whose main purpose is power control. It was used in a wide variety of + Motorola products, both Tegra and OMAP based. The most notable devices + using this PMIC are the Motorola Droid 4, Atrix 4G, and Droid X2. + Unlike most PMICs, this one is not I2C based; it uses the SPI bus. The + core driver provides both read and write access to the device registers. config PMIC_S5M8767 bool "Enable Driver Model for the Samsung S5M8767 PMIC" - ---help--- - The S5M8767 PMIC provides a large array of LDOs and BUCKs for use - as a SoC power controller. It also provides 32KHz clock outputs. This - driver provides basic register access and sets up the attached - regulators if regulator support is enabled. + help + The S5M8767 PMIC provides a large array of LDOs and BUCKs for use + as a SoC power controller. It also provides 32KHz clock outputs. This + driver provides basic register access and sets up the attached + regulators if regulator support is enabled. config PMIC_RN5T567 bool "Enable driver for Ricoh RN5T567 PMIC" - ---help--- - The RN5T567 is a PMIC with 4 step-down DC/DC converters, 5 LDO - regulators Real-Time Clock and 4 GPIOs. This driver provides - register access only. + help + The RN5T567 is a PMIC with 4 step-down DC/DC converters, 5 LDO + regulators Real-Time Clock and 4 GPIOs. This driver provides + register access only. config SPL_PMIC_RN5T567 bool "Enable driver for Ricoh RN5T567 PMIC in SPL" depends on SPL_DM_PMIC - ---help--- - The RN5T567 is a PMIC with 4 step-down DC/DC converters, 5 LDO - regulators Real-Time Clock and 4 GPIOs. This driver provides - register access only. + help + The RN5T567 is a PMIC with 4 step-down DC/DC converters, 5 LDO + regulators Real-Time Clock and 4 GPIOs. This driver provides + register access only. config PMIC_TPS65090 bool "Enable driver for Texas Instruments TPS65090 PMIC" - ---help--- - The TPS65090 is a PMIC containing several LDOs, DC to DC convertors, - FETs and a battery charger. This driver provides register access - only, and you can enable the regulator/charger drivers separately if - required. + help + The TPS65090 is a PMIC containing several LDOs, DC to DC convertors, + FETs and a battery charger. This driver provides register access + only, and you can enable the regulator/charger drivers separately if + required. config PMIC_PALMAS bool "Enable driver for Texas Instruments PALMAS PMIC" - ---help--- - The PALMAS is a PMIC containing several LDOs, SMPS. - This driver binds the pmic children. + help + The PALMAS is a PMIC containing several LDOs, SMPS. + This driver binds the pmic children. config PMIC_LP873X bool "Enable driver for Texas Instruments LP873X PMIC" - ---help--- - The LP873X is a PMIC containing couple of LDOs and couple of SMPS. - This driver binds the pmic children. + help + The LP873X is a PMIC containing couple of LDOs and couple of SMPS. + This driver binds the pmic children. config PMIC_LP87565 bool "Enable driver for Texas Instruments LP87565 PMIC" - ---help--- - The LP87565 is a PMIC containing a bunch of SMPS. - This driver binds the pmic children. + help + The LP87565 is a PMIC containing a bunch of SMPS. + This driver binds the pmic children. config DM_PMIC_TPS65910 bool "Enable driver for Texas Instruments TPS65910 PMIC" - ---help--- - The TPS65910 is a PMIC containing 3 buck DC-DC converters, one boost - DC-DC converter, 8 LDOs and a RTC. This driver binds the SMPS and LDO - pmic children. + help + The TPS65910 is a PMIC containing 3 buck DC-DC converters, one boost + DC-DC converter, 8 LDOs and a RTC. This driver binds the SMPS and LDO + pmic children. config DM_PMIC_TPS80031 bool "Enable driver for Texas Instruments TPS80031/TPS80032 PMIC" - ---help--- - This config enables implementation of driver-model pmic uclass features - for TPS80031/TPS80032 PMICs. The driver implements read/write operations. - This is a Power Management IC with a decent set of peripherals from which - 5 Buck Converters refered as Switched-mode power supply (SMPS), 11 General- - Purpose Low-Dropout Voltage Regulators (LDO), USB OTG Module, Real-Time - Clock (RTC) with Timer and Alarm Wake-Up, Two Digital PWM Outputs and more - with I2C Compatible Interface. PMIC occupies 4 I2C addresses. + help + This config enables implementation of driver-model pmic uclass features + for TPS80031/TPS80032 PMICs. The driver implements read/write operations. + This is a Power Management IC with a decent set of peripherals from which + 5 Buck Converters referred as Switched-mode power supply (SMPS), 11 General- + Purpose Low-Dropout Voltage Regulators (LDO), USB OTG Module, Real-Time + Clock (RTC) with Timer and Alarm Wake-Up, Two Digital PWM Outputs and more + with I2C Compatible Interface. PMIC occupies 4 I2C addresses. config PMIC_STPMIC1 bool "Enable support for STMicroelectronics STPMIC1 PMIC" depends on DM_I2C select SYSRESET_CMD_POWEROFF if SYSRESET && CMD_POWEROFF && !ARM_PSCI_FW - ---help--- - The STPMIC1 PMIC provides 4 BUCKs, 6 LDOs, 1 VREF and 2 power switches. - It is accessed via an I2C interface. The device is used with STM32MP1 - SoCs. This driver implements register read/write operations. + help + The STPMIC1 PMIC provides 4 BUCKs, 6 LDOs, 1 VREF and 2 power switches. + It is accessed via an I2C interface. The device is used with STM32MP1 + SoCs. This driver implements register read/write operations. config SPL_PMIC_PALMAS bool "Enable driver for Texas Instruments PALMAS PMIC" depends on SPL_DM_PMIC help - The PALMAS is a PMIC containing several LDOs, SMPS. - This driver binds the pmic children in SPL. + The PALMAS is a PMIC containing several LDOs, SMPS. + This driver binds the pmic children in SPL. config SPL_PMIC_LP873X bool "Enable driver for Texas Instruments LP873X PMIC" depends on SPL_DM_PMIC help - The LP873X is a PMIC containing couple of LDOs and couple of SMPS. - This driver binds the pmic children in SPL. + The LP873X is a PMIC containing couple of LDOs and couple of SMPS. + This driver binds the pmic children in SPL. config SPL_PMIC_LP87565 bool "Enable driver for Texas Instruments LP87565 PMIC" depends on SPL_DM_PMIC help - The LP87565 is a PMIC containing a bunch of SMPS. - This driver binds the pmic children in SPL. + The LP87565 is a PMIC containing a bunch of SMPS. + This driver binds the pmic children in SPL. config PMIC_TPS65941 bool "Enable driver for Texas Instruments TPS65941 PMIC" depends on DM_PMIC help - The TPS65941 is a PMIC containing a bunch of SMPS & LDOs. - This driver binds the pmic children. + The TPS65941 is a PMIC containing a bunch of SMPS & LDOs. + This driver binds the pmic children. config PMIC_TPS65219 bool "Enable driver for Texas Instruments TPS65219 PMIC" depends on DM_PMIC help - The TPS65219 is a PMIC containing a bunch of SMPS & LDOs. - This driver binds the pmic children. + The TPS65219 is a PMIC containing a bunch of SMPS & LDOs. + This driver binds the pmic children. config PMIC_RAA215300 bool "Renesas RAA215300 PMIC driver" @@ -434,6 +434,14 @@ config PMIC_RAA215300 allows register access and will bind the sysreset driver (CONFIG_SYSRESET_RAA215300) if it is enabled. +config PMIC_SPACEMIT_P1 + bool "Enable driver for Spacemit P1 power management chip" + depends on DM_PMIC + help + The P1 PMIC integrates multiple functions including + voltage regulators, a watchdog timer, GPIO interfaces, and a + real-time clock. + config DM_PMIC_MTK_PWRAP bool "Enable driver for MediaTek PMIC Wrapper Support" help @@ -445,11 +453,11 @@ endif config PMIC_TPS65217 bool "Enable driver for Texas Instruments TPS65217 PMIC" - ---help--- - The TPS65217 is a PMIC containing several LDOs, DC to DC convertors, - FETs and a battery charger. This driver provides register access - only, and you can enable the regulator/charger drivers separately if - required. + help + The TPS65217 is a PMIC containing several LDOs, DC to DC convertors, + FETs and a battery charger. This driver provides register access + only, and you can enable the regulator/charger drivers separately if + required. config POWER_TPS65218 bool "Enable legacy driver for TPS65218 PMIC" @@ -485,9 +493,9 @@ config POWER_PFUZE3000 config POWER_MC34VR500 bool "Enable driver for Freescale MC34VR500 PMIC" - ---help--- - The MC34VR500 is used in conjunction with the FSL T1 and LS1 series - SoC. It provides 4 buck DC-DC convertors and 5 LDOs, and it is accessed - via an I2C interface. + help + The MC34VR500 is used in conjunction with the FSL T1 and LS1 series + SoC. It provides 4 buck DC-DC convertors and 5 LDOs, and it is accessed + via an I2C interface. endif diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 2cda5a892fd..0ac92084221 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_$(PHASE_)DM_PMIC_TPS80031) += tps80031.o obj-$(CONFIG_$(PHASE_)PMIC_PALMAS) += palmas.o obj-$(CONFIG_$(PHASE_)PMIC_LP873X) += lp873x.o obj-$(CONFIG_$(PHASE_)PMIC_LP87565) += lp87565.o +obj-$(CONFIG_PMIC_SPACEMIT_P1) += pmic_spacemit_p1.o obj-$(CONFIG_PMIC_STPMIC1) += stpmic1.o obj-$(CONFIG_PMIC_TPS65217) += pmic_tps65217.o obj-$(CONFIG_PMIC_TPS65219) += tps65219.o diff --git a/drivers/power/pmic/i2c_pmic_emul.c b/drivers/power/pmic/i2c_pmic_emul.c index 6e81b9c3427..b5c8efd427a 100644 --- a/drivers/power/pmic/i2c_pmic_emul.c +++ b/drivers/power/pmic/i2c_pmic_emul.c @@ -146,7 +146,7 @@ static int sandbox_i2c_pmic_probe(struct udevice *emul) return 0; } -struct dm_i2c_ops sandbox_i2c_pmic_emul_ops = { +static const struct dm_i2c_ops sandbox_i2c_pmic_emul_ops = { .xfer = sandbox_i2c_pmic_xfer, }; diff --git a/drivers/power/pmic/mtk-pwrap.c b/drivers/power/pmic/mtk-pwrap.c index 3e3a691d9e8..47347785519 100644 --- a/drivers/power/pmic/mtk-pwrap.c +++ b/drivers/power/pmic/mtk-pwrap.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * MT6357 regulator driver + * MediaTek PMIC Wrapper driver * * Copyright (c) 2026 BayLibre, SAS. * Author: Julien Masson <[email protected]> @@ -59,9 +59,11 @@ static const struct pmic_child_info mt6359_pmic_children_info[] = { #define HAS_CAP(_c, _x_val) (((_c) & (_x_val)) == (_x_val)) /* Group of bits used for shown pwrap capability */ -#define PWRAP_CAP_INT1_EN BIT(3) -#define PWRAP_CAP_WDT_SRC1 BIT(4) -#define PWRAP_CAP_ARB BIT(5) +#define PWRAP_CAP_WDT_SRC BIT(4) +#define PWRAP_CAP_WDT_SRC1 BIT(5) +#define PWRAP_CAP_ARB BIT(6) +/* To implement this capability, the registers used in pwrap_init() must be defined. */ +#define PWRAP_CAP_INIT BIT(7) /* defines for slave device wrapper registers */ enum dew_regs { @@ -249,20 +251,20 @@ enum pwrap_regs { }; static int mt8188_regs[] = { - [PWRAP_INIT_DONE2] = 0x0, - [PWRAP_STAUPD_CTRL] = 0x4C, - [PWRAP_TIMER_EN] = 0x3E4, - [PWRAP_INT_EN] = 0x420, - [PWRAP_INT_FLG] = 0x428, - [PWRAP_INT_CLR] = 0x42C, - [PWRAP_INT1_EN] = 0x450, - [PWRAP_INT1_FLG] = 0x458, - [PWRAP_INT1_CLR] = 0x45C, - [PWRAP_WACS2_CMD] = 0x880, - [PWRAP_SWINF_2_WDATA_31_0] = 0x884, - [PWRAP_SWINF_2_RDATA_31_0] = 0x894, - [PWRAP_WACS2_VLDCLR] = 0x8A4, - [PWRAP_WACS2_RDATA] = 0x8A8, + [PWRAP_INIT_DONE2] = 0x0, + [PWRAP_STAUPD_CTRL] = 0x4C, + [PWRAP_TIMER_EN] = 0x3E4, + [PWRAP_INT_EN] = 0x420, + [PWRAP_INT_FLG] = 0x428, + [PWRAP_INT_CLR] = 0x42C, + [PWRAP_INT1_EN] = 0x450, + [PWRAP_INT1_FLG] = 0x458, + [PWRAP_INT1_CLR] = 0x45C, + [PWRAP_WACS2_CMD] = 0x880, + [PWRAP_SWINF_2_WDATA_31_0] = 0x884, + [PWRAP_SWINF_2_RDATA_31_0] = 0x894, + [PWRAP_WACS2_VLDCLR] = 0x8A4, + [PWRAP_WACS2_RDATA] = 0x8A8, }; static int mt8189_regs[] = { @@ -276,6 +278,23 @@ static int mt8189_regs[] = { [PWRAP_WACS2_RDATA] = 0x8A8, }; +static int mt8195_regs[] = { + [PWRAP_INIT_DONE2] = 0x0, + [PWRAP_STAUPD_CTRL] = 0x4C, + [PWRAP_TIMER_EN] = 0x3E4, + [PWRAP_INT_EN] = 0x420, + [PWRAP_INT_FLG] = 0x428, + [PWRAP_INT_CLR] = 0x42C, + [PWRAP_INT1_EN] = 0x450, + [PWRAP_INT1_FLG] = 0x458, + [PWRAP_INT1_CLR] = 0x45C, + [PWRAP_WACS2_CMD] = 0x880, + [PWRAP_SWINF_2_WDATA_31_0] = 0x884, + [PWRAP_SWINF_2_RDATA_31_0] = 0x894, + [PWRAP_WACS2_VLDCLR] = 0x8A4, + [PWRAP_WACS2_RDATA] = 0x8A8, +}; + static int mt8365_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, @@ -338,12 +357,6 @@ static int mt8365_regs[] = { [PWRAP_WDT_SRC_EN_1] = 0xf8, }; -enum pwrap_type { - PWRAP_MT8188, - PWRAP_MT8189, - PWRAP_MT8365, -}; - struct pwrap_slv_type { const u32 *dew_regs; u32 caps; @@ -362,10 +375,7 @@ struct pmic_wrapper { struct pmic_wrapper_type { int *regs; - enum pwrap_type type; u32 arb_en_all; - u32 int_en_all; - u32 int1_en_all; u32 spi_w; u32 wdt_src; /* Flags indicating the capability for the target pwrap */ @@ -644,7 +654,7 @@ static const struct pwrap_slv_type pmic_mt6357 = { static const struct pwrap_slv_type pmic_mt6359 = { .dew_regs = mt6359_regs, - .caps = PWRAP_SLV_CAP_DUALIO, + .caps = 0, }; static const struct udevice_id mtk_pmic_ids[] = { @@ -734,6 +744,11 @@ static int mtk_pwrap_probe(struct udevice *dev) * Skip initialization here in this case. */ if (!pwrap_readl(wrp, PWRAP_INIT_DONE2)) { + if (!HAS_CAP(wrp->master->caps, PWRAP_CAP_INIT)) { + dev_err(dev, "initialization is required but not supported\n"); + return -EOPNOTSUPP; + } + ret = pwrap_init(wrp); if (ret) { dev_err(dev, "init failed with %d\n", ret); @@ -755,7 +770,8 @@ static int mtk_pwrap_probe(struct udevice *dev) * Since STAUPD was not used on mt8173 platform, * so STAUPD of WDT_SRC which should be turned off */ - pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN); + if (HAS_CAP(wrp->master->caps, PWRAP_CAP_WDT_SRC)) + pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN); if (HAS_CAP(wrp->master->caps, PWRAP_CAP_WDT_SRC1)) pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN_1); @@ -765,15 +781,6 @@ static int mtk_pwrap_probe(struct udevice *dev) else pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN); - pwrap_writel(wrp, wrp->master->int_en_all, PWRAP_INT_EN); - - /* - * We add INT1 interrupt to handle starvation and request exception - * If we support it, we should enable it here. - */ - if (HAS_CAP(wrp->master->caps, PWRAP_CAP_INT1_EN)) - pwrap_writel(wrp, wrp->master->int1_en_all, PWRAP_INT1_EN); - return 0; } @@ -782,7 +789,6 @@ static int mtk_pwrap_bind(struct udevice *dev) ofnode pmic_node, regulators_node; int children; const struct pmic_child_info *pmic_children_info; - struct pmic_wrapper_type *pw_type = (void *)dev_get_driver_data(dev); pmic_node = dev_read_first_subnode(dev); if (!ofnode_valid(pmic_node)) { @@ -790,16 +796,13 @@ static int mtk_pwrap_bind(struct udevice *dev) return -ENXIO; } - switch (pw_type->type) { - case PWRAP_MT8365: + if (ofnode_device_is_compatible(pmic_node, "mediatek,mt6357")) { pmic_children_info = mt6357_pmic_children_info; - break; - case PWRAP_MT8188: - case PWRAP_MT8189: + } else if (ofnode_device_is_compatible(pmic_node, "mediatek,mt6359")) { pmic_children_info = mt6359_pmic_children_info; - break; - default: - dev_err(dev, "pwrap type %d not supported\n", pw_type->type); + } else { + dev_err(dev, "pmic type %s not supported\n", + ofnode_read_string(pmic_node, "compatible")); return -ENXIO; } @@ -848,20 +851,23 @@ static struct dm_pmic_ops mtk_pwrap_ops = { static struct pmic_wrapper_type pwrap_mt8188 = { .regs = mt8188_regs, - .type = PWRAP_MT8188, .arb_en_all = 0x777f, - .int_en_all = 0x180000, - .int1_en_all = 0x0, .spi_w = PWRAP_MAN_CMD_SPI_WRITE, .wdt_src = PWRAP_WDT_SRC_MASK_ALL, - .caps = PWRAP_CAP_INT1_EN | PWRAP_CAP_ARB, + .caps = PWRAP_CAP_ARB, }; static struct pmic_wrapper_type pwrap_mt8189 = { .regs = mt8189_regs, - .type = PWRAP_MT8189, .arb_en_all = 0x777f, - .int_en_all = 0x180000, + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .caps = PWRAP_CAP_ARB, +}; + +static const struct pmic_wrapper_type pwrap_mt8195 = { + .regs = mt8195_regs, + .arb_en_all = 0x777f, /* NEED CONFIRM */ .spi_w = PWRAP_MAN_CMD_SPI_WRITE, .wdt_src = PWRAP_WDT_SRC_MASK_ALL, .caps = PWRAP_CAP_ARB, @@ -869,18 +875,16 @@ static struct pmic_wrapper_type pwrap_mt8189 = { static const struct pmic_wrapper_type pwrap_mt8365 = { .regs = mt8365_regs, - .type = PWRAP_MT8365, .arb_en_all = 0x3ffff, - .int_en_all = 0x7f1fffff, - .int1_en_all = 0x0, .spi_w = PWRAP_MAN_CMD_SPI_WRITE, .wdt_src = PWRAP_WDT_SRC_MASK_ALL, - .caps = PWRAP_CAP_INT1_EN | PWRAP_CAP_WDT_SRC1, + .caps = PWRAP_CAP_WDT_SRC1 | PWRAP_CAP_INIT, }; static const struct udevice_id mtk_pwrap_ids[] = { { .compatible = "mediatek,mt8188-pwrap", .data = (ulong)&pwrap_mt8188 }, { .compatible = "mediatek,mt8189-pwrap", .data = (ulong)&pwrap_mt8189 }, + { .compatible = "mediatek,mt8195-pwrap", .data = (ulong)&pwrap_mt8195 }, { .compatible = "mediatek,mt8365-pwrap", .data = (ulong)&pwrap_mt8365 }, { } }; diff --git a/drivers/power/pmic/pca9450.c b/drivers/power/pmic/pca9450.c index c95e6357ee8..cbe8cd05be7 100644 --- a/drivers/power/pmic/pca9450.c +++ b/drivers/power/pmic/pca9450.c @@ -90,7 +90,7 @@ static int pca9450_probe(struct udevice *dev) return ret; } - if (ofnode_read_bool(dev_ofnode(dev), "nxp,wdog_b-warm-reset")) + if (dev_read_bool(dev, "nxp,wdog_b-warm-reset")) reset_ctrl = PCA9450_PMIC_RESET_WDOG_B_CFG_WARM; else reset_ctrl = PCA9450_PMIC_RESET_WDOG_B_CFG_COLD_LDO12; diff --git a/drivers/power/pmic/pmic_qcom.c b/drivers/power/pmic/pmic_qcom.c index 92d0a95859b..4b8dcc6104c 100644 --- a/drivers/power/pmic/pmic_qcom.c +++ b/drivers/power/pmic/pmic_qcom.c @@ -72,7 +72,7 @@ static int pmic_qcom_probe(struct udevice *dev) * contains two discrete values, not a single 64-bit address. * The address is the first value. */ - ret = ofnode_read_u32_index(dev_ofnode(dev), "reg", 0, &priv->usid); + ret = dev_read_u32_index(dev, "reg", 0, &priv->usid); if (ret < 0) return -EINVAL; diff --git a/drivers/power/pmic/pmic_spacemit_p1.c b/drivers/power/pmic/pmic_spacemit_p1.c new file mode 100644 index 00000000000..46c5926874c --- /dev/null +++ b/drivers/power/pmic/pmic_spacemit_p1.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025-2026 RISCstar Ltd. + */ + +#include <dm.h> +#include <power/pmic.h> +#include <power/spacemit_p1.h> + +static int pmic_p1_reg_count(struct udevice *dev) +{ + return P1_MAX_REGS; +} + +static int pmic_p1_write(struct udevice *dev, uint reg, const u8 *buffer, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buffer, len); + if (ret) + pr_err("%s write error on register %02x\n", dev->name, reg); + + return ret; +} + +static int pmic_p1_read(struct udevice *dev, uint reg, u8 *buffer, + int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buffer, len); + if (ret) + pr_err("%s read error on register %02x\n", dev->name, reg); + + return ret; +} + +static const struct pmic_child_info p1_children_info[] = { + { .prefix = "buck", .driver = P1_BUCK_DRIVER }, + { .prefix = "aldo", .driver = P1_ALDO_DRIVER }, + { .prefix = "dldo", .driver = P1_DLDO_DRIVER }, + { }, +}; + +static int pmic_p1_bind(struct udevice *dev) +{ + const struct pmic_child_info *p1_children_info = + (struct pmic_child_info *)dev_get_driver_data(dev); + ofnode regulators_node; + int children; + + regulators_node = dev_read_subnode(dev, "regulators"); + if (!ofnode_valid(regulators_node)) { + debug("%s regulators subnode not found\n", dev->name); + return -EINVAL; + } + + children = pmic_bind_children(dev, regulators_node, + p1_children_info); + if (!children) + debug("%s has no children (regulators)\n", dev->name); + + return 0; +} + +static int pmic_p1_probe(struct udevice *dev) +{ + return 0; +} + +static struct dm_pmic_ops pmic_p1_ops = { + .reg_count = pmic_p1_reg_count, + .read = pmic_p1_read, + .write = pmic_p1_write, +}; + +static const struct udevice_id pmic_p1_match[] = { + { + .compatible = "spacemit,p1", + .data = (ulong)&p1_children_info, + }, { + /* sentinel */ + } +}; + +U_BOOT_DRIVER(pmic_p1) = { + .name = "pmic_p1", + .id = UCLASS_PMIC, + .of_match = pmic_p1_match, + .bind = pmic_p1_bind, + .probe = pmic_p1_probe, + .ops = &pmic_p1_ops, +}; diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index a4ee5f1335a..c3dc5d6f97b 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -1,38 +1,38 @@ config DM_REGULATOR bool "Enable Driver Model for REGULATOR drivers (UCLASS_REGULATOR)" depends on DM - ---help--- - This config enables the driver model regulator support. - UCLASS_REGULATOR - designed to provide a common API for basic regulator's - functions, like get/set Voltage or Current value, enable state, etc... - Note: - When enabling this, please read the description, found in the files: - - 'include/power/pmic.h' - - 'include/power/regulator.h' - - 'drivers/power/pmic/pmic-uclass.c' - - 'drivers/power/pmic/regulator-uclass.c' - It's important to call the device_bind() with the proper node offset, - when binding the regulator devices. The pmic_bind_childs() can be used - for this purpose if PMIC I/O driver is implemented or dm_scan_fdt_dev() - otherwise. Detailed information can be found in the header file. + help + This config enables the driver model regulator support. + UCLASS_REGULATOR - designed to provide a common API for basic regulator's + functions, like get/set Voltage or Current value, enable state, etc... + Note: + When enabling this, please read the description, found in the files: + - 'include/power/pmic.h' + - 'include/power/regulator.h' + - 'drivers/power/pmic/pmic-uclass.c' + - 'drivers/power/pmic/regulator-uclass.c' + It's important to call the device_bind() with the proper node offset, + when binding the regulator devices. The pmic_bind_childs() can be used + for this purpose if PMIC I/O driver is implemented or dm_scan_fdt_dev() + otherwise. Detailed information can be found in the header file. config SPL_DM_REGULATOR bool "Enable regulators for SPL" depends on DM_REGULATOR && SPL_POWER - ---help--- - Regulators are seldom needed in SPL. Even if they are accessed, some - code space can be saved by accessing the PMIC registers directly. - Enable this option if you need regulators in SPL and can cope with - the extra code size. + help + Regulators are seldom needed in SPL. Even if they are accessed, some + code space can be saved by accessing the PMIC registers directly. + Enable this option if you need regulators in SPL and can cope with + the extra code size. config REGULATOR_ACT8846 bool "Enable driver for ACT8846 regulator" depends on DM_REGULATOR && PMIC_ACT8846 - ---help--- - Enable support for the regulator functions of the ACT8846 PMIC. The - driver implements get/set api for the various BUCKS and LDOS supported - by the PMIC device. This driver is controlled by a device tree node - which includes voltage limits. + help + Enable support for the regulator functions of the ACT8846 PMIC. The + driver implements get/set api for the various BUCKS and LDOS supported + by the PMIC device. This driver is controlled by a device tree node + which includes voltage limits. config REGULATOR_AS3722 bool "Enable driver for AS7322 regulator" @@ -75,33 +75,33 @@ config DM_REGULATOR_BD71837 bool "Enable Driver Model for ROHM BD71837/BD71847 regulators" depends on DM_REGULATOR && DM_PMIC_BD71837 help - This config enables implementation of driver-model regulator uclass - features for regulators on ROHM BD71837 and BD71847 PMICs. - BD71837 contains 8 bucks and 7 LDOS. BD71847 is reduced version - containing 6 bucks and 6 LDOs. The driver implements get/set api for - value and enable. + This config enables implementation of driver-model regulator uclass + features for regulators on ROHM BD71837 and BD71847 PMICs. + BD71837 contains 8 bucks and 7 LDOS. BD71847 is reduced version + containing 6 bucks and 6 LDOs. The driver implements get/set api for + value and enable. config SPL_DM_REGULATOR_BD71837 bool "Enable Driver Model for ROHM BD71837/BD71847 regulators in SPL" depends on DM_REGULATOR_BD71837 && SPL help - This config enables implementation of driver-model regulator uclass - features for regulators on ROHM BD71837 and BD71847 in SPL. + This config enables implementation of driver-model regulator uclass + features for regulators on ROHM BD71837 and BD71847 in SPL. config DM_REGULATOR_PCA9450 bool "Enable Driver Model for NXP PCA9450 regulators" depends on DM_REGULATOR && DM_PMIC_PCA9450 help - This config enables implementation of driver-model regulator uclass - features for regulators on NXP PCA9450 PMICs. PCA9450 contains 6 bucks - and 5 LDOS. The driver implements get/set api for value and enable. + This config enables implementation of driver-model regulator uclass + features for regulators on NXP PCA9450 PMICs. PCA9450 contains 6 bucks + and 5 LDOS. The driver implements get/set api for value and enable. config SPL_DM_REGULATOR_PCA9450 bool "Enable Driver Model for NXP PCA9450 regulators in SPL" depends on DM_REGULATOR_PCA9450 && SPL help - This config enables implementation of driver-model regulator uclass - features for regulators on ROHM PCA9450 in SPL. + This config enables implementation of driver-model regulator uclass + features for regulators on ROHM PCA9450 in SPL. config DM_REGULATOR_DA9063 bool "Enable Driver Model for REGULATOR DA9063" @@ -126,46 +126,56 @@ config SPL_DM_REGULATOR_DA9063 config DM_REGULATOR_PFUZE100 bool "Enable Driver Model for REGULATOR PFUZE100" depends on DM_REGULATOR && DM_PMIC_PFUZE100 - ---help--- - This config enables implementation of driver-model regulator uclass - features for REGULATOR PFUZE100. The driver implements get/set api for: - value, enable and mode. + default DM_PMIC_PFUZE100 + help + This config enables implementation of driver-model regulator uclass + features for REGULATOR PFUZE100. The driver implements get/set api for: + value, enable and mode. + +config SPL_DM_REGULATOR_PFUZE100 + bool "Enable Driver Model for REGULATOR PFUZE100 in SPL" + depends on SPL_DM_REGULATOR && SPL_DM_PMIC_PFUZE100 + default SPL_DM_PMIC_PFUZE100 + help + This config enables implementation of driver-model regulator uclass + features for REGULATOR PFUZE100. The driver implements get/set api for: + value, enable and mode. config REGULATOR_PWM bool "Enable driver for PWM regulators" depends on DM_REGULATOR && DM_PWM - ---help--- - Enable support for the PWM regulator functions which voltage are - controlled by PWM duty ratio. Some of Rockchip board using this kind - of regulator. The driver implements get/set api for the various BUCKS. - This driver is controlled by a device tree node - which includes voltage limits. + help + Enable support for the PWM regulator functions which voltage are + controlled by PWM duty ratio. Some of Rockchip board using this kind + of regulator. The driver implements get/set api for the various BUCKS. + This driver is controlled by a device tree node + which includes voltage limits. config DM_REGULATOR_MAX8907 bool "Enable Driver Model for REGULATOR MAX8907" depends on DM_REGULATOR && DM_PMIC_MAX8907 - ---help--- - This config enables implementation of driver-model regulator uclass - features for REGULATOR MAX8907. The driver supports both DC-to-DC - Step-Down (SD) Regulators and Low-Dropout Linear (LDO) Regulators - found in MAX8907 PMIC and implements get/set api for value and enable. + help + This config enables implementation of driver-model regulator uclass + features for REGULATOR MAX8907. The driver supports both DC-to-DC + Step-Down (SD) Regulators and Low-Dropout Linear (LDO) Regulators + found in MAX8907 PMIC and implements get/set api for value and enable. config DM_REGULATOR_MAX77663 bool "Enable Driver Model for REGULATOR MAX77663" depends on DM_REGULATOR && DM_PMIC_MAX77663 - ---help--- - This config enables implementation of driver-model regulator uclass - features for REGULATOR MAX77663. The driver supports both DC-to-DC - Step-Down (SD) Regulators and Low-Dropout Linear (LDO) Regulators - found in MAX77663 PMIC and implements get/set api for value and enable. + help + This config enables implementation of driver-model regulator uclass + features for REGULATOR MAX77663. The driver supports both DC-to-DC + Step-Down (SD) Regulators and Low-Dropout Linear (LDO) Regulators + found in MAX77663 PMIC and implements get/set api for value and enable. config DM_REGULATOR_MAX77686 bool "Enable Driver Model for REGULATOR MAX77686" depends on DM_REGULATOR && DM_PMIC_MAX77686 - ---help--- - This config enables implementation of driver-model regulator uclass - features for REGULATOR MAX77686. The driver implements get/set api for: - value, enable and mode. + help + This config enables implementation of driver-model regulator uclass + features for REGULATOR MAX77686. The driver implements get/set api for: + value, enable and mode. config DM_REGULATOR_NPCM8XX bool "Enable Driver Model for NPCM8xx voltage supply" @@ -211,33 +221,33 @@ config DM_REGULATOR_FIXED bool "Enable Driver Model for REGULATOR Fixed value" depends on DM_REGULATOR select DM_REGULATOR_COMMON - ---help--- - This config enables implementation of driver-model regulator uclass - features for fixed value regulators. The driver implements get/set api - for enable and get only for voltage value. + help + This config enables implementation of driver-model regulator uclass + features for fixed value regulators. The driver implements get/set api + for enable and get only for voltage value. config SPL_DM_REGULATOR_FIXED bool "Enable Driver Model for REGULATOR Fixed value in SPL" depends on DM_REGULATOR_FIXED && SPL select SPL_DM_REGULATOR_COMMON - ---help--- - This config enables implementation of driver-model regulator uclass - features for fixed value regulators in SPL. + help + This config enables implementation of driver-model regulator uclass + features for fixed value regulators in SPL. config DM_REGULATOR_GPIO bool "Enable Driver Model for GPIO REGULATOR" depends on DM_REGULATOR && DM_GPIO select DM_REGULATOR_COMMON - ---help--- - This config enables implementation of driver-model regulator uclass - features for gpio regulators. The driver implements get/set for - voltage value. + help + This config enables implementation of driver-model regulator uclass + features for gpio regulators. The driver implements get/set for + voltage value. config DM_REGULATOR_QCOM_RPMH bool "Enable driver model for Qualcomm RPMh regulator" depends on DM_REGULATOR && QCOM_RPMH select DEVRES - ---help--- + help Enable support for the Qualcomm RPMh regulator. The driver implements get/set api for a limited set of regulators used by u-boot. @@ -245,7 +255,7 @@ config DM_REGULATOR_QCOM_RPMH config DM_REGULATOR_QCOM_USB_VBUS bool "Enable driver model for Qualcomm USB vbus regulator" depends on DM_REGULATOR && DM_PMIC - ---help--- + help Enable support for the Qualcomm USB Vbus regulator. The driver implements get/set api for the regulator to be used by u-boot. @@ -253,18 +263,18 @@ config SPL_DM_REGULATOR_GPIO bool "Enable Driver Model for GPIO REGULATOR in SPL" depends on DM_REGULATOR_GPIO && SPL_DM_GPIO select SPL_DM_REGULATOR_COMMON - ---help--- - This config enables implementation of driver-model regulator uclass - features for gpio regulators in SPL. + help + This config enables implementation of driver-model regulator uclass + features for gpio regulators in SPL. config REGULATOR_RK8XX bool "Enable driver for RK8XX regulators" depends on DM_REGULATOR && PMIC_RK8XX - ---help--- - Enable support for the regulator functions of the RK8XX PMIC. The - driver implements get/set api for the various BUCKS and LDOs supported - by the PMIC device. This driver is controlled by a device tree node - which includes voltage limits. + help + Enable support for the regulator functions of the RK8XX PMIC. The + driver implements get/set api for the various BUCKS and LDOs supported + by the PMIC device. This driver is controlled by a device tree node + which includes voltage limits. config SPL_REGULATOR_RK8XX bool "Enable driver for RK8XX regulators in SPL" @@ -278,162 +288,162 @@ config SPL_REGULATOR_RK8XX config DM_REGULATOR_S2MPS11 bool "Enable driver for S2MPS11 regulator" depends on DM_REGULATOR && PMIC_S2MPS11 - ---help--- - This enables implementation of driver-model regulator uclass - features for REGULATOR S2MPS11. - The driver implements get/set api for: value and enable. + help + This enables implementation of driver-model regulator uclass + features for REGULATOR S2MPS11. + The driver implements get/set api for: value and enable. config REGULATOR_S5M8767 bool "Enable support for S5M8767 regulator" depends on DM_REGULATOR && PMIC_S5M8767 - ---help--- - This enables the regulator features of the S5M8767, allowing voltages - to be set, etc. The driver is not fully complete but supports most - common requirements, including all LDOs and BUCKs. This allows many - supplies to be set automatically using the device tree values. + help + This enables the regulator features of the S5M8767, allowing voltages + to be set, etc. The driver is not fully complete but supports most + common requirements, including all LDOs and BUCKs. This allows many + supplies to be set automatically using the device tree values. config DM_REGULATOR_SANDBOX bool "Enable Driver Model for Sandbox PMIC regulator" depends on DM_REGULATOR && DM_PMIC_SANDBOX - ---help--- - Enable the regulator driver for emulated Sandbox PMIC. - The emulated PMIC device depends on two drivers: - - sandbox PMIC I/O driver - implements dm pmic operations - - sandbox PMIC regulator driver - implements dm regulator operations - - sandbox PMIC i2c emul driver - emulates the PMIC's I2C transmission + help + Enable the regulator driver for emulated Sandbox PMIC. + The emulated PMIC device depends on two drivers: + - sandbox PMIC I/O driver - implements dm pmic operations + - sandbox PMIC regulator driver - implements dm regulator operations + - sandbox PMIC i2c emul driver - emulates the PMIC's I2C transmission - The regulator driver provides uclass operations for sandbox PMIC's - regulators. The driver implements get/set api for: voltage, current, - operation mode and enable state. - The driver supports LDO and BUCK regulators. + The regulator driver provides uclass operations for sandbox PMIC's + regulators. The driver implements get/set api for: voltage, current, + operation mode and enable state. + The driver supports LDO and BUCK regulators. - The Sandbox PMIC info: - * I/O interface: - - I2C chip address: 0x40 - - first register address: 0x0 - - register count: 0x10 - * Adjustable outputs: - - 2x LDO - - 2x BUCK - - Each, with a different operating conditions (header). - * Reset values: - - set by i2c emul driver's probe() (defaults in header) + The Sandbox PMIC info: + * I/O interface: + - I2C chip address: 0x40 + - first register address: 0x0 + - register count: 0x10 + * Adjustable outputs: + - 2x LDO + - 2x BUCK + - Each, with a different operating conditions (header). + * Reset values: + - set by i2c emul driver's probe() (defaults in header) - A detailed information can be found in header: '<power/sandbox_pmic.h>' - Binding info: 'doc/device-tree-bindings/pmic/max77686.txt' + A detailed information can be found in header: '<power/sandbox_pmic.h>' + Binding info: 'doc/device-tree-bindings/pmic/max77686.txt' config REGULATOR_TPS65090 bool "Enable driver for TPS65090 PMIC regulators" depends on PMIC_TPS65090 - ---help--- - The TPS65090 provides several FETs (Field-effect Transistors, - effectively switches) which are supported by this driver as - regulators, one for each FET. The standard regulator interface is - supported, but it is only possible to turn the regulators on or off. - There is no voltage/current control. + help + The TPS65090 provides several FETs (Field-effect Transistors, + effectively switches) which are supported by this driver as + regulators, one for each FET. The standard regulator interface is + supported, but it is only possible to turn the regulators on or off. + There is no voltage/current control. config DM_REGULATOR_PALMAS bool "Enable driver for PALMAS PMIC regulators" - depends on PMIC_PALMAS - ---help--- - This enables implementation of driver-model regulator uclass - features for REGULATOR PALMAS and the family of PALMAS PMICs. - The driver implements get/set api for: value and enable. + depends on PMIC_PALMAS + help + This enables implementation of driver-model regulator uclass + features for REGULATOR PALMAS and the family of PALMAS PMICs. + The driver implements get/set api for: value and enable. config DM_REGULATOR_PBIAS bool "Enable driver for PBIAS regulator" depends on DM_REGULATOR select REGMAP select SYSCON - ---help--- - This enables implementation of driver-model regulator uclass - features for pseudo-regulator PBIAS found in the OMAP SOCs. - This pseudo-regulator is used to provide a BIAS voltage to MMC1 - signal pads and must be configured properly during a voltage switch. - Voltage switching is required by some operating modes of SDcards and - eMMC. + help + This enables implementation of driver-model regulator uclass + features for pseudo-regulator PBIAS found in the OMAP SOCs. + This pseudo-regulator is used to provide a BIAS voltage to MMC1 + signal pads and must be configured properly during a voltage switch. + Voltage switching is required by some operating modes of SDcards and + eMMC. config DM_REGULATOR_LP873X bool "Enable driver for LP873X PMIC regulators" - depends on PMIC_LP873X - ---help--- - This enables implementation of driver-model regulator uclass - features for REGULATOR LP873X and the family of LP873X PMICs. - The driver implements get/set api for: value and enable. + depends on PMIC_LP873X + help + This enables implementation of driver-model regulator uclass + features for REGULATOR LP873X and the family of LP873X PMICs. + The driver implements get/set api for: value and enable. config DM_REGULATOR_LP87565 bool "Enable driver for LP87565 PMIC regulators" - depends on PMIC_LP87565 - ---help--- - This enables implementation of driver-model regulator uclass - features for REGULATOR LP87565 and the family of LP87565 PMICs. - LP87565 series of PMICs have 4 single phase BUCKs that can also - be configured in multi phase modes. The driver implements - get/set api for value and enable. + depends on PMIC_LP87565 + help + This enables implementation of driver-model regulator uclass + features for REGULATOR LP87565 and the family of LP87565 PMICs. + LP87565 series of PMICs have 4 single phase BUCKs that can also + be configured in multi phase modes. The driver implements + get/set api for value and enable. config DM_REGULATOR_STM32_VREFBUF bool "Enable driver for STMicroelectronics STM32 VREFBUF" depends on DM_REGULATOR && (STM32H7 || ARCH_STM32MP) help - This driver supports STMicroelectronics STM32 VREFBUF (voltage - reference buffer) which can be used as voltage reference for - internal ADCs, DACs and also for external components through - dedicated Vref+ pin. + This driver supports STMicroelectronics STM32 VREFBUF (voltage + reference buffer) which can be used as voltage reference for + internal ADCs, DACs and also for external components through + dedicated Vref+ pin. config DM_REGULATOR_TPS65910 bool "Enable driver for TPS65910 PMIC regulators" depends on DM_PMIC_TPS65910 - ---help--- - The TPS65910 PMIC provides 4 SMPSs and 8 LDOs. This driver supports all - regulator types of the TPS65910 (BUCK, BOOST and LDO). It implements - the get/set api for value and enable. + help + The TPS65910 PMIC provides 4 SMPSs and 8 LDOs. This driver supports all + regulator types of the TPS65910 (BUCK, BOOST and LDO). It implements + the get/set api for value and enable. config DM_REGULATOR_TPS65911 bool "Enable driver for TPS65911 PMIC regulators" depends on DM_PMIC_TPS65910 - ---help--- - This config enables implementation of driver-model regulator - uclass features for the TPS65911 PMIC. The driver supports Step-Down - DC-DC Converters for Processor Cores (VDD1 and VDD2), Step-Down DC-DC - Converter for I/O Power (VIO), Controller for External FETs (VDDCtrl) - and LDO Voltage Regulators found in TPS65911 PMIC and implements - get/set api for value and enable. + help + This config enables implementation of driver-model regulator + uclass features for the TPS65911 PMIC. The driver supports Step-Down + DC-DC Converters for Processor Cores (VDD1 and VDD2), Step-Down DC-DC + Converter for I/O Power (VIO), Controller for External FETs (VDDCtrl) + and LDO Voltage Regulators found in TPS65911 PMIC and implements + get/set api for value and enable. config DM_REGULATOR_TPS62360 bool "Enable driver for TPS6236x Power Regulator" depends on DM_REGULATOR help - The TPS6236X DC/DC step down converter provides a single output - power line peaking at 3A current. This driver supports all four - variants of the chip (TPS62360, TPS62361, TPS62362, TPS62363). It - implements the get/set api for value only, as the power line is - always on. + The TPS6236X DC/DC step down converter provides a single output + power line peaking at 3A current. This driver supports all four + variants of the chip (TPS62360, TPS62361, TPS62362, TPS62363). It + implements the get/set api for value only, as the power line is + always on. config DM_REGULATOR_TPS80031 bool "Enable driver for TPS80031/TPS80032 PMIC regulators" depends on DM_PMIC_TPS80031 - ---help--- - This enables implementation of driver-model regulator uclass - features for TPS80031/TPS80032 PMICs. The driver implements - get/set api for: value and enable. + help + This enables implementation of driver-model regulator uclass + features for TPS80031/TPS80032 PMICs. The driver implements + get/set api for: value and enable. config DM_REGULATOR_TPS6287X bool "Enable driver for TPS6287x Power Regulator" depends on DM_REGULATOR help - The TPS6287X is a step down converter with a fast transient - response. This driver supports all four variants of the chip - (TPS62870, TPS62871, TPS62872, TPS62873). It implements the - get/set api for value only, as the power line is always on. + The TPS6287X is a step down converter with a fast transient + response. This driver supports all four variants of the chip + (TPS62870, TPS62871, TPS62872, TPS62873). It implements the + get/set api for value only, as the power line is always on. config DM_REGULATOR_STPMIC1 bool "Enable driver for STPMIC1 regulators" depends on DM_REGULATOR && PMIC_STPMIC1 - ---help--- - Enable support for the regulator functions of the STPMIC1 PMIC. The - driver implements get/set api for the various BUCKS and LDOs supported - by the PMIC device. This driver is controlled by a device tree node - which includes voltage limits. + help + Enable support for the regulator functions of the STPMIC1 PMIC. The + driver implements get/set api for the various BUCKS and LDOs supported + by the PMIC device. This driver is controlled by a device tree node + which includes voltage limits. config DM_REGULATOR_ANATOP bool "Enable driver for ANATOP regulators" @@ -441,18 +451,18 @@ config DM_REGULATOR_ANATOP select REGMAP select SYSCON help - Enable support for the Freescale i.MX on-chip ANATOP LDO - regulators. It is recommended that this option be enabled on - i.MX6 platform. + Enable support for the Freescale i.MX on-chip ANATOP LDO + regulators. It is recommended that this option be enabled on + i.MX6 platform. config SPL_DM_REGULATOR_TPS6287X bool "Enable driver for TPS6287x Power Regulator" depends on SPL_DM_REGULATOR help - The TPS6287X is a step down converter with a fast transient - response. This driver supports all four variants of the chip - (TPS62870, TPS62871, TPS62872, TPS62873). It implements the - get/set api for value only, as the power line is always on. + The TPS6287X is a step down converter with a fast transient + response. This driver supports all four variants of the chip + (TPS62870, TPS62871, TPS62872, TPS62873). It implements the + get/set api for value only, as the power line is always on. config SPL_DM_REGULATOR_STPMIC1 bool "Enable driver for STPMIC1 regulators in SPL" @@ -464,54 +474,54 @@ config SPL_DM_REGULATOR_PALMAS bool "Enable driver for PALMAS PMIC regulators" depends on SPL_PMIC_PALMAS help - This enables implementation of driver-model regulator uclass - features for REGULATOR PALMAS and the family of PALMAS PMICs. - The driver implements get/set api for: value and enable in SPL. + This enables implementation of driver-model regulator uclass + features for REGULATOR PALMAS and the family of PALMAS PMICs. + The driver implements get/set api for: value and enable in SPL. config SPL_DM_REGULATOR_LP87565 bool "Enable driver for LP87565 PMIC regulators" depends on SPL_PMIC_LP87565 help - This enables implementation of driver-model regulator uclass - features for REGULATOR LP87565 and the family of LP87565 PMICs. - LP87565 series of PMICs have 4 single phase BUCKs that can also - be configured in multi phase modes. The driver implements - get/set api for value and enable in SPL. + This enables implementation of driver-model regulator uclass + features for REGULATOR LP87565 and the family of LP87565 PMICs. + LP87565 series of PMICs have 4 single phase BUCKs that can also + be configured in multi phase modes. The driver implements + get/set api for value and enable in SPL. config SPL_DM_REGULATOR_LP873X bool "Enable driver for LP873X PMIC regulators" depends on SPL_PMIC_LP873X help - This enables implementation of driver-model regulator uclass - features for REGULATOR LP873X and the family of LP873X PMICs. - The driver implements get/set api for: value and enable in SPL. + This enables implementation of driver-model regulator uclass + features for REGULATOR LP873X and the family of LP873X PMICs. + The driver implements get/set api for: value and enable in SPL. config DM_REGULATOR_TPS65941 bool "Enable driver for TPS65941 PMIC regulators" - depends on PMIC_TPS65941 + depends on PMIC_TPS65941 help - This enables implementation of driver-model regulator uclass - features for REGULATOR TPS65941 and the family of TPS65941 PMICs. - TPS65941 series of PMICs have 5 single phase BUCKs that can also - be configured in multi phase modes & 4 LDOs. The driver implements - get/set api for value and enable. + This enables implementation of driver-model regulator uclass + features for REGULATOR TPS65941 and the family of TPS65941 PMICs. + TPS65941 series of PMICs have 5 single phase BUCKs that can also + be configured in multi phase modes & 4 LDOs. The driver implements + get/set api for value and enable. config DM_REGULATOR_SCMI bool "Enable driver for SCMI voltage domain regulators" depends on DM_REGULATOR select SCMI_AGENT - help - Enable this option if you want to support regulators exposed through + help + Enable this option if you want to support regulators exposed through the SCMI voltage domain protocol by a SCMI server. config DM_REGULATOR_TPS65219 bool "Enable driver for TPS65219 PMIC regulators" - depends on PMIC_TPS65219 + depends on PMIC_TPS65219 help - This enables implementation of driver-model regulator uclass - features for REGULATOR TPS65219 and the family of TPS65219 PMICs. - TPS65219 series of PMICs have 3 single phase BUCKs & 4 LDOs. - The driver implements get/set api for value and enable. + This enables implementation of driver-model regulator uclass + features for REGULATOR TPS65219 and the family of TPS65219 PMICs. + TPS65219 series of PMICs have 3 single phase BUCKs & 4 LDOs. + The driver implements get/set api for value and enable. config REGULATOR_RZG2L_USBPHY bool "Enable driver for RZ/G2L USB PHY VBUS supply" @@ -524,11 +534,11 @@ config REGULATOR_RZG2L_USBPHY config DM_REGULATOR_CPCAP bool "Enable driver for CPCAP PMIC regulators" depends on DM_REGULATOR && DM_PMIC_CPCAP - ---help--- - Enable implementation of driver-model regulator uclass features for - REGULATOR CPCAP. The driver supports both DC-to-DC Step-Down Switching - (SW) Regulators and Low-Dropout Linear (LDO) Regulators found in CPCAP - PMIC and implements get/set api for voltage and state. + help + Enable implementation of driver-model regulator uclass features for + REGULATOR CPCAP. The driver supports both DC-to-DC Step-Down Switching + (SW) Regulators and Low-Dropout Linear (LDO) Regulators found in CPCAP + PMIC and implements get/set api for voltage and state. config DM_REGULATOR_MT6357 bool "Enable driver for MediaTek MT6357 PMIC regulators" @@ -547,3 +557,53 @@ config DM_REGULATOR_MT6359 MediaTek MT6359 PMIC. This driver supports the control of different power rails of device through regulator interface. + +config DM_REGULATOR_PMBUS_HELPER + bool "Shared regulator helpers for PMBus chip drivers" + depends on DM_REGULATOR && PMBUS && DM_I2C + help + Provide shared get_value / set_value / get_enable / set_enable + operations for UCLASS_REGULATOR drivers that bind PMBus 1.x + compliant voltage regulators. Per chip drivers + (mps,mpq8785, lltc,ltc3882, ...) consume this helper to avoid + duplicating the LINEAR16 / DIRECT decoder dispatch and the + VOUT_MODE / VOUT_COMMAND / OPERATION transport sequences. + +config DM_REGULATOR_PMBUS_GENERIC + bool "Generic PMBus 1.x regulator driver (compatible=\"pmbus\")" + depends on DM_REGULATOR_PMBUS_HELPER + help + Catch all UCLASS_REGULATOR driver bound to compatible = "pmbus". + Auto detects the VOUT numeric format from the chip's VOUT_MODE + register and exposes telemetry plus voltage set / get against + the standard PMBus 1.x command codes. Use this for PMBus + compliant chips that have no per chip driver yet; promote to a + per chip driver only when chip specific quirks (vendor + registers, VID coercion, ADDR pin auto promotion, non standard + m / b / R coefficients) need handling. + +config DM_REGULATOR_MPQ8785 + bool "MPS MPQ8785 / MPM3695 / MPM82504 PMBus voltage regulator" + depends on DM_REGULATOR_PMBUS_HELPER + help + Driver for the Monolithic Power Systems MPQ8785 family of + digital multiphase voltage regulators with PMBus. Supports + MPM3695, MPM3695-25, MPM82504, and MPQ8785. Adapted from the + Linux drivers/hwmon/pmbus/mpq8785.c reference. + +config SANDBOX_PMBUS + bool "Sandbox PMBus 1.x chip emulator" + depends on SANDBOX && PMBUS && DM_I2C + help + Emulate a PMBus 1.x compliant chip behind a sandbox I2C bus so + the PMBus framework (lib/pmbus.c), the generic regulator + (DM_REGULATOR_PMBUS_GENERIC) and the pmbus CLI command can be + exercised by the dm unit tests with no real hardware. Only + useful for testing; say N on real boards. + +config DM_REGULATOR_SPACEMIT_P1 + bool "Enable driver for Spacemit P1 PMIC regulators" + depends on DM_REGULATOR && PMIC_SPACEMIT_P1 + help + Enable implementation of driver-model regulator uclass features + for regulator P1. The driver supports BUCKs, LDOs and SWITCHes. diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index 9e303d4f7f8..3a148545387 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_$(PHASE_)DM_REGULATOR_MAX77663) += max77663_regulator.o obj-$(CONFIG_$(PHASE_)DM_REGULATOR_MAX8907) += max8907_regulator.o obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_DM_REGULATOR_NPCM8XX) += npcm8xx_regulator.o -obj-$(CONFIG_$(PHASE_)DM_PMIC_PFUZE100) += pfuze100.o +obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PFUZE100) += pfuze100.o obj-$(CONFIG_$(PHASE_)DM_REGULATOR_BD71837) += bd71837.o obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PCA9450) += pca9450.o obj-$(CONFIG_$(PHASE_)REGULATOR_PWM) += pwm_regulator.o @@ -29,6 +29,7 @@ obj-$(CONFIG_$(PHASE_)REGULATOR_RK8XX) += rk8xx.o obj-$(CONFIG_DM_REGULATOR_S2MPS11) += s2mps11_regulator.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o +obj-$(CONFIG_DM_REGULATOR_SPACEMIT_P1) += spacemit_p1_regulator.o obj-$(CONFIG_REGULATOR_TPS65090) += tps65090_regulator.o obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PALMAS) += palmas_regulator.o obj-$(CONFIG_$(PHASE_)DM_REGULATOR_PBIAS) += pbias_regulator.o @@ -49,3 +50,7 @@ obj-$(CONFIG_REGULATOR_RZG2L_USBPHY) += rzg2l-usbphy-regulator.o obj-$(CONFIG_$(PHASE_)DM_REGULATOR_CPCAP) += cpcap_regulator.o obj-$(CONFIG_DM_REGULATOR_MT6357) += mt6357_regulator.o obj-$(CONFIG_DM_REGULATOR_MT6359) += mt6359_regulator.o +obj-$(CONFIG_DM_REGULATOR_PMBUS_HELPER) += pmbus_helper.o +obj-$(CONFIG_DM_REGULATOR_PMBUS_GENERIC) += pmbus_generic.o +obj-$(CONFIG_DM_REGULATOR_MPQ8785) += mpq8785.o +obj-$(CONFIG_SANDBOX_PMBUS) += sandbox_pmbus.o diff --git a/drivers/power/regulator/anatop_regulator.c b/drivers/power/regulator/anatop_regulator.c index 824a753db16..88570a1f624 100644 --- a/drivers/power/regulator/anatop_regulator.c +++ b/drivers/power/regulator/anatop_regulator.c @@ -170,8 +170,7 @@ static int anatop_regulator_probe(struct udevice *dev) anatop_reg = dev_get_plat(dev); uc_pdata = dev_get_uclass_plat(dev); - anatop_reg->name = ofnode_read_string(dev_ofnode(dev), - "regulator-name"); + anatop_reg->name = dev_read_string(dev, "regulator-name"); if (!anatop_reg->name) return log_msg_ret("regulator-name", -EINVAL); diff --git a/drivers/power/regulator/mpq8785.c b/drivers/power/regulator/mpq8785.c new file mode 100644 index 00000000000..dc321f0e410 --- /dev/null +++ b/drivers/power/regulator/mpq8785.c @@ -0,0 +1,494 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2026 Free Mobile, Vincent Jardin + * + * MPS MPQ8785 / MPM3695 / MPM3695-25 / MPM82504 PMBus voltage + * regulator driver. Adapted from + * linux/drivers/hwmon/pmbus/mpq8785.c + * (Charles Hsu, GPL-2.0-or-later) with the kernel hwmon publication + * and caching layers stripped. + * + * Hooks the shared pmbus_helper UCLASS_REGULATOR ops + adds the MPS + * specific identify (VOUT_MODE switch between LINEAR16 and DIRECT + * m=64 R=1 for the chip's "VID" mode), the MPS vendor extension + * (pmbus mps last|clear last|clear force), and ADDR_VBOOT auto + * promotion when the DT declared address fails the MFR_ID probe. + */ + +#include <command.h> +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <pmbus.h> +#include <vsprintf.h> +#include <linux/bitops.h> +#include <power/regulator.h> + +#include "pmbus_helper.h" + +/* Chip family identifiers (driver_data). */ +enum mpq_chip_id { + MPQ_MPM3695 = 0, + MPQ_MPM3695_25 = 1, + MPQ_MPM82504 = 2, + MPQ_MPQ8785 = 3, +}; + +/* + * MPS vendor extended command codes (NOT in PMBus 1.3 Part II). + * + * CLEAR_LAST_FAULT (08h) clears the NVM backed PROTECTION_LAST + * register. Gated by MFR_CFG_EXT (F5h) + * bit[6] = 1; chip silently no ops if the + * gate is cleared. + * PROTECTION_LAST (FBh) single event, NVM backed log of the last + * protection event. Survives the chip's own + * power cycle. The boot time post mortem the + * SoC has no other way to obtain. + * + * NEVER issue CLEAR_LAST_FAULT (08h) implicitly; it would erase the + * post mortem trail. Only the explicit pmbus mps clear last and + * pmbus mps clear force subcommands write it. + */ +#define PMBUS_CLEAR_LAST_FAULT 0x08 +#define MPS_PROTECTION_LAST 0xfb + +/* + * MFR_CFG_EXT (F5h) is an MPS extended config WORD (16 bits, not a + * byte). Bit[6] (MFR_CLR_FAULT_CFG) gates CLEAR_LAST_FAULT (08h) + * clearing PROTECTION_LAST. Several other bits are fixed and MUST be + * preserved on writeback; always read modify write the full 16 bits, + * only flip bit[6], restore on the way out. + */ +#define MPS_MFR_CFG_EXT 0xf5 +#define MPS_MFR_CFG_EXT_CLR_LAST_EN BIT(6) + +/* + * MPQ8785 driver_info (transcribed from Linux's + * drivers/hwmon/pmbus/mpq8785.c::mpq8785_info). DIRECT format with + * chip specific m / b / R coefficients on VIN, IOUT, TEMPERATURE. + * VOUT format is selected at probe time from VOUT_MODE: bits[7:5] == 0 + * selects LINEAR16, bits[7:5] == 1 or 2 selects DIRECT m=64 R=1. + */ + +/* + * MPS-extended STATUS_* bit names. The MPQ8785 family reuses several + * bit positions documented as RESERVED / UNKNOWN / NONE_ABOVE / + * MFR_SPECIFIC by PMBus 1.3 for chip specific signals. The override + * table below substitutes the chip name for the standard one when + * the bit is set, leaving every other PMBus 1.3 standard bit + * (VOUT_OV, IOUT_OC, TEMP, CML, ...) unchanged. + * + * STATUS_WORD bit[12] spec MFR_SPECIFIC chip NVM_SUMMARY (NVM + * backed PROTECTION_LAST + * register is non zero) + * STATUS_WORD bit[8] spec UNKNOWN chip WATCH_DOG (internal + * calculation FSM watchdog + * overflow) + * STATUS_WORD bit[0] spec NONE_ABOVE chip DRMOS_FAULT (DrMOS + * stage fault) + * STATUS_CML bit[4] spec MEMORY chip MTP_CRC_FAULT (NVM + * CRC mismatch on restore) + * STATUS_CML bit[0] spec OTHER_MEM_LOGIC chip MTP_FAULT (NVM + * signature fault) + * STATUS_TEMPERATURE bit[0] (PMBus leaves bits[3:0] reserved on + * this register) chip + * OT_SELF (controller die + * OT condition) + */ +static const struct pmbus_status_override mpq8785_status_overrides[] = { + { PMBUS_STATUS_WORD, BIT(12), "NVM_SUMMARY" }, + { PMBUS_STATUS_WORD, BIT(8), "WATCH_DOG" }, + { PMBUS_STATUS_WORD, BIT(0), "DRMOS_FAULT" }, + { PMBUS_STATUS_CML, BIT(4), "MTP_CRC_FAULT" }, + { PMBUS_STATUS_CML, BIT(0), "MTP_FAULT" }, + { PMBUS_STATUS_TEMPERATURE, BIT(0), "OT_SELF" }, + { /* sentinel */ } +}; + +static struct pmbus_driver_info mpq8785_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = pmbus_fmt_direct, + .format[PSC_VOLTAGE_OUT] = pmbus_fmt_linear, /* refined per VOUT_MODE */ + .format[PSC_CURRENT_OUT] = pmbus_fmt_direct, + .format[PSC_TEMPERATURE] = pmbus_fmt_direct, + .m[PSC_VOLTAGE_IN] = 4, .b[PSC_VOLTAGE_IN] = 0, .R[PSC_VOLTAGE_IN] = 1, + .m[PSC_CURRENT_OUT] = 16, .b[PSC_CURRENT_OUT] = 0, .R[PSC_CURRENT_OUT] = 0, + .m[PSC_TEMPERATURE] = 1, .b[PSC_TEMPERATURE] = 0, .R[PSC_TEMPERATURE] = 0, + /* + * Sensor set this family actually implements with calibrated + * coefficients: VIN, VOUT, IOUT, TEMP. READ_IIN / READ_POUT are + * ACKed by the silicon but uncalibrated here (the kernel's mpq8646 + * / mpq8785 drivers expose neither), so declaring the set keeps + * pmbus_print_telemetry from printing a bogus POUT / IIN -- matching + * the kernel's per-chip sensor list. + */ + .classes_present = BIT(PSC_VOLTAGE_IN) | BIT(PSC_VOLTAGE_OUT) | + BIT(PSC_CURRENT_OUT) | BIT(PSC_TEMPERATURE), + .status_overrides = mpq8785_status_overrides, +}; + +/* + * MPM3695 / MPM3695-25 / MPM82504 driver_info: VOUT in DIRECT format + * with chip family default m=8 R=2. Other sensor classes default to + * LINEAR (the chip family does not document non standard formats for + * VIN / IOUT / TEMPERATURE; the helper falls back to LINEAR11 when + * the active info is non NULL but format[c] is linear). + */ +static struct pmbus_driver_info mpm82504_info = { + .pages = 1, + .format[PSC_VOLTAGE_OUT] = pmbus_fmt_direct, + .m[PSC_VOLTAGE_OUT] = 8, .b[PSC_VOLTAGE_OUT] = 0, .R[PSC_VOLTAGE_OUT] = 2, + .format[PSC_VOLTAGE_IN] = pmbus_fmt_linear, + .format[PSC_CURRENT_OUT] = pmbus_fmt_linear, + .format[PSC_TEMPERATURE] = pmbus_fmt_linear, +}; + +/* + * Chip match for the framework's pmbus dev <bus>:<addr> raw I2C + * path. Used when the operator selects the chip directly by address + * instead of by regulator-name; the framework probes MFR_ID, sees + * "MPS" (after the byte reverse helper), and caches mpq8785_info. + */ +static const struct pmbus_chip_match mpq8785_match = { + .mfr_id = "MPS", + .mfr_id_reverse = true, + .vendor = "mps", + .info = &mpq8785_info, +}; + +static const struct pmbus_bit mpq_protection_last_bits[] = { + { 1u << 15, "INIT_FAULT" }, + { 1u << 14, "NVM_CRC_ERROR" }, + { 1u << 13, "NVM_FAULT" }, + { 1u << 12, "OC_PHASE_FAULT" }, + { 1u << 11, "OTP_SELF_FAULT" }, + { 1u << 9, "SWITCH_PRD_FAULT" }, + { 1u << 8, "VIN_OV_FAULT" }, + { 1u << 7, "VOUT_OV_FAULT" }, + { 1u << 6, "VOUT_UV_FAULT" }, + { 1u << 5, "OC_TOT_FAULT" }, + { 1u << 4, "VIN_UVLO_FAULT" }, + { 1u << 3, "DRMOS_OTP" }, + { /* sentinel */ } +}; + +static int mps_require_active(struct udevice **chip) +{ + const struct pmbus_active_dev *act = pmbus_active(); + + if (!act) { + printf("pmbus mps: no active device. Use 'pmbus dev <bus>:<addr>' first.\n"); + return CMD_RET_FAILURE; + } + if (strcmp(act->vendor, "mps") != 0) { + printf("pmbus mps: active device is not from vendor 'mps' (got '%s')\n", + act->vendor[0] ? act->vendor : "(generic)"); + return CMD_RET_FAILURE; + } + if (pmbus_active_get_i2c(chip)) { + printf("pmbus mps: cannot reach i2c%d:0x%02x\n", + act->bus_seq, act->addr); + return CMD_RET_FAILURE; + } + return CMD_RET_SUCCESS; +} + +static int mps_do_last(struct udevice *chip) +{ + u16 prot_last = 0; + + if (pmbus_read_word(chip, MPS_PROTECTION_LAST, &prot_last)) { + printf("pmbus mps: PROTECTION_LAST (FBh) read failed\n"); + return CMD_RET_FAILURE; + } + printf("PROTECTION_LAST (FBh) = 0x%04x [", prot_last); + pmbus_print_bits(prot_last, mpq_protection_last_bits); + printf("] (NVM, survives MPQ power cycle)\n"); + return CMD_RET_SUCCESS; +} + +static int mps_do_clear_last(struct udevice *chip) +{ + int ret; + + printf("pmbus mps: WARNING, erasing NVM PROTECTION_LAST (FBh) post mortem\n"); + ret = dm_i2c_write(chip, PMBUS_CLEAR_LAST_FAULT, NULL, 0); + if (ret) { + printf("pmbus mps: CLEAR_LAST_FAULT (08h) write failed (%d)\n", ret); + return CMD_RET_FAILURE; + } + printf("pmbus mps: CLEAR_LAST_FAULT (08h) issued; gated by MFR_CFG_EXT bit[6]\n"); + printf(" (chip silently no ops if F5h bit[6] = 0; verify by re reading FBh)\n"); + return CMD_RET_SUCCESS; +} + +static int mps_do_clear_force(struct udevice *chip) +{ + u8 wp_orig = 0; + u16 cfg_orig = 0, cfg_unlocked; + int ret, last_rc = 0, rc; + + printf("pmbus mps: FORCE; temporarily lowering WRITE_PROTECT and MFR_CFG_EXT.CLEAR_LAST_EN\n"); + printf("pmbus mps: WARNING, erasing NVM PROTECTION_LAST (FBh) post mortem\n"); + + ret = pmbus_read_byte(chip, PMBUS_WRITE_PROTECT, &wp_orig); + if (ret) { + printf("pmbus mps: WRITE_PROTECT (10h) read failed (%d), aborting force\n", ret); + return CMD_RET_FAILURE; + } + ret = pmbus_read_word(chip, MPS_MFR_CFG_EXT, &cfg_orig); + if (ret) { + printf("pmbus mps: MFR_CFG_EXT (F5h) read failed (%d), aborting force\n", ret); + return CMD_RET_FAILURE; + } + printf("pmbus mps: saved WRITE_PROTECT=0x%02x MFR_CFG_EXT=0x%04x\n", + wp_orig, cfg_orig); + + if (wp_orig != 0) { + u8 wp_open = 0x00; + + ret = dm_i2c_write(chip, PMBUS_WRITE_PROTECT, &wp_open, 1); + if (ret) { + printf("pmbus mps: WRITE_PROTECT clear failed (%d), chip refuses unlock\n", + ret); + return CMD_RET_FAILURE; + } + } + + cfg_unlocked = cfg_orig | MPS_MFR_CFG_EXT_CLR_LAST_EN; + ret = pmbus_write_word(chip, MPS_MFR_CFG_EXT, cfg_unlocked); + if (ret) { + printf("pmbus mps: MFR_CFG_EXT <- 0x%04x failed (%d)\n", + cfg_unlocked, ret); + goto restore_wp; + } + + last_rc = dm_i2c_write(chip, PMBUS_CLEAR_LAST_FAULT, NULL, 0); + if (last_rc) + printf("pmbus mps: CLEAR_LAST_FAULT (08h) write failed (%d) even with gate open\n", + last_rc); + else + printf("pmbus mps: CLEAR_LAST_FAULT (08h) issued with MFR_CFG_EXT bit[6]=1, PROTECTION_LAST should now read 0x0000\n"); + + rc = pmbus_write_word(chip, MPS_MFR_CFG_EXT, cfg_orig); + if (rc) + printf("pmbus mps: MFR_CFG_EXT restore failed (%d), gate may stay open until POR\n", + rc); + +restore_wp: + if (wp_orig != 0) { + rc = dm_i2c_write(chip, PMBUS_WRITE_PROTECT, &wp_orig, 1); + if (rc) + printf("pmbus mps: WRITE_PROTECT restore failed (%d), chip stays unlocked until POR\n", + rc); + } + + return (ret || last_rc) ? CMD_RET_FAILURE : CMD_RET_SUCCESS; +} + +static int mps_vendor_handler(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *chip; + int rc; + + if (argc < 2) + return CMD_RET_USAGE; + + rc = mps_require_active(&chip); + if (rc) + return rc; + + if (!strcmp(argv[1], "last") && argc == 2) + return mps_do_last(chip); + if (!strcmp(argv[1], "clear") && argc >= 3) { + if (!strcmp(argv[2], "last")) + return mps_do_clear_last(chip); + if (!strcmp(argv[2], "force")) + return mps_do_clear_force(chip); + } + return CMD_RET_USAGE; +} + +static const struct pmbus_vendor_op mps_vendor_op = { + .vendor = "mps", + .handler = mps_vendor_handler, + .help = "pmbus mps last : read MPS PROTECTION_LAST (FBh)\n" + "pmbus mps clear last : issue MPS CLEAR_LAST_FAULT (08h) (DESTRUCTIVE)\n" + "pmbus mps clear force : force clear via MFR_CFG_EXT bit[6] (DESTRUCTIVE)\n", +}; + +static void mpq8785_identify_vout(struct udevice *i2c_dev) +{ + enum pmbus_data_format fmt; + + /* + * Let the shared helper read VOUT_MODE and pick the base format + * (the single source of truth for the bit layout). The MPS quirk: + * this family encodes VOUT in DIRECT with m=64 R=1 whenever + * VOUT_MODE reports VID *or* DIRECT -- override the helper's + * generic DIRECT m=1 / VID-unwired result in those two modes. + * LINEAR and IEEE754 keep the helper's selection unchanged. + */ + fmt = pmbus_regulator_identify_vout(i2c_dev, &mpq8785_info); + if (fmt == pmbus_fmt_vid || fmt == pmbus_fmt_direct) { + mpq8785_info.format[PSC_VOLTAGE_OUT] = pmbus_fmt_direct; + mpq8785_info.m[PSC_VOLTAGE_OUT] = 64; + mpq8785_info.b[PSC_VOLTAGE_OUT] = 0; + mpq8785_info.R[PSC_VOLTAGE_OUT] = 1; + } +} + +/* + * The MPQ8785 datasheet revision letter changes which window the + * analog ADDR_VBOOT level resolves to. Boards have been observed at + * 0x10 (later die rev) versus the 0x20 the original driver assumed. + * If the DT declared address fails the MFR_ID probe at probe time, + * walk the three documented windows looking for an MPS responder. + * + * Each window covers 16 consecutive 7 bit I2C addresses; the low + * nibble selects the chip's MFR_ADDR_PMBUS slot within the window. + */ +#define MPS_ADDR_VBOOT_WINDOW_SIZE 16 +static const u8 mps_addr_window_starts[] = { 0x10, 0x20, 0x60 }; + +static int mpq8785_probe_addr(struct udevice *bus, u8 addr, + struct udevice **chip_out) +{ + char id[PMBUS_MFR_STRING_MAX] = ""; + struct udevice *chip; + int ret; + + ret = i2c_get_chip(bus, addr, 1, &chip); + if (ret) + return ret; + ret = pmbus_read_string(chip, PMBUS_MFR_ID, id, sizeof(id), true); + if (ret < 0) + return ret; + if (strncmp(id, "MPS", 3) != 0) + return -ENODEV; + *chip_out = chip; + return 0; +} + +static int mpq8785_scan_windows(struct udevice *bus, u8 *found_addr, + struct udevice **chip_out) +{ + unsigned int i, j; + + for (i = 0; i < ARRAY_SIZE(mps_addr_window_starts); i++) { + for (j = 0; j < MPS_ADDR_VBOOT_WINDOW_SIZE; j++) { + u8 addr = mps_addr_window_starts[i] + j; + + if (mpq8785_probe_addr(bus, addr, chip_out) == 0) { + *found_addr = addr; + return 0; + } + } + } + return -ENODEV; +} + +static struct pmbus_driver_info *mpq8785_pick_info(enum mpq_chip_id chip_id) +{ + switch (chip_id) { + case MPQ_MPM3695: + case MPQ_MPM3695_25: + case MPQ_MPM82504: + return &mpm82504_info; + case MPQ_MPQ8785: + default: + return &mpq8785_info; + } +} + +static int mpq8785_probe(struct udevice *dev) +{ + enum mpq_chip_id chip_id = (enum mpq_chip_id)dev_get_driver_data(dev); + struct pmbus_regulator_priv *priv = dev_get_priv(dev); + struct pmbus_driver_info *info = mpq8785_pick_info(chip_id); + static bool match_registered; + static bool vendor_registered; + u32 fb_div; + int ret; + + ret = pmbus_regulator_probe_common(dev, info, 0); + if (ret) + return ret; + + /* + * Verify the chip answers MFR_ID="MPS" at the DT declared + * address. If it doesn't, walk the documented ADDR_VBOOT windows + * looking for it (a die rev address shift). On a hit, replace + * priv->i2c_dev with the discovered chip handle and continue. + */ + { + char id[PMBUS_MFR_STRING_MAX] = ""; + + ret = pmbus_read_string(priv->i2c_dev, PMBUS_MFR_ID, id, + sizeof(id), true); + if (ret < 0 || strncmp(id, "MPS", 3) != 0) { + struct udevice *bus = dev_get_parent(dev); + struct udevice *promoted; + u8 found = 0; + + if (mpq8785_scan_windows(bus, &found, &promoted) == 0) { + printf("MPQ8785: DT addr 0x%02x silent, auto promoted to 0x%02x\n", + (unsigned int)dev_read_addr(dev), found); + priv->i2c_dev = promoted; + } else { + printf("MPQ8785: no MPS responder found in 0x10..0x1f / 0x20..0x2f / 0x60..0x6f\n"); + return -ENODEV; + } + } + } + + /* MPQ8785 specific: refine VOUT format from VOUT_MODE. */ + if (chip_id == MPQ_MPQ8785) + mpq8785_identify_vout(priv->i2c_dev); + + /* Apply mps,vout-fb-divider-ratio-permille if present in DT. */ + fb_div = dev_read_u32_default(dev, "mps,vout-fb-divider-ratio-permille", 0); + if (fb_div) { + ret = pmbus_regulator_apply_voltage_scale(dev, fb_div); + if (ret) { + printf("MPQ8785: VOUT_SCALE_LOOP write failed (%d)\n", ret); + return ret; + } + } + + /* + * Register the chip match and the MPS vendor handler exactly + * once across all bound MPS regulators (a board could legally + * carry several). Both registries are global and idempotent + * matches return -ENOSPC, so the static guards keep things + * tidy. + */ + if (!match_registered) { + if (pmbus_register_chip(&mpq8785_match) == 0) + match_registered = true; + } + if (!vendor_registered) { + if (pmbus_register_vendor_handler(&mps_vendor_op) == 0) + vendor_registered = true; + } + return 0; +} + +static const struct udevice_id mpq8785_ids[] = { + { .compatible = "mps,mpm3695", .data = MPQ_MPM3695 }, + { .compatible = "mps,mpm3695-25", .data = MPQ_MPM3695_25 }, + { .compatible = "mps,mpm82504", .data = MPQ_MPM82504 }, + { .compatible = "mps,mpq8785", .data = MPQ_MPQ8785 }, + { } +}; + +U_BOOT_DRIVER(mpq8785_regulator) = { + .name = "mpq8785_regulator", + .id = UCLASS_REGULATOR, + .of_match = mpq8785_ids, + .probe = mpq8785_probe, + .ops = &pmbus_regulator_ops, + .priv_auto = sizeof(struct pmbus_regulator_priv), +}; diff --git a/drivers/power/regulator/pfuze100.c b/drivers/power/regulator/pfuze100.c index f864b1d8834..57af16cfbb9 100644 --- a/drivers/power/regulator/pfuze100.c +++ b/drivers/power/regulator/pfuze100.c @@ -13,29 +13,43 @@ #include <power/regulator.h> #include <power/pfuze100_pmic.h> +struct pfuze100_high_volt_desc { + unsigned int uV_step; + unsigned int min_uV; +}; + /** * struct pfuze100_regulator_desc - regulator descriptor * * @name: Identify name for the regulator. * @type: Indicates the regulator type. * @uV_step: Voltage increase for each selector. + * @min_uV: Indicates the minimal voltage supported. * @vsel_reg: Register for adjust regulator voltage for normal. * @vsel_mask: Mask bit for setting regulator voltage for normal. * @stby_reg: Register for adjust regulator voltage for standby. * @stby_mask: Mask bit for setting regulator voltage for standby. * @volt_table: Voltage mapping table (if table based mapping). * @voltage: Current voltage for REGULATOR_TYPE_FIXED type regulator. + * @high_volt_mask: Low or High Output voltage mode mask + * @high_volt_desc: High Output voltage description + * @b: Some regulators could work together to provide one output when working + * in single phase or dual phase mode. */ struct pfuze100_regulator_desc { char *name; enum regulator_type type; unsigned int uV_step; + unsigned int min_uV; unsigned int vsel_reg; unsigned int vsel_mask; unsigned int stby_reg; unsigned int stby_mask; unsigned int *volt_table; unsigned int voltage; + unsigned int high_volt_mask; + struct pfuze100_high_volt_desc *high_volt_desc; + struct pfuze100_regulator_desc *b; }; /** @@ -54,15 +68,33 @@ struct pfuze100_regulator_plat { .voltage = (vol), \ } -#define PFUZE100_SW_REG(_name, base, step) \ +#define PFUZE100_SW_REG(_name, base, step, min, desc, mask) \ + { \ + .name = #_name, \ + .type = REGULATOR_TYPE_BUCK, \ + .uV_step = (step), \ + .min_uV = (min), \ + .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ + .vsel_mask = 0x3F, \ + .stby_reg = (base) + PFUZE100_STBY_OFFSET, \ + .stby_mask = 0x3F, \ + .high_volt_desc = (desc), \ + .high_volt_mask = (mask), \ + } + +#define PFUZE100_SWAB_REG(_name, base, step, min, volt_desc, mask, desc) \ { \ .name = #_name, \ .type = REGULATOR_TYPE_BUCK, \ .uV_step = (step), \ + .min_uV = (min), \ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ .vsel_mask = 0x3F, \ .stby_reg = (base) + PFUZE100_STBY_OFFSET, \ .stby_mask = 0x3F, \ + .high_volt_desc = (volt_desc), \ + .high_volt_mask = (mask), \ + .b = (desc), \ } #define PFUZE100_SWB_REG(_name, base, mask, step, voltages) \ @@ -84,32 +116,35 @@ struct pfuze100_regulator_plat { .volt_table = (voltages), \ } -#define PFUZE100_VGEN_REG(_name, base, step) \ +#define PFUZE100_VGEN_REG(_name, base, step, min) \ { \ .name = #_name, \ .type = REGULATOR_TYPE_LDO, \ .uV_step = (step), \ + .min_uV = (min), \ .vsel_reg = (base), \ .vsel_mask = 0xF, \ .stby_reg = (base), \ .stby_mask = 0x20, \ } -#define PFUZE3000_VCC_REG(_name, base, step) \ +#define PFUZE3000_VCC_REG(_name, base, step, min) \ { \ .name = #_name, \ .type = REGULATOR_TYPE_LDO, \ .uV_step = (step), \ + .min_uV = (min), \ .vsel_reg = (base), \ .vsel_mask = 0x3, \ .stby_reg = (base), \ .stby_mask = 0x20, \ } -#define PFUZE3000_SW1_REG(_name, base, step) \ +#define PFUZE3000_SW1_REG(_name, base, step, min) \ { \ .name = #_name, \ .type = REGULATOR_TYPE_BUCK, \ + .min_uV = (min), \ .uV_step = (step), \ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ .vsel_mask = 0x1F, \ @@ -128,11 +163,12 @@ struct pfuze100_regulator_plat { .stby_mask = 0x7, \ } -#define PFUZE3000_SW3_REG(_name, base, step) \ +#define PFUZE3000_SW3_REG(_name, base, step, min) \ { \ .name = #_name, \ .type = REGULATOR_TYPE_BUCK, \ .uV_step = (step), \ + .min_uV = (min), \ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \ .vsel_mask = 0xF, \ .stby_reg = (base) + PFUZE100_STBY_OFFSET, \ @@ -155,57 +191,66 @@ static unsigned int pfuze3000_sw2lo[] = { 1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000 }; +static struct pfuze100_high_volt_desc high_desc = { + .min_uV = 800000, + .uV_step = 50000, +}; + /* PFUZE100 */ static struct pfuze100_regulator_desc pfuze100_regulators[] = { - PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000), - PFUZE100_SW_REG(sw1c, PFUZE100_SW1CVOL, 25000), - PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000), - PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000), - PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000), - PFUZE100_SW_REG(sw4, PFUZE100_SW4VOL, 25000), + PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000, 300000, NULL, 0), + PFUZE100_SW_REG(sw1c, PFUZE100_SW1CVOL, 25000, 300000, NULL, 0), + PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000, 400000, &high_desc, BIT(6)), + PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000, 400000, &high_desc, BIT(6)), + PFUZE100_SWAB_REG(sw3ab, PFUZE100_SW3AVOL, 25000, 400000, &high_desc, BIT(6), + &pfuze100_regulators[5]), + PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000, 400000, &high_desc, BIT(6)), + PFUZE100_SW_REG(sw4, PFUZE100_SW4VOL, 25000, 400000, &high_desc, BIT(6)), PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst), PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000), - PFUZE100_VGEN_REG(vgen1, PFUZE100_VGEN1VOL, 50000), - PFUZE100_VGEN_REG(vgen2, PFUZE100_VGEN2VOL, 50000), - PFUZE100_VGEN_REG(vgen3, PFUZE100_VGEN3VOL, 100000), - PFUZE100_VGEN_REG(vgen4, PFUZE100_VGEN4VOL, 100000), - PFUZE100_VGEN_REG(vgen5, PFUZE100_VGEN5VOL, 100000), - PFUZE100_VGEN_REG(vgen6, PFUZE100_VGEN6VOL, 100000), + PFUZE100_VGEN_REG(vgen1, PFUZE100_VGEN1VOL, 50000, 800000), + PFUZE100_VGEN_REG(vgen2, PFUZE100_VGEN2VOL, 50000, 1800000), + PFUZE100_VGEN_REG(vgen3, PFUZE100_VGEN3VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vgen4, PFUZE100_VGEN4VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vgen5, PFUZE100_VGEN5VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vgen6, PFUZE100_VGEN6VOL, 100000, 1800000), }; /* PFUZE200 */ static struct pfuze100_regulator_desc pfuze200_regulators[] = { - PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000), - PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000), - PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000), - PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000), + PFUZE100_SW_REG(sw1ab, PFUZE100_SW1ABVOL, 25000, 300000, NULL, 0), + PFUZE100_SW_REG(sw2, PFUZE100_SW2VOL, 25000, 400000, &high_desc, BIT(6)), + PFUZE100_SW_REG(sw3a, PFUZE100_SW3AVOL, 25000, 400000, &high_desc, BIT(6)), + PFUZE100_SWAB_REG(sw3ab, PFUZE100_SW3AVOL, 25000, 400000, &high_desc, BIT(6), + &pfuze200_regulators[4]), + PFUZE100_SW_REG(sw3b, PFUZE100_SW3BVOL, 25000, 400000, &high_desc, BIT(6)), PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst), PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs), PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000), - PFUZE100_VGEN_REG(vgen1, PFUZE100_VGEN1VOL, 50000), - PFUZE100_VGEN_REG(vgen2, PFUZE100_VGEN2VOL, 50000), - PFUZE100_VGEN_REG(vgen3, PFUZE100_VGEN3VOL, 100000), - PFUZE100_VGEN_REG(vgen4, PFUZE100_VGEN4VOL, 100000), - PFUZE100_VGEN_REG(vgen5, PFUZE100_VGEN5VOL, 100000), - PFUZE100_VGEN_REG(vgen6, PFUZE100_VGEN6VOL, 100000), + PFUZE100_VGEN_REG(vgen1, PFUZE100_VGEN1VOL, 50000, 800000), + PFUZE100_VGEN_REG(vgen2, PFUZE100_VGEN2VOL, 50000, 800000), + PFUZE100_VGEN_REG(vgen3, PFUZE100_VGEN3VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vgen4, PFUZE100_VGEN4VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vgen5, PFUZE100_VGEN5VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vgen6, PFUZE100_VGEN6VOL, 100000, 1800000), }; /* PFUZE3000 */ static struct pfuze100_regulator_desc pfuze3000_regulators[] = { - PFUZE3000_SW1_REG(sw1a, PFUZE100_SW1ABVOL, 25000), - PFUZE3000_SW1_REG(sw1b, PFUZE100_SW1CVOL, 25000), + PFUZE3000_SW1_REG(sw1a, PFUZE100_SW1ABVOL, 25000, 700000), + PFUZE3000_SW1_REG(sw1b, PFUZE100_SW1CVOL, 25000, 700000), PFUZE100_SWB_REG(sw2, PFUZE100_SW2VOL, 0x7, 50000, pfuze3000_sw2lo), - PFUZE3000_SW3_REG(sw3, PFUZE100_SW3AVOL, 50000), + PFUZE3000_SW3_REG(sw3, PFUZE100_SW3AVOL, 50000, 900000), PFUZE100_SWB_REG(swbst, PFUZE100_SWBSTCON1, 0x3, 50000, pfuze100_swbst), PFUZE100_SNVS_REG(vsnvs, PFUZE100_VSNVSVOL, 0x7, pfuze3000_vsnvs), PFUZE100_FIXED_REG(vrefddr, PFUZE100_VREFDDRCON, 750000), - PFUZE100_VGEN_REG(vldo1, PFUZE100_VGEN1VOL, 100000), - PFUZE100_VGEN_REG(vldo2, PFUZE100_VGEN2VOL, 50000), - PFUZE3000_VCC_REG(vccsd, PFUZE100_VGEN3VOL, 150000), - PFUZE3000_VCC_REG(v33, PFUZE100_VGEN4VOL, 150000), - PFUZE100_VGEN_REG(vldo3, PFUZE100_VGEN5VOL, 100000), - PFUZE100_VGEN_REG(vldo4, PFUZE100_VGEN6VOL, 100000), + PFUZE100_VGEN_REG(vldo1, PFUZE100_VGEN1VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vldo2, PFUZE100_VGEN2VOL, 50000, 800000), + PFUZE3000_VCC_REG(vccsd, PFUZE100_VGEN3VOL, 150000, 2850000), + PFUZE3000_VCC_REG(v33, PFUZE100_VGEN4VOL, 150000, 2850000), + PFUZE100_VGEN_REG(vldo3, PFUZE100_VGEN5VOL, 100000, 1800000), + PFUZE100_VGEN_REG(vldo4, PFUZE100_VGEN6VOL, 100000, 1800000), }; #define MODE(_id, _val, _name) { \ @@ -357,6 +402,16 @@ static int pfuze100_regulator_mode(struct udevice *dev, int op, int *opmode) desc->vsel_reg + PFUZE100_MODE_OFFSET, SW_MODE_MASK, *opmode << SW_MODE_SHIFT); + if (val) + return val; + + if (desc->b) { + desc = desc->b; + val = pmic_clrsetbits(dev->parent, + desc->vsel_reg + PFUZE100_MODE_OFFSET, + SW_MODE_MASK, + *opmode << SW_MODE_SHIFT); + } } else if (desc->type == REGULATOR_TYPE_LDO) { val = pmic_clrsetbits(dev->parent, desc->vsel_reg, @@ -435,8 +490,8 @@ static int pfuze100_regulator_enable(struct udevice *dev, int op, bool *enable) static int pfuze100_regulator_val(struct udevice *dev, int op, int *uV) { - int i; - int val; + int i, ret; + int val, min_uV, uV_step; struct pfuze100_regulator_plat *plat = dev_get_plat(dev); struct pfuze100_regulator_desc *desc = plat->desc; struct dm_regulator_uclass_plat *uc_pdata = @@ -460,8 +515,15 @@ static int pfuze100_regulator_val(struct udevice *dev, int op, int *uV) val = pmic_reg_read(dev->parent, desc->vsel_reg); if (val < 0) return val; + if (desc->high_volt_mask && (val & desc->high_volt_mask)) { + min_uV = desc->high_volt_desc->min_uV; + uV_step = desc->high_volt_desc->uV_step; + } else { + min_uV = desc->min_uV ?: uc_pdata->min_uV; + uV_step = desc->uV_step; + } val &= desc->vsel_mask; - *uV = uc_pdata->min_uV + (int)val * desc->uV_step; + *uV = min_uV + (int)val * uV_step; } return 0; @@ -487,9 +549,29 @@ static int pfuze100_regulator_val(struct udevice *dev, int op, int *uV) debug("Need to provide min_uV in dts.\n"); return -EINVAL; } - return pmic_clrsetbits(dev->parent, desc->vsel_reg, - desc->vsel_mask, - (*uV - uc_pdata->min_uV) / desc->uV_step); + val = pmic_reg_read(dev->parent, desc->vsel_reg); + if (val < 0) + return val; + if (desc->high_volt_mask && (val & desc->high_volt_mask)) { + min_uV = desc->high_volt_desc->min_uV; + uV_step = desc->high_volt_desc->uV_step; + } else { + min_uV = desc->min_uV ?: uc_pdata->min_uV; + uV_step = desc->uV_step; + } + + ret = pmic_clrsetbits(dev->parent, desc->vsel_reg, + desc->vsel_mask, (*uV - min_uV) / uV_step); + if (ret) + return ret; + + if (desc->b) { + desc = desc->b; + ret = pmic_clrsetbits(dev->parent, desc->vsel_reg, + desc->vsel_mask, (*uV - min_uV) / uV_step); + if (ret) + return ret; + } } return 0; diff --git a/drivers/power/regulator/pmbus_generic.c b/drivers/power/regulator/pmbus_generic.c new file mode 100644 index 00000000000..6ba50ce08f8 --- /dev/null +++ b/drivers/power/regulator/pmbus_generic.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2026 Free Mobile, Vincent Jardin + * + * Generic PMBus 1.x compatible voltage regulator driver. + * + * Catch all driver bound to compatible = "pmbus" for chips that have + * no per chip driver under drivers/power/regulator/. The probe path + * detects the VOUT numeric format from VOUT_MODE bits[7:5]: + * + * - 0 LINEAR16 with the exponent supplied via VOUT_MODE bits[4:0] + * - 1 VID; mapped to pmbus_fmt_vid (decoder returns 0 today; per + * chip driver still required to plug a VID table) + * - 2 DIRECT; default coefficients m=1, b=0, R=0 (per chip + * coefficients arrive via PMBUS_QUERY / PMBUS_COEFFICIENTS, + * not yet consumed by U-Boot; values may need a per chip + * driver if telemetry numbers are wrong) + * - 3 IEEE754; mapped to pmbus_fmt_ieee754 (decoder returns 0 + * today; per chip driver required) + * + * Other sensor classes (VIN, IIN, IOUT, TEMPERATURE) default to + * LINEAR which is the spec baseline for compliant chips. If an + * operator sees wrong telemetry numbers on this driver, the answer + * is to write a per chip driver with the correct format[] / m / b / R. + * + * Adapted in spirit from linux/drivers/hwmon/pmbus/pmbus.c (the + * kernel's generic probe driver). The U-Boot version drops the + * page count auto detection (most generic compliant parts are + * single rail; multi rail chips are quirky enough to need a per + * chip driver) and the kernel hwmon publication layers. + */ + +#include <dm.h> +#include <i2c.h> +#include <log.h> +#include <pmbus.h> +#include <power/regulator.h> + +#include "pmbus_helper.h" + +struct pmbus_generic_priv { + struct pmbus_regulator_priv base; /* must be first */ + struct pmbus_driver_info info; +}; + +static int pmbus_generic_probe(struct udevice *dev) +{ + struct pmbus_generic_priv *gpriv = dev_get_priv(dev); + struct pmbus_driver_info *info = &gpriv->info; + enum pmbus_sensor_classes c; + int ret; + + info->pages = 1; + for (c = 0; c < PSC_NUM_CLASSES; c++) { + info->format[c] = pmbus_fmt_linear; + info->m[c] = 0; + info->b[c] = 0; + info->R[c] = 0; + } + + ret = pmbus_regulator_probe_common(dev, info, 0); + if (ret) + return ret; + + /* + * Avoid reading non supported pages to avoid device's sticky + * status. + */ + info->pages = dev_read_u32_default(dev, "pmbus,num-pages", 1); + if (info->pages < 1) + info->pages = 1; + + pmbus_regulator_identify_vout(gpriv->base.i2c_dev, info); + + return 0; +} + +static const struct udevice_id pmbus_generic_ids[] = { + { .compatible = "pmbus" }, + { } +}; + +U_BOOT_DRIVER(pmbus_generic_regulator) = { + .name = "pmbus_generic_regulator", + .id = UCLASS_REGULATOR, + .of_match = pmbus_generic_ids, + .probe = pmbus_generic_probe, + .ops = &pmbus_regulator_ops, + .priv_auto = sizeof(struct pmbus_generic_priv), +}; diff --git a/drivers/power/regulator/pmbus_helper.c b/drivers/power/regulator/pmbus_helper.c new file mode 100644 index 00000000000..4763470442d --- /dev/null +++ b/drivers/power/regulator/pmbus_helper.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2026 Free Mobile, Vincent Jardin + * + * Shared UCLASS_REGULATOR operations over the PMBus 1.x framework. + * See pmbus_helper.h for the API surface and doc/develop/pmbus.rst + * for the porting guide. + * + * No code in this file may reference a specific chip family or + * board. Chip specific quirks (vendor registers, VID coercion, + * ADDR pin auto promotion, byte reversed MFR strings, etc.) belong + * in the per chip driver under drivers/power/regulator/<chip>.c. + */ + +#include <dm.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <i2c.h> +#include <log.h> +#include <pmbus.h> +#include <vsprintf.h> +#include <linux/types.h> +#include <power/regulator.h> + +#include "pmbus_helper.h" + +static int pmbus_regulator_select_page(struct pmbus_regulator_priv *priv) +{ + u8 p; + + if (priv->page <= 0) + return 0; + p = (u8)priv->page; + return dm_i2c_write(priv->i2c_dev, PMBUS_PAGE, &p, 1); +} + +static int pmbus_regulator_get_value(struct udevice *dev) +{ + struct pmbus_regulator_priv *priv = dev_get_priv(dev); + u8 vout_mode = 0; + u16 raw = 0; + s64 uv; + int ret; + + ret = pmbus_regulator_select_page(priv); + if (ret) + return ret; + pmbus_read_byte(priv->i2c_dev, PMBUS_VOUT_MODE, &vout_mode); + if (pmbus_read_word(priv->i2c_dev, PMBUS_READ_VOUT, &raw)) + return -EIO; + + if (priv->info) + uv = pmbus_reg2data(priv->info, PSC_VOLTAGE_OUT, raw, vout_mode); + else + uv = pmbus_reg2data_linear16(raw, vout_mode); + + if (uv > INT_MAX) + uv = INT_MAX; + if (uv < INT_MIN) + uv = INT_MIN; + return (int)uv; +} + +static int pmbus_regulator_set_value(struct udevice *dev, int uV) +{ + struct pmbus_regulator_priv *priv = dev_get_priv(dev); + u8 vout_mode = 0; + u8 buf[2]; + u16 raw; + int ret; + + ret = pmbus_regulator_select_page(priv); + if (ret) + return ret; + if (pmbus_read_byte(priv->i2c_dev, PMBUS_VOUT_MODE, &vout_mode)) + return -EIO; + + /* + * Dispatch on the chip's VOUT_MODE selector. LINEAR16 and DIRECT + * are wired today; VID and IEEE754 return -ENOSYS until their + * encoders land. For DIRECT, the m / b / R triple comes from the + * chip's pmbus_driver_info[PSC_VOLTAGE_OUT]; if the per chip + * driver did not populate them, the encoder cannot run. + */ + switch (vout_mode & PB_VOUT_MODE_MODE_MASK) { + case PB_VOUT_MODE_LINEAR: + raw = pmbus_data2reg_linear16((s64)uV, vout_mode); + break; + case PB_VOUT_MODE_DIRECT: + if (!priv->info || + priv->info->format[PSC_VOLTAGE_OUT] != pmbus_fmt_direct) + return -ENODATA; + raw = pmbus_data2reg_direct((s64)uV, + priv->info->m[PSC_VOLTAGE_OUT], + priv->info->b[PSC_VOLTAGE_OUT], + priv->info->R[PSC_VOLTAGE_OUT]); + break; + default: + return -ENOSYS; + } + + buf[0] = (u8)(raw & 0xff); + buf[1] = (u8)((raw >> 8) & 0xff); + return dm_i2c_write(priv->i2c_dev, PMBUS_VOUT_COMMAND, buf, 2); +} + +static int pmbus_regulator_get_enable(struct udevice *dev) +{ + struct pmbus_regulator_priv *priv = dev_get_priv(dev); + u8 op = 0; + int ret; + + ret = pmbus_regulator_select_page(priv); + if (ret) + return ret; + if (pmbus_read_byte(priv->i2c_dev, PMBUS_OPERATION, &op)) + return -EIO; + return (op & PB_OPERATION_ON) ? 1 : 0; +} + +static int pmbus_regulator_set_enable(struct udevice *dev, bool enable) +{ + struct pmbus_regulator_priv *priv = dev_get_priv(dev); + u8 op = 0; + int ret; + + ret = pmbus_regulator_select_page(priv); + if (ret) + return ret; + if (pmbus_read_byte(priv->i2c_dev, PMBUS_OPERATION, &op)) + return -EIO; + + if (enable) + op |= PB_OPERATION_ON; + else + op &= (u8)~PB_OPERATION_ON; + return dm_i2c_write(priv->i2c_dev, PMBUS_OPERATION, &op, 1); +} + +const struct dm_regulator_ops pmbus_regulator_ops = { + .get_value = pmbus_regulator_get_value, + .set_value = pmbus_regulator_set_value, + .get_enable = pmbus_regulator_get_enable, + .set_enable = pmbus_regulator_set_enable, +}; + +int pmbus_regulator_read_temp(struct udevice *reg_dev, int *temp_mc) +{ + struct pmbus_regulator_priv *priv; + u16 raw = 0; + s64 udeg; + int ret; + + if (!reg_dev || !temp_mc) + return -EINVAL; + priv = dev_get_priv(reg_dev); + if (!priv || !priv->i2c_dev) + return -ENODEV; + + ret = pmbus_regulator_select_page(priv); + if (ret) + return ret; + if (pmbus_read_word(priv->i2c_dev, PMBUS_READ_TEMPERATURE_1, &raw)) + return -EIO; + + /* + * vout_mode is meaningless for the temperature class. With a + * chip info record the dispatcher honours its per-class format + * (DIRECT m/b/R for MPS, LINEAR11 for spec-compliant parts); + * without one, fall back to the PMBus 1.x standard LINEAR11. + */ + if (priv->info) + udeg = pmbus_reg2data(priv->info, PSC_TEMPERATURE, raw, 0); + else + udeg = pmbus_reg2data_linear11(raw); + + *temp_mc = (int)(udeg / 1000); + return 0; +} + +enum pmbus_data_format +pmbus_regulator_identify_vout(struct udevice *i2c_dev, + struct pmbus_driver_info *info) +{ + u8 vout_mode = 0; + + if (pmbus_read_byte(i2c_dev, PMBUS_VOUT_MODE, &vout_mode)) + return info->format[PSC_VOLTAGE_OUT]; + + switch (vout_mode & PB_VOUT_MODE_MODE_MASK) { + case PB_VOUT_MODE_LINEAR: + info->format[PSC_VOLTAGE_OUT] = pmbus_fmt_linear; + break; + case PB_VOUT_MODE_VID: + info->format[PSC_VOLTAGE_OUT] = pmbus_fmt_vid; + break; + case PB_VOUT_MODE_DIRECT: + info->format[PSC_VOLTAGE_OUT] = pmbus_fmt_direct; + info->m[PSC_VOLTAGE_OUT] = 1; + info->b[PSC_VOLTAGE_OUT] = 0; + info->R[PSC_VOLTAGE_OUT] = 0; + break; + case PB_VOUT_MODE_IEEE754: + info->format[PSC_VOLTAGE_OUT] = pmbus_fmt_ieee754; + break; + default: + break; + } + return info->format[PSC_VOLTAGE_OUT]; +} + +const struct pmbus_driver_info *pmbus_regulator_info_by_addr(int bus_seq, + u8 addr) +{ + struct uclass *uc; + struct udevice *r; + + if (uclass_get(UCLASS_REGULATOR, &uc)) + return NULL; + + uclass_foreach_dev(r, uc) { + struct udevice *parent = dev_get_parent(r); + struct pmbus_regulator_priv *priv; + int ra; + + if (!parent || device_get_uclass_id(parent) != UCLASS_I2C) + continue; + if (dev_seq(parent) != bus_seq) + continue; + ra = dev_read_addr(r); + if (ra < 0 || (u8)ra != addr) + continue; + + /* + * Address matches. Only chips driven through this helper + * carry a pmbus_regulator_priv at the head of their priv; + * identify them by their shared ops vector so we never + * misread a foreign regulator's private layout. + */ + if (!r->driver || r->driver->ops != &pmbus_regulator_ops) + return NULL; + if (device_probe(r)) + return NULL; + priv = dev_get_priv(r); + return priv ? priv->info : NULL; + } + return NULL; +} + +/* + * Spawn the generic UCLASS_THERMAL companion (drivers/thermal/ + * pmbus_thermal.c) as a child of this regulator so READ_TEMPERATURE_1 + * is reachable through the standard `temperature list` / `temperature + * get` interface. Named "<regulator-name>-temp" so several PMBus rails + * on one board produce distinct, descriptive device names. Failure is + * non-fatal: the chip still works as a UCLASS_REGULATOR. + */ +static void pmbus_regulator_bind_thermal(struct udevice *dev) +{ + struct udevice *therm; + const char *rname; + char name[48]; + + if (!IS_ENABLED(CONFIG_PMBUS_THERMAL)) + return; + if (device_bind_driver(dev, "pmbus_thermal", "pmbus-temp", &therm)) + return; + rname = dev_read_string(dev, "regulator-name"); + snprintf(name, sizeof(name), "%s-temp", rname ? rname : dev->name); + device_set_name(therm, name); +} + +int pmbus_regulator_probe_common(struct udevice *dev, + const struct pmbus_driver_info *info, + int page) +{ + struct pmbus_regulator_priv *priv = dev_get_priv(dev); + int chip_addr; + int ret; + + chip_addr = dev_read_addr(dev); + if (chip_addr < 0) + return -EINVAL; + + ret = i2c_get_chip(dev_get_parent(dev), (u32)chip_addr, 1, &priv->i2c_dev); + if (ret) + return ret; + + priv->info = info; + priv->page = page; + + if (page > 0) { + u8 p = (u8)page; + + ret = dm_i2c_write(priv->i2c_dev, PMBUS_PAGE, &p, 1); + if (ret) + return ret; + } + + pmbus_regulator_bind_thermal(dev); + return 0; +} + +int pmbus_regulator_apply_voltage_scale(struct udevice *dev, + u32 fb_divider_permille) +{ + struct pmbus_regulator_priv *priv = dev_get_priv(dev); + u8 buf[2]; + + if (fb_divider_permille == 0) + return 0; + buf[0] = (u8)(fb_divider_permille & 0xff); + buf[1] = (u8)((fb_divider_permille >> 8) & 0xff); + return dm_i2c_write(priv->i2c_dev, PMBUS_VOUT_SCALE_LOOP, buf, 2); +} diff --git a/drivers/power/regulator/pmbus_helper.h b/drivers/power/regulator/pmbus_helper.h new file mode 100644 index 00000000000..82f263cd513 --- /dev/null +++ b/drivers/power/regulator/pmbus_helper.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2026 Free Mobile, Vincent Jardin + * + * Shared UCLASS_REGULATOR ops for PMBus 1.x voltage regulator chips. + * + * Per chip drivers under drivers/power/regulator/<chip>.c bind a + * vendor,chip compatible from DT and call pmbus_regulator_probe_common() + * in their .probe. They install pmbus_regulator_ops as the .ops vector; + * the helper handles VOUT_MODE / READ_VOUT / VOUT_COMMAND / OPERATION + * via the tree level <pmbus.h> framework. + * + * Per chip drivers retain control of identify hooks (VOUT_MODE based + * format selection), chip specific quirks (vendor registers, ADDR pin + * auto promotion), and DT property handling (e.g. MPS + * mps,vout-fb-divider-ratio-permille). + */ + +#ifndef _DRIVERS_POWER_REGULATOR_PMBUS_HELPER_H_ +#define _DRIVERS_POWER_REGULATOR_PMBUS_HELPER_H_ + +#include <linux/types.h> +#include <pmbus.h> + +struct udevice; +struct dm_regulator_ops; + +/* + * Per chip private state. The first field of every per chip driver's + * priv_auto must be (or contain at offset 0) a struct + * pmbus_regulator_priv so the shared ops vector can recover it via + * dev_get_priv(dev). + * + * i2c_dev chip handle obtained from dev->parent at probe time + * (the parent must be a UCLASS_I2C bus). + * page PMBUS_PAGE selector for multi rail chips. Single rail + * chips set page = 0; the helper writes PMBUS_PAGE only + * when page > 0 to avoid wasted bus traffic on single + * rail parts. + * info pointer to the chip's pmbus_driver_info; consumed by + * pmbus_reg2data() / pmbus_data2reg_linear16() to pick + * the right format[] / m / b / R coefficients. + */ +struct pmbus_regulator_priv { + struct udevice *i2c_dev; + int page; + const struct pmbus_driver_info *info; +}; + +extern const struct dm_regulator_ops pmbus_regulator_ops; + +/* + * Per chip probe glue. Reads `reg` from DT, gets the I2C chip handle + * from dev->parent, populates priv->i2c_dev / page / info, and writes + * PMBUS_PAGE if page > 0. Per chip drivers call this in their .probe + * before any chip specific identification. + */ +int pmbus_regulator_probe_common(struct udevice *dev, + const struct pmbus_driver_info *info, + int page); + +/* + * Optional helper for per chip drivers that honour an external + * feedback divider DT property (e.g. MPS mps,vout-fb-divider-ratio- + * permille). Writes the supplied ratio to PMBUS_VOUT_SCALE_LOOP at + * probe time. fb_divider_permille == 0 leaves the chip default. + */ +int pmbus_regulator_apply_voltage_scale(struct udevice *dev, + u32 fb_divider_permille); + +/* + * Read PMBUS_VOUT_MODE and set info->format[PSC_VOLTAGE_OUT] from its + * mode selector bits[7:5] per PMBus 1.3 Part II sec 8.3: + * LINEAR -> pmbus_fmt_linear + * VID -> pmbus_fmt_vid + * DIRECT -> pmbus_fmt_direct (default coefficients m=1, b=0, R=0) + * IEEE754 -> pmbus_fmt_ieee754 + * + * The single place that knows the VOUT_MODE bit layout; both the + * generic regulator and per chip drivers call it so they never + * re-implement the switch. Returns the selected format so a chip + * driver can post-adjust a quirk (e.g. MPS encodes VOUT in DIRECT + * with m=64 R=1 even when VOUT_MODE reports VID). On a VOUT_MODE read + * failure the format is left unchanged and the prior value is returned. + */ +enum pmbus_data_format +pmbus_regulator_identify_vout(struct udevice *i2c_dev, + struct pmbus_driver_info *info); + +#endif /* _DRIVERS_POWER_REGULATOR_PMBUS_HELPER_H_ */ diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c index 3f0f1845469..c458f227bed 100644 --- a/drivers/power/regulator/qcom-rpmh-regulator.c +++ b/drivers/power/regulator/qcom-rpmh-regulator.c @@ -5,6 +5,7 @@ #define pr_fmt(fmt) "%s: " fmt, __func__ #include <linux/err.h> +#include <dm.h> #include <dm/device_compat.h> #include <dm/device.h> #include <dm/devres.h> @@ -295,6 +296,56 @@ static int rpmh_regulator_vrm_get_value(struct udevice *rdev) return vreg->uv; } +static int rpmh_regulator_vrm_set_mode_bypass(struct rpmh_vreg *vreg, + unsigned int mode, bool bypassed) +{ + struct tcs_cmd cmd = { + .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_MODE, + }; + struct dm_regulator_mode *pmic_mode; + int i; + + if (mode > REGULATOR_MODE_HPM) + return -EINVAL; + + for (i = 0; i < vreg->hw_data->n_modes; i++) { + pmic_mode = &vreg->hw_data->pmic_mode_map[i]; + if (pmic_mode->id == mode) + break; + } + if (pmic_mode->id != mode) { + printf("Invalid mode %d\n", mode); + return -EINVAL; + } + + if (bypassed) + // XXX: should have a version check for PMIC4 but we don't have any yet + // and we don't use bypass mode + cmd.data = PMIC5_BOB_MODE_PASS; + else + cmd.data = pmic_mode->register_value; + + return rpmh_regulator_send_request(vreg, &cmd, true); +} + +static int rpmh_regulator_vrm_set_mode(struct udevice *rdev, + int mode) +{ + struct rpmh_vreg *vreg = dev_get_priv(rdev); + int ret; + + debug("%s: set_mode %d (current %d)\n", rdev->name, mode, vreg->mode); + + if (mode == vreg->mode) + return 0; + + ret = rpmh_regulator_vrm_set_mode_bypass(vreg, mode, vreg->bypassed); + if (!ret) + vreg->mode = mode; + + return ret; +} + static int rpmh_regulator_is_enabled(struct udevice *rdev) { struct rpmh_vreg *vreg = dev_get_priv(rdev); @@ -331,6 +382,12 @@ static int rpmh_regulator_set_enable_state(struct udevice *rdev, debug("%s: set_enable %d (current %d)\n", rdev->name, enable, vreg->enabled); + if (vreg->mode != -EINVAL) { + ret = rpmh_regulator_vrm_set_mode_bypass(vreg, vreg->mode, vreg->bypassed); + if (ret < 0) + return ret; + } + if (vreg->enabled == -EINVAL && vreg->uv != -ENOTRECOVERABLE) { ret = _rpmh_regulator_vrm_set_value(rdev, @@ -346,56 +403,6 @@ static int rpmh_regulator_set_enable_state(struct udevice *rdev, return ret; } -static int rpmh_regulator_vrm_set_mode_bypass(struct rpmh_vreg *vreg, - unsigned int mode, bool bypassed) -{ - struct tcs_cmd cmd = { - .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_MODE, - }; - struct dm_regulator_mode *pmic_mode; - int i; - - if (mode > REGULATOR_MODE_HPM) - return -EINVAL; - - for (i = 0; i < vreg->hw_data->n_modes; i++) { - pmic_mode = &vreg->hw_data->pmic_mode_map[i]; - if (pmic_mode->id == mode) - break; - } - if (pmic_mode->id != mode) { - printf("Invalid mode %d\n", mode); - return -EINVAL; - } - - if (bypassed) - // XXX: should have a version check for PMIC4 but we don't have any yet - // and we don't use bypass mode - cmd.data = PMIC5_BOB_MODE_PASS; - else - cmd.data = pmic_mode->register_value; - - return rpmh_regulator_send_request(vreg, &cmd, true); -} - -static int rpmh_regulator_vrm_set_mode(struct udevice *rdev, - int mode) -{ - struct rpmh_vreg *vreg = dev_get_priv(rdev); - int ret; - - debug("%s: set_mode %d (current %d)\n", rdev->name, mode, vreg->mode); - - if (mode == vreg->mode) - return 0; - - ret = rpmh_regulator_vrm_set_mode_bypass(vreg, mode, vreg->bypassed); - if (!ret) - vreg->mode = mode; - - return ret; -} - static int rpmh_regulator_vrm_get_pmic_mode(struct rpmh_vreg *vreg, int *pmic_mode) { struct tcs_cmd cmd = { @@ -640,6 +647,35 @@ static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = { {} }; +static const struct rpmh_vreg_init_data pm7550_vreg_data[] = { + /* smps1 - smps6 are not added to u-boot yet */ + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-l3"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l2-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l4-l5"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo515, "vdd-l4-l5"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo515, "vdd-l6"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo515, "vdd-l7"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo515, "vdd-l8"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo515, "vdd-l9-l10"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo515, "vdd-l9-l10"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo515, "vdd-l11"), + RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo515_mv, "vdd-l12-l14"), + RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo515_mv, "vdd-l13-l16"), + RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, "vdd-l12-l14"), + RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16"), + RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("ldo20", "ldo%s20", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("ldo21", "ldo%s21", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("ldo22", "ldo%s22", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("ldo23", "ldo%s23", &pmic5_pldo, "vdd-l15-l17-l18-l19-l20-l21-l22-l23"), + RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"), + {} +}; + static const struct rpmh_vreg_init_data pm8150_vreg_data[] = { RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), @@ -853,7 +889,7 @@ static int rpmh_regulator_probe(struct udevice *dev) priv->hw_data = init_data->hw_data; priv->enabled = -EINVAL; priv->uv = -ENOTRECOVERABLE; - if (ofnode_read_u32(dev_ofnode(dev), "regulator-initial-mode", &priv->mode)) + if (dev_read_u32(dev, "regulator-initial-mode", &priv->mode)) priv->mode = -EINVAL; plat_data->mode = priv->hw_data->pmic_mode_map; @@ -904,7 +940,7 @@ static int rpmh_regulators_bind(struct udevice *dev) return -ENODEV; } - pmic_id = ofnode_read_string(dev_ofnode(dev), "qcom,pmic-id"); + pmic_id = dev_read_string(dev, "qcom,pmic-id"); if (!pmic_id) { dev_err(dev, "No PMIC ID\n"); return -ENODEV; @@ -912,7 +948,7 @@ static int rpmh_regulators_bind(struct udevice *dev) drv = lists_driver_lookup_name("rpmh_regulator_drm"); - ofnode_for_each_subnode(node, dev_ofnode(dev)) { + dev_for_each_subnode(node, dev) { data = vreg_get_init_data(init_data, node); if (!data) continue; @@ -947,6 +983,10 @@ static const struct udevice_id rpmh_regulator_ids[] = { .data = (ulong)pm7325_vreg_data, }, { + .compatible = "qcom,pm7550-rpmh-regulators", + .data = (ulong)pm7550_vreg_data, + }, + { .compatible = "qcom,pm8150-rpmh-regulators", .data = (ulong)pm8150_vreg_data, }, diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c index 1c7f75a9338..0f5ba51ad6c 100644 --- a/drivers/power/regulator/regulator-uclass.c +++ b/drivers/power/regulator/regulator-uclass.c @@ -111,6 +111,33 @@ int regulator_get_suspend_value(struct udevice *dev) return ops->get_suspend_value(dev); } +int regulator_set_value_clamp(struct udevice *dev, + int min_uV, int target_uV, int max_uV) +{ + const struct dm_regulator_ops *ops = dev_get_driver_ops(dev); + struct dm_regulator_uclass_plat *uc_pdata; + int uV; + + if (!ops || !ops->set_value) + return -ENOSYS; + + uc_pdata = dev_get_uclass_plat(dev); + if (uc_pdata->min_uV != -ENODATA && max_uV < uc_pdata->min_uV) + return -EINVAL; + if (uc_pdata->max_uV != -ENODATA && min_uV > uc_pdata->max_uV) + return -EINVAL; + if (min_uV > max_uV) + return -EINVAL; + + if (uc_pdata->min_uV != -ENODATA) + min_uV = max(min_uV, uc_pdata->min_uV); + if (uc_pdata->max_uV != -ENODATA) + max_uV = min(max_uV, uc_pdata->max_uV); + uV = clamp(target_uV, min_uV, max_uV); + + return regulator_set_value(dev, uV); +} + /* * To be called with at most caution as there is no check * before setting the actual voltage value. diff --git a/drivers/power/regulator/regulator_common.c b/drivers/power/regulator/regulator_common.c index 85af8d599ad..c0387eff4fc 100644 --- a/drivers/power/regulator/regulator_common.c +++ b/drivers/power/regulator/regulator_common.c @@ -87,6 +87,9 @@ int regulator_common_set_enable(const struct udevice *dev, } } + if (enable && plat->off_on_delay_us) + udelay(plat->off_on_delay_us); + ret = dm_gpio_set_value(&plat->gpio, enable); if (ret) { pr_err("Can't set regulator : %s gpio to: %d\n", dev->name, @@ -97,9 +100,6 @@ int regulator_common_set_enable(const struct udevice *dev, if (enable && plat->startup_delay_us) udelay(plat->startup_delay_us); - if (!enable && plat->off_on_delay_us) - udelay(plat->off_on_delay_us); - if (enable) plat->enable_count++; else diff --git a/drivers/power/regulator/sandbox.c b/drivers/power/regulator/sandbox.c index 80a68f5a30d..813ee301e73 100644 --- a/drivers/power/regulator/sandbox.c +++ b/drivers/power/regulator/sandbox.c @@ -56,10 +56,11 @@ static struct dm_regulator_mode sandbox_buck_modes[] = { MODE(BUCK_OM_PWM, OM2REG(BUCK_OM_PWM), "PWM"), }; -/* LDO: 1,2 - voltage range */ +/* LDO: 1,2,3 - voltage range */ static struct output_range ldo_voltage_range[] = { RANGE(OUT_LDO1_UV_MIN, OUT_LDO1_UV_MAX, OUT_LDO1_UV_STEP), RANGE(OUT_LDO2_UV_MIN, OUT_LDO2_UV_MAX, OUT_LDO2_UV_STEP), + RANGE(OUT_LDO3_UV_MIN, OUT_LDO3_UV_MAX, OUT_LDO3_UV_STEP), }; /* LDO: 1 - current range */ @@ -288,8 +289,8 @@ static int ldo_set_voltage(struct udevice *dev, int uV) static int ldo_get_current(struct udevice *dev) { - /* LDO2 - unsupported */ - if (dev->driver_data == 2) + /* LDO: 2,3 - unsupported */ + if (dev->driver_data >= 2) return -ENOSYS; return out_get_value(dev, SANDBOX_LDO_COUNT, OUT_REG_UA, @@ -298,8 +299,8 @@ static int ldo_get_current(struct udevice *dev) static int ldo_set_current(struct udevice *dev, int uA) { - /* LDO2 - unsupported */ - if (dev->driver_data == 2) + /* LDO: 2,3 - unsupported */ + if (dev->driver_data >= 2) return -ENOSYS; return out_set_value(dev, SANDBOX_LDO_COUNT, OUT_REG_UA, diff --git a/drivers/power/regulator/sandbox_pmbus.c b/drivers/power/regulator/sandbox_pmbus.c new file mode 100644 index 00000000000..7b52d2ca293 --- /dev/null +++ b/drivers/power/regulator/sandbox_pmbus.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2026 Free Mobile - Vincent Jardin + * + * Sandbox PMBus 1.x chip stub (UCLASS_I2C_EMUL). + * + * Stub a DT i2c node so the PMBus framework, the generic pmbus + * regulator and the pmbus CLI command can be tested. + * The model is a flat per-command 16 bit + * register file combined with some fixed identification strings. + */ + +#include <dm.h> +#include <i2c.h> +#include <pmbus.h> +#include <linux/ctype.h> + +#define PMBUS_EMUL_NREG 256 + +struct sandbox_pmbus_priv { + u16 reg[PMBUS_EMUL_NREG]; + bool supported[PMBUS_EMUL_NREG]; +}; + +/* Identification strings reported in the natural (forward) byte order. */ +static const char *pmbus_emul_string(u8 cmd) +{ + switch (cmd) { + case PMBUS_MFR_ID: + return "SANDBOX"; + case PMBUS_MFR_MODEL: + return "PMBUS-EMUL"; + case PMBUS_MFR_REVISION: + return "1.0"; + default: + return NULL; + } +} + +static int sandbox_pmbus_read(struct sandbox_pmbus_priv *priv, u8 cmd, + u8 *buf, int len) +{ + const char *str = pmbus_emul_string(cmd); + int i; + + if (len < 1) + return -EINVAL; + + if (str) { + int slen = strlen(str); + + /* + * Block payload: [length][bytes...]. A one-byte read is + * the SMBus length probe and reports the true length (the + * master just NAKs early). Any longer read must have room + * for length + payload, otherwise the length byte would + * lie about the data actually returned. + */ + if (len > 1 && len < slen + 1) + return -EREMOTEIO; + buf[0] = (u8)slen; + for (i = 1; i < len; i++) + buf[i] = (i - 1 < slen) ? (u8)str[i - 1] : 0; + return 0; + } + + if (!priv->supported[cmd]) + return -EREMOTEIO; /* chip NAKs an unimplemented command */ + + for (i = 0; i < len; i++) + buf[i] = (u8)(priv->reg[cmd] >> (8 * i)); + return 0; +} + +static int sandbox_pmbus_write(struct sandbox_pmbus_priv *priv, u8 cmd, + const u8 *buf, int len) +{ + if (len == 0) + return 0; /* send-byte (eg CLEAR_FAULTS): just ACK */ + if (!priv->supported[cmd]) + return -EREMOTEIO; + if (len == 1) + priv->reg[cmd] = buf[0]; + else + priv->reg[cmd] = (u16)buf[0] | ((u16)buf[1] << 8); + return 0; +} + +static int sandbox_pmbus_xfer(struct udevice *emul, struct i2c_msg *msg, + int nmsgs) +{ + struct sandbox_pmbus_priv *priv = dev_get_priv(emul); + u8 cmd; + + if (nmsgs == 0) + return 0; + /* A PMBus transaction always opens with the command-code write. */ + if (msg[0].flags & I2C_M_RD) + return -EIO; + if (msg[0].len == 0) + return 0; /* address-only probe */ + cmd = msg[0].buf[0]; + + if (nmsgs >= 2 && (msg[1].flags & I2C_M_RD)) + return sandbox_pmbus_read(priv, cmd, msg[1].buf, msg[1].len); + + return sandbox_pmbus_write(priv, cmd, msg[0].buf + 1, msg[0].len - 1); +} + +static void sandbox_pmbus_support(struct sandbox_pmbus_priv *priv, u8 cmd, + u16 val) +{ + priv->supported[cmd] = true; + priv->reg[cmd] = val; +} + +static int sandbox_pmbus_probe(struct udevice *emul) +{ + struct sandbox_pmbus_priv *priv = dev_get_priv(emul); + + /* Configuration / identification. */ + sandbox_pmbus_support(priv, PMBUS_PAGE, 0); + sandbox_pmbus_support(priv, PMBUS_OPERATION, PB_OPERATION_ON); + sandbox_pmbus_support(priv, PMBUS_ON_OFF_CONFIG, 0); + sandbox_pmbus_support(priv, PMBUS_WRITE_PROTECT, 0); + sandbox_pmbus_support(priv, PMBUS_CAPABILITY, 0x30); + sandbox_pmbus_support(priv, PMBUS_VOUT_MODE, 0x18); /* LINEAR 2^-8 */ + sandbox_pmbus_support(priv, PMBUS_VOUT_COMMAND, 0x0200); + sandbox_pmbus_support(priv, PMBUS_VOUT_TRIM, 0); + sandbox_pmbus_support(priv, PMBUS_VOUT_MAX, 0x0400); + sandbox_pmbus_support(priv, PMBUS_VOUT_SCALE_LOOP, 0); + sandbox_pmbus_support(priv, PMBUS_REVISION, PMBUS_REV_13); + + /* Status registers, all clean. */ + sandbox_pmbus_support(priv, PMBUS_STATUS_BYTE, 0); + sandbox_pmbus_support(priv, PMBUS_STATUS_WORD, 0); + sandbox_pmbus_support(priv, PMBUS_STATUS_VOUT, 0); + sandbox_pmbus_support(priv, PMBUS_STATUS_IOUT, 0); + sandbox_pmbus_support(priv, PMBUS_STATUS_INPUT, 0); + sandbox_pmbus_support(priv, PMBUS_STATUS_TEMPERATURE, 0); + sandbox_pmbus_support(priv, PMBUS_STATUS_CML, 0); + + /* + * Telemetry the emulated chip implements. READ_IIN and READ_POUT + * are intentionally absent so callers see the unsupported path. + */ + sandbox_pmbus_support(priv, PMBUS_READ_VIN, 0x0abc); + sandbox_pmbus_support(priv, PMBUS_READ_VOUT, 0x0200); + sandbox_pmbus_support(priv, PMBUS_READ_IOUT, 0x0123); + sandbox_pmbus_support(priv, PMBUS_READ_TEMPERATURE_1, 0x0019); + + return 0; +} + +static struct dm_i2c_ops sandbox_pmbus_emul_ops = { + .xfer = sandbox_pmbus_xfer, +}; + +static const struct udevice_id sandbox_pmbus_ids[] = { + { .compatible = "sandbox,i2c-pmbus" }, + { } +}; + +U_BOOT_DRIVER(sandbox_pmbus_emul) = { + .name = "sandbox_pmbus_emul", + .id = UCLASS_I2C_EMUL, + .of_match = sandbox_pmbus_ids, + .probe = sandbox_pmbus_probe, + .priv_auto = sizeof(struct sandbox_pmbus_priv), + .ops = &sandbox_pmbus_emul_ops, +}; diff --git a/drivers/power/regulator/scmi_regulator.c b/drivers/power/regulator/scmi_regulator.c index 7d2db1e2bee..aa7b4278260 100644 --- a/drivers/power/regulator/scmi_regulator.c +++ b/drivers/power/regulator/scmi_regulator.c @@ -180,7 +180,7 @@ static int scmi_regulator_bind(struct udevice *dev) ofnode node; int ret; - regul_node = ofnode_find_subnode(dev_ofnode(dev), "regulators"); + regul_node = dev_read_subnode(dev, "regulators"); if (!ofnode_valid(regul_node)) { dev_err(dev, "no regulators node\n"); return -ENXIO; diff --git a/drivers/power/regulator/spacemit_p1_regulator.c b/drivers/power/regulator/spacemit_p1_regulator.c new file mode 100644 index 00000000000..7b5eb710edf --- /dev/null +++ b/drivers/power/regulator/spacemit_p1_regulator.c @@ -0,0 +1,464 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2025-2026 RISCstar Ltd. + */ + +#include <dm.h> +#include <dm/lists.h> +#include <errno.h> +#include <log.h> +#include <power/pmic.h> +#include <power/regulator.h> +#include <power/spacemit_p1.h> + +struct p1_reg_info { + uint min_uv; + uint step_uv; + u8 vsel_reg; + u8 vsel_sleep_reg; + u8 config_reg; + u8 vsel_mask; + u8 min_sel; + u8 max_sel; +}; + +static const struct p1_reg_info p1_bucks[] = { + /* BUCK 1 */ + { 500000, 5000, P1_BUCK_VSEL(1), P1_BUCK_SVSEL(1), P1_BUCK_CTRL(1), + BUCK_VSEL_MASK, 0x00, 0xaa }, + { 1375000, 25000, P1_BUCK_VSEL(1), P1_BUCK_SVSEL(1), P1_BUCK_CTRL(1), + BUCK_VSEL_MASK, 0xab, 0xfe }, + /* BUCK 2 */ + { 500000, 5000, P1_BUCK_VSEL(2), P1_BUCK_SVSEL(2), P1_BUCK_CTRL(2), + BUCK_VSEL_MASK, 0x00, 0xaa }, + { 1375000, 25000, P1_BUCK_VSEL(2), P1_BUCK_SVSEL(2), P1_BUCK_CTRL(2), + BUCK_VSEL_MASK, 0xab, 0xfe }, + /* BUCK 3 */ + { 500000, 5000, P1_BUCK_VSEL(3), P1_BUCK_SVSEL(3), P1_BUCK_CTRL(3), + BUCK_VSEL_MASK, 0x00, 0xaa }, + { 1375000, 25000, P1_BUCK_VSEL(3), P1_BUCK_SVSEL(3), P1_BUCK_CTRL(3), + BUCK_VSEL_MASK, 0xab, 0xfe }, + /* BUCK 4 */ + { 500000, 5000, P1_BUCK_VSEL(4), P1_BUCK_SVSEL(4), P1_BUCK_CTRL(4), + BUCK_VSEL_MASK, 0x00, 0xaa }, + { 1375000, 25000, P1_BUCK_VSEL(4), P1_BUCK_SVSEL(4), P1_BUCK_CTRL(4), + BUCK_VSEL_MASK, 0xab, 0xfe }, + /* BUCK 5 */ + { 500000, 5000, P1_BUCK_VSEL(5), P1_BUCK_SVSEL(5), P1_BUCK_CTRL(5), + BUCK_VSEL_MASK, 0x00, 0xaa }, + { 1375000, 25000, P1_BUCK_VSEL(5), P1_BUCK_SVSEL(5), P1_BUCK_CTRL(5), + BUCK_VSEL_MASK, 0xab, 0xfe }, + /* BUCK 6 */ + { 500000, 5000, P1_BUCK_VSEL(6), P1_BUCK_SVSEL(6), P1_BUCK_CTRL(6), + BUCK_VSEL_MASK, 0x00, 0xaa }, + { 1375000, 25000, P1_BUCK_VSEL(6), P1_BUCK_SVSEL(6), P1_BUCK_CTRL(6), + BUCK_VSEL_MASK, 0xab, 0xfe }, +}; + +static const struct p1_reg_info p1_aldos[] = { + /* ALDO 1 */ + { 500000, 25000, P1_ALDO_VOLT(1), P1_ALDO_SVOLT(1), P1_ALDO_CTRL(1), + ALDO_VSEL_MASK, 0x0b, 0x7f }, + /* ALDO 2 */ + { 500000, 25000, P1_ALDO_VOLT(2), P1_ALDO_SVOLT(2), P1_ALDO_CTRL(2), + ALDO_VSEL_MASK, 0x0b, 0x7f }, + /* ALDO 3 */ + { 500000, 25000, P1_ALDO_VOLT(3), P1_ALDO_SVOLT(3), P1_ALDO_CTRL(3), + ALDO_VSEL_MASK, 0x0b, 0x7f }, + /* ALDO 4 */ + { 500000, 25000, P1_ALDO_VOLT(4), P1_ALDO_SVOLT(4), P1_ALDO_CTRL(4), + ALDO_VSEL_MASK, 0x0b, 0x7f }, +}; + +static const struct p1_reg_info p1_dldos[] = { + /* DLDO 1 */ + { 500000, 25000, P1_DLDO_VOLT(1), P1_DLDO_SVOLT(1), P1_DLDO_CTRL(1), + ALDO_VSEL_MASK, 0x0b, 0x7f }, + /* DLDO 2 */ + { 500000, 25000, P1_DLDO_VOLT(2), P1_DLDO_SVOLT(2), P1_DLDO_CTRL(2), + ALDO_VSEL_MASK, 0x0b, 0x7f }, + /* DLDO 3 */ + { 500000, 25000, P1_DLDO_VOLT(3), P1_DLDO_SVOLT(3), P1_DLDO_CTRL(3), + ALDO_VSEL_MASK, 0x0b, 0x7f }, + /* DLDO 4 */ + { 500000, 25000, P1_DLDO_VOLT(4), P1_DLDO_SVOLT(4), P1_DLDO_CTRL(4), + ALDO_VSEL_MASK, 0x0b, 0x7f }, + /* DLDO 5 */ + { 500000, 25000, P1_DLDO_VOLT(5), P1_DLDO_SVOLT(5), P1_DLDO_CTRL(5), + ALDO_VSEL_MASK, 0x0b, 0x7f }, + /* DLDO 6 */ + { 500000, 25000, P1_DLDO_VOLT(6), P1_DLDO_SVOLT(6), P1_DLDO_CTRL(6), + ALDO_VSEL_MASK, 0x0b, 0x7f }, + /* DLDO 7 */ + { 500000, 25000, P1_DLDO_VOLT(7), P1_DLDO_SVOLT(7), P1_DLDO_CTRL(7), + ALDO_VSEL_MASK, 0x0b, 0x7f }, +}; + +static const struct p1_reg_info *get_buck_reg(struct udevice *pmic, + int idx, int uvolt) +{ + if (idx < 0) + return NULL; + if (uvolt < 1375000) + return &p1_bucks[(idx - 1) * 2 + 0]; + return &p1_bucks[(idx - 1) * 2 + 1]; +} + +static const struct p1_reg_info *get_aldo_reg(struct udevice *pmic, + int idx, int uvolt) +{ + if (idx < 1 || idx > ARRAY_SIZE(p1_aldos)) + return NULL; + return &p1_aldos[idx - 1]; +} + +static const struct p1_reg_info *get_dldo_reg(struct udevice *pmic, + int idx, int uvolt) +{ + if (idx < 1 || idx > ARRAY_SIZE(p1_dldos)) + return NULL; + return &p1_dldos[idx - 1]; +} + +static int buck_get_value(struct udevice *dev) +{ + const struct dm_pmic_ops *ops = device_get_ops(dev->parent); + const struct p1_reg_info *info; + uint val; + int ret; + + if (!ops || !ops->read) + return -ENOSYS; + + info = get_buck_reg(dev->parent, dev->driver_data, 0); + if (!info) + return -ENOENT; + ret = pmic_reg_read(dev->parent, info->vsel_reg); + if (ret < 0) + return ret; + val = ret & info->vsel_mask; + while (val > info->max_sel) + info++; + + return info->min_uv + (val - info->min_sel) * info->step_uv; +} + +static int buck_set_value(struct udevice *dev, int uvolt) +{ + const struct dm_pmic_ops *ops = device_get_ops(dev->parent); + const struct p1_reg_info *info; + uint val; + int ret; + + if (!ops || !ops->write) + return -ENOSYS; + + info = get_buck_reg(dev->parent, dev->driver_data, uvolt); + if (!info) + return -ENOENT; + val = (uvolt - info->min_uv); + val = val / info->step_uv; + val += info->min_sel; + ret = pmic_reg_write(dev->parent, info->vsel_reg, val); + if (ret < 0) + return ret; + return 0; +} + +static int buck_get_enable(struct udevice *dev) +{ + const struct p1_reg_info *info; + int ret; + + info = get_buck_reg(dev->parent, dev->driver_data, 0); + if (!info) + return -ENOENT; + + ret = pmic_reg_read(dev->parent, info->config_reg); + if (ret < 0) + return ret; + return ret & BUCK_EN_MASK; +} + +static int buck_set_enable(struct udevice *dev, bool enable) +{ + const struct p1_reg_info *info; + uint val; + int ret; + + info = get_buck_reg(dev->parent, dev->driver_data, 0); + if (!info) + return -ENOENT; + + ret = pmic_reg_read(dev->parent, info->config_reg); + if (ret < 0) + return ret; + val = (unsigned int)ret; + val &= BUCK_EN_MASK; + + if (enable == val) + return 0; + + val = enable; + ret = pmic_clrsetbits(dev->parent, info->config_reg, BUCK_EN_MASK, val); + if (ret < 0) + return ret; + + return 0; +} + +static const struct dm_regulator_ops p1_buck_ops = { + .get_value = buck_get_value, + .set_value = buck_set_value, + .get_enable = buck_get_enable, + .set_enable = buck_set_enable, +}; + +static int p1_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_count = 0; + + return 0; +} + +U_BOOT_DRIVER(p1_buck) = { + .name = P1_BUCK_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &p1_buck_ops, + .probe = p1_buck_probe, +}; + +static int aldo_get_value(struct udevice *dev) +{ + const struct dm_pmic_ops *ops = device_get_ops(dev->parent); + const struct p1_reg_info *info; + uint val; + int ret; + + if (!ops || !ops->read) + return -ENOSYS; + + info = get_aldo_reg(dev->parent, dev->driver_data, 0); + if (!info) + return -ENOENT; + + ret = pmic_reg_read(dev->parent, info->vsel_reg); + if (ret < 0) + return ret; + + val = ret & info->vsel_mask; + while (val > info->max_sel) + info++; + + return info->min_uv + (val - info->min_sel) * info->step_uv; +} + +static int aldo_set_value(struct udevice *dev, int uvolt) +{ + const struct dm_pmic_ops *ops = device_get_ops(dev->parent); + const struct p1_reg_info *info; + uint val; + int ret; + + if (!ops || !ops->write) + return -ENOSYS; + + info = get_aldo_reg(dev->parent, dev->driver_data, uvolt); + if (!info) + return -ENOENT; + val = (uvolt - info->min_uv); + val = val / info->step_uv; + val += info->min_sel; + ret = pmic_reg_write(dev->parent, info->vsel_reg, val); + if (ret < 0) + return ret; + return 0; +} + +static int aldo_get_enable(struct udevice *dev) +{ + const struct p1_reg_info *info; + int ret; + + info = get_aldo_reg(dev->parent, dev->driver_data, 0); + if (!info) + return -ENOENT; + + ret = pmic_reg_read(dev->parent, info->config_reg); + if (ret < 0) + return ret; + return ret & ALDO_EN_MASK; +} + +static int aldo_set_enable(struct udevice *dev, bool enable) +{ + const struct p1_reg_info *info; + uint val; + int ret; + + info = get_aldo_reg(dev->parent, dev->driver_data, 0); + if (!info) + return -ENOENT; + + ret = pmic_reg_read(dev->parent, info->config_reg); + if (ret < 0) + return ret; + val = (unsigned int)ret; + val &= ALDO_EN_MASK; + + if (enable == val) + return 0; + + val = enable; + ret = pmic_clrsetbits(dev->parent, info->config_reg, ALDO_EN_MASK, val); + if (ret < 0) + return ret; + + return 0; +} + +static const struct dm_regulator_ops p1_aldo_ops = { + .get_value = aldo_get_value, + .set_value = aldo_set_value, + .get_enable = aldo_get_enable, + .set_enable = aldo_set_enable, +}; + +static int p1_aldo_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_plat *uc_pdata; + + uc_pdata = dev_get_uclass_plat(dev); + + uc_pdata->type = REGULATOR_TYPE_LDO; + uc_pdata->mode_count = 0; + + return 0; +} + +U_BOOT_DRIVER(p1_aldo) = { + .name = P1_ALDO_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &p1_aldo_ops, + .probe = p1_aldo_probe, +}; + +static int dldo_get_value(struct udevice *dev) +{ + const struct dm_pmic_ops *ops = device_get_ops(dev->parent); + const struct p1_reg_info *info; + uint val; + int ret; + + if (!ops || !ops->read) + return -ENOSYS; + + info = get_dldo_reg(dev->parent, dev->driver_data, 0); + if (!info) + return -ENOENT; + + ret = pmic_reg_read(dev->parent, info->vsel_reg); + if (ret < 0) + return ret; + + val = ret & info->vsel_mask; + while (val > info->max_sel) + info++; + + return info->min_uv + (val - info->min_sel) * info->step_uv; +} + +static int dldo_set_value(struct udevice *dev, int uvolt) +{ + const struct dm_pmic_ops *ops = device_get_ops(dev->parent); + const struct p1_reg_info *info; + uint val; + int ret; + + if (!ops || !ops->write) + return -ENOSYS; + + info = get_dldo_reg(dev->parent, dev->driver_data, uvolt); + if (!info) + return -ENOENT; + val = (uvolt - info->min_uv); + val = val / info->step_uv; + val += info->min_sel; + ret = pmic_reg_write(dev->parent, info->vsel_reg, val); + if (ret < 0) + return ret; + return 0; +} + +static int dldo_get_enable(struct udevice *dev) +{ + const struct p1_reg_info *info; + int ret; + + info = get_dldo_reg(dev->parent, dev->driver_data, 0); + if (!info) + return -ENOENT; + + ret = pmic_reg_read(dev->parent, info->config_reg); + if (ret < 0) + return ret; + return ret & DLDO_EN_MASK; +} + +static int dldo_set_enable(struct udevice *dev, bool enable) +{ + const struct p1_reg_info *info; + uint val; + int ret; + + info = get_dldo_reg(dev->parent, dev->driver_data, 0); + if (!info) + return -ENOENT; + + ret = pmic_reg_read(dev->parent, info->config_reg); + if (ret < 0) + return ret; + val = (unsigned int)ret; + val &= DLDO_EN_MASK; + + if (enable == val) + return 0; + + val = enable; + ret = pmic_clrsetbits(dev->parent, info->config_reg, DLDO_EN_MASK, val); + if (ret < 0) + return ret; + + return 0; +} + +static const struct dm_regulator_ops p1_dldo_ops = { + .get_value = dldo_get_value, + .set_value = dldo_set_value, + .get_enable = dldo_get_enable, + .set_enable = dldo_set_enable, +}; + +static int p1_dldo_probe(struct udevice *dev) +{ + struct dm_regulator_uclass_plat *uc_pdata; + + uc_pdata = dev_get_uclass_plat(dev); + + uc_pdata->type = REGULATOR_TYPE_LDO; + uc_pdata->mode_count = 0; + + return 0; +} + +U_BOOT_DRIVER(p1_dldo) = { + .name = P1_DLDO_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &p1_dldo_ops, + .probe = p1_dldo_probe, +}; diff --git a/drivers/power/regulator/tps6287x_regulator.c b/drivers/power/regulator/tps6287x_regulator.c index 6d185719199..2e6d85f677a 100644 --- a/drivers/power/regulator/tps6287x_regulator.c +++ b/drivers/power/regulator/tps6287x_regulator.c @@ -141,7 +141,7 @@ static int tps6287x_regulator_probe(struct udevice *dev) pdata->config = (void *)dev_get_driver_data(dev); - slave_id = devfdt_get_addr_index(dev, 0); + slave_id = dev_read_addr_index(dev, 0); ret = i2c_get_chip(dev->parent, slave_id, 1, &pdata->i2c); if (ret) { diff --git a/drivers/power/regulator/tps65941_regulator.c b/drivers/power/regulator/tps65941_regulator.c index 2561d6f4c6c..209968b5718 100644 --- a/drivers/power/regulator/tps65941_regulator.c +++ b/drivers/power/regulator/tps65941_regulator.c @@ -63,13 +63,14 @@ static inline int tps65941_get_chip_id(struct udevice *dev) static int tps65941_buck_enable(struct udevice *dev, int op, bool *enable) { - int ret; + int ret, idx; unsigned int adr; struct dm_regulator_uclass_plat *uc_pdata; uc_pdata = dev_get_uclass_plat(dev); adr = uc_pdata->ctrl_reg; + idx = dev->driver_data; ret = pmic_reg_read(dev->parent, adr); if (ret < 0) return ret; @@ -84,10 +85,18 @@ static int tps65941_buck_enable(struct udevice *dev, int op, bool *enable) return 0; } else if (op == PMIC_OP_SET) { - if (*enable) + if (*enable) { ret |= TPS65941_BUCK_MODE_MASK; - else + /* Enable FPWM */ + ret |= TPS65941_BUCK_FPWM_MASK; + /* If Multiphase enable FPWM_MP */ + if (idx == TPS65941_BUCK_ID_12 || + idx == TPS65941_BUCK_ID_123 || + idx == TPS65941_BUCK_ID_1234) + ret |= TPS65941_BUCK_FPWM_MP_MASK; + } else { ret &= ~TPS65941_BUCK_MODE_MASK; + } ret = pmic_reg_write(dev->parent, adr, ret); if (ret) return ret; diff --git a/drivers/ram/aspeed/Kconfig b/drivers/ram/aspeed/Kconfig index e4918460de6..fa5c890bb7a 100644 --- a/drivers/ram/aspeed/Kconfig +++ b/drivers/ram/aspeed/Kconfig @@ -4,19 +4,19 @@ menuconfig ASPEED_RAM depends on ARCH_ASPEED || TARGET_ASPEED_AST2700_IBEX default ARCH_ASPEED help - Configuration options for DDR SDRAM on ASPEED systems. + Configuration options for DDR SDRAM on ASPEED systems. - RAM initialisation is always built in for the platform. This menu - allows customisation of the configuration used. + RAM initialisation is always built in for the platform. This menu + allows customisation of the configuration used. config ASPEED_DDR4_DUALX8 bool "Enable Dual X8 DDR4 die" depends on ASPEED_RAM help - Say Y if dual X8 DDR4 die is used on the board. The ASPEED DDRM - SRAM controller needs to know if the memory chip mounted on the - board is dual x8 die or not, otherwise it may get the wrong - size of the memory space. + Say Y if dual X8 DDR4 die is used on the board. The ASPEED DDRM + SRAM controller needs to know if the memory chip mounted on the + board is dual x8 die or not, otherwise it may get the wrong + size of the memory space. config ASPEED_BYPASS_SELFTEST depends on ASPEED_RAM @@ -77,7 +77,7 @@ choice prompt "AST2700 DDR target date rate" default ASPEED_DDR_3200 depends on ASPEED_RAM - depends on TARGET_ASPEED_AST2700_IBEX + depends on ASPEED_AST2700 || TARGET_ASPEED_AST2700_IBEX config ASPEED_DDR_1600 bool "1600 Mbps" diff --git a/drivers/ram/aspeed/Makefile b/drivers/ram/aspeed/Makefile index 1f0b22c8e9f..d29e2154ce9 100644 --- a/drivers/ram/aspeed/Makefile +++ b/drivers/ram/aspeed/Makefile @@ -2,4 +2,5 @@ # obj-$(CONFIG_ASPEED_AST2500) += sdram_ast2500.o obj-$(CONFIG_ASPEED_AST2600) += sdram_ast2600.o +obj-$(CONFIG_ASPEED_AST2700) += sdram_ast2700.o obj-$(CONFIG_TARGET_ASPEED_AST2700_IBEX) += sdram_ast2700.o diff --git a/drivers/ram/aspeed/sdram_ast2600.c b/drivers/ram/aspeed/sdram_ast2600.c index 55e80fba3dc..2cf9296468d 100644 --- a/drivers/ram/aspeed/sdram_ast2600.c +++ b/drivers/ram/aspeed/sdram_ast2600.c @@ -1076,10 +1076,10 @@ static int ast2600_sdrammc_probe(struct udevice *dev) return ret; } - priv->scu = devfdt_get_addr_ptr(clk_dev); - if (IS_ERR(priv->scu)) { + priv->scu = dev_read_addr_ptr(clk_dev); + if (!priv->scu) { debug("%s(): can't get SCU\n", __func__); - return PTR_ERR(priv->scu); + return -ENODEV; } if (readl(&priv->scu->dram_hdshk) & SCU_DRAM_HDSHK_RDY) { @@ -1136,12 +1136,11 @@ static int ast2600_sdrammc_of_to_plat(struct udevice *dev) { struct dram_info *priv = dev_get_priv(dev); - priv->regs = (void *)(uintptr_t)devfdt_get_addr_index(dev, 0); - priv->phy_setting = (void *)(uintptr_t)devfdt_get_addr_index(dev, 1); - priv->phy_status = (void *)(uintptr_t)devfdt_get_addr_index(dev, 2); + priv->regs = (void *)(uintptr_t)dev_read_addr_index(dev, 0); + priv->phy_setting = (void *)(uintptr_t)dev_read_addr_index(dev, 1); + priv->phy_status = (void *)(uintptr_t)dev_read_addr_index(dev, 2); - priv->clock_rate = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "clock-frequency", 0); + priv->clock_rate = ofnode_read_s32_default(dev_ofnode(dev), "clock-frequency", 0); if (!priv->clock_rate) { debug("DDR Clock Rate not defined\n"); return -EINVAL; diff --git a/drivers/ram/aspeed/sdram_ast2700.c b/drivers/ram/aspeed/sdram_ast2700.c index 4a019c4edb1..8605a92abb2 100644 --- a/drivers/ram/aspeed/sdram_ast2700.c +++ b/drivers/ram/aspeed/sdram_ast2700.c @@ -14,6 +14,11 @@ #include <linux/sizes.h> #include <ram.h> +__weak int fmc_hdr_get_prebuilt(u32 type, u32 *ofst, u32 *size) +{ + return -ENOSYS; +} + enum ddr_type { DDR4_1600 = 0x0, DDR4_2400, @@ -128,13 +133,13 @@ static size_t ast2700_sdrammc_get_vga_mem_size(struct sdrammc *sdrammc) reg = readl(scu0 + SCU0_PCI_MISC70); if (reg & SCU0_PCI_MISC70_EN_PCIEVGA0) { - debug("VGA0:%dMB\n", vga_memsz[sel] / SZ_1M); + debug("VGA0:%zuMB\n", vga_memsz[sel] / SZ_1M); dual++; } reg = readl(scu0 + SCU0_PCI_MISC80); if (reg & SCU0_PCI_MISC80_EN_PCIEVGA1) { - debug("VGA1:%dMB\n", vga_memsz[sel] / SZ_1M); + debug("VGA1:%zuMB\n", vga_memsz[sel] / SZ_1M); dual++; } @@ -560,7 +565,7 @@ void dwc_get_mailbox(struct sdrammc *sdrammc, const int mode, u32 *mbox) dwc_ddrphy_apb_wr(0xd0031, 1); } -uint32_t dwc_readMsgBlock(struct sdrammc *sdrammc, const u32 addr_half) +u32 dwc_readMsgBlock(struct sdrammc *sdrammc, const u32 addr_half) { u32 data_word; @@ -727,7 +732,7 @@ int dwc_ddrphy_phyinit_userCustom_D_loadIMEM(struct sdrammc *sdrammc, const int fmc_hdr_get_prebuilt(pb_type, &imem_ofst, &imem_size); memcpy(sdrammc->phy + (DWC_PHY_IMEM_OFST << 1), - (void *)(0x20000000 + imem_ofst), imem_size); + (void *)(uintptr_t)(0x20000000 + imem_ofst), imem_size); return 0; } @@ -746,7 +751,7 @@ int dwc_ddrphy_phyinit_userCustom_F_loadDMEM(struct sdrammc *sdrammc, fmc_hdr_get_prebuilt(pb_type, &dmem_ofst, &dmem_size); memcpy(sdrammc->phy + (DWC_PHY_DMEM_OFST << 1), - (void *)(0x20000000 + dmem_ofst), dmem_size); + (void *)(uintptr_t)(0x20000000 + dmem_ofst), dmem_size); return 0; } @@ -956,13 +961,13 @@ static int ast2700_sdrammc_of_to_plat(struct udevice *dev) ofnode node; int rc; - sdrammc->regs = (struct sdrammc_regs *)devfdt_get_addr_index(dev, 0); + sdrammc->regs = (struct sdrammc_regs *)dev_read_addr_index(dev, 0); if (sdrammc->regs == (void *)FDT_ADDR_T_NONE) { debug("cannot map DRAM register\n"); return -ENODEV; } - sdrammc->phy = (void *)devfdt_get_addr_index(dev, 1); + sdrammc->phy = (void *)dev_read_addr_index(dev, 1); if (sdrammc->phy == (void *)FDT_ADDR_T_NONE) { debug("cannot map PHY memory\n"); return -ENODEV; diff --git a/drivers/ram/octeon/Kconfig b/drivers/ram/octeon/Kconfig index f19957293f9..37bf4851400 100644 --- a/drivers/ram/octeon/Kconfig +++ b/drivers/ram/octeon/Kconfig @@ -2,14 +2,14 @@ config RAM_OCTEON bool "Ram drivers for Octeon SoCs" depends on RAM && ARCH_OCTEON help - This enables support for RAM drivers for Octeon SoCs. + This enables support for RAM drivers for Octeon SoCs. if RAM_OCTEON config RAM_OCTEON_DDR4 bool "Octeon III DDR4 RAM support" help - This enables support for DDR4 RAM suppoort for Octeon III. This does - not include support for Octeon CN70XX. + This enables support for DDR4 RAM suppoort for Octeon III. This does + not include support for Octeon CN70XX. endif # RAM_OCTEON diff --git a/drivers/ram/renesas/Kconfig b/drivers/ram/renesas/Kconfig index 6a1ef2a0c63..8c3e5fab96f 100644 --- a/drivers/ram/renesas/Kconfig +++ b/drivers/ram/renesas/Kconfig @@ -1,7 +1,7 @@ config RAM_RENESAS_DBSC5 - bool "Renesas R-Car V4H/V4M DBSC5 controller driver" - depends on SPL && RAM && (R8A779G0 || R8A779H0) + bool "Renesas R-Car V4H/V4M/X5H DBSC5 controller driver" + depends on RAM && (R8A78000 || (SPL && (R8A779G0 || R8A779H0))) default n help Enable this to support the DBSC5 DRAM controller initialization - on Renesas R8A779G0/R8A779H0 SoCs. + on Renesas R8A779G0/R8A779H0/R8A78000 SoCs. diff --git a/drivers/ram/renesas/Makefile b/drivers/ram/renesas/Makefile index 578d05622d7..699b726972b 100644 --- a/drivers/ram/renesas/Makefile +++ b/drivers/ram/renesas/Makefile @@ -1,6 +1,4 @@ # SPDX-License-Identifier: GPL-2.0+ -ifdef CONFIG_XPL_BUILD obj-$(CONFIG_RAM_RENESAS_DBSC5) += dbsc5/ -endif obj-$(CONFIG_RZN1) += rzn1/ diff --git a/drivers/ram/renesas/dbsc5/Makefile b/drivers/ram/renesas/dbsc5/Makefile index 177be893e10..0ae2193e09b 100644 --- a/drivers/ram/renesas/dbsc5/Makefile +++ b/drivers/ram/renesas/dbsc5/Makefile @@ -1,3 +1,5 @@ # SPDX-License-Identifier: GPL-2.0+ -obj-y += dbsc5.o dram.o qos.o rtvram.o +obj-$(CONFIG_R8A779G0) += r8a779g0-dbsc5.o r8a779g0-dram.o qos.o +obj-$(CONFIG_R8A78000) += r8a78000-dbsc5.o r8a78000-dram.o ecc.o +obj-y += rtvram.o diff --git a/drivers/ram/renesas/dbsc5/ecc.c b/drivers/ram/renesas/dbsc5/ecc.c new file mode 100644 index 00000000000..77295a696ab --- /dev/null +++ b/drivers/ram/renesas/dbsc5/ecc.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2026 Renesas Electronics Corp. + */ + +#include <asm/io.h> +#include <dm.h> +#include <errno.h> +#include <ram.h> +#include <linux/sizes.h> + +#define DBSC5_DBSC_CNT 8 + +#define DBSC_D_BASE(n) (0xe9900000 + ((n) * 0x4000)) +#define DBSC_A_BASE(n) (0xe9800000 + ((n) * 0x8000)) +#define DBSYSCNT 0x100 +#define DBACEN 0x200 +#define DBFSINTENB02A 0x7088 +#define DBFSINTENB04A 0x7090 +#define DBFSCONFAXI0 0x7400 +#define DBFSDRAMECCAREA00 0x7450 +#define DBFSCTRL01A 0x7604 +#define DBFSCONF00A 0x7640 +#define DBFSCONF01A 0x7644 +#define DBFSCONF02A 0x7648 +#define DBFSSTAT00A 0x7680 +#define DBFSSTAT01A 0x7684 + +#define DBSYSCNT_ENABLE 0x1234 +#define DBSYSCNT_DISABLE 0x0 +#define DBACEN_ACCESS_DISABLE 0 +#define DBACEN_ACCESS_ENABLE 1 + +#define ECM_BASE 0xb89a0000 +#define ECMERRCTLR0 (ECM_BASE + 0x0) +#define ECMERRINCR0 (ECM_BASE + 0x200) +#define ECMERROMKR0 (ECM_BASE + 0x600) +#define ECMERRCTLR6 (ECM_BASE + (0x4 * 6)) +#define ECMERRINCR6 (ECM_BASE + 0x200U + (0x4 * 6)) +#define ECMERROMKR6 (ECM_BASE + 0x600U + (0x4 * 6)) +#define ECMWPCNTR (ECM_BASE + 0xa00) +#define ECMWACNTR (ECM_BASE + 0xa04) + +struct renesas_dbsc5_ecc_priv { + void __iomem *regs; +}; + +static void ecm_reg_unlock(void) +{ + writel(0xacce0001, ECMWPCNTR); +} + +static void ecm_reg_lock(void) +{ + writel(0xacce0000, ECMWPCNTR); +} + +static void ecm_reg_write(u32 adr, u32 val) +{ + writel(0xacce0000 | (adr & 0xffff), ECMWACNTR); + writel(val, adr); +} + +static int renesas_dbsc5_ecc_probe(struct udevice *dev) +{ + int i; + + ecm_reg_unlock(); + + for (i = 0; i < DBSC5_DBSC_CNT; i++) { + writel(DBSYSCNT_ENABLE, DBSC_D_BASE(i) + DBSYSCNT); + writel(DBSYSCNT_ENABLE, DBSC_A_BASE(i) + DBSYSCNT); + } + + ecm_reg_write(ECMERRINCR0, readl(ECMERRINCR0) | 0xAAA); + ecm_reg_write(ECMERROMKR0, readl(ECMERROMKR0) | 0xAAA); + ecm_reg_write(ECMERRCTLR0, readl(ECMERRCTLR0) | 0xAAA); + ecm_reg_write(ECMERRINCR6, readl(ECMERRINCR6) | 0xA000); + ecm_reg_write(ECMERROMKR6, readl(ECMERROMKR6) | 0xA000); + ecm_reg_write(ECMERRCTLR6, readl(ECMERRCTLR6) | 0xA000); + + for (i = 0; i < DBSC5_DBSC_CNT; i++) + writel(0xcccc, DBSC_A_BASE(i) + DBFSDRAMECCAREA00); + + for (i = 0; i < DBSC5_DBSC_CNT; i++) + writel(DBACEN_ACCESS_DISABLE, DBSC_A_BASE(i) + DBACEN); + + for (i = 0; i < DBSC5_DBSC_CNT; i++) + writel(0, DBSC_A_BASE(i) + DBFSCONF00A); + + for (i = 0; i < DBSC5_DBSC_CNT; i++) + writel(0, DBSC_A_BASE(i) + DBFSCONF01A); + + for (i = 0; i < DBSC5_DBSC_CNT; i++) + writel(0xcccb, DBSC_A_BASE(i) + DBFSCONF02A); + + for (i = 0; i < DBSC5_DBSC_CNT; i++) + writel(0x1, DBSC_A_BASE(i) + DBFSCTRL01A); + + u32 fsstat; + do { + fsstat = 0x1; + for (i = 0; i < DBSC5_DBSC_CNT; i++) + fsstat &= readl(DBSC_A_BASE(i) + DBFSSTAT01A); + } while (!(fsstat & 0x1)); + + for (i = 0; i < DBSC5_DBSC_CNT; i++) + writel(DBACEN_ACCESS_ENABLE, DBSC_A_BASE(i) + DBACEN); + + for (i = 0; i < DBSC5_DBSC_CNT; i++) + setbits_le32(DBSC_A_BASE(i) + DBFSCONFAXI0, 0x100); + + for (i = 0; i < DBSC5_DBSC_CNT; i++) + writel(0xff00ff00, DBSC_A_BASE(i) + DBFSINTENB02A); + + for (i = 0; i < DBSC5_DBSC_CNT; i++) + writel(0xffffffff, DBSC_A_BASE(i) + DBFSINTENB04A); + + ecm_reg_lock(); + + for (i = 0; i < DBSC5_DBSC_CNT; i++) { + writel(DBSYSCNT_DISABLE, DBSC_D_BASE(i) + DBSYSCNT); + writel(DBSYSCNT_DISABLE, DBSC_A_BASE(i) + DBSYSCNT); + } + + return 0; +} + +static int renesas_dbsc5_ecc_of_to_plat(struct udevice *dev) +{ + struct renesas_dbsc5_ecc_priv *priv = dev_get_priv(dev); + + priv->regs = dev_read_addr_ptr(dev); + if (!priv->regs) + return -EINVAL; + + return 0; +} + +static int renesas_dbsc5_ecc_get_info(struct udevice *dev, + struct ram_info *info) +{ + struct renesas_dbsc5_ecc_priv *priv = dev_get_priv(dev); + + info->base = (phys_addr_t)priv->regs; + info->size = 32 * SZ_1M; + + return 0; +} + +static const struct ram_ops renesas_dbsc5_ecc_ops = { + .get_info = renesas_dbsc5_ecc_get_info, +}; + +static const struct udevice_id renesas_dbsc5_ecc_ids[] = { + { .compatible = "renesas,r8a78000-ecc" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(renesas_dbsc5_ecc) = { + .name = "dbsc5_ecc", + .id = UCLASS_RAM, + .of_match = renesas_dbsc5_ecc_ids, + .of_to_plat = renesas_dbsc5_ecc_of_to_plat, + .ops = &renesas_dbsc5_ecc_ops, + .probe = renesas_dbsc5_ecc_probe, + .priv_auto = sizeof(struct renesas_dbsc5_ecc_priv), +}; diff --git a/drivers/ram/renesas/dbsc5/qos.c b/drivers/ram/renesas/dbsc5/qos.c index 56a60b987af..a9fc0b1439a 100644 --- a/drivers/ram/renesas/dbsc5/qos.c +++ b/drivers/ram/renesas/dbsc5/qos.c @@ -9,7 +9,7 @@ #include <hang.h> #include <linux/sizes.h> #include <ram.h> -#include "dbsc5.h" +#include "r8a779g0-dbsc5.h" /* AXMM */ #define AXMM_ADSPLCR0 0x4008 diff --git a/drivers/ram/renesas/dbsc5/dbsc5.c b/drivers/ram/renesas/dbsc5/r8a779g0-dbsc5.c index 4cbc6aeda43..b57c885fc59 100644 --- a/drivers/ram/renesas/dbsc5/dbsc5.c +++ b/drivers/ram/renesas/dbsc5/r8a779g0-dbsc5.c @@ -10,7 +10,7 @@ #include <errno.h> #include <linux/sizes.h> #include <ram.h> -#include "dbsc5.h" +#include "r8a779g0-dbsc5.h" static int renesas_dbsc5_probe(struct udevice *dev) { diff --git a/drivers/ram/renesas/dbsc5/dbsc5.h b/drivers/ram/renesas/dbsc5/r8a779g0-dbsc5.h index bf22fcb8c11..592c9badbd7 100644 --- a/drivers/ram/renesas/dbsc5/dbsc5.h +++ b/drivers/ram/renesas/dbsc5/r8a779g0-dbsc5.h @@ -3,8 +3,8 @@ * Copyright (C) 2024 Renesas Electronics Corp. */ -#ifndef __DRIVERS_RAM_RENESAS_DBSC5_DBSC5_H__ -#define __DRIVERS_RAM_RENESAS_DBSC5_DBSC5_H__ +#ifndef __DRIVERS_RAM_RENESAS_DBSC5_R8A779G0_DBSC5_H__ +#define __DRIVERS_RAM_RENESAS_DBSC5_R8A779G0_DBSC5_H__ /* * DBSC5 ... 0xe678_0000..0xe67fffff @@ -26,4 +26,4 @@ struct renesas_dbsc5_data { const char *otp_node; }; -#endif /* __DRIVERS_RAM_RENESAS_DBSC5_DBSC5_H__ */ +#endif /* __DRIVERS_RAM_RENESAS_DBSC5_R8A779G0_DBSC5_H__ */ diff --git a/drivers/ram/renesas/dbsc5/dram.c b/drivers/ram/renesas/dbsc5/r8a779g0-dram.c index 3ed02e11f9e..8dd4e321849 100644 --- a/drivers/ram/renesas/dbsc5/dram.c +++ b/drivers/ram/renesas/dbsc5/r8a779g0-dram.c @@ -4,14 +4,14 @@ */ #include <asm/io.h> -#include <dbsc5.h> +#include <r8a779g0-dbsc5.h> #include <dm.h> #include <errno.h> #include <hang.h> #include <ram.h> #include <linux/iopoll.h> #include <linux/sizes.h> -#include "dbsc5.h" +#include "r8a779g0-dbsc5.h" /* Number of array elements in Data Slice */ #define DDR_PHY_SLICE_REGSET_SIZE_V4H 0x100 diff --git a/drivers/ram/renesas/dbsc5/r8a78000-dbsc5.c b/drivers/ram/renesas/dbsc5/r8a78000-dbsc5.c new file mode 100644 index 00000000000..b6b4ed8a5c0 --- /dev/null +++ b/drivers/ram/renesas/dbsc5/r8a78000-dbsc5.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * + * Portions Copyright (C) 2026 Synopsys, Inc. Used with permission. All rights reserved. + */ + +#include <asm/io.h> +#include <dm.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <errno.h> +#include <linux/sizes.h> +#include <ram.h> +#include "r8a78000-dbsc5.h" + +static int renesas_dbsc5_probe(struct udevice *dev) +{ + struct udevice *ddev, *vdev, *edev; + int ret; + + ret = uclass_get_device_by_name(UCLASS_RAM, "dbsc5_dram", &ddev); + if (ret) + return ret; + + ret = uclass_get_device_by_name(UCLASS_RAM, "ram@b8940000", &vdev); + if (ret) + return ret; + + ret = uclass_get_device_by_name(UCLASS_RAM, "dbsc5_ecc", &edev); + if (ret) + return ret; + + return 0; +} + +int renesas_dbsc5_bind(struct udevice *dev) +{ + struct udevice *ramdev, *eccdev; + struct driver *ramdrv, *eccdrv; + int ret; + + ramdrv = lists_driver_lookup_name("dbsc5_dram"); + if (!ramdrv) + return -ENOENT; + + eccdrv = lists_driver_lookup_name("dbsc5_ecc"); + if (!eccdrv) + return -ENOENT; + + ret = device_bind_with_driver_data(dev, ramdrv, "dbsc5_dram", + dev_get_driver_data(dev), + dev_ofnode(dev), &ramdev); + if (ret) + return ret; + + ret = device_bind_with_driver_data(dev, eccdrv, "dbsc5_ecc", 0, + dev_ofnode(dev), &eccdev); + if (ret) + device_unbind(ramdev); + + return ret; +} + +static const struct udevice_id renesas_dbsc5_ids[] = { + { .compatible = "renesas,r8a78000-dbsc", }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(renesas_dbsc5) = { + .name = "dbsc5", + .id = UCLASS_NOP, + .of_match = renesas_dbsc5_ids, + .bind = renesas_dbsc5_bind, + .probe = renesas_dbsc5_probe, +}; diff --git a/drivers/ram/renesas/dbsc5/r8a78000-dbsc5.h b/drivers/ram/renesas/dbsc5/r8a78000-dbsc5.h new file mode 100644 index 00000000000..b8c9a6f81fa --- /dev/null +++ b/drivers/ram/renesas/dbsc5/r8a78000-dbsc5.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * + * Portions Copyright (C) 2026 Synopsys, Inc. Used with permission. All rights reserved. + */ + +#ifndef __DRIVERS_RAM_RENESAS_DBSC5_R8A78000_DBSC5_H__ +#define __DRIVERS_RAM_RENESAS_DBSC5_R8A78000_DBSC5_H__ + +struct renesas_dbsc5_data { + const char *clock_node; + const char *reset_node; + const char *otp_node; +}; + +#endif /* __DRIVERS_RAM_RENESAS_DBSC5_R8A78000_DBSC5_H__ */ diff --git a/drivers/ram/renesas/dbsc5/r8a78000-dram.c b/drivers/ram/renesas/dbsc5/r8a78000-dram.c new file mode 100644 index 00000000000..f1c12901d52 --- /dev/null +++ b/drivers/ram/renesas/dbsc5/r8a78000-dram.c @@ -0,0 +1,2795 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * + * Portions Copyright (C) 2026 Synopsys, Inc. Used with permission. All rights reserved. + */ + +#include <asm/io.h> +#include <r8a78000-dbsc5.h> +#include <dm.h> +#include <errno.h> +#include <hang.h> +#include <ram.h> +#include <linux/iopoll.h> +#include <linux/sizes.h> +#include "r8a78000-dbsc5.h" +#include "r8a78000-dram.h" + +#define DBSC5_PHYNUM_CNT 8 +#define DBSC5_DBSC_CNT 8 +#define DBSC5_PLL3_CNT 4 + +/* Minimum value table for JS1 configuration table that can be taken */ +#define JS1_USABLEC_SPEC_LO 5 +/* Maximum value table for JS1 configuration table that can be taken */ +#define JS1_USABLEC_SPEC_HI 14 +/* The number of JS1 setting table */ +#define JS1_FREQ_TBL_NUM 15 +/* Macro to set the value of MR1 */ +#define JS1_MR1(f) ((f) << 4) /* CK mode = 0B */ +/* Macro to set the value of MR2 */ +#define JS1_MR2(f) (((f) << 4) | (f)) + +#define JS2_tSR 0 /* Element for self refresh */ +#define JS2_tXP 1 /* Exit power-down mode to first valid command */ +#define JS2_tRCD 2 /* Active to read or write delay */ +#define JS2_tRPpb 3 /* Minimum Row Precharge Delay Time */ +#define JS2_tRPab 4 /* Minimum Row Precharge Delay Time */ +#define JS2_tRAS 5 /* ACTIVE-to-PRECHARGE command */ +#define JS2_tWTR_S 6 /* Internal WRITE-to-READ command delay */ +#define JS2_tWTR_L 7 /* Internal WRITE-to-READ command delay */ +#define JS2_tRRD 8 /* Active bank a to active bank b command */ +#define JS2_tPPD 9 /* Precharge Power Down */ +#define JS2_tFAW 10 /* Four bank ACT window */ +#define JS2_tMRR 11 /* Mode Register Read */ +#define JS2_tMRW 12 /* Mode Register Write */ +#define JS2_tMRD 13 /* LOAD MODE REGISTER command cycle time */ +#define JS2_tZQCALns 14 /* ZQ Calibration */ +#define JS2_tZQLAT 15 /* ZQ Latency */ +#define JS2_tODTon_min 16 /* Minimum time on die termination */ +#define JS2_tPDN_DSM 17 /* Recommended minimum time for Deep Sleep Mode duration */ +#define JS2_tXSR_DSM 18 /* Required time to be fully re-powered up from Deep Sleep Mode */ +#define JS2_tXDSM_XP 19 /* Delay from Deep Sleep Mode Exit to Power-Down Exit */ +#define JS2_tWCK2DQI_HF 20 /* Setting value of DQ to WCK input offset */ +#define JS2_tWCK2DQO_HF 21 /* Setting value of WCK to DQ output offset */ +#define JS2_tWCK2DQI_LF 22 /* Setting value of DQ to WCK input offset */ +#define JS2_tWCK2DQO_LF 23 /* Setting value of WCK to DQ output offset */ +#define JS2_tOSCODQI 24 /* Delay time from Stop WCK2DQI Interval Oscillator command to Mode Register Readout */ +#define JS2_tOSCODQO 25 +#define JS2_tDQ72DQns 26 /* Reception time to change the value fof REF(CA) for Command Bus Training Mode2 */ +#define JS2_tCAENTns 27 /* Reception time to change the value fof REF(CA) for Command Bus Training Mode1 */ +#define JS2_tCSCAL 28 /* Minimum CA Low Duration time */ +#define JS2_tWCKSTOP 29 +#define JS2_tpbR2act 30 +#define JS2_TBLCNT 31 /* The number of table */ + +#define JS2_tRCpb JS2_TBLCNT /* ACTIVATE-to-ACTIVATE command period with per bank precharge */ +#define JS2_tRCab (JS2_TBLCNT + 1) /* ACTIVATE-to-ACTIVATE command period with all bank precharge */ +#define JS2_tRFCab (JS2_TBLCNT + 2) /* Refresh Cycle Time with All Banks */ +#define JS2_tRBTP (JS2_TBLCNT + 3) /* READ Burst end to PRECHARGE command delay */ +#define JS2_tXSR (JS2_TBLCNT + 4) /* Exit Self Refresh to Valid commands */ +#define JS2_tPDN (JS2_TBLCNT + 5) +#define JS2_tWLWCKOFF (JS2_TBLCNT + 6) +#define JS2_tRFCpb (JS2_TBLCNT + 7) +#define JS2_tpbR2pbR (JS2_TBLCNT + 8) +#define JS2_tRFMab (JS2_TBLCNT + 9) +#define JS2_tRFMpb (JS2_TBLCNT + 10) +#define JS2_CNT (JS2_TBLCNT + 11) + +#define JS2_DERATE 0 +#define DBSC_REFINT 1920 +#define PERIODIC_TRAINING_INTERVAL 20000 + +#define DBMEMCONF_REG(d3, row, BG, bank, col, dw) \ + (((d3) << 30) | ((row) << 24) | ((BG) << 20) | \ + ((bank) << 16) | ((col) << 8) | (dw)) + +#define DBMEMCONF_REGD(density) \ + (DBMEMCONF_REG(((density) % 2), (((density) + 1) / 2) + (28 - 2 - 2 - 10 - 1), \ + 2, 2, 10, 1)) + +struct jedec_spec1 { + u32 fx3; + u32 RLset0; + u32 RLset1; + u32 RLset2; + u32 WLsetA; + u32 WLsetB; + u32 nWR; + u32 nRBTP; + u32 ODTLon; + u32 MR1; + u32 MR2; + u32 WCKENLR0; + u32 WCKENLR1; + u32 WCKENLW; + u32 WCKENLF; + u32 WCKPRESTA; + u32 WCKPRETGLR; + u32 tRRD; + u32 tFAW; +}; + +static const struct jedec_spec1 js1[JS1_FREQ_TBL_NUM] = { + /* fx3,RL0,RL1,RL2,WLA.WLB.nWR.nRBTP,ODTLon */ + { 800, 3, 3, 3, 2, 2, 3, 0, 1, JS1_MR1(0), JS1_MR2(0), 0, 0, 0, 0, 1, 3, 3750, 15000 }, /* 533.333Mbps */ + { 1600, 4, 4, 4, 2, 3, 5, 0, 1, JS1_MR1(1), JS1_MR2(1), 0, 0, 0, 0, 1, 4, 3750, 15000 }, /* 1066.666Mbps */ + { 2400, 5, 5, 6, 3, 4, 7, 0, 2, JS1_MR1(2), JS1_MR2(2), 1, 1, 1, 1, 1, 4, 3750, 15000 }, /* 1600.000Mbps */ + { 3200, 6, 7, 7, 4, 5, 10, 0, 2, JS1_MR1(3), JS1_MR2(3), 1, 2, 1, 1, 2, 4, 3750, 15000 }, /* 2133.333Mbps */ + { 4000, 8, 8, 9, 4, 7, 12, 1, 2, JS1_MR1(4), JS1_MR2(4), 2, 2, 1, 1, 2, 5, 3750, 15000 }, /* 2666.666Mbps */ + { 4800, 9, 10, 10, 5, 8, 14, 1, 3, JS1_MR1(5), JS1_MR2(5), 3, 4, 2, 1, 2, 5, 3750, 15000 }, /* 3200.000Mbps */ + { 5600, 10, 11, 12, 6, 9, 16, 2, 4, JS1_MR1(6), JS1_MR2(6), 3, 4, 2, 1, 3, 5, 3750, 15000 }, /* 3733.333Mbps */ + { 6400, 12, 13, 14, 6, 11, 19, 2, 3, JS1_MR1(7), JS1_MR2(7), 4, 5, 2, 1, 3, 6, 3750, 15000 }, /* 4266.666Mbps */ + { 7200, 13, 14, 15, 7, 12, 21, 3, 4, JS1_MR1(8), JS1_MR2(8), 5, 6, 3, 2, 3, 6, 3750, 15000 }, /* 4800.000Mbps */ + { 8250, 15, 16, 17, 8, 14, 24, 4, 5, JS1_MR1(9), JS1_MR2(9), 6, 7, 3, 2, 4, 6, 3750, 15000 }, /* 5500.000Mbps */ + { 9000, 16, 17, 19, 9, 15, 26, 4, 6, JS1_MR1(10), JS1_MR2(10), 6, 7, 4, 2, 4, 7, 3750, 15000 }, /* 6000.000Mbps */ + { 9600, 17, 18, 20, 9, 16, 28, 4, 6, JS1_MR1(11), JS1_MR2(11), 7, 8, 4, 2, 4, 7, 3750, 15000 }, /* 6400.000Mbps */ + { 11250, 20, 22, 24, 11, 19, 32, 6, 7, JS1_MR1(12), JS1_MR2(12), 7, 9, 5, 3, 5, 9, 3750, 15000 }, /* 7500.000Mbps */ + { 12800, 23, 25, 26, 12, 22, 37, 6, 8, JS1_MR1(13), JS1_MR2(13), 8, 10, 5, 3, 6, 10, 3750, 15000 }, /* 8533.333Mbps */ + { 14400, 25, 28, 29, 14, 24, 41, 7, 9, JS1_MR1(14), JS1_MR2(14), 8, 11, 6, 3, 7, 11, 3330, 13320 } /* 9600.000Mbps */ +}; + +struct jedec_spec2 { + u32 ps; + u32 cyc; +}; + +static const struct jedec_spec2 jedec_spec2[2][JS2_TBLCNT] = { + { + { 15000, 2 }, /* tSR */ + { 7000, 3 }, /* tXP */ + { 18000, 2 }, /* tRCD */ + { 18000, 2 }, /* tRPpb */ + { 21000, 2 }, /* tRPab */ + { 42000, 3 }, /* tRAS */ + { 6250, 4 }, /* tWTR_S */ + { 12000, 4 }, /* tWTR_L */ + { 0, 2 }, /* tRRD */ + { 0, 2 }, /* tPPD */ + { 0, 0 }, /* tFAW */ + { 0, 4 }, /* tMRR */ + { 10000, 5 }, /* tMRW */ + { 14000, 5 }, /* tMRD */ + { 1500, 0 }, /* tZQCALns */ + { 30000, 4 }, /* tZQLAT */ + { 1500, 0 }, /* tODTon_min */ + { 4000, 0 }, /* tPDN_DSMus */ + { 200, 0 }, /* tXSR_DSMus */ + { 190, 0 }, /* tXDSM_XPus */ + { 700, 0 }, /* tWCK2DQI_HF */ + { 1600, 0 }, /* tWCK2DQO_HF */ + { 900, 0 }, /* tWCK2DQI_LF */ + { 1900, 0 }, /* tWCK2DQO_LF */ + { 40000, 8 }, /* tOSCODQI */ + { 40000, 8 }, /* tOSCODQO */ + { 125, 0 }, /* tDQ72DQns */ + { 250, 0 }, /* tCAENTns */ + { 1750, 0 }, /* tCSCAL */ + { 6000, 2 }, /* tWCKSTOP */ + { 7500, 0 }, /* tpbR2act */ + }, { + { 15000, 2 }, /* tSR */ + { 7000, 3 }, /* tXP */ + { 19875, 2 }, /* tRCD */ + { 19875, 2 }, /* tRPpb */ + { 22875, 2 }, /* tRPab */ + { 43875, 3 }, /* tRAS */ + { 6250, 4 }, /* tWTR_S */ + { 12000, 4 }, /* tWTR_L */ + { 0, 2 }, /* tRRD */ + { 0, 2 }, /* tPPD */ + { 0, 0 }, /* tFAW */ + { 0, 4 }, /* tMRR */ + { 10000, 5 }, /* tMRW */ + { 14000, 5 }, /* tMRD */ + { 1500, 0 }, /* tZQCALns */ + { 30000, 4 }, /* tZQLAT */ + { 1500, 0 }, /* tODTon_min */ + { 4000, 0 }, /* tPDN_DSMus */ + { 200, 0 }, /* tXSR_DSMus */ + { 190, 0 }, /* tXDSM_XPus */ + { 715, 0 }, /* tWCK2DQI_HF */ + { 1635, 0 }, /* tWCK2DQO_HF */ + { 920, 0 }, /* tWCK2DQI_LF */ + { 1940, 0 }, /* tWCK2DQO_LF */ + { 40000, 8 }, /* tOSCODQI */ + { 40000, 8 }, /* tOSCODQO */ + { 125, 0 }, /* tDQ72DQns */ + { 250, 0 }, /* tCAENTns */ + { 1750, 0 }, /* tCSCAL */ + { 6000, 2 }, /* tWCKSTOP */ + { 7500, 0 }, /* tpbR2act */ + } +}; + +static const u32 jedec_spec2_tRFC_ab[9] = { + /* 2Gb, 3Gb, 4Gb, 6Gb, 8Gb, 12Gb, 16Gb, 24Gb, 32Gb */ + 130, 180, 180, 210, 210, 280, 280, 380, 380 +}; + +static const u32 jedec_spec2_tRFC_pb[9] = { + /* 2Gb, 3Gb, 4Gb, 6Gb, 8Gb, 12Gb, 16Gb, 24Gb, 32Gb */ + 60, 90, 90, 120, 120, 140, 140, 190, 190 +}; + +static const u32 jedec_spec2_tpbR2pbR[9] = { + /* 2Gb, 3Gb, 4Gb, 6Gb, 8Gb, 12Gb, 16Gb, 24Gb, 32Gb */ + 60, 90, 90, 90, 90, 90, 90, 90, 90 +}; + +static const u32 jedec_spec2_tRFM_ab[9] = { + /* 2Gb, 3Gb, 4Gb, 6Gb, 8Gb, 12Gb, 16Gb, 24Gb, 32Gb */ + 0, 0, 0, 0, 210, 280, 280, 380, 380 +}; + +static const u32 jedec_spec2_tRFM_pb[9] = { + /* 2Gb, 3Gb, 4Gb, 6Gb, 8Gb, 12Gb, 16Gb, 24Gb, 32Gb */ + 0, 0, 0, 0, 170, 190, 190, 260, 260 +}; + +/* System registers */ +#define SYSSS_TOP_BASE 0xc6480000 +#define SYSSS_ZB3CKCR0 (SYSSS_TOP_BASE + 0x10a0) +#define SYSSS_ZB3CKCR1 (SYSSS_TOP_BASE + 0x10a4) +#define SYSSS_ZB3CKCR_KICK BIT(31) +#define SYSSS_ZB3CKCR_PHYx(ch) ((0x7 * ((ch) & 0x1)) + (0x8 * ((ch) & 0x2))) +#define SYSSS_PLL1_1_CR0 (SYSSS_TOP_BASE + 0x1114) +#define SYSSS_PLL1_1DCR (SYSSS_TOP_BASE + 0x127c) +#define SYSSS_PLL3_x_CR0(ch) (SYSSS_TOP_BASE + 0x1180 + ((ch) * 0xc)) +#define SYSSS_PLL3_x_CR1(ch) (SYSSS_TOP_BASE + 0x1184 + ((ch) * 0xc)) +#define SYSSS_PLL3_x_CR2(ch) (SYSSS_TOP_BASE + 0x1188 + ((ch) * 0xc)) +#define SYSSS_PLL3_x_DCR(ch) (SYSSS_TOP_BASE + 0x12c4 + ((ch) * 0x8)) +#define SYSSS_PLL6_CR0 (SYSSS_TOP_BASE + 0x11c8) +#define SYSSS_PLL3_xSCR(ch) (SYSSS_TOP_BASE + 0x12c0 + ((ch) * 0x8)) +#define SYSSS_CLKTOPPKCPROT0 (SYSSS_TOP_BASE + 0x1370) +#define CLK_DIV(a, diva, b, divb) (((a) * (divb)) / ((b) * (diva))) + +/* MDLC registers */ +#define MODULE_CONTROL_DDRx_BASE(ch) (0xe8000000 + ((ch) * 0x80000)) +#define MODULE_CONTROL_DDRFI_BASE 0xc6480000 +#define MODULE_CONTROL_MDLC12PKCPROT1 (MODULE_CONTROL_DDRFI_BASE + 0xCF4) +#define MODULE_CONTROL_MDLC0xPKCPROT1(ch) (MODULE_CONTROL_DDRx_BASE(ch) + 0xCF4) +#define MODULE_CONTROL_MDLC15MSRES8 (MODULE_CONTROL_DDRFI_BASE + 0x920) +#define MODULE_CONTROL_MDLC0xMSRES1(ch) (MODULE_CONTROL_DDRx_BASE(ch) + 0x904) +#define MODULE_CONTROL_MDLC0xMSRES3(ch) (MODULE_CONTROL_DDRx_BASE(ch) + 0x90C) +#define MODULE_CONTROL_MDLC15MSRESS8 (MODULE_CONTROL_DDRFI_BASE + 0x980) +#define MODULE_CONTROL_MDLC0xMSRESS1(ch) (MODULE_CONTROL_DDRx_BASE(ch) + 0x964) +#define MODULE_CONTROL_MDLC0xMSRESS3(ch) (MODULE_CONTROL_DDRx_BASE(ch) + 0x96C) +#define MODULE_STANDBY 0 +#define MODULE_RUN 3 + +/* DBSC5 registers */ +#define DBSC_A_BASE 0xE9800000 +#define DBSC_D_BASE 0xE9900000 + +#define DBSC_DBSYSCONF0 (DBSC_A_BASE + 0x0) +#define DBSC_DBSYSCONF1 (DBSC_D_BASE + 0x0) +#define DBSC_DBSYSCONF1A (DBSC_A_BASE + 0x4) +#define DBSC_DBSYSCONF2 (DBSC_D_BASE + 0x4) +#define DBSC_DBPHYCONF0 (DBSC_D_BASE + 0x8) +#define DBSC_DBSYSCONF2A (DBSC_A_BASE + 0x8) +#define DBSC_DBMEMKIND (DBSC_D_BASE + 0x20) +#define DBSC_DBMEMKINDA (DBSC_A_BASE + 0x20) +#define DBSC_DBMEMCONF(ch, cs) \ + (DBSC_D_BASE + 0x30 + (0x2000 * ((ch) & 0xE)) + (0x10 * ((ch) & 0x1)) + (0x4 * (cs))) +#define DBSC_DBMEMCONFA(ch, cs) \ + (DBSC_A_BASE + 0x30 + (0x4000 * ((ch) & 0xE)) + (0x10 * ((ch) & 0x1)) + (0x4 * (cs))) +#define DBSC_DBSYSCNT0 (DBSC_D_BASE + 0x100) +#define DBSC_DBSYSCNT0A (DBSC_A_BASE + 0x100) +#define DBSC_DBSYSCNT1A (DBSC_A_BASE + 0x104) +#define DBSC_DBACEN (DBSC_A_BASE + 0x200) +#define DBSC_DBRFEN (DBSC_D_BASE + 0x204) +#define DBSC_DBCMD (DBSC_D_BASE + 0x208) +#define DBSC_DBWAIT (DBSC_D_BASE + 0x210) +#define DBSC_DBTR(x) (DBSC_D_BASE + 0x300 + (0x4 * (x))) +#define DBSC_DBBL (DBSC_D_BASE + 0x400) +#define DBSC_DBBLA (DBSC_A_BASE + 0x400) +#define DBSC_DBRFCNF1 (DBSC_D_BASE + 0x414) +#define DBSC_DBRFCNF2 (DBSC_D_BASE + 0x418) +#define DBSC_DBCALCNF (DBSC_D_BASE + 0x424) +#define DBSC_DBSNOOPC (DBSC_D_BASE + 0x42C) +#define DBSC_DBRNK(x) (DBSC_D_BASE + 0x430 + (0x4 * (x))) +#define DBSC_DBDBICNT (DBSC_D_BASE + 0x518) +#define DBSC_DBDFIPMSTRCNF (DBSC_D_BASE + 0x520) +#define DBSC_DBDFICUPDCNF (DBSC_D_BASE + 0x540) +#define DBSC_DBDFISTAT(ch) \ + (DBSC_D_BASE + 0x600 + (0x2000 * ((ch) & 0xE)) + (0x40 * ((ch) & 0x1))) +#define DBSC_DBDFICNT(ch) \ + (DBSC_D_BASE + 0x604 + (0x2000 * ((ch) & 0xE)) + (0x40 * ((ch) & 0x1))) +#define DBSC_DBPDSTAT01(ch) (DBSC_D_BASE + 0x634 + (0x4000 * (ch))) +#define DBSC_DBBUS0CNF1 (DBSC_A_BASE + 0x804) +#define DBSC_DBBCAMDIS (DBSC_A_BASE + 0x9FC) +#define DBSC_DBSCHRW(x) (DBSC_A_BASE + 0x1020 + (0x4 * (x))) +#define DBSC_DBSCHTR0 (DBSC_A_BASE + 0x1030) +#define DBSC_DBSCHFCTST(x) (DBSC_A_BASE + 0x1040 + (0x4 * (x))) + +/* DDR PHY registers */ +#define DDR_PHY_BASE(ch) (0xA0000000 + (0x1000000 * (ch))) +#define DDR_PHY_DMA_TRANS_BASE(ch) (0xE0000000 + (0x1000000 * (ch))) + +#define PHY_HMAC_BASE(n) ((n) * 0x1000) +#define PHY_HMAC_TXSLEWAC(n) (PHY_HMAC_BASE(n) + 0x6d) +#define PHY_HMAC_TXIMPEDANCEAC(n) (PHY_HMAC_BASE(n) + 0x70) +#define PHY_HMAC_ODTIMPEDANCEAC(n) (PHY_HMAC_BASE(n) + 0x79) + +#define PHY_DBYTE_BASE(n) (0x10000 + ((n) * 0x1000)) +#define PHY_DBYTE_ENABLEWRITELINKECC(n) (PHY_DBYTE_BASE(n) + 0x01) +#define PHY_DBYTE_DQ0LNSEL(n) (PHY_DBYTE_BASE(n) + 0x80) +#define PHY_DBYTE_DQ1LNSEL(n) (PHY_DBYTE_BASE(n) + 0x81) +#define PHY_DBYTE_DQ2LNSEL(n) (PHY_DBYTE_BASE(n) + 0x82) +#define PHY_DBYTE_DQ3LNSEL(n) (PHY_DBYTE_BASE(n) + 0x83) +#define PHY_DBYTE_DQ4LNSEL(n) (PHY_DBYTE_BASE(n) + 0x84) +#define PHY_DBYTE_DQ5LNSEL(n) (PHY_DBYTE_BASE(n) + 0x85) +#define PHY_DBYTE_DQ6LNSEL(n) (PHY_DBYTE_BASE(n) + 0x86) +#define PHY_DBYTE_DQ7LNSEL(n) (PHY_DBYTE_BASE(n) + 0x87) +#define PHY_DBYTE_DQ8LNSEL(n) (PHY_DBYTE_BASE(n) + 0x88) +#define PHY_DBYTE_PPTCTLSTATIC(n) (PHY_DBYTE_BASE(n) + 0xa3) + +#define PHY_AC_BASE(n) (0x30000 + ((n) * 0x1000)) +#define PHY_AC_MAPCA0TODFI(n) (PHY_AC_BASE(n) + 0x90) +#define PHY_AC_MAPCA1TODFI(n) (PHY_AC_BASE(n) + 0x91) +#define PHY_AC_MAPCA2TODFI(n) (PHY_AC_BASE(n) + 0x92) +#define PHY_AC_MAPCA3TODFI(n) (PHY_AC_BASE(n) + 0x93) +#define PHY_AC_MAPCA4TODFI(n) (PHY_AC_BASE(n) + 0x94) +#define PHY_AC_MAPCA5TODFI(n) (PHY_AC_BASE(n) + 0x95) +#define PHY_AC_MAPCA6TODFI(n) (PHY_AC_BASE(n) + 0x96) +#define PHY_AC_ACLNDISABLE(n) (PHY_AC_BASE(n) + 0xac) +#define PHY_AC_DFICLKACLNDIS(n) (PHY_AC_BASE(n) + 0xad) +#define PHY_AC_PCLKACLNDIS(n) (PHY_AC_BASE(n) + 0xae) + +#define PHY_APB_BASE 0x58000 +#define PHY_APB_DRAMFREQ (PHY_APB_BASE + 0x01) +#define PHY_APB_DCAOPTS (PHY_APB_BASE + 0x02) +#define PHY_APB_SEQUENCECTRL (PHY_APB_BASE + 0x04) +#define PHY_APB_HDTCTRL (PHY_APB_BASE + 0x04) +#define PHY_APB_RXDFEOPT (PHY_APB_BASE + 0x07) +#define PHY_APB_CSPRESENTCHA (PHY_APB_BASE + 0x09) +#define PHY_APB_CSPRESENTCHB (PHY_APB_BASE + 0x10) +#define PHY_APB_MR1_A0 (PHY_APB_BASE + 0x16) +#define PHY_APB_MR1_A1 (PHY_APB_BASE + 0x16) +#define PHY_APB_MR1_B0 (PHY_APB_BASE + 0x17) +#define PHY_APB_MR1_B1 (PHY_APB_BASE + 0x17) +#define PHY_APB_MR2_A0 (PHY_APB_BASE + 0x17) +#define PHY_APB_MR2_A1 (PHY_APB_BASE + 0x17) +#define PHY_APB_MR2_B0 (PHY_APB_BASE + 0x18) +#define PHY_APB_MR2_B1 (PHY_APB_BASE + 0x18) +#define PHY_APB_MR3_A0 (PHY_APB_BASE + 0x18) +#define PHY_APB_MR3_A1 (PHY_APB_BASE + 0x18) +#define PHY_APB_MR3_B0 (PHY_APB_BASE + 0x19) +#define PHY_APB_MR3_B1 (PHY_APB_BASE + 0x19) +#define PHY_APB_MR11_A0 (PHY_APB_BASE + 0x1A) +#define PHY_APB_MR11_A1 (PHY_APB_BASE + 0x1A) +#define PHY_APB_MR11_B0 (PHY_APB_BASE + 0x1B) +#define PHY_APB_MR11_B1 (PHY_APB_BASE + 0x1B) +#define PHY_APB_MR12_A0 (PHY_APB_BASE + 0x1B) +#define PHY_APB_MR12_A1 (PHY_APB_BASE + 0x1B) +#define PHY_APB_MR12_B0 (PHY_APB_BASE + 0x1C) +#define PHY_APB_MR12_B1 (PHY_APB_BASE + 0x1C) +#define PHY_APB_MR22_A0 (PHY_APB_BASE + 0x25) +#define PHY_APB_MR22_A1 (PHY_APB_BASE + 0x25) +#define PHY_APB_MR22_B0 (PHY_APB_BASE + 0x26) +#define PHY_APB_MR22_B1 (PHY_APB_BASE + 0x26) +#define PHY_APB_MR24_A0 (PHY_APB_BASE + 0x26) +#define PHY_APB_MR24_A1 (PHY_APB_BASE + 0x26) +#define PHY_APB_MR24_B0 (PHY_APB_BASE + 0x27) +#define PHY_APB_MR24_B1 (PHY_APB_BASE + 0x27) +#define PHY_APB_MR41_A0 (PHY_APB_BASE + 0x32) +#define PHY_APB_MR41_A1 (PHY_APB_BASE + 0x32) +#define PHY_APB_MR41_B0 (PHY_APB_BASE + 0x33) +#define PHY_APB_MR41_B1 (PHY_APB_BASE + 0x33) +#define PHY_APB_MR58_A0 (PHY_APB_BASE + 0x34) +#define PHY_APB_MR58_A1 (PHY_APB_BASE + 0x34) +#define PHY_APB_MR58_B0 (PHY_APB_BASE + 0x35) +#define PHY_APB_MR58_B1 (PHY_APB_BASE + 0x35) +#define PHY_APB_TXDFETRAINOPT (PHY_APB_BASE + 0x3E) +#define PHY_APB_UPPERLOWERBYTE (PHY_APB_BASE + 0x48) +#define PHY_APB_ALT_RL (PHY_APB_BASE + 0x48) +#define PHY_APB_MAIN_RL (PHY_APB_BASE + 0x49) +#define PHY_APB_RXVREFSTARTPAT (PHY_APB_BASE + 0x4E) +#define PHY_APB_RXVREFSTARTPRBS (PHY_APB_BASE + 0x4E) +#define PHY_APB_RXVREFENDPAT (PHY_APB_BASE + 0x4F) +#define PHY_APB_RXVREFENDPRBS (PHY_APB_BASE + 0x4F) +#define PHY_APB_RXVREFSTEPPAT (PHY_APB_BASE + 0x50) +#define PHY_APB_TXVREFSTART (PHY_APB_BASE + 0x50) +#define PHY_APB_TXVREFEND (PHY_APB_BASE + 0x50) +#define PHY_APB_TXVREFSTEP (PHY_APB_BASE + 0x51) +#define PHY_APB_RXVREFSTEPPRBS (PHY_APB_BASE + 0x51) +#define PHY_APB_RXDFEBITTIMECONTROL (PHY_APB_BASE + 0x59) + +#define PHY_HMMAS_BASE 0x60000 +#define PHY_HMMAS_CPLLCTRL1 (PHY_HMMAS_BASE + 0x05) +#define PHY_HMMAS_CPLLCTRL4 (PHY_HMMAS_BASE + 0x07) +#define PHY_HMMAS_CPLLCTRL5 (PHY_HMMAS_BASE + 0x08) +#define PHY_HMMAS_CPLLUPLLPROG0 (PHY_HMMAS_BASE + 0x0d) +#define PHY_HMMAS_CPLLUPLLPROG1 (PHY_HMMAS_BASE + 0x0e) +#define PHY_HMMAS_CPLLUPLLPROG2 (PHY_HMMAS_BASE + 0x0f) +#define PHY_HMMAS_CPLLUPLLPROG3 (PHY_HMMAS_BASE + 0x10) + +#define PHY_PPGC_BASE 0x70000 +#define PHY_PPGC_ACSMDONE (PHY_PPGC_BASE + 0x121) +#define PHY_PPGC_ACSMSTARTADDRXLATVAL0 (PHY_PPGC_BASE + 0x324) +#define PHY_PPGC_ACSMSTOPADDRXLATVAL0 (PHY_PPGC_BASE + 0x38b) +#define PHY_PPGC_HWTLPCSENA (PHY_PPGC_BASE + 0x072) +#define PHY_PPGC_HWTLPCSENB (PHY_PPGC_BASE + 0x073) +#define PHY_PPGC_HWTCONTROLVAL (PHY_PPGC_BASE + 0x07e) +#define PHY_PPGC_ACSMRPTCNTOVERRIDE (PHY_PPGC_BASE + 0x145) +#define PHY_PPGC_ACSMNOPADDR (PHY_PPGC_BASE + 0x18a) + +#define PHY_INITENG_BASE 0x90000 +#define PHY_INITENG_SEQ0BDISABLEFLAG0 (PHY_INITENG_BASE + 0x70c) +#define PHY_INITENG_SEQ0BGPR1 (PHY_INITENG_BASE + 0x801) +#define PHY_INITENG_SEQ0BDLY0 (PHY_INITENG_BASE + 0x8e0) +#define PHY_INITENG_SEQ0BGPR14 (PHY_INITENG_BASE + 0x80e) +#define PHY_INITENG_SEQ0BGPR15 (PHY_INITENG_BASE + 0x80f) + +#define PHY_DRTUB_BASE 0xc0000 +#define PHY_DRTUB_PIEINITVECSEL (PHY_DRTUB_BASE + 0x01) +#define PHY_DRTUB_UCCLKHCLKENABLES (PHY_DRTUB_BASE + 0x80) +#define PHY_DRTUB_STARTDCCMCLEAR (PHY_DRTUB_BASE + 0x88) + +#define PHY_APBONLY_BASE 0xd0000 +#define PHY_APBONLY_MICROCONTMUXSEL (PHY_APBONLY_BASE + 0x00) +#define PHY_APBONLY_UCTSHADOWREGS (PHY_APBONLY_BASE + 0x04) +#define PHY_APBONLY_DCTWRITEPROT (PHY_APBONLY_BASE + 0x31) +#define PHY_APBONLY_UCTWRITEONLYSHADOW (PHY_APBONLY_BASE + 0x32) +#define PHY_APBONLY_UCTDATWRITEONLYSHADOW (PHY_APBONLY_BASE + 0x34) +#define PHY_APBONLY_MICRORESET (PHY_APBONLY_BASE + 0x99) +#define PHY_APBONLY_SEQUENCEROVERRIDE (PHY_APBONLY_BASE + 0xe7) + +#define PHY_HMDBYTE_BASE(n) (0xe0000 + ((n) * 0x1000)) +#define PHY_HMDBYTE_VREGCTRL1DQ(n) (PHY_HMDBYTE_BASE(n) + 0x00) +#define PHY_HMDBYTE_TXDQSLEW(n) (PHY_HMDBYTE_BASE(n) + 0x1c) +#define PHY_HMDBYTE_TXIMPEDANCEDQ(n) (PHY_HMDBYTE_BASE(n) + 0x2c) +#define PHY_HMDBYTE_TXIMPEDANCEDQS(n) (PHY_HMDBYTE_BASE(n) + 0x2d) +#define PHY_HMDBYTE_ODTIMPEDANCEDQ(n) (PHY_HMDBYTE_BASE(n) + 0x2e) +#define PHY_HMDBYTE_ODTIMPEDANCEDQS(n) (PHY_HMDBYTE_BASE(n) + 0x2f) + +/* RENESAS X5H Board (64Gb 1rank x 4pcs) */ +static const struct renesas_dbsc5_board_config renesas_x5h_dbsc5_board_config = { + .bdcfg_phyvalid = 0xffff, + .bdcfg_tx_drv = 0x77777, + .bdcfg_tx_ffc = 0x30000000, + .bdcfg_rx_odt = 0x33333, + .bdcfg_rx_dfe = 0x0, + .bdcfg_tx_odt = 0x43, + .bdcfg_tx_ntodt = 0x3, + .bdcfg_tx_dfe = 0x0, + .bdcfg_rx_dca = 0x1, + .bdcfg_rx_drv = 0x6, + .bdcfg_rx_emphasis = 0x0, + .bdcfg_tx_dca = 0x1, + .bdcfg_ca_vref = 0x2e, + .bdcfg_rx_vref = 0xff001e, + .bdcfg_rx_vref_step = 0xf, + .bdcfg_tx_vref = 0x56e0a, + .bdcfg_rfm_chk = 0x1, + .ch = { + [0] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x2641350, + .bdcfg_dqs_swap = 0x1, + .bdcfg_dq_swap = { 0x47583016, 0x85013247 }, + .bdcfg_dm_swap = { 0x2, 0x6 }, + }, + [1] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x3265410, + .bdcfg_dqs_swap = 0x10, + .bdcfg_dq_swap = { 0x54263701, 0x84650312 }, + .bdcfg_dm_swap = { 0x8, 0x7 }, + }, + [2] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x1240635, + .bdcfg_dqs_swap = 0x1, + .bdcfg_dq_swap = { 0x56420713, 0x57802134 }, + .bdcfg_dm_swap = { 0x8, 0x6 }, + }, + [3] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x5462301, + .bdcfg_dqs_swap = 0x10, + .bdcfg_dq_swap = { 0x74560128, 0x58760312 }, + .bdcfg_dm_swap = { 0x3, 0x4 }, + }, + [4] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x4215306, + .bdcfg_dqs_swap = 0x1, + .bdcfg_dq_swap = { 0x45760138, 0x75803124 }, + .bdcfg_dm_swap = { 0x2, 0x6 }, + }, + [5] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x4065321, + .bdcfg_dqs_swap = 0x10, + .bdcfg_dq_swap = { 0x65420371, 0x78560213 }, + .bdcfg_dm_swap = { 0x8, 0x4 }, + }, + [6] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x4612035, + .bdcfg_dqs_swap = 0x1, + .bdcfg_dq_swap = { 0x25481730, 0x56703128 }, + .bdcfg_dm_swap = { 0x6, 0x4 }, + }, + [7] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x5023416, + .bdcfg_dqs_swap = 0x10, + .bdcfg_dq_swap = { 0x54783026, 0x41650238 }, + .bdcfg_dm_swap = { 0x1, 0x7 }, + }, + [8] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x521463, + .bdcfg_dqs_swap = 0x1, + .bdcfg_dq_swap = { 0x76453012, 0x85430127 }, + .bdcfg_dm_swap = { 0x8, 0x6 }, + }, + [9] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x5326041, + .bdcfg_dqs_swap = 0x10, + .bdcfg_dq_swap = { 0x43620781, 0x81653420 }, + .bdcfg_dm_swap = { 0x5, 0x7 }, + }, + [10] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x2104635, + .bdcfg_dqs_swap = 0x1, + .bdcfg_dq_swap = { 0x54763210, 0x75831062 }, + .bdcfg_dm_swap = { 0x8, 0x4 }, + }, + [11] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x3654021, + .bdcfg_dqs_swap = 0x10, + .bdcfg_dq_swap = { 0x74561082, 0x56473012 }, + .bdcfg_dm_swap = { 0x3, 0x8 }, + }, + [12] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x514362, + .bdcfg_dqs_swap = 0x1, + .bdcfg_dq_swap = { 0x45761032, 0x74830126 }, + .bdcfg_dm_swap = { 0x8, 0x5 }, + }, + [13] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x4523016, + .bdcfg_dqs_swap = 0x10, + .bdcfg_dq_swap = { 0x54763021, 0x58470312 }, + .bdcfg_dm_swap = { 0x8, 0x6 }, + }, + [14] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x2315064, + .bdcfg_dqs_swap = 0x1, + .bdcfg_dq_swap = { 0x43620718, 0x68134207 }, + .bdcfg_dm_swap = { 0x5, 0x5 }, + }, + [15] = { + .bdcfg_ddr_density = { 0x6, 0xff }, + .bdcfg_ca_swap = 0x6315042, + .bdcfg_dqs_swap = 0x10, + .bdcfg_dq_swap = { 0x47653082, 0x64583012 }, + .bdcfg_dm_swap = { 0x1, 0x7 }, + } + } +}; + +struct renesas_dbsc5_dram_priv { + void __iomem *regs; + + /* The board parameter structure of the board */ + const struct renesas_dbsc5_board_config *dbsc5_board_config; + + /* The board clock frequency */ + u32 brd_clk; + u32 brd_clkdiv; + u32 brd_clkdiva; + /* The Mbps of DDR */ + u32 ddr_mbps; + u32 ddr_mbpsdiv; + /* Value indicating the enabled channel */ + u32 ddr_phyvalid; + u32 ddr_dramvalid; + /* Channels used for each memory rank */ + u32 ch_have_this_cs[CS_CNT]; + u32 upper_lower_byte[DBSC5_PHYNUM_CNT]; + u32 link_ecc_en; + /* The maximum memory capacity */ + u32 max_density; + /* Index of jedec spec1 setting table you use */ + u32 js1_ind; +}; + +/** + * vch_nxt() - Macro for channel selection loop + * @dev: DBSC5 device + * @pos: Iterator position + * + * Return the ID of the channel to be used. Check for valid channels + * between the value of posn and the maximum number of CHs. If a valid + * channel is found, returns the value of that channel. + */ +static u32 vch_nxt(struct udevice *dev, u32 pos) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 posn; + + for (posn = pos; posn < DRAM_CH_CNT; posn++) + if (priv->ddr_dramvalid & BIT(posn)) + break; + + return posn; +} + +/** + * vphych_nxt() - Macro for PHY channel selection loop + * @dev: DBSC5 device + * @pos: Iterator position + * + * Return the ID of the channel to be used. Check for valid channels + * between the value of posn and the maximum number of CHs. If a valid + * channel is found, returns the value of that channel. + */ +static u32 vphych_nxt(struct udevice *dev, u32 pos) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 posn; + + for (posn = pos; posn < DBSC5_PHYNUM_CNT; posn++) + if (priv->ddr_phyvalid & BIT(posn)) + break; + + return posn; +} + +#define foreach_vch(dev, ch) \ + for ((ch) = vch_nxt((dev), 0); (ch) < DRAM_CH_CNT; (ch) = vch_nxt((dev), (ch) + 1)) + +#define foreach_vphych(dev, ch) \ + for ((ch) = vphych_nxt((dev), 0); (ch) < DBSC5_PHYNUM_CNT; (ch) = vphych_nxt((dev), (ch) + 1)) + +#define foreach_ech(ch) \ + for (ch = 0; ch < DRAM_CH_CNT; ch++) + +/** + * dbsc5_soft_delay() - Wait loop number of CPU cycles + * @loop: Number of cycles to wait + * + * This is a cycle counting approximate delay loop, used in very + * early code to wait for near future events. + */ +static void dbsc5_soft_delay(const int loop) +{ + int i; + + for (i = 0; i < loop; i++) + asm volatile("nop"); +} + +/** + * dbsc5_init_pll3() - Set PLL3 + * @dev: DBSC5 device + */ +static void dbsc5_init_pll3(struct udevice *dev) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 data_cr0, data_cr1, data_div, data_dcr_1st, data_dcr_2nd, data_dcr_3rd; + u32 ddr_mul, ddr_mul_div, ddr_mul_ni, ddr_mul_nf; + const int pll3_frac_mode_threshold = 9000; + u32 ssmode, pll3vco, pll3_valid = 0; + u32 ddr_zb3ckcr[DBSC5_PHYNUM_CNT]; + u32 zb3ckcr0, zb3ckcr1; + u32 fvv, ch; + + /* Calculate valid PLL3 channel */ + for (ch = 0; ch < DBSC5_PHYNUM_CNT; ch++) { + pll3_valid |= (((priv->ddr_phyvalid >> (ch * 2)) | + (priv->ddr_phyvalid >> ((ch * 2) + 1))) & 0x1) << ch; + } + + /* Calculate PLL3 settings */ + if (priv->ddr_mbps < (pll3_frac_mode_threshold * priv->ddr_mbpsdiv)) + ssmode = 4; + else + ssmode = 0; + + ddr_mul = CLK_DIV(priv->ddr_mbps, priv->ddr_mbpsdiv * 2, priv->brd_clk, + priv->brd_clkdiv * (priv->brd_clkdiva + 1)); + + /* PLL3VCO = EXTAL * ddr_mul */ + pll3vco = ddr_mul * priv->brd_clk / (priv->brd_clkdiv * (priv->brd_clkdiva + 1)); + + if (pll3vco < 3000) { /* div = 4 */ + data_div = 2; + pll3vco = pll3vco * 2; + ddr_mul = ddr_mul * 2; + ddr_mul_div = 2; + } else { /* div = 2 */ + data_div = 0; + ddr_mul_div = 1; + } + + /* + * PLL3VCO FVV + * 3000 - 4000 0 + * 3750 - 4900 1 + * 4600 - 5800 2 + * 5450 - 6200 3 + */ + if (pll3vco > 5800) + fvv = 3; + else if (pll3vco > 4900) + fvv = 2; + else if (pll3vco > 4000) + fvv = 1; + else + fvv = 0; + + ddr_mul_ni = (ddr_mul / 2) - 1; + if (priv->ddr_mbps < (pll3_frac_mode_threshold * priv->ddr_mbpsdiv)) { + ddr_mul_nf = ((8 * priv->ddr_mbps * priv->brd_clkdiv * (priv->brd_clkdiva + 1) * ddr_mul_div) / + (priv->ddr_mbpsdiv * 2 * priv->brd_clk)) - (8 * (ddr_mul_ni + 1) * 2); + } else { + ddr_mul_nf = 0; + } + + data_cr0 = (ddr_mul_ni << 20) | (ssmode << 16); + data_cr1 = (fvv << 26) | ddr_mul_nf; + + /* Gradually frequency change settings */ + data_dcr_1st = 0x18; + data_dcr_2nd = 0x10; + data_dcr_3rd = 0; + + /* Disable write protection */ + writel(0xa5a5a501, SYSSS_CLKTOPPKCPROT0); + while (!((readl(SYSSS_CLKTOPPKCPROT0)) & BIT(0))) + ; + + /* Clock change & setting PLL3_x_CR0 and PLL3_x_CR1 */ + for (ch = 0; ch < DBSC5_PLL3_CNT; ch++) { + if (!(pll3_valid & BIT(ch))) + continue; + + /* 1. Confirm that the PLL3_x are stable with PLLCLKSTAB */ + while (!(readl(SYSSS_PLL3_x_CR2(ch)) & BIT(31))) + ; + + /* 2-1. Select PLL3_0SELID to CLK_IOSC1 */ + writel(0x1, SYSSS_PLL3_xSCR(ch)); + /* 2-2. Confirm PLL3_0SELACT register to ID equals CLK_IOSC1 */ + while (((readl(SYSSS_PLL3_xSCR(ch))) & 0x10001) != 0x10001) + ; + + /* 3. Stop the PLL3_x (PLLDISTRG = 1) */ + writel(0x20000000, SYSSS_PLL3_x_CR2(ch)); + /* 4. Confirm that the PLL3_0 has been stopped (PLLCLKSTAB = 0) */ + while (readl(SYSSS_PLL3_x_CR2(ch)) & BIT(31)) + ; + + /* set PLL3_x_CR0 */ + clrsetbits_le32(SYSSS_PLL3_x_CR0(ch), 0x1ff70000, data_cr0); + /* set PLL3_x_CR1 */ + clrsetbits_le32(SYSSS_PLL3_x_CR1(ch), 0x0dffffff, data_cr1); + /* set PLL3_x_DCR */ + writel(data_dcr_1st, SYSSS_PLL3_x_DCR(ch)); + /* set PLL3_x_CR2 (PLLENTRG = 1) */ + writel(BIT(28), SYSSS_PLL3_x_CR2(ch)); + } + + /* Clock change */ + for (ch = 0; ch < DBSC5_PLL3_CNT; ch++) { + if (!(pll3_valid & BIT(ch))) + continue; + + /* 1. Confirm that the PLL3_0 have been stable (PLLCLKSTAB = 1) */ + while (!(readl(SYSSS_PLL3_x_CR2(ch)) & BIT(31))) + ; + + /* 2-1. Select PLL input clock by PLLSELID register */ + writel(0, SYSSS_PLL3_xSCR(ch)); + /* 2-2. Confirm that PLL3_0SELACT register becomes same value with PLL3_0SELID */ + while (readl(SYSSS_PLL3_xSCR(ch)) & 0x10001) + ; + } + + /* Set PLL3_DCR gradually */ + for (ch = 0; ch < DBSC5_PLL3_CNT; ch++) { + if (!(pll3_valid & BIT(ch))) + continue; + + /* Set PLL3_x_DCR */ + writel(data_dcr_2nd, SYSSS_PLL3_x_DCR(ch)); + /* Wait PLL3DIVSYNC is changed from 0 to 1 */ + while (!(readl(SYSSS_PLL3_x_DCR(ch)) & BIT(16))) + ; + } + + /* Wait until the current stabilizes */ + dbsc5_soft_delay(1000); + + for (ch = 0; ch < DBSC5_PLL3_CNT; ch++) { + if (!(pll3_valid & BIT(ch))) + continue; + + /* Set PLL3_x_DCR */ + writel(data_dcr_3rd, SYSSS_PLL3_x_DCR(ch)); + /* Wait PLL3DIVSYNC is changed from 0 to 1 */ + while (((readl(SYSSS_PLL3_x_DCR(ch))) & 0x10000) != 0x10000) + ; + } + + /* Wait until the current stabilizes */ + dbsc5_soft_delay(1000); + + /* Set PLL3 divider */ + zb3ckcr0 = readl(SYSSS_ZB3CKCR0); + zb3ckcr1 = readl(SYSSS_ZB3CKCR1); + for (ch = 0; ch < DBSC5_PHYNUM_CNT; ch++) { + if (priv->ddr_phyvalid & BIT(ch)) { + /* set FC[3:0] = data_div */ + ddr_zb3ckcr[ch] = data_div; + } else { + if (ch < 4) + ddr_zb3ckcr[ch] = (zb3ckcr0 >> SYSSS_ZB3CKCR_PHYx(ch)) & 0x1f; + else + ddr_zb3ckcr[ch] = (zb3ckcr1 >> SYSSS_ZB3CKCR_PHYx(ch)) & 0x1f; + } + } + + zb3ckcr0 = (ddr_zb3ckcr[3] << 23) | (ddr_zb3ckcr[2] << 16) | + (ddr_zb3ckcr[1] << 7) | ddr_zb3ckcr[0]; + zb3ckcr1 = (ddr_zb3ckcr[7] << 23) | (ddr_zb3ckcr[6] << 16) | + (ddr_zb3ckcr[5] << 7) | ddr_zb3ckcr[4]; + + /* Check ZB3CKCR0/1 KICK bit = 0 */ + while (readl(SYSSS_ZB3CKCR0) & SYSSS_ZB3CKCR_KICK) + ; + while (readl(SYSSS_ZB3CKCR1) & SYSSS_ZB3CKCR_KICK) + ; + + /* Set ZB3CKCR0/1 */ + writel(zb3ckcr0, SYSSS_ZB3CKCR0); + writel(zb3ckcr1, SYSSS_ZB3CKCR1); + + /* Set kickbit = 1 */ + setbits_le32(SYSSS_ZB3CKCR0, SYSSS_ZB3CKCR_KICK); + setbits_le32(SYSSS_ZB3CKCR1, SYSSS_ZB3CKCR_KICK); + + /* Wait ZB3CKCR0/1 KICK bit neg */ + while (readl(SYSSS_ZB3CKCR0) & SYSSS_ZB3CKCR_KICK) + ; + while (readl(SYSSS_ZB3CKCR1) & SYSSS_ZB3CKCR_KICK) + ; +} + +/** + * dbsc5_msres_sync_wait() - Wait for MSRES and MSRESS to synchronize + * @msres: MSRES register + * @msress: MSRESS register + */ +static void dbsc5_msres_sync_wait(u32 msres, u32 msress) +{ + while (readl(msres) != readl(msress)) + ; +} + +/** + * dbsc5_msres_status_set - Set DBSC5 into RUN or STANDBY mode + * @dev: DBSC5 device + * @status: RUN or STANDBY mode + */ +static void dbsc5_msres_status_set(struct udevice *dev, u32 status) +{ + u32 ch; + + foreach_vphych(dev, ch) { + /* + * Enable write access of protected registers + * dbq_reset / ddr_reset_apb / ddr_reset_hard / ddr_reset + */ + writel(0xa5a5a501, MODULE_CONTROL_MDLC0xPKCPROT1(ch)); + /* ddrfi */ + writel(0xa5a5a501, MODULE_CONTROL_MDLC12PKCPROT1); + + /* Check MDLCnMSRESS[i] = MDLCnMSRES[i] */ + /* dbq_reset */ + dbsc5_msres_sync_wait(MODULE_CONTROL_MDLC0xMSRES1(ch), + MODULE_CONTROL_MDLC0xMSRESS1(ch)); + + /* ddr_reset_apb / ddr_reset_hard / ddr_reset */ + dbsc5_msres_sync_wait(MODULE_CONTROL_MDLC0xMSRES3(ch), + MODULE_CONTROL_MDLC0xMSRESS3(ch)); + + /* ddrfi */ + dbsc5_msres_sync_wait(MODULE_CONTROL_MDLC15MSRES8, + MODULE_CONTROL_MDLC15MSRESS8); + + /* Set MDLCnMSRESx */ + /* dbq_reset */ + clrsetbits_le32(MODULE_CONTROL_MDLC0xMSRES1(ch), 0x3, status); + + /* ddr_reset_apb / ddr_reset_hard / ddr_reset */ + clrsetbits_le32(MODULE_CONTROL_MDLC0xMSRES3(ch), 0x3f, + (status << 4) | (status << 2) | status); + + /* ddrfi */ + clrsetbits_le32(MODULE_CONTROL_MDLC15MSRES8, 0x3 << (ch * 2), + status << (ch * 2)); + + /* Check MDLCnMSRESS[i] = MDLCnMSRES[i] */ + /* dbq_reset */ + dbsc5_msres_sync_wait(MODULE_CONTROL_MDLC0xMSRES1(ch), + MODULE_CONTROL_MDLC0xMSRESS1(ch)); + + /* ddr_reset_apb / ddr_reset_hard / ddr_reset */ + dbsc5_msres_sync_wait(MODULE_CONTROL_MDLC0xMSRES3(ch), + MODULE_CONTROL_MDLC0xMSRESS3(ch)); + + /* ddrfi */ + dbsc5_msres_sync_wait(MODULE_CONTROL_MDLC15MSRES8, + MODULE_CONTROL_MDLC15MSRESS8); + + /* Disables write access of protected registers */ + /* dbq_reset / ddr_reset_apb / ddr_reset_hard / ddr_reset */ + writel(0xa5a5a500, MODULE_CONTROL_MDLC0xPKCPROT1(ch)); + /* ddrfi */ + writel(0xa5a5a500, MODULE_CONTROL_MDLC12PKCPROT1); + } +} + +/** + * dbsc5_reg_write() - Write DBSC register + * @dev: DBSC5 device + * @addr: Destination address + * @data: Setting value to be written + * + * Write 32bit value @data to register at @addr . + */ +static void dbsc5_reg_write(struct udevice *dev, uintptr_t addr, u32 data) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + int i; + + for (i = 0; i < DBSC5_DBSC_CNT; i++) { + if (!(priv->ddr_phyvalid & BIT(i))) + continue; + + if ((addr & 0xFFF00000) == 0xE9900000) /* clk_dbsc region */ + writel(data, addr + (0x4000 * i)); + else /* clk_axim region */ + writel(data, addr + (0x8000 * i)); + } +} + +/** + * dbsc5_regset_unlock() - Unlock DBSC access + * @dev: DBSC5 device + */ +static void dbsc5_regset_unlock(struct udevice *dev) +{ + dbsc5_reg_write(dev, DBSC_DBSYSCNT0, 0x1234); + dbsc5_reg_write(dev, DBSC_DBSYSCNT0A, 0x1234); +} + +/** + * dbsc5_regset_lock() - Lock DBSC access + * @dev: DBSC5 device + */ +static void dbsc5_regset_lock(struct udevice *dev) +{ + dbsc5_reg_write(dev, DBSC_DBSYSCNT0, 0); + dbsc5_reg_write(dev, DBSC_DBSYSCNT0A, 0); +} + +/** + * dbsc5_send_dbcmd() - DRAM Command Write + * @dev: DBSC5 device + * @cmd: Command + */ +static void dbsc5_send_dbcmd(struct udevice *dev, u32 cmd) +{ + readl(DBSC_DBCMD); /* Dummy read */ + + while (readl(DBSC_DBWAIT) & BIT(0)) /* Wait for not busy */ + ; + + dbsc5_reg_write(dev, DBSC_DBCMD, cmd); +} + +/** + * dbsc5_send_dbcmd_ch() - DRAM Command Write on channel + * @ch: DBSC5 channel + * @cmd: Command + */ +static void dbsc5_send_dbcmd_ch(u32 ch, u32 cmd) +{ + readl(DBSC_DBCMD); /* Dummy read */ + + while (readl(DBSC_DBWAIT) & BIT(0)) /* Wait for not busy */ + ; + + writel(cmd, DBSC_DBCMD + (0x4000 * ch)); +} + +/** + * dbsc5_f_scale_rate() - Calculate the best value for DBSC timing setting + * @priv: Driver private data + * @frac: Perform fractional rounding + * @ddr_mbps: DRAM Mbps + * @ddr_mbpsdiv: DRAM Mbps divider + * @ps: Optimal setting value in pico second + * @cyc: Optimal setting value in cycle count + * + * Convert the optimal value in pico second to in cycle count. Optionally, if @frac is true, + * perform fractional rounding. Compare the value of the result of the conversion with the + * value of the argument @cyc and return the larger value. + */ +static u32 dbsc5_f_scale_rate(struct renesas_dbsc5_dram_priv *priv, const bool frac, + u32 ddr_mbps, u32 ddr_mbpsdiv, u32 ps, u32 cyc) +{ + const u32 mul = frac ? 8 : 800000; + const u32 tmp = DIV_ROUND_UP(ps, 10UL) * ddr_mbps; + const u32 f_scale_div = DIV_ROUND_UP(tmp, mul * ddr_mbpsdiv); + + return (f_scale_div > cyc) ? f_scale_div : cyc; +} + +/** + * dbsc5_f_scale() - Calculate the best value for DBSC timing setting + * @priv: Driver private data + * @frac: Perform fractional rounding + * @ps: Optimal setting value in pico second + * @cyc: Optimal setting value in cycle count + * + * Convert the optimal value in pico second to in cycle count. Optionally, if @frac is true, + * perform fractional rounding. Compare the value of the result of the conversion with the + * value of the argument @cyc and return the larger value. + */ +static u32 dbsc5_f_scale(struct renesas_dbsc5_dram_priv *priv, const bool frac, u32 ps, u32 cyc) +{ + return dbsc5_f_scale_rate(priv, frac, priv->ddr_mbps, priv->ddr_mbpsdiv, ps, cyc); +} + +/** + * dbsc5_f_scale_js2() - Select optimal settings based on jedec_spec2 + * @priv: Driver private data + * @js2: Array of jedec spec2 setting table + * + * Calculate and assign each setting value of jedec_spec2 by "dbsc5_f_scale" function. + * Only the following array elements are calculated using different formulas from those + * described above -- JS2_tRRD/JS2_tFAW/JS2_tZQCALns/JS2_tRCpb/JS2_tRCab. + */ +static void dbsc5_f_scale_js2(struct renesas_dbsc5_dram_priv *priv, u32 *f_js2) +{ + int i; + + for (i = 0; i < JS2_TBLCNT; i++) { + f_js2[i] = dbsc5_f_scale(priv, false, + jedec_spec2[JS2_DERATE][i].ps, + jedec_spec2[JS2_DERATE][i].cyc); + } + + f_js2[JS2_tRRD] = dbsc5_f_scale(priv, false, + js1[priv->js1_ind].tRRD + jedec_spec2[JS2_DERATE][JS2_tRRD].ps, + jedec_spec2[JS2_DERATE][JS2_tRRD].cyc); + f_js2[JS2_tFAW] = dbsc5_f_scale(priv, false, + js1[priv->js1_ind].tFAW + jedec_spec2[JS2_DERATE][JS2_tFAW].ps, + jedec_spec2[JS2_DERATE][JS2_tFAW].cyc); + f_js2[JS2_tZQCALns] = dbsc5_f_scale(priv, false, + jedec_spec2[JS2_DERATE][JS2_tZQCALns].ps * 1000, 0); + f_js2[JS2_tDQ72DQns] = dbsc5_f_scale(priv, false, + jedec_spec2[JS2_DERATE][JS2_tDQ72DQns].ps * 1000, 0); + f_js2[JS2_tCAENTns] = dbsc5_f_scale(priv, false, + jedec_spec2[JS2_DERATE][JS2_tCAENTns].ps * 1000, 0); + f_js2[JS2_tRCpb] = f_js2[JS2_tRAS] + f_js2[JS2_tRPpb]; + f_js2[JS2_tRCab] = f_js2[JS2_tRAS] + f_js2[JS2_tRPab]; + f_js2[JS2_tRFCab] = dbsc5_f_scale(priv, false, + jedec_spec2_tRFC_ab[priv->max_density] * 1000, 0); + f_js2[JS2_tRFCpb] = dbsc5_f_scale(priv, false, + jedec_spec2_tRFC_pb[priv->max_density] * 1000, 0); + f_js2[JS2_tpbR2pbR] = dbsc5_f_scale(priv, false, + jedec_spec2_tpbR2pbR[priv->max_density] * 1000, 0); + f_js2[JS2_tRFMab] = dbsc5_f_scale(priv, false, + jedec_spec2_tRFM_ab[priv->max_density] * 1000, 0); + f_js2[JS2_tRFMpb] = dbsc5_f_scale(priv, false, + jedec_spec2_tRFM_pb[priv->max_density] * 1000, 0); + + f_js2[JS2_tRBTP] = dbsc5_f_scale(priv, false, 7500, 2) - 2; + f_js2[JS2_tXSR] = f_js2[JS2_tRFCab] + dbsc5_f_scale(priv, false, 7500, 2); + f_js2[JS2_tPDN] = dbsc5_f_scale(priv, false, 10000, 0) + 1; + f_js2[JS2_tPDN_DSM] = dbsc5_f_scale(priv, true, + jedec_spec2[JS2_DERATE][JS2_tPDN_DSM].ps * 10, 0); + f_js2[JS2_tXSR_DSM] = dbsc5_f_scale(priv, true, + jedec_spec2[JS2_DERATE][JS2_tXSR_DSM].ps * 10, 0); + f_js2[JS2_tXDSM_XP] = dbsc5_f_scale(priv, true, + jedec_spec2[JS2_DERATE][JS2_tXDSM_XP].ps * 10, 0); + f_js2[JS2_tWLWCKOFF] = dbsc5_f_scale(priv, false, 14000, 5); +} + +/** + * dbsc5_dbsc_regset_pre() - Configure primary DDR registers + * @dev: DBSC5 device + * + * Set SDRAM type, Burst length, and PHY type. Frequency mode setting. + * Write SDRAM configuration contents to registers. + */ +static void dbsc5_dbsc_regset_pre(struct udevice *dev) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 ddr_density[DRAM_CH_CNT][CS_CNT]; + u32 RL, WL, WCKENLR; + u32 ch, cs, i, val; + u32 js2[JS2_CNT]; + u32 param_trdwr; + u32 tmp[4]; + + /* Determine DBSC clock frequency (in MHz) */ + const u32 ni = (readl(SYSSS_PLL1_1_CR0) >> 20) & 0x1FF; + const u32 cksel = (readl(SYSSS_PLL1_1_CR0) >> 7) & 0x1; + const u32 div = 0x20 - ((readl(SYSSS_PLL1_1DCR)) & 0x1F); + const u32 bus_clk = ((priv->brd_clk * (ni + 1) * 2) * div) / (cksel + 1) / 32 / 4; + + /* Determine board density */ + priv->max_density = 0; + for (ch = 0; ch < DRAM_CH_CNT; ch++) { + for (cs = 0; cs < CS_CNT; cs++) { + ddr_density[ch][cs] = priv->dbsc5_board_config->ch[ch].bdcfg_ddr_density[cs]; + if (priv->dbsc5_board_config->ch[ch].bdcfg_ddr_density[cs] == 0xFF) + continue; + + if (priv->dbsc5_board_config->ch[ch].bdcfg_ddr_density[cs] > priv->max_density) + priv->max_density = priv->dbsc5_board_config->ch[ch].bdcfg_ddr_density[cs]; + } + } + + /* Search jedec_spec1 index */ + for (i = JS1_USABLEC_SPEC_LO; i < (JS1_FREQ_TBL_NUM - 1); i++) + if ((js1[i].fx3 * 2 * priv->ddr_mbpsdiv) >= (priv->ddr_mbps * 3)) + break; + + if (i > JS1_USABLEC_SPEC_HI) + priv->js1_ind = JS1_USABLEC_SPEC_HI; + else + priv->js1_ind = i; + + RL = js1[priv->js1_ind].RLset0; + WL = js1[priv->js1_ind].WLsetA; + WCKENLR = js1[priv->js1_ind].WCKENLR0; + + /* Calculate jedec_spec2 */ + dbsc5_f_scale_js2(priv, js2); + + /* LPDDR5, BL=16, DFI interface */ + dbsc5_reg_write(dev, DBSC_DBMEMKIND, 0xC); + dbsc5_reg_write(dev, DBSC_DBMEMKINDA, 0xC); + dbsc5_reg_write(dev, DBSC_DBBL, 0x2); + dbsc5_reg_write(dev, DBSC_DBBLA, 0x2); + + /* dcmpmd = 2 : bypass mode */ + dbsc5_reg_write(dev, DBSC_DBSYSCNT1A, 0x2); + dbsc5_reg_write(dev, DBSC_DBPHYCONF0, 0x1); + dbsc5_reg_write(dev, DBSC_DBSYSCONF0, 0x1); + + /* FREQRATIO=2 */ + dbsc5_reg_write(dev, DBSC_DBSYSCONF1, 0x20000); + dbsc5_reg_write(dev, DBSC_DBSYSCONF1A, 0); + dbsc5_reg_write(dev, DBSC_DBSYSCONF2, 0x1); + dbsc5_reg_write(dev, DBSC_DBSYSCONF2A, 0x241); + + for (ch = 0; ch < DRAM_CH_CNT; ch++) { + for (cs = 0; cs < CS_CNT; cs++) { + if (ddr_density[ch][cs] == 0xFF) { + writel(0, DBSC_DBMEMCONF(ch, cs)); + writel(0, DBSC_DBMEMCONFA(ch, cs)); + } else { + writel(DBMEMCONF_REGD(ddr_density[ch][cs]), + DBSC_DBMEMCONF(ch, cs)); + writel(DBMEMCONF_REGD(ddr_density[ch][cs]), + DBSC_DBMEMCONFA(ch, cs)); + } + } + } + + /* DBTR0.cl : RL */ + dbsc5_reg_write(dev, DBSC_DBTR(0), RL); + + /* DBTR1.cwl : WL */ + dbsc5_reg_write(dev, DBSC_DBTR(1), WL); + + /* DBTR2.al = 0 */ + dbsc5_reg_write(dev, DBSC_DBTR(2), 0); + + /* DBTR3.trcd : tRCD */ + dbsc5_reg_write(dev, DBSC_DBTR(3), js2[JS2_tRCD]); + + /* DBTR4.trpa,trp : tRPab,tRPpb */ + dbsc5_reg_write(dev, DBSC_DBTR(4), (js2[JS2_tRPab] << 16) | js2[JS2_tRPpb]); + + /* DBTR5.trc : tRCpb */ + dbsc5_reg_write(dev, DBSC_DBTR(5), js2[JS2_tRCpb]); + + /* DBTR6.tras : tRAS */ + dbsc5_reg_write(dev, DBSC_DBTR(6), js2[JS2_tRAS]); + + /* DBTR7.trrd : tRRD */ + dbsc5_reg_write(dev, DBSC_DBTR(7), (js2[JS2_tRRD] << 16) | js2[JS2_tRRD]); + + /* DBTR8.tfaw : tFAW */ + dbsc5_reg_write(dev, DBSC_DBTR(8), js2[JS2_tFAW]); + + /* DBTR9.trdpr : nRBTP */ + dbsc5_reg_write(dev, DBSC_DBTR(9), js1[priv->js1_ind].nRBTP); + + /* DBTR10.twr : nWR */ + dbsc5_reg_write(dev, DBSC_DBTR(10), js1[priv->js1_ind].nWR); + + /* + * DBTR11.trdwr : RL + BL/n_max + RU(tWCK2DQO(max)/tCK) + RD(tRPST/tCK) - + * ODTLon - RD(tODTon(min)/tCK) + 1 + feature + */ + param_trdwr = RL + 4 + js2[JS2_tWCK2DQO_HF] + 0 - js1[priv->js1_ind].ODTLon - + (js2[JS2_tODTon_min] - 1) + 1 + 0; + dbsc5_reg_write(dev, DBSC_DBTR(11), param_trdwr); + + /* DBTR12.twrrd_s,twrrd : WL + BL/2 + tWTR_S,WL + BL + tWTR_L */ + dbsc5_reg_write(dev, DBSC_DBTR(12), ((WL + 2 + js2[JS2_tWTR_S]) << 16) | + (WL + 4 + js2[JS2_tWTR_L])); + + /* DBTR13.trfcpb,trfc : tRFCpb,tRFCab */ + dbsc5_reg_write(dev, DBSC_DBTR(13), (js2[JS2_tRFCpb] << 16) | (js2[JS2_tRFCab])); + + /* DBTR14.tcscal,tckehdll,tckeh : tCSCAL,tXP,tXP */ + dbsc5_reg_write(dev, DBSC_DBTR(14), (js2[JS2_tCSCAL] << 24) | (js2[JS2_tXP] << 16) | + js2[JS2_tXP]); + + /* DBTR15 */ + /* tckel : tSR */ + tmp[0] = js2[JS2_tSR]; + /* tckesr : tSR */ + tmp[1] = js2[JS2_tSR]; + /* tespd : tESPD = 2 */ + tmp[2] = 0x2; + dbsc5_reg_write(dev, DBSC_DBTR(15), (tmp[2] << 24) | (tmp[1] << 16) | tmp[0]); + + /* DBTR16 */ + /* wdql(tphy_wrlat + tphy_wrdata) */ + tmp[0] = (WL * 4) - 5 + 2; + /* dqenltcy(tphy_wrlat) */ + tmp[1] = (WL * 4) - 5; + /* dql(tphy_rdlat + trddata_en) : (6 + csrDFIMRL) * 4 + trddata_en */ + tmp[2] = ((6 + 7) * 4) + ((RL * 4) - 13); + /* dqienltncy(trddata_en) : RL * 4 - 13 */ + tmp[3] = (RL * 4) - 13; + dbsc5_reg_write(dev, DBSC_DBTR(16), (tmp[3] << 25) | (tmp[2] << 16) | (tmp[1] << 8) | tmp[0]); + + /* DBTR17.tmodrd,tmod : tMRR,tMRW */ + dbsc5_reg_write(dev, DBSC_DBTR(17), (js2[JS2_tMRR] << 24) | (js2[JS2_tMRW] << 16)); + + /* DBTR18.rodtl,rodta = 0 */ + dbsc5_reg_write(dev, DBSC_DBTR(18), 0); + + /* DBTR19.tzqcl,tzqcs = 0 */ + dbsc5_reg_write(dev, DBSC_DBTR(19), 0); + + /* DBTR20.txsdll,txs : tXSR,tXSR */ + dbsc5_reg_write(dev, DBSC_DBTR(20), (js2[JS2_tXSR] << 16) | js2[JS2_tXSR]); + + /* DBTR21.tccdmw, tccd */ + /* tccd(BL/2_max) */ + tmp[0] = 0x4; + /* tccd_s(BL/2_min) */ + tmp[1] = 0x2; + /* tccdmw */ + if ((priv->ddr_mbps * 3) > (25600 * priv->ddr_mbpsdiv)) + tmp[2] = 0x14; + else + tmp[2] = 0x10; + dbsc5_reg_write(dev, DBSC_DBTR(21), (tmp[2] << 24) | (tmp[1] << 16) | tmp[0]); + + /* DBTR22.tzqcal,tzqlat : tZQCAL,tZQLAT */ + dbsc5_reg_write(dev, DBSC_DBTR(22), (js2[JS2_tZQCALns] << 16) | js2[JS2_tZQLAT]); + + /* DBTR23.rrspc = 0 */ + dbsc5_reg_write(dev, DBSC_DBTR(23), 0); + + /* DBTR24 */ + /* wrcslat(tphy_wrcslat) */ + tmp[0] = (WL * 4) - 5; + /* wrcsgap(tphy_wrcsgap) */ + tmp[1] = 0x4; + /* rdcslat(tphy_rdcslat) */ + tmp[2] = (RL * 4) - 13; + /* rdcsgap(tphy_rdcsgap) */ + tmp[3] = 0x4; + dbsc5_reg_write(dev, DBSC_DBTR(24), (tmp[3] << 24) | (tmp[2] << 16) | + (tmp[1] << 8) | tmp[0]); + + /* DBTR25 */ + dbsc5_reg_write(dev, DBSC_DBTR(25), 0); + + /* DBTR26 */ + dbsc5_reg_write(dev, DBSC_DBTR(26), 0); + + /* DBTR27.tpdn : tPDN */ + dbsc5_reg_write(dev, DBSC_DBTR(27), js2[JS2_tPDN]); + + /* DBTR28.txsrdsm : tXSR_DSM */ + dbsc5_reg_write(dev, DBSC_DBTR(28), js2[JS2_tXSR_DSM]); + + /* DBTR29.tdsmxp : tXDSM_XP */ + dbsc5_reg_write(dev, DBSC_DBTR(29), js2[JS2_tXDSM_XP]); + + /* DBTR30.tcmdpd : tCMDPD = 3 */ + dbsc5_reg_write(dev, DBSC_DBTR(30), 0x3); + + /* DBTR31.twck2dqomax,twck2dqimax : tWCK2DQO_HF/LF,tWCK2DQI_HF/LF */ + dbsc5_reg_write(dev, DBSC_DBTR(31), (js2[JS2_tWCK2DQO_HF] << 4) | js2[JS2_tWCK2DQI_HF]); + + /* DBTR32 */ + /* twckenr */ + tmp[0] = (WCKENLR * 4) - 4 - 1; + /* twckenw */ + tmp[1] = (js1[priv->js1_ind].WCKENLW * 4) - 4 - 1; + /* twckenlf */ + tmp[2] = (js1[priv->js1_ind].WCKENLF * 4) - 4; + /* twckpresta */ + tmp[3] = js1[priv->js1_ind].WCKPRESTA * 4; + dbsc5_reg_write(dev, DBSC_DBTR(32), (tmp[3] << 24) | (tmp[2] << 16) | + (tmp[1] << 8) | tmp[0]); + + /* DBTR33 */ + /* twcktgl */ + tmp[0] = 4; + /* twckdis : (RL+ bl/n_max) * 4 + RU(tWCKPST/tWCK),tWCKPST = MR10[3:2] = 2.5 */ + tmp[1] = ((RL + 4) * 4) + 3; + dbsc5_reg_write(dev, DBSC_DBTR(33), (tmp[1] << 8) | tmp[0]); + + /* DBTR34 */ + /* twcksus = 4 */ + tmp[0] = 4; + /* twckpst : RU(tWCKPST/tCK),tWCKPST = MR10[3:2] = 2.5 */ + tmp[1] = 1; + dbsc5_reg_write(dev, DBSC_DBTR(34), (tmp[1] << 8) | tmp[0]); + + /* DBTR35 */ + /* trd2wckoff : RL + BL/n_max + RD(tWCKPST/tCK) + 1 */ + tmp[0] = RL + 4 + 0 + 1; + /* twr2wckoff : WL + BL/n_max + RD(tWCKPST/tCK) + 1 */ + tmp[1] = WL + 4 + 0 + 1; + dbsc5_reg_write(dev, DBSC_DBTR(35), (tmp[1] << 16) | tmp[0]); + + /* DBTR36 */ + /* twssuswrx : CAS(WCKSUS)WRX */ + tmp[0] = 3; + /* twsoffwrx : CAS(WS_OFF)WRX */ + tmp[1] = 3; + /* twsfswrx : CAS(WS_FS)WRX */ + tmp[2] = 2; + dbsc5_reg_write(dev, DBSC_DBTR(36), (tmp[2] << 16) | (tmp[1] << 8) | tmp[0]); + + /* DBTR37 */ + /* tosco : tOSCODQI */ + tmp[0] = js2[JS2_tOSCODQI]; + /* toscodqi : tOSCODQI */ + tmp[1] = js2[JS2_tOSCODQI]; + /* toscodqo : tOSCODQO */ + tmp[2] = js2[JS2_tOSCODQO]; + dbsc5_reg_write(dev, DBSC_DBTR(37), (tmp[2] << 24) | (tmp[1] << 16) | tmp[0]); + + /* DBTR38.tpbr2act,tpbr2pbr : tpbR2act,tpbR2pbR */ + dbsc5_reg_write(dev, DBSC_DBTR(38), (js2[JS2_tpbR2act] << 8) | js2[JS2_tpbR2pbR]); + + /* DBTR39.trfmpb,trmbab : tRFMpb,tRFMab */ + dbsc5_reg_write(dev, DBSC_DBTR(39), (js2[JS2_tRFMpb] << 16) | js2[JS2_tRFMab]); + + /* DBRNK2 */ + /* rnkrr = tphy_wckcsgap + tWCK2DQO_rank2rank_HF/tWCK */ + val = dbsc5_f_scale_rate(priv, false, priv->ddr_mbps * 4, priv->ddr_mbpsdiv, 650, 0); + tmp[0] = (4 + val) / 4; + if ((tmp[0] * 4) == (4 + val)) + val = tmp[0]; + else + val = tmp[0] + 1; + dbsc5_reg_write(dev, DBSC_DBRNK(2), (val << 4) | val); + + /* DBRNK3 */ + /* rnkrw = tphy_wckcsgap + tWCK2DQO_rank2rank_HF/tWCK */ + val = dbsc5_f_scale_rate(priv, false, priv->ddr_mbps * 4, priv->ddr_mbpsdiv, 650, 0); + tmp[0] = (4 + val) / 4; + if ((tmp[0] * 4) == (4 + val)) + val = tmp[0]; + else + val = (tmp[0] + 1); + + /* trd2wckoff - trdwr */ + tmp[0] = (RL + 4 + 0 + 1) - param_trdwr; + if (tmp[0] > val) + val = tmp[0]; + dbsc5_reg_write(dev, DBSC_DBRNK(3), (val << 4) | val); + + /* DBRNK4 */ + /* rnkwr = tphy_wckcsgap */ + dbsc5_reg_write(dev, DBSC_DBRNK(4), 0x11); + + /* DBRNK5 */ + /* rnkww = tphy_wckcsgap */ + dbsc5_reg_write(dev, DBSC_DBRNK(5), 0x11); + + /* DBRNK6 */ + /* refmode = tphy_wckcsgap */ + /* per_bank_refresh */ + dbsc5_reg_write(dev, DBSC_DBRNK(6), 0x1); + + /* SCFCTST0 */ + /* scpreact */ + tmp[0] = 1UL * js2[JS2_tRPpb] * bus_clk * priv->ddr_mbpsdiv * 8 / + priv->ddr_mbps / priv->brd_clkdiv; + /* scactrdwr */ + tmp[1] = 1UL * (WL + 2 + 1 + js1[priv->js1_ind].nWR + js2[JS2_tRPpb]) * + bus_clk * priv->ddr_mbpsdiv * 8 / priv->ddr_mbps / priv->brd_clkdiv; + /* scrdacrt */ + tmp[2] = 1UL * ((js1[priv->js1_ind].nRBTP + 2) + js2[JS2_tRPpb]) * + bus_clk * priv->ddr_mbpsdiv * 8 / priv->ddr_mbps / priv->brd_clkdiv; + /* scactact */ + tmp[3] = 1UL * js2[JS2_tRCpb] * bus_clk * priv->ddr_mbpsdiv * 8 / + priv->ddr_mbps / priv->brd_clkdiv; + dbsc5_reg_write(dev, DBSC_DBSCHFCTST(0), (tmp[3] << 24) | (tmp[2] << 16) | + (tmp[1] << 8) | tmp[0]); + + /* SCFCTST1 */ + /* scasyncofs */ + tmp[0] = 12; + /* scactrdwr */ + tmp[1] = 1UL * js2[JS2_tRCD] * bus_clk * priv->ddr_mbpsdiv * 8 / + priv->ddr_mbps / priv->brd_clkdiv; + /* scwrrd */ + tmp[2] = 1UL * (WL + 4 + js2[JS2_tWTR_L]) * bus_clk * priv->ddr_mbpsdiv * 8 / + priv->ddr_mbps / priv->brd_clkdiv; + /* scrdwr */ + tmp[3] = 1UL * param_trdwr * bus_clk * priv->ddr_mbpsdiv * 8 / + priv->ddr_mbps / priv->brd_clkdiv; + dbsc5_reg_write(dev, DBSC_DBSCHFCTST(1), (tmp[3] << 24) | (tmp[2] << 16) | + (tmp[1] << 8) | tmp[0]); + + /* DBSCHRW1 */ + /* sctrfcab */ + val = 1UL * (js2[JS2_tRFCab] + js2[JS2_tZQLAT]) * bus_clk * priv->ddr_mbpsdiv * 8 / + priv->ddr_mbps / priv->brd_clkdiv; + /* sctrfcab[7:0] = DBSCHRW1[7:0] */ + tmp[0] = val & 0xFF; + /* sctrfcab[8] = DBSCHRW1[24] */ + tmp[3] = val & 0x100; + /* sctrfcpb */ + tmp[1] = 1UL * (js2[JS2_tRFCpb]) * bus_clk * priv->ddr_mbpsdiv * 8 / + priv->ddr_mbps / priv->brd_clkdiv; + /* sctrfcpb */ + tmp[2] = 1UL * (js2[JS2_tpbR2pbR]) * bus_clk * priv->ddr_mbpsdiv * 8 / + priv->ddr_mbps / priv->brd_clkdiv; + dbsc5_reg_write(dev, DBSC_DBSCHRW(1), (tmp[3] << 24) | (tmp[2] << 16) | + (tmp[1] << 8) | tmp[0]); + + /* DBSCHRW2 */ + /* scrfpben */ + tmp[0] = 1; + /* screfipb : tREFIpb */ + tmp[1] = DBSC_REFINT * bus_clk / priv->brd_clkdiv / 1000 / 8; + dbsc5_reg_write(dev, DBSC_DBSCHRW(2), (tmp[1] << 16) | tmp[0]); + + /* DBSCHTR0 */ + /* scdt0 */ + tmp[0] = (1UL * 4 * bus_clk * priv->ddr_mbpsdiv * 8 / priv->ddr_mbps / priv->brd_clkdiv) - 1; + /* scdt1 */ + tmp[1] = (1UL * 8 * bus_clk * priv->ddr_mbpsdiv * 8 / priv->ddr_mbps / priv->brd_clkdiv) - 1; + /* scdt2 */ + tmp[2] = (1UL * 12 * bus_clk * priv->ddr_mbpsdiv * 8 / priv->ddr_mbps / priv->brd_clkdiv) - 1; + /* scdt3 */ + tmp[3] = (1UL * 16 * bus_clk * priv->ddr_mbpsdiv * 8 / priv->ddr_mbps / priv->brd_clkdiv) - 1; + dbsc5_reg_write(dev, DBSC_DBSCHTR0, (tmp[3] << 24) | (tmp[2] << 16) | + (tmp[1] << 8) | tmp[0]); + + dbsc5_reg_write(dev, DBSC_DBBCAMDIS, 0x10); + + /* Dummy PDE */ + dbsc5_send_dbcmd(dev, 0x8840000); + /* Dummy PDX */ + dbsc5_send_dbcmd(dev, 0x8840001); +} + +/** + * dbsc5_dbsc_regset_post() - Set DBSC registers + * @dev: DBSC5 device + */ +static void dbsc5_dbsc_regset_post(struct udevice *dev) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 val; + u32 tmp; + + dbsc5_reg_write(dev, DBSC_DBBUS0CNF1, 0); + + /* SRX */ + dbsc5_send_dbcmd(dev, 0xA840001); + + /* Write DBI ON */ + dbsc5_reg_write(dev, DBSC_DBDBICNT, 0x1); + + /* set REFCYCLE */ + val = DBSC_REFINT * priv->ddr_mbps / 8000 / priv->ddr_mbpsdiv; + /* refpmax=8 */ + dbsc5_reg_write(dev, DBSC_DBRFCNF1, 0x80000 | (val & 0xFFFF)); + /* refpmin=1 */ + dbsc5_reg_write(dev, DBSC_DBRFCNF2, 0x10000); + + /* periodic dram zqcal enable */ + dbsc5_reg_write(dev, DBSC_DBCALCNF, 0x1000010); + + /* wtmode = 1, pmstrmd = 2(WA for WS1), pmstren = 1 */ + dbsc5_reg_write(dev, DBSC_DBDFIPMSTRCNF, 0x15); + + /* periodic phy ctrl update enable */ + /* max = 80, min = 76, en = 1 */ + dbsc5_reg_write(dev, DBSC_DBDFICUPDCNF, 0x504C0001); + + /* set Auto Refresh */ + dbsc5_reg_write(dev, DBSC_DBRFEN, 0x1); + + /* dram access enable */ + dbsc5_reg_write(dev, DBSC_DBACEN, 0x1); + + tmp = (PERIODIC_TRAINING_INTERVAL * 1000) / DBSC_REFINT; + /* (ZQCalibration_interval + 1) / ZQCalibration_interval */ + val = (tmp * (0x10 + 1)) / 0x10; + /* snoopen=1 */ + dbsc5_reg_write(dev, DBSC_DBSNOOPC, BIT(24) | val); +} + +#define RTMMAC_BASE 0xb8900000 +#define RTDMAC_RDMSAR_0(ch) (RTMMAC_BASE + 0x0 + ((ch) * 0x1000)) +#define RTDMAC_RDMDAR_0(ch) (RTMMAC_BASE + 0x4 + ((ch) * 0x1000)) +#define RTDMAC_RDMTCR_0(ch) (RTMMAC_BASE + 0x8 + ((ch) * 0x1000)) +#define RTDMAC_RDMCHCR_0(ch) (RTMMAC_BASE + 0xc + ((ch) * 0x1000)) +#define RTDMAC_RDMCHCLR(ch) (RTMMAC_BASE + 0x100 + ((ch) * 0x1000)) +#define RTDMAC_RDMOR 0xb9438060 + +/** + * dbsc5_rtdmac_init() - Configure RTDMAC DMA controller + * @ch: DMA Channel + * @dst: Destination address + * @src: Source address + * @cnt: Byte count + */ +static void dbsc5_rtdmac_init(u32 ch, u32 dst, u32 src, u32 cnt) +{ + /* DMA Setting - 64Byte/AutoRequest mode */ + writel(src, RTDMAC_RDMSAR_0(ch)); + writel(dst, RTDMAC_RDMDAR_0(ch)); + writel(cnt, RTDMAC_RDMTCR_0(ch)); + writel(0x105409, RTDMAC_RDMCHCR_0(ch)); +} + +/** + * dbsc5_rtdmac_start() - Start RTDMAC DMA controller + */ +static void dbsc5_rtdmac_start(void) +{ + /* Start DMA */ + writew(0x1, RTDMAC_RDMOR); +} + +/** + * dbsc5_rtdmac_wait() - Wait for RTDMAC DMA completion + * @ch: DMA Channel + */ +static void dbsc5_rtdmac_wait(int ch) +{ + u32 val; + + /* Wait for DMA completion */ + for (;;) { + val = readl(RTDMAC_RDMCHCR_0(ch)); + if (val & BIT(1)) { /* Clear TE */ + writel(val & ~BIT(1), RTDMAC_RDMCHCR_0(ch)); + break; + } + + if (val & BIT(31)) { /* Clear CAE */ + writel(val & ~BIT(31), RTDMAC_RDMCHCR_0(ch)); + break; + } + } +} + +/** + * dbsc5_rtdmac_stop() - Stop RTDMAC DMA controller + */ +static void dbsc5_rtdmac_stop(void) +{ + u32 ch; + + /* Disable DMA */ + writew(0, RTDMAC_RDMOR); + for (ch = 0; ch < 16; ch++) + writel(readl(RTDMAC_RDMCHCR_0(ch)) | BIT(0), RTDMAC_RDMCHCLR(ch)); +} + +/** + * dbsc5_rtdmac_phyinit_trans_ach() - Load PHY using RTDMAC + * @dev: DBSC5 device + * @dst: Destination address + * @src: Source address + * @size: Transfer size + */ +static void dbsc5_rtdmac_phyinit_trans_ach(struct udevice *dev, u32 dst, u32 src, u32 size) +{ + u32 ch; + + foreach_vphych(dev, ch) { + dbsc5_rtdmac_init(ch, DDR_PHY_DMA_TRANS_BASE(ch) + (dst << 2), + src, (size + 0x3f) >> 6); + dbsc5_rtdmac_start(); + } + + foreach_vphych(dev, ch) + dbsc5_rtdmac_wait(ch); + + dbsc5_rtdmac_stop(); +} + +/** + * dbsc5_phy_apb_wr() - Write PHY register + * @ch: PHY channel + * @addr: Register address + * @data: Register value + */ +static void dbsc5_phy_apb_wr(u32 ch, u32 addr, u32 data) +{ + writel(data, DDR_PHY_BASE(ch) + (addr << 2)); +} + +/** + * dbsc5_phy_apb_wr_ach() - Write PHY register on all channels + * @addr: Register address + * @data: Register value + */ +static void dbsc5_phy_apb_wr_ach(struct udevice *dev, u32 addr, u32 data) +{ + u32 ch; + + foreach_vphych(dev, ch) + dbsc5_phy_apb_wr(ch, addr, data); +} + +/** + * dbsc5_phy_apb_rd() - Read PHY register + * @ch: PHY channel + * @addr: Register address + */ +static u32 dbsc5_phy_apb_rd(u32 ch, u32 addr) +{ + return readl(DDR_PHY_BASE(ch) + (addr << 2)); +} + +/** + * ddrphy_apb_rd_mod_wr() - Read-modify-Write PHY register + * @ch: PHY channel + * @addr: Register address + * @len: Clearing bitmask length + * @lsb: Clearing bitmask shift + * @data: Register value + */ +static void ddrphy_apb_rd_mod_wr(u32 ch, u32 addr, u32 len, u32 lsb, u32 data) +{ + u32 msk = 0xffffffff; + u32 val; + + if (len != 32) + msk = (BIT(len) - 1) << lsb; + + val = dbsc5_phy_apb_rd(ch, addr); + val &= ~msk; + val |= data << lsb; + dbsc5_phy_apb_wr(ch, addr, val); +} + +/** + * dbsc5_phy_apb_rd() - Read PHY message block + * @ch: PHY channel + */ +static u32 dbsc5_phy_apb_msg_rd(u32 ch) +{ + u32 ret; + + while (dbsc5_phy_apb_rd(ch, PHY_APBONLY_UCTSHADOWREGS) & BIT(0)) + ; + + ret = dbsc5_phy_apb_rd(ch, PHY_APBONLY_UCTWRITEONLYSHADOW); + dbsc5_phy_apb_wr(ch, PHY_APBONLY_DCTWRITEPROT, 0); + + while (!(dbsc5_phy_apb_rd(ch, PHY_APBONLY_UCTSHADOWREGS) & BIT(0))) + ; + + dbsc5_phy_apb_wr(ch, PHY_APBONLY_DCTWRITEPROT, BIT(0)); + + return ret; +} + +/** + * dbsc5_ddr_config_post() - Set DDR user configuration + * @dev: DBSC5 device + */ +static void dbsc5_ddr_config_post(struct udevice *dev) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 ch, tmp; + + foreach_vphych(dev, ch) { + /* 2-Rank settings */ + if (priv->ch_have_this_cs[1] & (0x3 << (ch * 2))) + dbsc5_phy_apb_wr(ch, PHY_PPGC_HWTCONTROLVAL, 0xc3); + + /* Configure IO parameters */ + /* DRAM Tx ODT for DQ */ + ddrphy_apb_rd_mod_wr(ch, 0x41036, 3, 7, + (priv->dbsc5_board_config->bdcfg_tx_odt >> 4) & 0x7); + + /* DRAM Tx ODT for CA */ + ddrphy_apb_rd_mod_wr(ch, 0x41036, 3, 11, + (priv->dbsc5_board_config->bdcfg_tx_odt) & 0x7); + + /* DRAM Tx NT DQ ODT */ + tmp = (priv->dbsc5_board_config->bdcfg_tx_ntodt) & 0x7; + if (tmp < 0x4) { + ddrphy_apb_rd_mod_wr(ch, 0x4105A, 1, 6, 0x0); + tmp += 4; + } + ddrphy_apb_rd_mod_wr(ch, 0x4105A, 3, 12, tmp); + + /* DRAM Tx NT ODT */ + ddrphy_apb_rd_mod_wr(ch, 0x41036, 1, 10, + ((priv->dbsc5_board_config->bdcfg_tx_ntodt) >> 4) & 0x1); + + /* DRAM Tx Per-pin DFE */ + ddrphy_apb_rd_mod_wr(ch, 0x4105A, 1, 7, + (priv->dbsc5_board_config->bdcfg_tx_dfe) & 0x1); + + /* DRAM Rx DRV */ + ddrphy_apb_rd_mod_wr(ch, 0x41026, 3, 7, + (priv->dbsc5_board_config->bdcfg_rx_drv) & 0x7); + + /* Link ECC setting */ + if (priv->link_ecc_en) { + ddrphy_apb_rd_mod_wr(ch, 0x41052, 1, 11, 0x1); + ddrphy_apb_rd_mod_wr(ch, 0x41052, 1, 13, 0x1); + } + } +} + +/** + * dbsc5_ddr_smb_config() - Set user configuration + * @dev: DBSC5 device + */ +static void dbsc5_ddr_smb_config(struct udevice *dev) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 ch, val; + + foreach_vphych(dev, ch) { + /* Frequency settings */ + if (priv->ddr_mbps < (6401 * priv->ddr_mbpsdiv)) { + /* 5501 - 6400 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_DRAMFREQ, 16, 16, 0x1900); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR1_A0, 8, 16, 0xB0); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR1_A1, 8, 24, 0xB0); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR1_B0, 8, 0, 0xB0); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR1_B1, 8, 8, 0xB0); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR2_A0, 8, 16, 0xBB); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR2_A1, 8, 24, 0xBB); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR2_B0, 8, 0, 0xBB); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR2_B1, 8, 8, 0xBB); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_ALT_RL, 8, 24, 0x3B); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MAIN_RL, 8, 0, 0x37); + } else if (priv->ddr_mbps < (7501 * priv->ddr_mbpsdiv)) { + /* 6401 - 7500 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_DRAMFREQ, 16, 16, 0x1D48); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR1_A0, 8, 16, 0xC0); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR1_A1, 8, 24, 0xC0); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR1_B0, 8, 0, 0xC0); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR1_B1, 8, 8, 0xC0); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR2_A0, 8, 16, 0xCC); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR2_A1, 8, 24, 0xCC); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR2_B0, 8, 0, 0xCC); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR2_B1, 8, 8, 0xCC); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_ALT_RL, 8, 24, 0x4B); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MAIN_RL, 8, 0, 0x43); + } else if (priv->ddr_mbps < (8534 * priv->ddr_mbpsdiv)) { + /* 7501 - 8533 -- None */ + } else { + /* 8534 - 9600 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_DRAMFREQ, 16, 16, 0x2580); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_DCAOPTS, 8, 8, 0x44); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR1_A0, 8, 16, 0xE0); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR1_A1, 8, 24, 0xE0); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR1_B0, 8, 0, 0xE0); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR1_B1, 8, 8, 0xE0); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR2_A0, 8, 16, 0xEE); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR2_A1, 8, 24, 0xEE); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR2_B0, 8, 0, 0xEE); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR2_B1, 8, 8, 0xEE); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_ALT_RL, 8, 24, 0x63); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MAIN_RL, 8, 0, 0x57); + } + + /* 2Rank settings */ + if (priv->ch_have_this_cs[1] & (0x3 << (ch * 2))) { + ddrphy_apb_rd_mod_wr(ch, PHY_APB_CSPRESENTCHA, 2, 8, 0x3); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_CSPRESENTCHB, 2, 0, 0x3); + } + + /* Board settings, data byte swap */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_UPPERLOWERBYTE, 4, 8, priv->upper_lower_byte[ch]); + + /* Configure Training settings */ + /* SOC Rx DFE function */ + if (!(priv->dbsc5_board_config->bdcfg_rx_dfe & BIT(0))) { + /* Rx DFE Disable */ + /* RxDFEBitTimeControl[4] */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_RXDFEBITTIMECONTROL, 1, 4, 0x1); + } else { + /* Rx DFE DQ 1tap */ + /* RxDFEOpt[6] */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_RXDFEOPT, 1, 30, 0); + /* RxClk scan skip */ + /* RxDFEBitTimeControl[6] */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_RXDFEBITTIMECONTROL, 1, 6, 1); + } + + /* DRAM Tx DFE function */ + val = priv->dbsc5_board_config->bdcfg_tx_dfe & 0x7; + if (val == 0x0) { + /* Tx DFE Disable */ + /* PHY_APB_SEQUENCECTRL[10] */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_SEQUENCECTRL, 1, 10, 0x0); + } else { + /* Select Tx DFE step */ + /* DRAM Tx DFE for Upper */ + /* PHY_APB_MR24_A0, PHY_APB_MR24_A1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR24_A0, 3, 20, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR24_A1, 3, 28, val); + /* PHY_APB_MR24_B0, PHY_APB_MR24_B1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR24_B0, 3, 4, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR24_B1, 3, 12, val); + + /* DRAM Tx DFE for Lower */ + /* PHY_APB_MR24_A0, PHY_APB_MR24_A1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR24_A0, 3, 16, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR24_A1, 3, 24, val); + /* PHY_APB_MR24_B0, PHY_APB_MR24_B1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR24_B0, 3, 0, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR24_B1, 3, 8, val); + } + + /* DRAM Tx Per-pin DFE */ + val = (priv->dbsc5_board_config->bdcfg_tx_dfe >> 4) & 0x1; + /* PHY_APB_MR41_A0, PHY_APB_MR41_A1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR41_A0, 1, 16, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR41_A1, 1, 24, val); + /* PHY_APB_MR41_B0, PHY_APB_MR41_B1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR41_B0, 1, 0, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR41_B1, 1, 8, val); + /* TxDFETrainOpt[0] */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_TXDFETRAINOPT, val, 1, 0); + + /* DRAM Rx DCA function */ + /* PHY_APB_SEQUENCECTRL[7] */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_SEQUENCECTRL, 1, 7, + priv->dbsc5_board_config->bdcfg_rx_dca & 0x1); + + /* DRAM Tx DCA function */ + /* PHY_APB_SEQUENCECTRL[6] */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_SEQUENCECTRL, 1, 6, + priv->dbsc5_board_config->bdcfg_tx_dca & 0x1); + + /* CA Vref training initial value */ + val = priv->dbsc5_board_config->bdcfg_ca_vref & 0x7F; + /* PHY_APB_MR12_A0, PHY_APB_MR12_A1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR12_A0, 7, 16, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR12_A1, 7, 24, val); + /* PHY_APB_MR12_B0, PHY_APB_MR12_B1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR12_B0, 7, 0, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR12_B1, 7, 8, val); + + /* Rx Vref training range */ + /* RxVrefStartPat, RxVrefStartPrbs */ + val = priv->dbsc5_board_config->bdcfg_rx_vref & 0xFFFF; + ddrphy_apb_rd_mod_wr(ch, PHY_APB_RXVREFSTARTPAT, 16, 0, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_RXVREFSTARTPRBS, 16, 16, val); + /* RxVrefEndPat, RxVrefEndPrbs */ + val = (priv->dbsc5_board_config->bdcfg_rx_vref >> 16) & 0xFFFF; + ddrphy_apb_rd_mod_wr(ch, PHY_APB_RXVREFENDPAT, 16, 0, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_RXVREFENDPRBS, 16, 16, val); + /* RxVrefStepPat, RxVrefStepPrbs */ + val = priv->dbsc5_board_config->bdcfg_rx_vref_step & 0xFFFF; + ddrphy_apb_rd_mod_wr(ch, PHY_APB_RXVREFSTEPPAT, 16, 16, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_RXVREFSTEPPRBS, 16, 0, val); + + /* Tx Vref training range */ + /* TxVrefStart */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_TXVREFSTART, 8, 0, + priv->dbsc5_board_config->bdcfg_tx_vref & 0xFF); + /* TxVrefEnd */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_TXVREFEND, 8, 8, + (priv->dbsc5_board_config->bdcfg_tx_vref >> 8) & 0xFF); + /* TxVrefStep */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_TXVREFSTEP, 8, 16, + (priv->dbsc5_board_config->bdcfg_tx_vref >> 16) & 0xFF); + + /* FW message setting */ + /* HdtCtrl */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_HDTCTRL, 8, 16, 0xff); + + /* Configure IO parameters */ + /* DRAM Tx ODT for DQ */ + val = (priv->dbsc5_board_config->bdcfg_tx_odt >> 4) & 0x7; + /* PHY_APB_MR11_A0, PHY_APB_MR11_B0 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR11_A0, 3, 16, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR11_A1, 3, 24, val); + /* PHY_APB_MR11_A1, PHY_APB_MR11_B1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR11_B0, 3, 0, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR11_B1, 3, 8, val); + + /* DRAM Tx ODT for CA */ + val = priv->dbsc5_board_config->bdcfg_tx_odt & 0x7; + /* PHY_APB_MR11_A0, PHY_APB_MR11_A1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR11_A0, 3, 20, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR11_A1, 3, 28, val); + /* PHY_APB_MR11_B0, PHY_APB_MR11_B1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR11_B0, 3, 4, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR11_B1, 3, 12, val); + + /* DRAM Tx NT DQ ODT */ + val = priv->dbsc5_board_config->bdcfg_tx_ntodt & 0x7; + /* PHY_APB_MR41_A0, PHY_APB_MR41_A1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR41_A0, 3, 21, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR41_A1, 3, 29, val); + /* PHY_APB_MR41_B0, PHY_APB_MR41_B1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR41_B0, 3, 5, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR41_B1, 3, 13, val); + + /* DRAM Tx NT ODT */ + val = (priv->dbsc5_board_config->bdcfg_tx_ntodt >> 4) & 0x1; + /* PHY_APB_MR11_A0, PHY_APB_MR11_A1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR11_A0, 1, 19, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR11_A1, 1, 27, val); + /* PHY_APB_MR11_B0, PHY_APB_MR11_B1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR11_B0, 1, 3, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR11_B1, 1, 11, val); + + /* DRAM Rx DRV */ + val = priv->dbsc5_board_config->bdcfg_rx_drv & 0x7; + /* PHY_APB_MR3_A0, PHY_APB_MR3_A1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR3_A0, 3, 16, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR3_A1, 3, 24, val); + /* PHY_APB_MR3_B0, PHY_APB_MR3_B1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR3_B0, 3, 0, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR3_B1, 3, 8, val); + + /* DRAM Rx Pre-emphasis */ + val = ((priv->dbsc5_board_config->bdcfg_rx_emphasis >> 12) & 0x3); + val |= ((priv->dbsc5_board_config->bdcfg_rx_emphasis >> 8) & 0x3) << 2; + val |= ((priv->dbsc5_board_config->bdcfg_rx_emphasis >> 4) & 0x3) << 4; + val |= (priv->dbsc5_board_config->bdcfg_rx_emphasis & 0x3) << 6; + /* PHY_APB_MR58_A0, PHY_APB_MR58_A1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR58_A0, 8, 16, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR58_A1, 8, 24, val); + /* PHY_APB_MR58_B0, PHY_APB_MR58_B1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR58_B0, 8, 0, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR58_B1, 8, 8, val); + + /* Link ECC setting */ + if (priv->link_ecc_en) { + /* PHY_APB_MR22_A0, PHY_APB_MR22_A1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR22_A0, 1, 20, 0x1); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR22_A1, 1, 28, 0x1); + /* PHY_APB_MR22_B0, PHY_APB_MR22_B1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR22_B0, 1, 4, 0x1); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR22_B1, 1, 12, 0x1); + /* PHY_APB_MR22_A0, PHY_APB_MR22_A1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR22_A0, 1, 22, 0x1); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR22_A1, 1, 30, 0x1); + /* PHY_APB_MR22_B0, PHY_APB_MR22_B1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR22_B0, 1, 6, 0x1); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MR22_B1, 1, 14, 0x1); + /* PHY_APB_ALT_RL, PHY_APB_MAIN_RL */ + if (priv->ddr_mbps < (7501 * priv->ddr_mbpsdiv)) { + /* 6401 - 7500 */ + val = 0x5B; + } else { + /* 7501 - 8533 */ + val = 0x4F; + } + ddrphy_apb_rd_mod_wr(ch, PHY_APB_ALT_RL, 8, 24, val); + ddrphy_apb_rd_mod_wr(ch, PHY_APB_MAIN_RL, 8, 0, val); + } + } +} + +/** + * dbsc5_phy_data_load() - Load PHY data memory + * @dev: DBSC5 device + */ +static void dbsc5_phy_data_load(struct udevice *dev) +{ + dbsc5_phy_apb_wr_ach(dev, PHY_DRTUB_STARTDCCMCLEAR, 0x0); + dbsc5_phy_apb_wr_ach(dev, PHY_APBONLY_MICROCONTMUXSEL, 0x0); + dbsc5_rtdmac_phyinit_trans_ach(dev, DDR_PHY_DCCM_OFS, + (uintptr_t)DMAC_TRANS_DCCM, + ARRAY_SIZE(DMAC_TRANS_DCCM) * 4); + dbsc5_ddr_smb_config(dev); + dbsc5_phy_apb_wr_ach(dev, PHY_APBONLY_MICROCONTMUXSEL, 0x1); +} + +/** + * dbsc5_phy_init_load() - Load PHY init memory + * @dev: DBSC5 device + */ +static void dbsc5_phy_init_load(struct udevice *dev) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 ch, i; + + foreach_vphych(dev, ch) + for (i = 0; i < ARRAY_SIZE(cpu_trans_tab4); i++) + dbsc5_phy_apb_wr(ch, cpu_trans_tab4[i].addr, cpu_trans_tab4[i].data); + + if (priv->ddr_mbps < (6401 * priv->ddr_mbpsdiv)) /* 5501 - 6400 */ + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL5, 0x2d56); + + foreach_vphych(dev, ch) { + if ((priv->ch_have_this_cs[1] & (0x3 << (ch * 2))) != 0x0) { + dbsc5_phy_apb_wr(ch, PHY_PPGC_HWTLPCSENA, 0x3); + dbsc5_phy_apb_wr(ch, PHY_INITENG_SEQ0BGPR14, 0x3); + dbsc5_phy_apb_wr(ch, PHY_PPGC_HWTLPCSENB, 0x3); + dbsc5_phy_apb_wr(ch, PHY_INITENG_SEQ0BGPR15, 0x3); + } + } + + dbsc5_phy_apb_wr_ach(dev, PHY_APBONLY_MICROCONTMUXSEL, 0); + dbsc5_phy_apb_wr_ach(dev, 0x41000, 0); + dbsc5_phy_apb_wr_ach(dev, 0x41001, 0); + dbsc5_phy_apb_wr_ach(dev, 0x41002, 0); + dbsc5_phy_apb_wr_ach(dev, 0x41003, 0); + + dbsc5_rtdmac_phyinit_trans_ach(dev, DDR_PHY_ACSM_OFS, + (uintptr_t)DMAC_TRANS_ACSM, + ARRAY_SIZE(DMAC_TRANS_ACSM) * 4); + + dbsc5_rtdmac_phyinit_trans_ach(dev, DDR_PHY_PIE_OFS, + (uintptr_t)DMAC_TRANS_PIE, + ARRAY_SIZE(DMAC_TRANS_PIE) * 4); + + dbsc5_phy_apb_wr_ach(dev, PHY_APBONLY_SEQUENCEROVERRIDE, 0x600); + dbsc5_phy_apb_wr_ach(dev, PHY_PPGC_ACSMNOPADDR, 0x0); + + dbsc5_rtdmac_phyinit_trans_ach(dev, PHY_PPGC_ACSMSTARTADDRXLATVAL0, + (uintptr_t)DATA_A, 64); + + foreach_vphych(dev, ch) + for (i = 0; i < ARRAY_SIZE(cpu_trans_tab5); i++) + dbsc5_phy_apb_wr(ch, cpu_trans_tab5[i].addr, cpu_trans_tab5[i].data); + + dbsc5_rtdmac_phyinit_trans_ach(dev, PHY_PPGC_ACSMSTOPADDRXLATVAL0, + (uintptr_t)DATA_B, 64); + + foreach_vphych(dev, ch) + for (i = 0; i < ARRAY_SIZE(cpu_trans_tab6); i++) + dbsc5_phy_apb_wr(ch, cpu_trans_tab6[i].addr, cpu_trans_tab6[i].data); + + if (priv->ddr_mbps < (6401 * priv->ddr_mbpsdiv)) /* 5501 - 6400 */ + dbsc5_phy_apb_wr_ach(dev, PHY_PPGC_ACSMRPTCNTOVERRIDE, 0x2); + else if (priv->ddr_mbps < (7501 * priv->ddr_mbpsdiv)) /* 6401 - 7500 */ + dbsc5_phy_apb_wr_ach(dev, PHY_PPGC_ACSMRPTCNTOVERRIDE, 0x3); + else if (priv->ddr_mbps < (8534 * priv->ddr_mbpsdiv)) { /* 7501 - 8533 */ + } else /* 8534 - 9600 */ + dbsc5_phy_apb_wr_ach(dev, PHY_PPGC_ACSMRPTCNTOVERRIDE, 0x5); + + dbsc5_rtdmac_phyinit_trans_ach(dev, 0x41004, (uintptr_t)ACSM_0, 384); + + if (priv->ddr_mbps < (6401 * priv->ddr_mbpsdiv)) { /* 5501 - 6400 */ + dbsc5_phy_apb_wr_ach(dev, 0x41009, 0x4B000000); + dbsc5_phy_apb_wr_ach(dev, 0x41011, 0x4B000000); + dbsc5_phy_apb_wr_ach(dev, 0x41016, 0xD848); + dbsc5_phy_apb_wr_ach(dev, 0x41019, 0x4B000000); + dbsc5_phy_apb_wr_ach(dev, 0x4101E, 0xDDC8); + dbsc5_phy_apb_wr_ach(dev, 0x41021, 0x4B000000); + dbsc5_phy_apb_wr_ach(dev, 0x41029, 0x4B000000); + dbsc5_phy_apb_wr_ach(dev, 0x41031, 0x4B000000); + dbsc5_phy_apb_wr_ach(dev, 0x41039, 0x4B000000); + dbsc5_phy_apb_wr_ach(dev, 0x41045, 0x4B000000); + dbsc5_phy_apb_wr_ach(dev, 0x4104D, 0x4B000000); + dbsc5_phy_apb_wr_ach(dev, 0x41055, 0x4B000000); + dbsc5_phy_apb_wr_ach(dev, 0x4105D, 0x4B000000); + } else if (priv->ddr_mbps < (7501 * priv->ddr_mbpsdiv)) { /* 6401 - 7500 */ + dbsc5_phy_apb_wr_ach(dev, 0x41016, 0xE048); + dbsc5_phy_apb_wr_ach(dev, 0x4101E, 0xE648); + } else if (priv->ddr_mbps < (8534 * priv->ddr_mbpsdiv)) { /* 7501 - 8533 */ + /* Nothing */ + } else { /* 8534 - 9600 */ + dbsc5_phy_apb_wr_ach(dev, 0x41009, 0x6B000000); + dbsc5_phy_apb_wr_ach(dev, 0x41011, 0x6B000000); + dbsc5_phy_apb_wr_ach(dev, 0x41016, 0xF048); + dbsc5_phy_apb_wr_ach(dev, 0x41019, 0x6B000000); + dbsc5_phy_apb_wr_ach(dev, 0x4101E, 0xF748); + dbsc5_phy_apb_wr_ach(dev, 0x41021, 0x6B000000); + dbsc5_phy_apb_wr_ach(dev, 0x41029, 0x6B000000); + dbsc5_phy_apb_wr_ach(dev, 0x41031, 0x6B000000); + dbsc5_phy_apb_wr_ach(dev, 0x41039, 0x6B000000); + dbsc5_phy_apb_wr_ach(dev, 0x41045, 0x6B000000); + dbsc5_phy_apb_wr_ach(dev, 0x4104D, 0x6B000000); + dbsc5_phy_apb_wr_ach(dev, 0x41055, 0x6B000000); + dbsc5_phy_apb_wr_ach(dev, 0x4105D, 0x6B000000); + } + + dbsc5_rtdmac_phyinit_trans_ach(dev, 0x4110C, (uintptr_t)ACSM_123, 384); + dbsc5_rtdmac_phyinit_trans_ach(dev, 0x41214, (uintptr_t)ACSM_123, 384); + dbsc5_rtdmac_phyinit_trans_ach(dev, 0x4131C, (uintptr_t)ACSM_123, 384); + + dbsc5_phy_apb_wr_ach(dev, PHY_APBONLY_SEQUENCEROVERRIDE, 0x400); + dbsc5_phy_apb_wr_ach(dev, PHY_DRTUB_PIEINITVECSEL, 0x5821); + + dbsc5_rtdmac_phyinit_trans_ach(dev, PHY_INITENG_SEQ0BDISABLEFLAG0, + (uintptr_t)DATA_C, 64); + + foreach_vphych(dev, ch) + for (i = 0; i < ARRAY_SIZE(cpu_trans_tab7); i++) + dbsc5_phy_apb_wr(ch, cpu_trans_tab7[i].addr, cpu_trans_tab7[i].data); + + dbsc5_ddr_config_post(dev); + + dbsc5_phy_apb_wr_ach(dev, PHY_DRTUB_UCCLKHCLKENABLES, 0x6); + + if (priv->ddr_mbps < (6481 * priv->ddr_mbpsdiv)) { /* 5401 - 6480 */ + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL1, 0x1C7F); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL4, 0x1C7F); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL5, 0x2D56); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG0, 0x1009); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG1, 0x5060); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG2, 0x6B01); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG3, 0x423); + } else if (priv->ddr_mbps < (8537 * priv->ddr_mbpsdiv)) { /* 6481 - 8536 */ + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL1, 0x2C7F); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL4, 0x2C7F); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL5, 0x1956); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG0, 0x1009); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG1, 0x5060); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG2, 0x6B01); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG3, 0x423); + } else { /* 8537 - 9600 */ + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL1, 0x2C7F); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL4, 0x2C7F); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL5, 0x1956); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG0, 0x1009); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG1, 0x5060); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG2, 0x6B01); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG3, 0x423); + } + + dbsc5_phy_apb_wr_ach(dev, PHY_APBONLY_MICROCONTMUXSEL, 0x1); +} + +/** + * dbsc5_phy_training() - Perform PHY training and read message block back + * @dev: DBSC5 device + */ +static u32 dbsc5_phy_training(struct udevice *dev) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 phytrainingok = 0; + u32 fail_flag = 0; + u32 ch, val; + + dbsc5_phy_apb_wr_ach(dev, PHY_APBONLY_MICROCONTMUXSEL, 0x1); + dbsc5_phy_apb_wr_ach(dev, PHY_APBONLY_MICRORESET, 0x9); + dbsc5_phy_apb_wr_ach(dev, PHY_APBONLY_MICRORESET, 0x1); + dbsc5_phy_apb_wr_ach(dev, PHY_APBONLY_MICRORESET, 0x0); + + while ((phytrainingok != priv->ddr_phyvalid) && !fail_flag) { + foreach_vphych(dev, ch) { + val = dbsc5_phy_apb_msg_rd(ch); + if (val == 0x7) /* Training complete */ + phytrainingok |= BIT(ch); + else if (val == 0xFF) /* Training FAIL */ + fail_flag = 1; + } + } + + dbsc5_phy_apb_wr_ach(dev, PHY_APBONLY_MICRORESET, 1); + dbsc5_phy_apb_wr_ach(dev, PHY_APBONLY_MICROCONTMUXSEL, 0); + + return phytrainingok; +} + +/** + * dbsc5_ddr_config() - Configure DBSC5 registers + * @dev: DBSC5 device + */ +static void dbsc5_ddr_config(struct udevice *dev) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 ch, ddr_ch, i, tmp, val; + + foreach_vphych(dev, ch) { + /* Frequency settings */ + if (priv->ddr_mbps < (6401 * priv->ddr_mbpsdiv)) { /* 5501 - 6400 */ + for (i = 0; i < ARRAY_SIZE(cpu_trans_tab3_6400); i++) + dbsc5_phy_apb_wr(ch, cpu_trans_tab3_6400[i].addr, cpu_trans_tab3_6400[i].data); + } else if (priv->ddr_mbps < (7501 * priv->ddr_mbpsdiv)) { /* 6401 - 7500 */ + for (i = 0; i < ARRAY_SIZE(cpu_trans_tab3_7500); i++) + dbsc5_phy_apb_wr(ch, cpu_trans_tab3_7500[i].addr, cpu_trans_tab3_7500[i].data); + } else if (priv->ddr_mbps < (8534 * priv->ddr_mbpsdiv)) { /* 7501 - 8533 */ + /* Nothing */ + } else { /* 8534 - 9600 */ + for (i = 0; i < ARRAY_SIZE(cpu_trans_tab3_9600); i++) + dbsc5_phy_apb_wr(ch, cpu_trans_tab3_9600[i].addr, cpu_trans_tab3_9600[i].data); + } + + /* 2-Rank settings */ + if (priv->ch_have_this_cs[1] & (0x3 << (ch * 2))) { + /* PHY_ACx_P0_PCLKACLNDIS[9] : Tx SEC lane1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_AC_PCLKACLNDIS(0), 1, 9, 0x0); + ddrphy_apb_rd_mod_wr(ch, PHY_AC_PCLKACLNDIS(1), 1, 9, 0x0); + /* PHY_ACx_P0_DFICLKACLNDIS[9] : Tx SEC lane1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_AC_DFICLKACLNDIS(0), 1, 9, 0x0); + ddrphy_apb_rd_mod_wr(ch, PHY_AC_DFICLKACLNDIS(1), 1, 9, 0x0); + /* PHY_ACx_P0_ACLNDISABLE[9] : Tx SEC lane1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_AC_ACLNDISABLE(0), 1, 9, 0x0); + ddrphy_apb_rd_mod_wr(ch, PHY_AC_ACLNDISABLE(1), 1, 9, 0x0); + /* PHY_DBYTEx_P0_PPTCTLSTATIC[1] : PptEnDqs2DqTg1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(0), 1, 1, 0x1); + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(1), 1, 1, 0x1); + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(2), 1, 1, 0x1); + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(3), 1, 1, 0x1); + /* PHY_DBYTEx_P0_PPTCTLSTATIC[5] : PptEnWck2DqoTg1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(0), 1, 5, 0x1); + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(1), 1, 5, 0x1); + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(2), 1, 5, 0x1); + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(3), 1, 5, 0x1); + /* PHY_DBYTEx_P0_PPTCTLSTATIC[9] : PptEnRxEnDlyTg1 */ + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(0), 1, 9, 0x1); + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(1), 1, 9, 0x1); + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(2), 1, 9, 0x1); + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(3), 1, 9, 0x1); + } + + /* BOARD SETTINGS (CA, DQ, DMI) */ + /* CA_SWAP_CHA */ + ddr_ch = (ch * 2); + val = priv->dbsc5_board_config->ch[ddr_ch].bdcfg_ca_swap & 0xfffffff; + dbsc5_phy_apb_wr(ch, PHY_AC_MAPCA0TODFI(0), val & 0xf); + dbsc5_phy_apb_wr(ch, PHY_AC_MAPCA1TODFI(0), (val >> 4) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_AC_MAPCA2TODFI(0), (val >> 8) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_AC_MAPCA3TODFI(0), (val >> 12) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_AC_MAPCA4TODFI(0), (val >> 16) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_AC_MAPCA5TODFI(0), (val >> 20) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_AC_MAPCA6TODFI(0), (val >> 24) & 0xf); + + /* DQ_SWAP_CHA_SLICE0 */ + val = priv->dbsc5_board_config->ch[ddr_ch].bdcfg_dq_swap[0] & 0xffffffff; + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ0LNSEL(0), val & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ1LNSEL(0), (val >> 4) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ2LNSEL(0), (val >> 8) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ3LNSEL(0), (val >> 12) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ4LNSEL(0), (val >> 16) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ5LNSEL(0), (val >> 20) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ6LNSEL(0), (val >> 24) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ7LNSEL(0), (val >> 28) & 0xf); + + /* DM_SWAP_CHA_SLICE0 */ + val = priv->dbsc5_board_config->ch[ddr_ch].bdcfg_dm_swap[0] & 0xf; + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ8LNSEL(0), val & 0xf); + + /* DQ_SWAP_CHA_SLICE1 */ + val = priv->dbsc5_board_config->ch[ddr_ch].bdcfg_dq_swap[1] & 0xffffffff; + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ0LNSEL(1), val & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ1LNSEL(1), (val >> 4) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ2LNSEL(1), (val >> 8) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ3LNSEL(1), (val >> 12) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ4LNSEL(1), (val >> 16) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ5LNSEL(1), (val >> 20) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ6LNSEL(1), (val >> 24) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ7LNSEL(1), (val >> 28) & 0xf); + + /* DM_SWAP_CHA_SLICE1 */ + val = priv->dbsc5_board_config->ch[ddr_ch].bdcfg_dm_swap[1] & 0xf; + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ8LNSEL(1), val & 0xf); + + /* CA_SWAP_CHB */ + ddr_ch = ((ch * 2) + 1); + val = priv->dbsc5_board_config->ch[ddr_ch].bdcfg_ca_swap & 0xfffffff; + dbsc5_phy_apb_wr(ch, PHY_AC_MAPCA0TODFI(1), val & 0xf); + dbsc5_phy_apb_wr(ch, PHY_AC_MAPCA1TODFI(1), (val >> 4) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_AC_MAPCA2TODFI(1), (val >> 8) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_AC_MAPCA3TODFI(1), (val >> 12) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_AC_MAPCA4TODFI(1), (val >> 16) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_AC_MAPCA5TODFI(1), (val >> 20) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_AC_MAPCA6TODFI(1), (val >> 24) & 0xf); + + /* DQ_SWAP_CHB_SLICE0 */ + val = priv->dbsc5_board_config->ch[ddr_ch].bdcfg_dq_swap[0] & 0xffffffff; + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ0LNSEL(2), val & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ1LNSEL(2), (val >> 4) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ2LNSEL(2), (val >> 8) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ3LNSEL(2), (val >> 12) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ4LNSEL(2), (val >> 16) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ5LNSEL(2), (val >> 20) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ6LNSEL(2), (val >> 24) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ7LNSEL(2), (val >> 28) & 0xf); + + /* DM_SWAP_CHB_SLICE0 */ + val = priv->dbsc5_board_config->ch[ddr_ch].bdcfg_dm_swap[0] & 0xf; + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ8LNSEL(2), val & 0xf); + + /* DQ_SWAP_CHB_SLICE1 */ + val = priv->dbsc5_board_config->ch[ddr_ch].bdcfg_dq_swap[1] & 0xffffffff; + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ0LNSEL(3), val & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ1LNSEL(3), (val >> 4) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ2LNSEL(3), (val >> 8) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ3LNSEL(3), (val >> 12) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ4LNSEL(3), (val >> 16) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ5LNSEL(3), (val >> 20) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ6LNSEL(3), (val >> 24) & 0xf); + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ7LNSEL(3), (val >> 28) & 0xf); + + /* DM_SWAP_CHB_SLICE1 */ + val = priv->dbsc5_board_config->ch[ddr_ch].bdcfg_dm_swap[1] & 0xf; + dbsc5_phy_apb_wr(ch, PHY_DBYTE_DQ8LNSEL(3), val & 0xf); + + /* BOARD SETTINGS (DATA_BYTE_SWAP) */ + priv->upper_lower_byte[ch] = 0x0; + ddr_ch = ch * 2; + val = priv->dbsc5_board_config->ch[ddr_ch].bdcfg_dqs_swap; + if ((val & 0xff) == 0x1) { + /* PHY_DBYTEx_P0_PPTCTLSTATIC[3][2] : DOCByteSelTg1/0 */ + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(0), 2, 2, 0x3); + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(1), 2, 2, 0x0); + priv->upper_lower_byte[ch] |= 0x3; + } + + ddr_ch = (ch * 2) + 1; + val = priv->dbsc5_board_config->ch[ddr_ch].bdcfg_dqs_swap; + if ((val & 0xFF) == 0x1) { + /* PHY_DBYTEx_P0_PPTCTLSTATIC[3][2] : DOCByteSelTg1/0 */ + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(2), 2, 2, 0x3); + ddrphy_apb_rd_mod_wr(ch, PHY_DBYTE_PPTCTLSTATIC(3), 2, 2, 0x0); + priv->upper_lower_byte[ch] |= 0xc; + } + } + + /* Configure IO parameters */ + /* SOC Tx DRV for DQ */ + val = priv->dbsc5_board_config->bdcfg_tx_drv & 0xf; + tmp = (val << 4) | val; + for (i = 0; i < 8; i++) + dbsc5_phy_apb_wr_ach(dev, PHY_HMDBYTE_TXIMPEDANCEDQ(i), tmp); + + /* SOC Tx DRV for DQS */ + val = (priv->dbsc5_board_config->bdcfg_tx_drv >> 4) & 0xF; + tmp = (val << 8) | val; + for (i = 0; i < 8; i += 2) + dbsc5_phy_apb_wr_ach(dev, PHY_HMDBYTE_TXIMPEDANCEDQS(i), tmp); + + /* SOC Tx DRV for WCK */ + val = (priv->dbsc5_board_config->bdcfg_tx_drv >> 8) & 0xF; + tmp = (val << 12) | (val << 8) | (val << 4) | val; + for (i = 0; i < 8; i += 2) + dbsc5_phy_apb_wr_ach(dev, PHY_HMDBYTE_TXIMPEDANCEDQS(i + 1), tmp); + + /* SOC Tx DRV for CK */ + val = (priv->dbsc5_board_config->bdcfg_tx_drv >> 12) & 0xF; + tmp = (val << 4) | val; + dbsc5_phy_apb_wr_ach(dev, PHY_HMAC_TXIMPEDANCEAC(5), tmp); + dbsc5_phy_apb_wr_ach(dev, PHY_HMAC_TXIMPEDANCEAC(12), tmp); + + /* SOC Tx DRV for AC */ + val = (priv->dbsc5_board_config->bdcfg_tx_drv >> 16) & 0xF; + tmp = (val << 4) | val; + for (i = 0; i < 4; i++) + dbsc5_phy_apb_wr_ach(dev, PHY_HMAC_TXIMPEDANCEAC(i), tmp); + for (i = 0; i < 4; i++) + dbsc5_phy_apb_wr_ach(dev, PHY_HMAC_TXIMPEDANCEAC(i + 7), tmp); + + /* SOC Tx FFC for DQ */ + /* Rise */ + val = (priv->dbsc5_board_config->bdcfg_tx_ffc >> 28) & 0xF; + tmp = val; + /* Fall */ + val = (priv->dbsc5_board_config->bdcfg_tx_ffc >> 24) & 0xF; + tmp |= (val << 4); + for (i = 0; i < 8; i++) + dbsc5_phy_apb_wr_ach(dev, PHY_HMDBYTE_TXDQSLEW(i), tmp); + + /* SOC Tx FFC for CA */ + /* Rise */ + val = (priv->dbsc5_board_config->bdcfg_tx_ffc >> 20) & 0xF; + tmp = val; + /* Fall */ + val = (priv->dbsc5_board_config->bdcfg_tx_ffc >> 16) & 0xF; + tmp |= (val << 4); + for (i = 0; i < 4; i++) + dbsc5_phy_apb_wr_ach(dev, PHY_HMAC_TXSLEWAC(i), tmp); + for (i = 0; i < 4; i++) + dbsc5_phy_apb_wr_ach(dev, PHY_HMAC_TXSLEWAC(i + 7), tmp); + + /* SOC Tx FFC for CK */ + /* Rise */ + val = (priv->dbsc5_board_config->bdcfg_tx_ffc >> 12) & 0xF; + tmp = val; + /* Fall */ + val = (priv->dbsc5_board_config->bdcfg_tx_ffc >> 8) & 0xF; + tmp |= (val << 4); + dbsc5_phy_apb_wr_ach(dev, PHY_HMAC_TXSLEWAC(5), tmp); + dbsc5_phy_apb_wr_ach(dev, PHY_HMAC_TXSLEWAC(12), tmp); + + /* SOC Rx ODT for DQ */ + val = priv->dbsc5_board_config->bdcfg_rx_odt & 0xF; + tmp = val << 4; + for (i = 0; i < 8; i++) + dbsc5_phy_apb_wr_ach(dev, PHY_HMDBYTE_ODTIMPEDANCEDQ(i), tmp); + + /* SOC Rx ODT for DQS */ + val = (priv->dbsc5_board_config->bdcfg_rx_odt >> 4) & 0xF; + tmp = (val << 12) | (val << 8); + for (i = 0; i < 8; i += 2) + dbsc5_phy_apb_wr_ach(dev, PHY_HMDBYTE_ODTIMPEDANCEDQS(i), tmp); + + /* SOC Rx ODT for WCK */ + val = (priv->dbsc5_board_config->bdcfg_rx_odt >> 8) & 0xF; + tmp = (val << 12) | (val << 8); + for (i = 0; i < 8; i += 2) + dbsc5_phy_apb_wr_ach(dev, PHY_HMDBYTE_ODTIMPEDANCEDQS(i + 1), tmp); + + /* SOC Rx ODT for CK */ + val = (priv->dbsc5_board_config->bdcfg_rx_odt >> 12) & 0xF; + tmp = val << 4; + dbsc5_phy_apb_wr_ach(dev, PHY_HMAC_ODTIMPEDANCEAC(5), tmp); + dbsc5_phy_apb_wr_ach(dev, PHY_HMAC_ODTIMPEDANCEAC(12), tmp); + + /* SOC Rx ODT for AC */ + val = (priv->dbsc5_board_config->bdcfg_rx_odt >> 16) & 0xF; + tmp = val << 4; + for (i = 0; i < 5; i++) + dbsc5_phy_apb_wr_ach(dev, PHY_HMAC_ODTIMPEDANCEAC(i), tmp); + for (i = 0; i < 5; i++) + dbsc5_phy_apb_wr_ach(dev, PHY_HMAC_ODTIMPEDANCEAC(i + 7), tmp); + + /* Link ECC setting */ + if (priv->link_ecc_en) + for (i = 0; i < 4; i++) + dbsc5_phy_apb_wr_ach(dev, PHY_DBYTE_ENABLEWRITELINKECC(i), 0x1); +} + +/** + * dbsc5_phy_init() - Initialize DBSC5 PHY + * @dev: DBSC5 device + */ +static void dbsc5_phy_init(struct udevice *dev) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 ch, i; + + /* Initialize PHY Configuration */ + foreach_vphych(dev, ch) + for (i = 0; i < ARRAY_SIZE(cpu_trans_tab1); i++) + dbsc5_phy_apb_wr(ch, cpu_trans_tab1[i].addr, cpu_trans_tab1[i].data); + foreach_vphych(dev, ch) + for (i = 0; i < ARRAY_SIZE(cpu_trans_tab2); i++) + dbsc5_phy_apb_wr(ch, cpu_trans_tab2[i].addr, cpu_trans_tab2[i].data); + + if (priv->ddr_mbps < (6481 * priv->ddr_mbpsdiv)) { /* 5401 - 6480 */ + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL1, 0x808); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL4, 0x1C7F); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL5, 0x2E9A); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG0, 0x1009); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG1, 0x5060); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG2, 0x6B01); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG3, 0x423); + } else if (priv->ddr_mbps < (8537 * priv->ddr_mbpsdiv)) { /* 6481 - 8536 */ + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL1, 0x1008); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL4, 0x2C7F); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL5, 0x1A9A); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG0, 0x1009); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG1, 0x5060); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG2, 0x6B01); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG3, 0x423); + } else { + /* 8537 - 9600 */ + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL1, 0x1008); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL4, 0x2C7F); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLCTRL5, 0x1A9A); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG0, 0x1009); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG1, 0x5060); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG2, 0x6B01); + dbsc5_phy_apb_wr_ach(dev, PHY_HMMAS_CPLLUPLLPROG3, 0x423); + } + + dbsc5_phy_apb_wr_ach(dev, PHY_DRTUB_UCCLKHCLKENABLES, 0x5); + + dbsc5_rtdmac_phyinit_trans_ach(dev, DDR_PHY_ICCM_OFS, + (uintptr_t)DMAC_TRANS_ICCM, + ARRAY_SIZE(DMAC_TRANS_ICCM) * 4); + + dbsc5_phy_apb_wr_ach(dev, PHY_DRTUB_UCCLKHCLKENABLES, 0x7); + + foreach_vphych(dev, ch) + for (i = 0; i < ARRAY_SIZE(cpu_trans_tab3); i++) + dbsc5_phy_apb_wr(ch, cpu_trans_tab3[i].addr, cpu_trans_tab3[i].data); + + dbsc5_rtdmac_phyinit_trans_ach(dev, PHY_PPGC_ACSMDONE, ((uintptr_t)DATA_3_1), 128); + dbsc5_rtdmac_phyinit_trans_ach(dev, PHY_INITENG_SEQ0BGPR1, ((uintptr_t)DATA_3_2), 128); + dbsc5_rtdmac_phyinit_trans_ach(dev, PHY_INITENG_SEQ0BDLY0, ((uintptr_t)DATA_3_3), 64); + for (i = 0; i < 8; i += 2) { + dbsc5_rtdmac_phyinit_trans_ach(dev, PHY_HMDBYTE_VREGCTRL1DQ(i), + (uintptr_t)DATA_3_4, 256); + dbsc5_rtdmac_phyinit_trans_ach(dev, PHY_HMDBYTE_VREGCTRL1DQ(i + i), + (uintptr_t)DATA_3_5, 256); + } + + dbsc5_ddr_config(dev); + + dbsc5_phy_apb_wr_ach(dev, PHY_DRTUB_STARTDCCMCLEAR, 0x1); +} + +/** + * dbsc5_dfi_wait_init_complete() - Wait DFI init completion + * @dev: DBSC5 device + */ +static void dbsc5_dfi_wait_init_complete(struct udevice *dev) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 retry = 0, phytrainingok = 0; + const u32 RETRY_MAX = 0x10000; + u32 ch, val; + + while (retry < RETRY_MAX) { + foreach_vch(dev, ch) { + val = readl(DBSC_DBDFISTAT(ch)); + if (val & 0x1) + phytrainingok |= BIT(ch); + } + + if (phytrainingok == priv->ddr_dramvalid) + break; + + retry++; + } +} + +/** + * dbsc5_dfi_init_start() - Start DFI initialization + * @dev: DBSC5 device + */ +static void dbsc5_dfi_init_start(struct udevice *dev) +{ + u32 ch; + + foreach_vch(dev, ch) + writel(0x21, DBSC_DBDFICNT(ch)); + + dbsc5_dfi_wait_init_complete(dev); + + foreach_vch(dev, ch) + writel(0x20, DBSC_DBDFICNT(ch)); +} + +/** + * dbsc5_ddr_mode_register_set() - Set DDR mode registers + * @dev: DBSC5 device + */ +static void dbsc5_ddr_mode_register_set(struct udevice *dev) +{ + dbsc5_send_dbcmd(dev, 0xE841C24); /* MR28 */ + dbsc5_send_dbcmd(dev, 0xE842540); + dbsc5_send_dbcmd(dev, 0xE842840); +} + +/** + * dbsc5_ddr_mode_register_read() - Read DDR mode registers + * @dev: DBSC5 device + */ +static void dbsc5_ddr_mode_register_read(struct udevice *dev) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 ch, val; + + val = priv->dbsc5_board_config->bdcfg_rfm_chk; + if (!val) + return; + + dbsc5_send_dbcmd(dev, 0xF801B00); /* MR27:0 */ + dbsc5_send_dbcmd(dev, 0xF803900); /* MR57:0 */ + + foreach_vphych(dev, ch) { + if ((priv->ch_have_this_cs[1] & (0x3 << (ch * 2)))) { + dbsc5_send_dbcmd_ch(ch, 0xF811B00); /* MR27:1 */ + dbsc5_send_dbcmd_ch(ch, 0xF813900); /* MR57:1 */ + } + } +} + +/** + * dbsc5_phy_pll_lock_status_read() - Read PHY PLL lock status + * @dev: DBSC5 device + */ +static u32 dbsc5_phy_pll_lock_status_read(struct udevice *dev) +{ + u32 ch, ret = 0; + + foreach_vphych(dev, ch) + ret |= (readl(DBSC_DBPDSTAT01(ch)) & BIT(0)) << ch; + + return ret; +} + +/** + * dbsc5_ddr_initialize() - Initialize DDR + * @dev: DBSC5 device + */ +static int dbsc5_ddr_initialize(struct udevice *dev) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 ddrphy_pll_lock_ok, phytrainingok; + + dbsc5_regset_unlock(dev); + dbsc5_msres_status_set(dev, MODULE_STANDBY); + dbsc5_init_pll3(dev); + dbsc5_msres_status_set(dev, MODULE_RUN); + dbsc5_phy_init(dev); + dbsc5_dbsc_regset_pre(dev); + dbsc5_phy_data_load(dev); + phytrainingok = dbsc5_phy_training(dev); + if (phytrainingok != priv->ddr_phyvalid) + return -EINVAL; + + dbsc5_phy_init_load(dev); + dbsc5_dfi_init_start(dev); + ddrphy_pll_lock_ok = dbsc5_phy_pll_lock_status_read(dev); + if (ddrphy_pll_lock_ok != priv->ddr_phyvalid) + return -EINVAL; + + dbsc5_ddr_mode_register_set(dev); + dbsc5_ddr_mode_register_read(dev); + + dbsc5_dbsc_regset_post(dev); + dbsc5_regset_lock(dev); + + return 0; +} + +/** + * dbsc5_get_board_data() - Obtain board specific DRAM configuration + * @dev: DBSC5 device + * + * Return board specific DRAM configuration structure pointer. + */ +__weak const struct renesas_dbsc5_board_config * +dbsc5_get_board_data(struct udevice *dev) +{ + return &renesas_x5h_dbsc5_board_config; +} + +/** + * renesas_dbsc5_dram_probe() - DDR Initialize entry + * @dev: DBSC5 device + * + * Remove write protection on DBSC register. Read DDR configuration + * information from driver data. Calculate board clock frequency and + * operating frequency from DDR configuration information. Call the + * main function of DDR initialization. Perform DBSC write protection + * after initialization is complete. + */ +static int renesas_dbsc5_dram_probe(struct udevice *dev) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + u32 ch, cs, i; + + priv->dbsc5_board_config = dbsc5_get_board_data(dev); + + /* Link ECC only on SoC > 1.0 */ + if (renesas_get_cpu_rev_integer() == 1 && renesas_get_cpu_rev_fraction() == 0) + priv->link_ecc_en = 0; + else + priv->link_ecc_en = 1; + + priv->ddr_dramvalid = (u32)(priv->dbsc5_board_config->bdcfg_phyvalid); + priv->ddr_phyvalid = 0x0; + for (i = 0; i < DBSC5_PHYNUM_CNT; i++) { + priv->ddr_phyvalid |= ((((priv->ddr_dramvalid >> (i * 2)) | + (priv->ddr_dramvalid >> ((i * 2) + 1))) & 0x1) << i); + } + + for (cs = 0; cs < CS_CNT; cs++) + priv->ch_have_this_cs[cs] = 0; + + foreach_vch(dev, ch) + for (cs = 0; cs < CS_CNT; cs++) + if (priv->dbsc5_board_config->ch[ch].bdcfg_ddr_density[cs] != 0xff) + priv->ch_have_this_cs[cs] |= BIT(ch); + + /* Determine board clock frequency (in MHz) */ + priv->brd_clkdiv = 3; + switch (readl(SYSSS_PLL6_CR0)) { + case 0xa700000: /* 50 / 3 = 16.66MHz */ + priv->brd_clk = 50; + break; + case 0x8b00000: /* 60 / 3 = 20.00MHz */ + priv->brd_clk = 60; + break; + case 0xa700080: /* 100 / 3 = 33.33MHz */ + priv->brd_clk = 100; + break; + default: /* 50 / 3 = 16.66MHz */ + priv->brd_clk = 50; + break; + } + + priv->brd_clkdiva = !!(readl(SYSSS_PLL6_CR0) & BIT(7)); + + /* Determine DDR operating frequency clock (in Mbps) */ + priv->ddr_mbps = 6400; + priv->ddr_mbpsdiv = 1; + + /* Initialize DDR */ + return dbsc5_ddr_initialize(dev); +} + +/** + * renesas_dbsc5_dram_of_to_plat() - Convert OF data to plat data + * @dev: DBSC5 device + * + * Extract DBSC5 address from DT and store it in driver data. + */ +static int renesas_dbsc5_dram_of_to_plat(struct udevice *dev) +{ + struct renesas_dbsc5_dram_priv *priv = dev_get_priv(dev); + + priv->regs = dev_read_addr_ptr(dev); + if (!priv->regs) + return -EINVAL; + + return 0; +} + +/** + * renesas_dbsc5_dram_get_info() - Return RAM size + * @dev: DBSC5 device + * @info: Output RAM info + * + * Return size of the RAM managed by this RAM driver. + */ +static int renesas_dbsc5_dram_get_info(struct udevice *dev, + struct ram_info *info) +{ + info->base = 0x40000000; + info->size = 0; + + return 0; +} + +static const struct ram_ops renesas_dbsc5_dram_ops = { + .get_info = renesas_dbsc5_dram_get_info, +}; + +U_BOOT_DRIVER(renesas_dbsc5_dram) = { + .name = "dbsc5_dram", + .id = UCLASS_RAM, + .of_to_plat = renesas_dbsc5_dram_of_to_plat, + .ops = &renesas_dbsc5_dram_ops, + .probe = renesas_dbsc5_dram_probe, + .priv_auto = sizeof(struct renesas_dbsc5_dram_priv), +}; diff --git a/drivers/ram/renesas/dbsc5/r8a78000-dram.h b/drivers/ram/renesas/dbsc5/r8a78000-dram.h new file mode 100644 index 00000000000..ec810cd54bb --- /dev/null +++ b/drivers/ram/renesas/dbsc5/r8a78000-dram.h @@ -0,0 +1,7385 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * + * Portions Copyright (C) 2026 Synopsys, Inc. Used with permission. All rights reserved. + */ + +#ifndef __DRIVERS_RAM_RENESAS_DBSC5_R8A78000_DRAM_H__ +#define __DRIVERS_RAM_RENESAS_DBSC5_R8A78000_DRAM_H__ + +#define DDR_PHY_ICCM_OFS 0x00050000U +#define DDR_PHY_DCCM_OFS 0x00058000U +#define DDR_PHY_ACSM_OFS 0x00041454U +#define DDR_PHY_PIE_OFS 0x00044000U + +struct phyinitdata { + u32 addr; + u32 data; +}; + +static const struct phyinitdata cpu_trans_tab1[] = { + { 0x00030022, 0x00000002 }, + { 0x00031022, 0x00000002 }, + { 0x00004070, 0x000000FF }, + { 0x00005070, 0x00000077 }, + { 0x0000B070, 0x000000FF }, + { 0x0000C070, 0x00000077 }, + { 0x00104070, 0x000000FF }, + { 0x00105070, 0x00000077 }, + { 0x0010B070, 0x000000FF }, + { 0x0010C070, 0x00000077 }, + { 0x00204070, 0x000000FF }, + { 0x00205070, 0x00000077 }, + { 0x0020B070, 0x000000FF }, + { 0x0020C070, 0x00000077 }, + { 0x00304070, 0x000000FF }, + { 0x00305070, 0x00000077 }, + { 0x0030B070, 0x000000FF }, + { 0x0030C070, 0x00000077 }, + { 0x00000005, 0x00000003 }, + { 0x00001005, 0x00000003 }, + { 0x00002005, 0x00000003 }, + { 0x00003005, 0x00000003 }, + { 0x00004005, 0x00000003 }, + { 0x00005005, 0x00000003 }, + { 0x00007005, 0x00000003 }, + { 0x00008005, 0x00000003 }, + { 0x00009005, 0x00000003 }, + { 0x0000A005, 0x00000003 }, + { 0x0000B005, 0x00000003 }, + { 0x0000C005, 0x00000003 }, + { 0x000A0308, 0x00000002 }, + { 0x000A0002, 0x00000001 }, + { 0x000E0046, 0x00000006 }, + { 0x000E0047, 0x00000006 }, + { 0x000E0048, 0x00000006 }, + { 0x000E0049, 0x00000006 }, + { 0x000E1046, 0x00000006 }, + { 0x000E1047, 0x00000006 }, + { 0x000E1048, 0x00000006 }, + { 0x000E1049, 0x00000006 }, + { 0x000E104A, 0x00000006 }, + { 0x000E004B, 0x00000006 }, + { 0x000E104B, 0x00000006 }, + { 0x000E2046, 0x00000006 }, + { 0x000E2047, 0x00000006 }, + { 0x000E2048, 0x00000006 }, + { 0x000E2049, 0x00000006 }, + { 0x000E3046, 0x00000006 }, + { 0x000E3047, 0x00000006 }, + { 0x000E3048, 0x00000006 }, + { 0x000E3049, 0x00000006 }, + { 0x000E304A, 0x00000006 }, + { 0x000E204B, 0x00000006 }, + { 0x000E304B, 0x00000006 }, + { 0x000E4046, 0x00000006 }, + { 0x000E4047, 0x00000006 }, + { 0x000E4048, 0x00000006 }, + { 0x000E4049, 0x00000006 }, + { 0x000E5046, 0x00000006 }, + { 0x000E5047, 0x00000006 }, + { 0x000E5048, 0x00000006 }, + { 0x000E5049, 0x00000006 }, + { 0x000E504A, 0x00000006 }, + { 0x000E404B, 0x00000006 }, + { 0x000E504B, 0x00000006 }, + { 0x000E6046, 0x00000006 }, + { 0x000E6047, 0x00000006 }, + { 0x000E6048, 0x00000006 }, + { 0x000E6049, 0x00000006 }, + { 0x000E7046, 0x00000006 }, + { 0x000E7047, 0x00000006 }, + { 0x000E7048, 0x00000006 }, + { 0x000E7049, 0x00000006 }, + { 0x000E704A, 0x00000006 }, + { 0x000E604B, 0x00000006 }, + { 0x000E704B, 0x00000006 }, + { 0x00030020, 0x00000001 }, + { 0x00031020, 0x00000001 } +}; + +static const struct phyinitdata cpu_trans_tab2[] = { + { 0x00000005, 0x00000003 }, + { 0x00001005, 0x00000003 }, + { 0x00002005, 0x00000003 }, + { 0x00003005, 0x00000003 }, + { 0x00004005, 0x00000003 }, + { 0x00005005, 0x00000003 }, + { 0x00007005, 0x00000003 }, + { 0x00008005, 0x00000003 }, + { 0x00009005, 0x00000003 }, + { 0x0000A005, 0x00000003 }, + { 0x0000B005, 0x00000003 }, + { 0x0000C005, 0x00000003 }, + { 0x000A0308, 0x00000000 }, + { 0x000A0002, 0x00000001 }, + { 0x000E0046, 0x00000000 }, + { 0x000E0047, 0x00000000 }, + { 0x000E0048, 0x00000000 }, + { 0x000E0049, 0x00000000 }, + { 0x000E1046, 0x00000000 }, + { 0x000E1047, 0x00000000 }, + { 0x000E1048, 0x00000000 }, + { 0x000E1049, 0x00000000 }, + { 0x000E104A, 0x00000000 }, + { 0x000E004B, 0x00000002 }, + { 0x000E104B, 0x00000004 }, + { 0x000E2046, 0x00000000 }, + { 0x000E2047, 0x00000000 }, + { 0x000E2048, 0x00000000 }, + { 0x000E2049, 0x00000000 }, + { 0x000E3046, 0x00000000 }, + { 0x000E3047, 0x00000000 }, + { 0x000E3048, 0x00000000 }, + { 0x000E3049, 0x00000000 }, + { 0x000E304A, 0x00000000 }, + { 0x000E204B, 0x00000002 }, + { 0x000E304B, 0x00000004 }, + { 0x000E4046, 0x00000000 }, + { 0x000E4047, 0x00000000 }, + { 0x000E4048, 0x00000000 }, + { 0x000E4049, 0x00000000 }, + { 0x000E5046, 0x00000000 }, + { 0x000E5047, 0x00000000 }, + { 0x000E5048, 0x00000000 }, + { 0x000E5049, 0x00000000 }, + { 0x000E504A, 0x00000000 }, + { 0x000E404B, 0x00000002 }, + { 0x000E504B, 0x00000004 }, + { 0x000E6046, 0x00000000 }, + { 0x000E6047, 0x00000000 }, + { 0x000E6048, 0x00000000 }, + { 0x000E6049, 0x00000000 }, + { 0x000E7046, 0x00000000 }, + { 0x000E7047, 0x00000000 }, + { 0x000E7048, 0x00000000 }, + { 0x000E7049, 0x00000000 }, + { 0x000E704A, 0x00000000 }, + { 0x000E604B, 0x00000002 }, + { 0x000E704B, 0x00000004 }, + { 0x000200A5, 0x00000001 }, + { 0x00010097, 0x000007FF }, + { 0x00011097, 0x000007FF }, + { 0x00012097, 0x000007FF }, + { 0x00013097, 0x000007FF }, + { 0x0001003F, 0x00000001 }, + { 0x0001003F, 0x00000000 }, + { 0x0001103F, 0x00000001 }, + { 0x0001103F, 0x00000000 }, + { 0x0001203F, 0x00000001 }, + { 0x0001203F, 0x00000000 }, + { 0x0001303F, 0x00000001 }, + { 0x0001303F, 0x00000000 }, + { 0x000B0303, 0x00000009 }, + { 0x000A0302, 0x00000026 }, + { 0x000B0301, 0x00000000 }, + { 0x000B030F, 0x0000001D }, + { 0x00070067, 0x00000000 }, + { 0x000700E7, 0x00000000 }, + { 0x000300AE, 0x00001A80 }, + { 0x000300AD, 0x00001A80 }, + { 0x000300AC, 0x00001A80 }, + { 0x000310AE, 0x00001A80 }, + { 0x000310AD, 0x00001A80 }, + { 0x000310AC, 0x00001A80 }, + { 0x000100A3, 0x00000911 }, + { 0x000110A3, 0x0000091D }, + { 0x000120A3, 0x00000911 }, + { 0x000130A3, 0x0000091D }, + { 0x000C00F0, 0x00000001 }, + { 0x000C00F1, 0x00000002 }, + { 0x000C00F2, 0x00000007 }, + { 0x000C00F3, 0x00000034 }, + { 0x00090733, 0x0000002D }, + { 0x000C00F4, 0x00000005 }, + { 0x000C00F7, 0x0000F000 }, + { 0x00090737, 0x00000A00 }, + { 0x0009071F, 0x00000004 }, + { 0x00090829, 0x0000000F }, + { 0x00020007, 0x00000000 }, + { 0x000E007A, 0x00000000 }, + { 0x000E107A, 0x00000001 }, + { 0x000E207A, 0x00000000 }, + { 0x000E307A, 0x00000001 }, + { 0x000E407A, 0x00000000 }, + { 0x000E507A, 0x00000001 }, + { 0x000E607A, 0x00000000 }, + { 0x000E707A, 0x00000001 }, + { 0x0000061E, 0x00000000 }, + { 0x0000E61E, 0x00000000 }, + { 0x0000161E, 0x00000000 }, + { 0x0000261E, 0x00000000 }, + { 0x0000361E, 0x00000000 }, + { 0x0000461E, 0x00000000 }, + { 0x0000561E, 0x00000000 }, + { 0x0000761E, 0x00000000 }, + { 0x0000861E, 0x00000000 }, + { 0x0000961E, 0x00000000 }, + { 0x0000A61E, 0x00000000 }, + { 0x0000B61E, 0x00000000 }, + { 0x0000C61E, 0x00000000 }, + { 0x00010E1F, 0x00000000 }, + { 0x00011E1F, 0x00000000 }, + { 0x00012E1F, 0x00000000 }, + { 0x00013E1F, 0x00000000 }, + { 0x00030807, 0x0000EE66 }, + { 0x00031807, 0x0000EE66 }, + { 0x00010807, 0x0000EE66 }, + { 0x00011807, 0x0000EE66 }, + { 0x00012807, 0x0000EE66 }, + { 0x00013807, 0x0000EE66 }, + { 0x000300A0, 0x00003FFF }, + { 0x000310A0, 0x00003FFF }, + { 0x00010089, 0x00001FFF }, + { 0x0001008A, 0x000007FF }, + { 0x00011089, 0x00001FFF }, + { 0x0001108A, 0x000007FF }, + { 0x00012089, 0x00001FFF }, + { 0x0001208A, 0x000007FF }, + { 0x00013089, 0x00001FFF }, + { 0x0001308A, 0x000007FF }, + { 0x00020006, 0x0000000F }, + { 0x0002000C, 0x00000000 }, + { 0x000E000D, 0x00000001 }, + { 0x000E100D, 0x00000001 }, + { 0x000E200D, 0x00000001 }, + { 0x000E300D, 0x00000001 }, + { 0x000E400D, 0x00000001 }, + { 0x000E500D, 0x00000001 }, + { 0x000E600D, 0x00000001 }, + { 0x000E700D, 0x00000001 }, + { 0x00030027, 0x00000001 }, + { 0x0000003F, 0x00000001 }, + { 0x0000103F, 0x00000001 }, + { 0x0000203F, 0x00000001 }, + { 0x0000303F, 0x00000001 }, + { 0x0000403F, 0x00000001 }, + { 0x0000503F, 0x00000001 }, + { 0x00031027, 0x00000001 }, + { 0x0000703F, 0x00000001 }, + { 0x0000803F, 0x00000001 }, + { 0x0000903F, 0x00000001 }, + { 0x0000A03F, 0x00000001 }, + { 0x0000B03F, 0x00000001 }, + { 0x0000C03F, 0x00000001 } +}; + +static const struct phyinitdata cpu_trans_tab3[] = { + { 0x0002008B, 0x00000000 }, + { 0x000A03FF, 0x00004101 }, + { 0x000A030B, 0x00000000 }, + { 0x00060008, 0x00000E9A }, + { 0x00020002, 0x00000007 }, + { 0x00060040, 0x00000007 }, + { 0x00020000, 0x00000002 }, + { 0x000100FB, 0x00000000 }, + { 0x000110FB, 0x00000000 }, + { 0x000120FB, 0x00000000 }, + { 0x000130FB, 0x00000000 }, + { 0x00010024, 0x00000200 }, + { 0x00011024, 0x00000200 }, + { 0x00012024, 0x00000200 }, + { 0x00013024, 0x00000200 }, + { 0x00010025, 0x0000002C }, + { 0x00011025, 0x0000002C }, + { 0x00012025, 0x0000002C }, + { 0x00013025, 0x0000002C }, + { 0x00010004, 0x00000000 }, + { 0x00010003, 0x00000000 }, + { 0x00011004, 0x00000000 }, + { 0x00011003, 0x00000000 }, + { 0x00012004, 0x00000000 }, + { 0x00012003, 0x00000000 }, + { 0x00013004, 0x00000000 }, + { 0x00013003, 0x00000000 }, + { 0x000B0004, 0x0000042A }, + { 0x000A030C, 0x00000000 }, + { 0x0001003E, 0x00000005 }, + { 0x0001103E, 0x00000005 }, + { 0x0001203E, 0x00000005 }, + { 0x0001303E, 0x00000005 }, + { 0x00020003, 0x00000001 }, + { 0x0002000B, 0x00001111 }, + { 0x00010108, 0x00000000 }, + { 0x00011108, 0x00000000 }, + { 0x00012108, 0x00000000 }, + { 0x00013108, 0x00000000 }, + { 0x00070005, 0x00000003 }, + { 0x0007000F, 0x00000000 }, + { 0x0001000E, 0x00001301 }, + { 0x0001100E, 0x00001301 }, + { 0x0001200E, 0x00001301 }, + { 0x0001300E, 0x00001301 }, + { 0x00020019, 0x00000004 }, + { 0x00000070, 0x00000077 }, + { 0x00001070, 0x00000077 }, + { 0x00002070, 0x00000077 }, + { 0x00003070, 0x00000077 }, + { 0x00004070, 0x000000FF }, + { 0x00005070, 0x00000077 }, + { 0x00007070, 0x00000077 }, + { 0x00008070, 0x00000077 }, + { 0x00009070, 0x00000077 }, + { 0x0000A070, 0x00000077 }, + { 0x0000B070, 0x000000FF }, + { 0x0000C070, 0x00000077 }, + { 0x00000079, 0x00000030 }, + { 0x00001079, 0x00000030 }, + { 0x00002079, 0x00000030 }, + { 0x00003079, 0x00000030 }, + { 0x00004079, 0x00000030 }, + { 0x00005079, 0x00000030 }, + { 0x00007079, 0x00000030 }, + { 0x00008079, 0x00000030 }, + { 0x00009079, 0x00000030 }, + { 0x0000A079, 0x00000030 }, + { 0x0000B079, 0x00000030 }, + { 0x0000C079, 0x00000030 }, + { 0x0000006D, 0x00000000 }, + { 0x0000106D, 0x00000000 }, + { 0x0000206D, 0x00000000 }, + { 0x0000306D, 0x00000000 }, + { 0x0000406D, 0x00000000 }, + { 0x0000506D, 0x00000000 }, + { 0x0000706D, 0x00000000 }, + { 0x0000806D, 0x00000000 }, + { 0x0000906D, 0x00000000 }, + { 0x0000A06D, 0x00000000 }, + { 0x0000B06D, 0x00000000 }, + { 0x0000C06D, 0x00000000 }, + { 0x00010001, 0x00000000 }, + { 0x00011001, 0x00000000 }, + { 0x00012001, 0x00000000 }, + { 0x00013001, 0x00000000 }, + { 0x00070040, 0x00000050 }, + { 0x00070041, 0x0000000F }, + { 0x000100A5, 0x00000001 }, + { 0x000110A5, 0x00000001 }, + { 0x000120A5, 0x00000001 }, + { 0x000130A5, 0x00000001 }, + { 0x00010209, 0x00003232 }, + { 0x00011209, 0x00003232 }, + { 0x00012209, 0x00003232 }, + { 0x00013209, 0x00003232 }, + { 0x0001020F, 0x00000006 }, + { 0x0001120F, 0x00000006 }, + { 0x0001220F, 0x00000006 }, + { 0x0001320F, 0x00000006 }, + { 0x00020005, 0x00001111 }, + { 0x00010008, 0x00000001 }, + { 0x00011008, 0x00000001 }, + { 0x00012008, 0x00000001 }, + { 0x00013008, 0x00000001 }, + { 0x0007006B, 0x00000111 }, + { 0x00070066, 0x00000A10 }, + { 0x000700EB, 0x00000111 }, + { 0x000700E6, 0x00000A10 }, + { 0x00030008, 0x00000000 }, + { 0x00031008, 0x00000000 }, + { 0x000005E3, 0x00000004 }, + { 0x000015E3, 0x00000004 }, + { 0x000025E3, 0x00000004 }, + { 0x000035E3, 0x00000004 }, + { 0x000045E3, 0x00000004 }, + { 0x000055E3, 0x00000004 }, + { 0x000075E3, 0x00000004 }, + { 0x000085E3, 0x00000004 }, + { 0x000095E3, 0x00000004 }, + { 0x0000A5E3, 0x00000004 }, + { 0x0000B5E3, 0x00000004 }, + { 0x0000C5E3, 0x00000004 }, + { 0x000E05E3, 0x00000004 }, + { 0x000E15E3, 0x00000004 }, + { 0x000E25E3, 0x00000004 }, + { 0x000E35E3, 0x00000004 }, + { 0x000E45E3, 0x00000004 }, + { 0x000E55E3, 0x00000004 }, + { 0x000E65E3, 0x00000004 }, + { 0x000E75E3, 0x00000004 }, + { 0x0000050A, 0x00000001 }, + { 0x0000150A, 0x00000001 }, + { 0x0000250A, 0x00000001 }, + { 0x0000350A, 0x00000001 }, + { 0x0000450A, 0x00000001 }, + { 0x0000550A, 0x00000001 }, + { 0x0000750A, 0x00000001 }, + { 0x0000850A, 0x00000001 }, + { 0x0000950A, 0x00000001 }, + { 0x0000A50A, 0x00000001 }, + { 0x0000B50A, 0x00000001 }, + { 0x0000C50A, 0x00000001 }, + { 0x0001080B, 0x00000001 }, + { 0x0001180B, 0x00000001 }, + { 0x0001280B, 0x00000001 }, + { 0x0001380B, 0x00000001 }, + { 0x00030803, 0x0000108A }, + { 0x00031803, 0x0000108A }, + { 0x00010803, 0x0000108A }, + { 0x00011803, 0x0000108A }, + { 0x00012803, 0x0000108A }, + { 0x00013803, 0x0000108A }, + { 0x00000503, 0x0000002B }, + { 0x00001503, 0x0000002B }, + { 0x00002503, 0x0000002B }, + { 0x00003503, 0x0000002B }, + { 0x00004503, 0x0000002B }, + { 0x00005503, 0x0000002B }, + { 0x00007503, 0x0000002B }, + { 0x00008503, 0x0000002B }, + { 0x00009503, 0x0000002B }, + { 0x0000A503, 0x0000002B }, + { 0x0000B503, 0x0000002B }, + { 0x0000C503, 0x0000002B }, + { 0x00010C03, 0x0000002B }, + { 0x00011C03, 0x0000002B }, + { 0x00012C03, 0x0000002B }, + { 0x00013C03, 0x0000002B }, + { 0x00000110, 0x0000001F }, + { 0x00001110, 0x0000001F }, + { 0x00002110, 0x0000001F }, + { 0x00003110, 0x0000001F }, + { 0x00004110, 0x0000001F }, + { 0x00005110, 0x0000001F }, + { 0x00007110, 0x0000001F }, + { 0x00008110, 0x0000001F }, + { 0x00009110, 0x0000001F }, + { 0x0000A110, 0x0000001F }, + { 0x0000B110, 0x0000001F }, + { 0x0000C110, 0x0000001F }, + { 0x000E0110, 0x0000001F }, + { 0x000E1110, 0x0000001F }, + { 0x000E2110, 0x0000001F }, + { 0x000E3110, 0x0000001F }, + { 0x000E4110, 0x0000001F }, + { 0x000E5110, 0x0000001F }, + { 0x000E6110, 0x0000001F }, + { 0x000E7110, 0x0000001F }, + { 0x0001010B, 0x00000003 }, + { 0x0001110B, 0x00000003 }, + { 0x0001210B, 0x00000003 }, + { 0x0001310B, 0x00000003 }, + { 0x00000063, 0x0000004E }, + { 0x00001063, 0x0000004E }, + { 0x00002063, 0x0000004E }, + { 0x00003063, 0x0000004E }, + { 0x00004063, 0x0000004E }, + { 0x00005063, 0x0000004E }, + { 0x00007063, 0x0000004E }, + { 0x00008063, 0x0000004E }, + { 0x00009063, 0x0000004E }, + { 0x0000A063, 0x0000004E }, + { 0x0000B063, 0x0000004E }, + { 0x0000C063, 0x0000004E }, + { 0x000E0063, 0x0000004E }, + { 0x000E0064, 0x0000004E }, + { 0x000E0087, 0x0000004E }, + { 0x000E1063, 0x0000004E }, + { 0x000E1064, 0x0000004E }, + { 0x000E1087, 0x0000004E }, + { 0x000E2063, 0x0000004E }, + { 0x000E2064, 0x0000004E }, + { 0x000E2087, 0x0000004E }, + { 0x000E3063, 0x0000004E }, + { 0x000E3064, 0x0000004E }, + { 0x000E3087, 0x0000004E }, + { 0x000E4063, 0x0000004E }, + { 0x000E4064, 0x0000004E }, + { 0x000E4087, 0x0000004E }, + { 0x000E5063, 0x0000004E }, + { 0x000E5064, 0x0000004E }, + { 0x000E5087, 0x0000004E }, + { 0x000E6063, 0x0000004E }, + { 0x000E6064, 0x0000004E }, + { 0x000E6087, 0x0000004E }, + { 0x000E7063, 0x0000004E }, + { 0x000E7064, 0x0000004E }, + { 0x000E7087, 0x0000004E }, + { 0x000C0080, 0x00000007 }, + { 0x000300EB, 0x00000000 }, + { 0x000310EB, 0x00000000 } +}; + +static const struct phyinitdata cpu_trans_tab4[] = { + { 0x000B0310, 0x00000001 }, + { 0x000B0311, 0x00000001 }, + { 0x00060008, 0x00000D56 }, + { 0x00060006, 0x000003F0 }, + { 0x00010075, 0x00000001 }, + { 0x00011075, 0x00000001 }, + { 0x00012075, 0x00000001 }, + { 0x00013075, 0x00000001 }, + { 0x00030015, 0x00000000 }, + { 0x00031015, 0x00000000 }, + { 0x0001007C, 0x00000000 }, + { 0x0001107C, 0x00000000 }, + { 0x0001207C, 0x00000000 }, + { 0x0001307C, 0x00000000 }, + { 0x00070141, 0x00000000 }, + { 0x000B0001, 0x00000003 }, + { 0x0009080C, 0x00000003 }, + { 0x00010027, 0x00000001 }, + { 0x00011027, 0x00000001 }, + { 0x00012027, 0x00000001 }, + { 0x00013027, 0x00000001 }, + { 0x0001020F, 0x00000009 }, + { 0x0001120F, 0x00000009 }, + { 0x0001220F, 0x00000009 }, + { 0x0001320F, 0x00000009 }, + { 0x000E003F, 0x00000001 }, + { 0x000E008D, 0x00000001 }, + { 0x000E103F, 0x00000001 }, + { 0x000E108D, 0x00000001 }, + { 0x000E203F, 0x00000001 }, + { 0x000E208D, 0x00000001 }, + { 0x000E303F, 0x00000001 }, + { 0x000E308D, 0x00000001 }, + { 0x000E403F, 0x00000001 }, + { 0x000E408D, 0x00000001 }, + { 0x000E503F, 0x00000001 }, + { 0x000E508D, 0x00000001 }, + { 0x000E603F, 0x00000001 }, + { 0x000E608D, 0x00000001 }, + { 0x000E703F, 0x00000001 }, + { 0x000E708D, 0x00000001 }, + { 0x00090903, 0x00000000 }, + { 0x00070072, 0x00000001 }, + { 0x0009080E, 0x00000001 }, + { 0x00070073, 0x00000001 }, + { 0x0009080F, 0x00000001 } +}; + +static const struct phyinitdata cpu_trans_tab5[] = { + { 0x00070334, 0x0000011B }, + { 0x00070335, 0x0000011F }, + { 0x00070336, 0x00000121 }, + { 0x00070337, 0x00000122 }, + { 0x00070339, 0x00000123 }, + { 0x0007033A, 0x00000124 }, + { 0x0007033C, 0x00000125 }, + { 0x0007033D, 0x0000013E }, + { 0x0007033E, 0x00000148 }, + { 0x0007033F, 0x00000160 }, + { 0x00070350, 0x00000170 }, + { 0x00070351, 0x00000188 }, + { 0x00070352, 0x00000191 }, + { 0x00070353, 0x000001A3 } +}; + +static const struct phyinitdata cpu_trans_tab6[] = { + { 0x0007039B, 0x0000011E }, + { 0x0007039C, 0x00000120 }, + { 0x0007039D, 0x00000121 }, + { 0x0007039E, 0x00000122 }, + { 0x000703A0, 0x00000123 }, + { 0x000703A1, 0x00000124 }, + { 0x000703A3, 0x0000013D }, + { 0x000703A4, 0x00000147 }, + { 0x000703A5, 0x0000015F }, + { 0x000703A6, 0x0000016F }, + { 0x000703B7, 0x00000187 }, + { 0x000703B8, 0x00000190 }, + { 0x000703B9, 0x000001A2 }, + { 0x000703BA, 0x000001B3 }, + { 0x00070200, 0x0000040E }, + { 0x00070202, 0x0000044F }, + { 0x00070204, 0x000000C0 }, + { 0x00070205, 0x00000246 }, + { 0x00070206, 0x00000101 }, + { 0x00070207, 0x00000287 }, + { 0x00070208, 0x00000142 }, + { 0x00070209, 0x000002C8 }, + { 0x0007020A, 0x00000012 }, + { 0x0007020B, 0x0000034C }, + { 0x0007020C, 0x00000015 }, + { 0x0007020E, 0x00000016 }, + { 0x00070212, 0x0000002C }, + { 0x00070213, 0x00000018 }, + { 0x00070214, 0x0000002D }, + { 0x00070215, 0x00000019 }, + { 0x00070216, 0x0000002E }, + { 0x00070217, 0x0000001A }, + { 0x00070218, 0x0000002F }, + { 0x00070219, 0x0000001B }, + { 0x0007021A, 0x00000013 }, + { 0x0009001C, 0x00000267 }, + { 0x0009001D, 0x00000267 }, + { 0x0009001E, 0x00000267 }, + { 0x0009001F, 0x00000267 }, + { 0x00090020, 0x000002A0 }, + { 0x00090021, 0x00000267 }, + { 0x00090022, 0x00000000 }, + { 0x00090023, 0x00000000 }, + { 0x00090024, 0x00000000 }, + { 0x00090025, 0x00000000 }, + { 0x00090026, 0x00000000 }, + { 0x00090027, 0x00000000 }, + { 0x0009002B, 0x0000029D }, + { 0x00070145, 0x00000004 } +}; + +static const struct phyinitdata cpu_trans_tab7[] = { + { 0x000700F0, 0x00000B6D }, + { 0x000100B9, 0x00000001 }, + { 0x000100B1, 0x00000180 }, + { 0x000100BA, 0x00000001 }, + { 0x000100A2, 0x00000000 }, + { 0x000100B5, 0x00000001 }, + { 0x00010E2B, 0x00005A3C }, + { 0x00010E2A, 0x00005A3C }, + { 0x00010E20, 0x00000002 }, + { 0x000110B9, 0x00000001 }, + { 0x000110B1, 0x00000180 }, + { 0x000110BA, 0x00000001 }, + { 0x000110A2, 0x00000000 }, + { 0x000110B5, 0x00000001 }, + { 0x00011E2B, 0x00005A3C }, + { 0x00011E2A, 0x00005A3C }, + { 0x00011E20, 0x00000002 }, + { 0x000120B9, 0x00000001 }, + { 0x000120B1, 0x00000180 }, + { 0x000120BA, 0x00000001 }, + { 0x000120A2, 0x00000000 }, + { 0x000120B5, 0x00000001 }, + { 0x00012E2B, 0x00005A3C }, + { 0x00012E2A, 0x00005A3C }, + { 0x00012E20, 0x00000002 }, + { 0x000130B9, 0x00000001 }, + { 0x000130B1, 0x00000180 }, + { 0x000130BA, 0x00000001 }, + { 0x000130A2, 0x00000000 }, + { 0x000130B5, 0x00000001 }, + { 0x00013E2B, 0x00005A3C }, + { 0x00013E2A, 0x00005A3C }, + { 0x00013E20, 0x00000002 }, + { 0x0007001C, 0x00005A3C }, + { 0x0007001B, 0x00005A3C }, + { 0x00070010, 0x00000002 }, + { 0x0007007E, 0x00000041 }, + { 0x000701EF, 0x00007FFF }, + { 0x000300A6, 0x00000001 }, + { 0x000310A6, 0x00000001 }, + { 0x000701A8, 0x00000000 }, + { 0x00070128, 0x00000000 }, + { 0x00070131, 0x00000000 }, + { 0x00070132, 0x00000000 }, + { 0x00070133, 0x00000000 }, + { 0x00070134, 0x00000000 }, + { 0x00070142, 0x00000000 }, + { 0x00070144, 0x00000000 } +}; + +static const struct phyinitdata cpu_trans_tab3_7500[] = { + { 0x000908E0, 0x00000076 }, + { 0x000908E1, 0x00000160 }, + { 0x000908E2, 0x00000927 }, + { 0x000908E4, 0x00000018 }, + { 0x000908EA, 0x00000005 }, + { 0x000908EB, 0x00000005 }, + { 0x000908EC, 0x0000000C }, + { 0x000908ED, 0x0000005B }, + { 0x000B0004, 0x000003A9 }, + { 0x00070066, 0x00000910 }, + { 0x000700E6, 0x00000910 }, + { 0x00070135, 0x00001410 }, + { 0x00070136, 0x00001410 }, + { 0x00070137, 0x00000424 }, + { 0x00070138, 0x00001928 }, + { 0x00070139, 0x00001418 }, + { 0x0007013A, 0x00001418 }, + { 0x0007013B, 0x0000042C }, + { 0x0007013C, 0x00003530 }, + { 0x0007013D, 0x00001408 }, + { 0x0007013E, 0x00001408 }, + { 0x0007013F, 0x0000041C }, + { 0x00070140, 0x00001120 }, + { 0x0007012C, 0x00000843 }, + { 0x0007012D, 0x00000843 }, + { 0x00070130, 0x00000843 }, + { 0x0007012E, 0x00000827 }, + { 0x0007012F, 0x00000827 }, + { 0x00030803, 0x0000107A }, + { 0x00031803, 0x0000107A }, + { 0x00010803, 0x0000107A }, + { 0x00011803, 0x0000107A }, + { 0x00012803, 0x0000107A }, + { 0x00013803, 0x0000107A }, + { 0x00000503, 0x00000027 }, + { 0x00001503, 0x00000027 }, + { 0x00002503, 0x00000027 }, + { 0x00003503, 0x00000027 }, + { 0x00004503, 0x00000027 }, + { 0x00005503, 0x00000027 }, + { 0x00007503, 0x00000027 }, + { 0x00008503, 0x00000027 }, + { 0x00009503, 0x00000027 }, + { 0x0000A503, 0x00000027 }, + { 0x0000B503, 0x00000027 }, + { 0x0000C503, 0x00000027 }, + { 0x00010C03, 0x00000027 }, + { 0x00011C03, 0x00000027 }, + { 0x00012C03, 0x00000027 }, + { 0x00013C03, 0x00000027 }, + { 0x000908E8, 0x00000015 }, + { 0x000908E9, 0x00000048 }, + { 0x00000063, 0x00000058 }, + { 0x00001063, 0x00000058 }, + { 0x00002063, 0x00000058 }, + { 0x00003063, 0x00000058 }, + { 0x00004063, 0x00000058 }, + { 0x00005063, 0x00000058 }, + { 0x00007063, 0x00000058 }, + { 0x00008063, 0x00000058 }, + { 0x00009063, 0x00000058 }, + { 0x0000A063, 0x00000058 }, + { 0x0000B063, 0x00000058 }, + { 0x0000C063, 0x00000058 }, + { 0x0009080A, 0x00000258 }, + { 0x0009080B, 0x00000058 }, + { 0x00090815, 0x00000258 }, + { 0x00090816, 0x00000058 }, + { 0x000E0063, 0x00000058 }, + { 0x000E0064, 0x00000058 }, + { 0x000E0087, 0x00000058 }, + { 0x000E1063, 0x00000058 }, + { 0x000E1064, 0x00000058 }, + { 0x000E1087, 0x00000058 }, + { 0x000E2063, 0x00000058 }, + { 0x000E2064, 0x00000058 }, + { 0x000E2087, 0x00000058 }, + { 0x000E3063, 0x00000058 }, + { 0x000E3064, 0x00000058 }, + { 0x000E3087, 0x00000058 }, + { 0x000E4063, 0x00000058 }, + { 0x000E4064, 0x00000058 }, + { 0x000E4087, 0x00000058 }, + { 0x000E5063, 0x00000058 }, + { 0x000E5064, 0x00000058 }, + { 0x000E5087, 0x00000058 }, + { 0x000E6063, 0x00000058 }, + { 0x000E6064, 0x00000058 }, + { 0x000E6087, 0x00000058 }, + { 0x000E7063, 0x00000058 }, + { 0x000E7064, 0x00000058 }, + { 0x000E7087, 0x00000058 }, + { 0x00090817, 0x00000061 } +}; + +static const struct phyinitdata cpu_trans_tab3_9600[] = { + { 0x000908E0, 0x00000096 }, + { 0x000908E1, 0x000001C2 }, + { 0x000908E2, 0x00000BB8 }, + { 0x000908E4, 0x0000001E }, + { 0x000908EC, 0x0000000F }, + { 0x000908ED, 0x00000075 }, + { 0x000B0004, 0x000004B0 }, + { 0x00070066, 0x00000B10 }, + { 0x000700E6, 0x00000B10 }, + { 0x00070135, 0x00001C14 }, + { 0x00070136, 0x00001C14 }, + { 0x00070137, 0x00000430 }, + { 0x00070138, 0x00001934 }, + { 0x00070139, 0x00001C1C }, + { 0x0007013A, 0x00001C1C }, + { 0x0007013B, 0x00000438 }, + { 0x0007013C, 0x00003D3C }, + { 0x0007013D, 0x00001C08 }, + { 0x0007013E, 0x00001C08 }, + { 0x0007013F, 0x00000424 }, + { 0x00070140, 0x00001128 }, + { 0x0007012C, 0x00000857 }, + { 0x0007012D, 0x00000857 }, + { 0x00070130, 0x00000857 }, + { 0x0007012E, 0x00000833 }, + { 0x0007012F, 0x00000833 }, + { 0x00030803, 0x0000109A }, + { 0x00031803, 0x0000109A }, + { 0x00010803, 0x0000109A }, + { 0x00011803, 0x0000109A }, + { 0x00012803, 0x0000109A }, + { 0x00013803, 0x0000109A }, + { 0x00000503, 0x0000002F }, + { 0x00001503, 0x0000002F }, + { 0x00002503, 0x0000002F }, + { 0x00003503, 0x0000002F }, + { 0x00004503, 0x0000002F }, + { 0x00005503, 0x0000002F }, + { 0x00007503, 0x0000002F }, + { 0x00008503, 0x0000002F }, + { 0x00009503, 0x0000002F }, + { 0x0000A503, 0x0000002F }, + { 0x0000B503, 0x0000002F }, + { 0x0000C503, 0x0000002F }, + { 0x00010C03, 0x0000002F }, + { 0x00011C03, 0x0000002F }, + { 0x00012C03, 0x0000002F }, + { 0x00013C03, 0x0000002F }, + { 0x000908E8, 0x00000019 }, + { 0x000908E9, 0x00000056 }, + { 0x00000063, 0x00000045 }, + { 0x00001063, 0x00000045 }, + { 0x00002063, 0x00000045 }, + { 0x00003063, 0x00000045 }, + { 0x00004063, 0x00000045 }, + { 0x00005063, 0x00000045 }, + { 0x00007063, 0x00000045 }, + { 0x00008063, 0x00000045 }, + { 0x00009063, 0x00000045 }, + { 0x0000A063, 0x00000045 }, + { 0x0000B063, 0x00000045 }, + { 0x0000C063, 0x00000045 }, + { 0x0009080A, 0x00000245 }, + { 0x0009080B, 0x00000045 }, + { 0x00090815, 0x00000245 }, + { 0x00090816, 0x00000045 }, + { 0x000E0063, 0x00000045 }, + { 0x000E0064, 0x00000045 }, + { 0x000E0087, 0x00000045 }, + { 0x000E1063, 0x00000045 }, + { 0x000E1064, 0x00000045 }, + { 0x000E1087, 0x00000045 }, + { 0x000E2063, 0x00000045 }, + { 0x000E2064, 0x00000045 }, + { 0x000E2087, 0x00000045 }, + { 0x000E3063, 0x00000045 }, + { 0x000E3064, 0x00000045 }, + { 0x000E3087, 0x00000045 }, + { 0x000E4063, 0x00000045 }, + { 0x000E4064, 0x00000045 }, + { 0x000E4087, 0x00000045 }, + { 0x000E5063, 0x00000045 }, + { 0x000E5064, 0x00000045 }, + { 0x000E5087, 0x00000045 }, + { 0x000E6063, 0x00000045 }, + { 0x000E6064, 0x00000045 }, + { 0x000E6087, 0x00000045 }, + { 0x000E7063, 0x00000045 }, + { 0x000E7064, 0x00000045 }, + { 0x000E7087, 0x00000045 }, + { 0x00090817, 0x0000007D } +}; + +static const struct phyinitdata cpu_trans_tab3_6400[] = { + { 0x00060008, 0x00002E9A }, + { 0x000908E0, 0x00000064 }, + { 0x000908E1, 0x0000012C }, + { 0x000908E2, 0x000007D0 }, + { 0x000908E4, 0x00000014 }, + { 0x000908EA, 0x00000004 }, + { 0x000908EB, 0x00000004 }, + { 0x000908EC, 0x0000000A }, + { 0x000908ED, 0x0000004E }, + { 0x000B0004, 0x00000320 }, + { 0x00070066, 0x00000810 }, + { 0x000700E6, 0x00000810 }, + { 0x00070135, 0x0000100C }, + { 0x00070136, 0x0000100C }, + { 0x00070137, 0x0000041C }, + { 0x00070138, 0x00001920 }, + { 0x00070139, 0x00001018 }, + { 0x0007013A, 0x00001018 }, + { 0x0007013B, 0x00000428 }, + { 0x0007013C, 0x00002D2C }, + { 0x0007013D, 0x00001004 }, + { 0x0007013E, 0x00001004 }, + { 0x0007013F, 0x00000414 }, + { 0x00070140, 0x00001118 }, + { 0x0007012C, 0x00000837 }, + { 0x0007012D, 0x00000837 }, + { 0x00070130, 0x00000837 }, + { 0x0007012E, 0x0000081F }, + { 0x0007012F, 0x0000081F }, + { 0x00030803, 0x0000107A }, + { 0x00031803, 0x0000107A }, + { 0x00010803, 0x0000107A }, + { 0x00011803, 0x0000107A }, + { 0x00012803, 0x0000107A }, + { 0x00013803, 0x0000107A }, + { 0x00000503, 0x00000023 }, + { 0x00001503, 0x00000023 }, + { 0x00002503, 0x00000023 }, + { 0x00003503, 0x00000023 }, + { 0x00004503, 0x00000023 }, + { 0x00005503, 0x00000023 }, + { 0x00007503, 0x00000023 }, + { 0x00008503, 0x00000023 }, + { 0x00009503, 0x00000023 }, + { 0x0000A503, 0x00000023 }, + { 0x0000B503, 0x00000023 }, + { 0x0000C503, 0x00000023 }, + { 0x00010C03, 0x00000023 }, + { 0x00011C03, 0x00000023 }, + { 0x00012C03, 0x00000023 }, + { 0x00013C03, 0x00000023 }, + { 0x000908E8, 0x00000015 }, + { 0x000908E9, 0x00000048 }, + { 0x00000063, 0x00000068 }, + { 0x00001063, 0x00000068 }, + { 0x00002063, 0x00000068 }, + { 0x00003063, 0x00000068 }, + { 0x00004063, 0x00000068 }, + { 0x00005063, 0x00000068 }, + { 0x00007063, 0x00000068 }, + { 0x00008063, 0x00000068 }, + { 0x00009063, 0x00000068 }, + { 0x0000A063, 0x00000068 }, + { 0x0000B063, 0x00000068 }, + { 0x0000C063, 0x00000068 }, + { 0x0009080A, 0x00000268 }, + { 0x0009080B, 0x00000068 }, + { 0x00090815, 0x00000268 }, + { 0x00090816, 0x00000068 }, + { 0x000E0063, 0x00000068 }, + { 0x000E0064, 0x00000068 }, + { 0x000E0087, 0x00000068 }, + { 0x000E1063, 0x00000068 }, + { 0x000E1064, 0x00000068 }, + { 0x000E1087, 0x00000068 }, + { 0x000E2063, 0x00000068 }, + { 0x000E2064, 0x00000068 }, + { 0x000E2087, 0x00000068 }, + { 0x000E3063, 0x00000068 }, + { 0x000E3064, 0x00000068 }, + { 0x000E3087, 0x00000068 }, + { 0x000E4063, 0x00000068 }, + { 0x000E4064, 0x00000068 }, + { 0x000E4087, 0x00000068 }, + { 0x000E5063, 0x00000068 }, + { 0x000E5064, 0x00000068 }, + { 0x000E5087, 0x00000068 }, + { 0x000E6063, 0x00000068 }, + { 0x000E6064, 0x00000068 }, + { 0x000E6087, 0x00000068 }, + { 0x000E7063, 0x00000068 }, + { 0x000E7064, 0x00000068 }, + { 0x000E7087, 0x00000068 }, + { 0x00090817, 0x00000053 } +}; + +static const u32 DMAC_TRANS_ICCM[] = { + 0x0000058C, 0x00000090, 0x00000090, 0x00000090, + 0x00000090, 0x00000090, 0x00000090, 0x00000090, + 0x00000090, 0x00000090, 0x00000090, 0x00000090, + 0x00000090, 0x00000090, 0x00000090, 0x00000090, + 0x00000050, 0x00000050, 0x00000050, 0x00000050, + 0x7000264A, 0x7000264A, 0x7000264A, 0x7000264A, + 0x00402069, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xC0D1C0F1, 0x00007EE0, 0xC0D1C0F1, 0x00007EE0, + 0x0F80220A, 0x00008000, 0x0F80230A, 0xDEAD1234, + 0x00C01A00, 0x23AA7444, 0x1A000010, 0x744400C0, + 0x00D023AA, 0x00C01A00, 0x1A007444, 0x74440000, + 0x00401A00, 0x1A007444, 0x74440700, 0x06C01A00, + 0x230A7444, 0xABCD0F80, 0x1A00DEAD, 0x206900C0, + 0x78E00040, 0x803C2242, 0x42007CE0, 0x018020A8, + 0x04831101, 0x00D21A01, 0x78E07EE0, 0x803C2242, + 0x42007CE0, 0x010020A8, 0x00521A01, 0x78E07EE0, + 0xB6881CFC, 0xB6481CFC, 0xB6081CFC, 0xB5C81CFC, + 0xB5881CFC, 0xB5481CFC, 0xB5081CFC, 0xB4C81CFC, + 0xB4881CFC, 0xB4481CFC, 0xB4081CFC, 0xB3C81CFC, + 0xB3881CFC, 0x1CFC7FE0, 0x78E0B348, 0x78E07EE0, + 0xDD38748D, 0x78E0F038, 0xDD34748D, 0x78E0F036, + 0xDD30748D, 0x78E0F034, 0xDD2C748D, 0x78E0F032, + 0xDD28748D, 0x78E0F030, 0xDD24748D, 0x78E0F02E, + 0xDD20748D, 0x78E0F02C, 0xDD1C748D, 0x78E0F02A, + 0xDD18748D, 0x78E0F028, 0xDD14748D, 0x78E0F026, + 0xDD10748D, 0x78E0F024, 0xDD0C748D, 0x78E0F022, + 0xDD08748D, 0x78E0F01F, 0x74AD748D, 0x78E0F01C, + 0xF01C748D, 0x301A1434, 0x30191430, 0x3018142C, + 0x30171428, 0x30161424, 0x30151420, 0x3014141C, + 0x30131418, 0x30121414, 0x30111410, 0x3010140C, + 0xC601C702, 0x334D24B0, 0x331F24B0, 0x78E07EE0, + 0x1CFCC4C1, 0x1CFCB1C8, 0x1CFCB188, 0x1CFCB148, + 0xC3E1B108, 0xC1E1C2E1, 0xC4E1C0E1, 0xC0017FE0, + 0x0A11C2F0, 0x42300032, 0x0081292F, 0xF00369E1, + 0x280070ED, 0x274E03D1, 0x2A011800, 0x70F52000, + 0x03D02A00, 0x200921C5, 0x240E2841, 0x0AB24022, + 0x41C10020, 0x23C22A00, 0x000042D3, 0x4508FFFF, + 0xBA307F50, 0x2408232F, 0x20542240, 0x23640A13, + 0x04002940, 0x14C3251A, 0x080F6058, 0x61D900C5, + 0x852409ED, 0x294077A5, 0x251A2411, 0x72221400, + 0x0A6E4A10, 0x41C10020, 0x0A154300, 0x294020E4, + 0x231A0400, 0x60F804C2, 0x0085080D, 0x09EF61D9, + 0x77648524, 0x14002D40, 0x2000BD30, 0x254180C0, + 0xC6D09001, 0xEB884408, 0x00A5090D, 0x07554020, + 0x4181FFEF, 0x00200071, 0x78E04081, 0x4548C2E8, + 0x44084220, 0x41407034, 0x700CF646, 0x900C240E, + 0x80812003, 0x00330B11, 0x700C4668, 0x900D250E, + 0x80CE2003, 0x07CF2B41, 0x07D02A41, 0x0917EE8B, + 0x40200365, 0x42A14181, 0x2007FFC2, 0xF40EA3FE, + 0x4081C6C8, 0x082242A1, 0x43C10020, 0xA3FE2007, + 0x2505F3F8, 0xF3F693BE, 0x200E704C, 0x22038080, + 0xC6C88041, 0x00200031, 0x78E0708C, 0x00C42107, + 0xF040262F, 0x001270AC, 0x242F0026, 0x200E0104, + 0x25038140, 0x70740041, 0x0003000C, 0x8142220E, + 0x00C32503, 0x80852305, 0x00010116, 0x44484368, + 0x43204200, 0x82C0250A, 0x001A704D, 0x22C00004, + 0x25CA1821, 0x2F2F8301, 0x22C00141, 0x22C01063, + 0x70EC11C3, 0x80C0250A, 0x082127C0, 0x00040014, + 0x808125CA, 0x0141282F, 0x006327C0, 0x000327C0, + 0x8287270E, 0x002427CA, 0x45E071E4, 0x8800274C, + 0x0012702C, 0x700C0024, 0x42604140, 0x2742706C, + 0x240A8807, 0x002A7140, 0x274E0001, 0x007C880A, + 0x29000001, 0x29010280, 0x2A0001C1, 0x71A00285, + 0x01C22A01, 0x02852B00, 0x01C32B01, 0x224C72A0, + 0x00629800, 0x20A80009, 0x200005C0, 0x21018000, + 0x22018041, 0x23018082, 0x220200C3, 0x23038302, + 0x000E82C3, 0x22000006, 0x23018302, 0x20C082C3, + 0x70940066, 0x002270AC, 0x000E0001, 0x220E000A, + 0x25038142, 0x242F00C3, 0x000E8100, 0x200E0003, + 0x25038140, 0x7EE00041, 0x41404020, 0x706C4260, + 0x20A8F1CF, 0x20000380, 0x21018000, 0x22018041, + 0x72918082, 0x030622C2, 0x006620C5, 0x704CF1DB, + 0x706C6A09, 0x0002212F, 0x78E0F1E7, 0x81422253, + 0x224E7CE0, 0x00168803, 0x2801000C, 0x290000CC, + 0x28000081, 0x7FE00080, 0x234E7985, 0x28000003, + 0x7FE000C1, 0x78E07802, 0x81422253, 0x224E7CE0, + 0x00168803, 0x2900000C, 0x290100CC, 0x28010081, + 0x7FE00080, 0x234E7885, 0x29010003, 0x7FE000C0, + 0x78E07922, 0x00402069, 0xF1FE78E0, 0x0020001D, + 0x78E0700D, 0x87C82941, 0x002221CE, 0x87C32842, + 0x002220CE, 0x10C82007, 0x8040220A, 0x00210050, + 0x700C4100, 0x2D2F6869, 0x25CA8041, 0x2E2F00C4, + 0x26CA8081, 0x260200C4, 0x23CA8143, 0x23400024, + 0x2AC0007C, 0x20A800C3, 0x210202C0, 0x20CF8081, + 0x21C00F06, 0x222F0085, 0x202F0082, 0x202F9202, + 0x20CE0003, 0x7FE00025, 0x002221CE, 0x0F802020, + 0x05740000, 0xF000260A, 0x0FBF208A, 0x006420CA, + 0x202F7FE0, 0x7FE00003, 0x78E0770C, 0x704C702C, + 0x708C706C, 0x70CC70AC, 0x700D70EC, 0x704D702D, + 0x708D706D, 0x70CD70AD, 0x700E70ED, 0x704E702E, + 0x708E706E, 0x70CE70AE, 0x700F70EE, 0x706F702F, + 0x3000254A, 0x3000264A, 0x800144DB, 0x42DB8000, + 0x04008000, 0xFFCF0AB6, 0x05400E52, 0x0719D830, + 0xF1FEFFCF, 0x0C1EC0F1, 0xC1A1FFCF, 0x7487E805, + 0x7FE0C0D1, 0x40C3C0A8, 0x12218000, 0x206F8840, + 0xA84007C3, 0x208C8803, 0xF20D8FC3, 0xC040C084, + 0x08524020, 0xC18409A0, 0xD8FFD911, 0x02600AC2, + 0x0EF6B911, 0xD8FF0960, 0x20AB700C, 0x7FFF00C4, + 0x78E0F1FF, 0x47CBC2F8, 0x11DA8000, 0x10951746, + 0x23784310, 0x40580000, 0x4130781B, 0x2040704E, + 0x23140057, 0x19002556, 0x252F0001, 0x0FAF1487, + 0x72B52364, 0x2FC1208A, 0x20542244, 0x352E089B, + 0x202620CA, 0x70801600, 0x001B8000, 0x800146CB, + 0x08214D64, 0x40C3009E, 0x04868000, 0xE88A8800, + 0x20300B1F, 0x09E67EB4, 0x961200E0, 0xF00D961E, + 0x00E009DA, 0x134026F4, 0x96067EB4, 0x09CEF005, + 0x960C00E0, 0x09D69618, 0x700C00C0, 0x00A00D56, + 0x2C40712C, 0x70AD20CE, 0x23C02632, 0x10250D3B, + 0x21002D40, 0x04C02016, 0xE02460B8, 0x294060E9, + 0x20050380, 0x90040F80, 0x90000234, 0x02600AE6, + 0xB8C6B8C8, 0x200771A5, 0x40260401, 0x782579D8, + 0x20001900, 0x7146F1E2, 0xC6D8F1A9, 0xC1B4C3F6, + 0x16004110, 0x80007080, 0x4750000C, 0x800046CB, + 0x081B11DA, 0x4728003F, 0xF483B8E1, 0x41E14022, + 0x0F0642E2, 0x4380FFEF, 0x1F00C7D6, 0xC0801001, + 0x10951646, 0x800041C3, 0xDA4E0F12, 0xFFEF099A, + 0x700C708E, 0x704C702C, 0x04600B26, 0x42C3706C, + 0xFFFF0000, 0x722C700C, 0x44404340, 0x04600A8A, + 0xC0804540, 0x09E009F6, 0x2114D94E, 0x43D32552, + 0xF8049007, 0x21051B00, 0x208A7296, 0x24442FC1, + 0x0F8B2056, 0x20CA25AE, 0x45CB2026, 0x4D648001, + 0x07800AE2, 0x00E008D6, 0x150025F4, 0x15002514, + 0x00E008DA, 0x218A9006, 0x40C30FCF, 0xC2EC9007, + 0x712CB020, 0x00051800, 0x0C4A700C, 0x70AD00A0, + 0x23802232, 0x2E40E823, 0x2D4020D6, 0x20162100, + 0x60B80440, 0x60C9E024, 0x03802940, 0x0F802005, + 0x26FC9004, 0x208A9040, 0x09DA0FC7, 0x78460260, + 0x71A5B8C6, 0x04002007, 0x05812800, 0x78258700, + 0x2232A700, 0x0DC72380, 0x71869004, 0xA1140C6D, + 0x70051E00, 0x0004901C, 0x20051B00, 0x1F00C7D6, + 0x708E1001, 0x10931646, 0x24D22114, 0x208A7296, + 0x24442FC1, 0x0F692055, 0x20CA256E, 0x45CB2026, + 0x4D648001, 0x07800A2E, 0x00E00822, 0x150025F4, + 0x150D2514, 0x00E00826, 0x700C9506, 0x00A00BA6, + 0x2232712C, 0xE81C2380, 0x20D52D40, 0x2B4070AD, + 0x41222100, 0x04402016, 0xE02460B8, 0x076008DA, + 0xB8C660C8, 0x200771A5, 0x28000400, 0x87000541, + 0xA7007825, 0x23802232, 0x90040DD7, 0x0C917186, + 0xF144A114, 0x1CFCC2FA, 0x2482B6C8, 0x710C3E07, + 0x0FDF218A, 0x056008D6, 0xC808704C, 0x3643236F, + 0x685270AD, 0x0F802205, 0x00949004, 0xC0449000, + 0x30801300, 0x80BE2053, 0xC004F20B, 0x0F812205, + 0xC0949007, 0x0080206C, 0x00C02045, 0x2205B100, + 0x90080F80, 0x9040002C, 0x2443276F, 0x17004040, + 0x20842081, 0x217800CC, 0x20B80103, 0x41C30084, + 0x00020190, 0x40C37B04, 0x12DA8000, 0x0FB2A860, + 0x740C0220, 0x702CC08E, 0xFFAF0FC6, 0x0007228A, + 0xA08017F9, 0x019141C3, 0x20440000, 0x1C0C0200, + 0x20783344, 0xC5420000, 0xC540C541, 0xFFEF0C8A, + 0x1713C54B, 0x47CB2081, 0x04848000, 0x01002941, + 0x00DF0815, 0x009F0819, 0x007F081D, 0x1F00710C, + 0xF00D1043, 0x1F00D808, 0xF0091203, 0x1F00740C, + 0xF0051103, 0x1F00720C, 0xB9E21083, 0x800041C3, + 0x20CA0F0C, 0x764C0062, 0x0F3EAF01, 0xC08CFFAF, + 0x712CC08C, 0x07E00822, 0x0E1E714C, 0xC08003A0, + 0x050009A6, 0x46CB700E, 0x12208000, 0x30031C17, + 0x0408202F, 0x2440C187, 0x0B6E3AC2, 0x244003E0, + 0x08C535C3, 0x40C30011, 0x11388000, 0x00431800, + 0x30801417, 0x02E00A56, 0x0F2A4210, 0x142B0400, + 0x17133091, 0xB8E22080, 0x1F024022, 0xF42B1003, + 0x0C1A712C, 0xC28E0820, 0xC18B8E40, 0x3093141C, + 0x019645CB, 0x23140002, 0x61792083, 0xA9004362, + 0x0EAE740C, 0x41A10220, 0x0FFA4042, 0xC18E0260, + 0x702C4022, 0x08200BE6, 0x8E40C28E, 0x1401254F, + 0x0E8E740C, 0x43620220, 0x0FDA4042, 0xC18E0260, + 0xC18EF022, 0x706C714C, 0x0FC1248A, 0x00200C8E, + 0x8E2070AC, 0x2514C527, 0xC18B1042, 0xA9006159, + 0x088E4022, 0xC18E03A0, 0x740C8E40, 0x019441C3, + 0x0E4E0002, 0x43A10220, 0x0F9A4042, 0xC18E0260, + 0x10431F02, 0x202F7106, 0x08290408, 0xC8088114, + 0xDD07708D, 0x20057885, 0x00030F80, 0x0DB6F0D8, + 0x702C0960, 0x258DC808, 0x24561E3F, 0xB802180C, + 0x2005700F, 0x900F0F80, 0x0AF6C364, 0x18000720, + 0x14170604, 0x44D33080, 0x01668000, 0x30192440, + 0x1C00700E, 0x1CFF2FC3, 0xC046AFC3, 0x200CC006, + 0x02A2A000, 0xD9690026, 0x20801713, 0x00FF0821, + 0x0F52D840, 0x43000780, 0x41C3740C, 0x00020199, + 0x02200DBE, 0x228A4202, 0xF00E2001, 0x07A00F36, + 0x4300700C, 0x41C3740C, 0x00020198, 0x02200DA2, + 0x704E4202, 0x28152255, 0x2480260A, 0x203E2680, + 0x7676706E, 0x002D014A, 0x2FC3218A, 0x70AD70CD, + 0x708D706C, 0xC18E4002, 0x0803209A, 0x2B406038, + 0x61192141, 0x1F802604, 0xFFF80000, 0x610AB823, + 0x78C6D807, 0x7918712C, 0x0448202F, 0x8FC3208C, + 0x794BF408, 0xD8FF41A1, 0x41D170AD, 0xF02BF429, + 0xF224794B, 0x218C79D0, 0xF79D8042, 0x79707AB0, + 0x00850933, 0x07800EAE, 0x8F014300, 0x0EA64E10, + 0x781007A0, 0x0E9E4400, 0x404007A0, 0x740C4500, + 0x019B41C3, 0x0D0A0004, 0x42620220, 0x442A8F61, + 0x41A163BB, 0xF005D8FF, 0x40228F21, 0x452861B9, + 0x8F014110, 0x79D0661E, 0x8004218C, 0xFFC50768, + 0x262F7970, 0x2179F348, 0x651D0001, 0x006121C5, + 0x3082120B, 0x80412144, 0x78B0757C, 0x00A5081D, + 0x41C3D80A, 0x0001019F, 0x02000CB6, 0x702C7BAE, + 0x00832B44, 0xF01F710F, 0x70347BAE, 0x00832B44, + 0x144124CA, 0x23002600, 0x262F6078, 0x0016F006, + 0x704C0024, 0x0D137910, 0x25022065, 0x42A22001, + 0x4100F005, 0x702CF003, 0xC0874200, 0x04C02014, + 0x6179B040, 0x2048782E, 0x08170000, 0x780F2030, + 0x20811400, 0x00402009, 0x20021C00, 0x14FFF007, + 0x2009A081, 0x1CFF0040, 0x7166A002, 0x2840F15B, + 0x2440230D, 0xDE073713, 0x2640250A, 0x25001302, + 0x24831501, 0x07A00DAE, 0x44004610, 0x07A00DA6, + 0x45004042, 0x4202750C, 0x01A041C3, 0x0C120004, + 0x41700220, 0x22012940, 0x79A5C808, 0x20057825, + 0x00030F80, 0x0B8E00D8, 0x41C20960, 0x183F268D, + 0x3B112440, 0x24112114, 0x20C01100, 0x20487042, + 0x7E100000, 0x07A00D5E, 0x430040C1, 0x07A00D56, + 0x44004042, 0x41C3750C, 0x000301A1, 0x02200BC2, + 0xC8084202, 0x200578A5, 0x00030F80, 0x0B4608D8, + 0x41C10960, 0x20C01101, 0x20487042, 0x7E100000, + 0x07A00D22, 0x430040C1, 0x07A00D1A, 0x44004042, + 0x41C3750C, 0x000301A2, 0x02200B86, 0xC8084202, + 0x200578A5, 0x00030F80, 0x0B0A09D8, 0x41C10960, + 0x07A00CF2, 0x43004042, 0x41C3750C, 0x000201A3, + 0x02200B5E, 0xC8084202, 0x200578A5, 0x00030F80, + 0x0AE200D9, 0x41420960, 0x31D92140, 0xFFEF0561, + 0x20787106, 0x08423000, 0xB912FFEF, 0x07000822, + 0x07400CD2, 0x20801713, 0x003E0815, 0xB88D700C, + 0x70041E00, 0x00148000, 0x05000EBA, 0x30801300, + 0x80BE2053, 0x0CAEF20B, 0xC8080740, 0x2005B802, + 0x90070F81, 0xC004C094, 0xC08CB100, 0x0BEA712C, + 0x704C07A0, 0x702C700C, 0x05200BA2, 0x2480704C, + 0x14043E07, 0xC6DA341B, 0x47CBC2F4, 0x11DA8000, + 0x10921746, 0x46304550, 0x07600C6A, 0x40C24410, + 0x428241A2, 0x09A00B0A, 0x40C3706C, 0x27100000, + 0x05A00ED2, 0x2453702C, 0x702E2040, 0x00902078, + 0x201470CD, 0x70AD2493, 0x23C02332, 0x10250D4B, + 0x21002A40, 0x04002016, 0xE02460B8, 0x160060E9, + 0x80007080, 0x2053000C, 0xF20780BE, 0x0AFA4020, + 0x41020720, 0x2940F00B, 0x20050380, 0x90040F80, + 0x90000234, 0x02200B4E, 0x2053B8C8, 0x71A581BE, + 0x106226C5, 0x0BEEF1DA, 0x40C20740, 0x428241A2, + 0x09A00A8E, 0x2332DB7F, 0x094D23C0, 0x2A402025, + 0x20162100, 0x70220400, 0x60E9E024, 0x70801600, + 0x000C8000, 0x80BE2053, 0x4020F206, 0x07200A9A, + 0xF00C4102, 0x03802940, 0x0F802005, 0x02349004, + 0x0AF29000, 0xB8C80220, 0x7126B8C6, 0x0FC120B9, + 0xF1DB7E05, 0xC6D478CF, 0xC1A1C3FA, 0xD8404210, + 0x210AB89F, 0x250A3140, 0x47682100, 0x00901000, + 0x10E54350, 0x46308097, 0x800041D3, 0xEA081138, + 0x0F2A4042, 0x712C02A0, 0x20031900, 0x70801600, + 0x001B8000, 0x800045CB, 0x08291220, 0x708E007E, + 0x20300B21, 0x0A724042, 0x8D4004C0, 0x750C4410, + 0x018741C3, 0x43420003, 0x02200986, 0x0500240A, + 0x740C8D40, 0x41C34342, 0x0005018A, 0x04C0240A, + 0x260A45E1, 0x096A0540, 0x22530220, 0x46CB2058, + 0x04878000, 0xE8128E00, 0x201F0F09, 0x201E080B, + 0x04200E7A, 0x0F0B710C, 0x080D205F, 0x0E6E205E, + 0x720C0420, 0x10031E00, 0x41C37156, 0x08D80003, + 0x2078C808, 0x21D63097, 0x78250822, 0xB90C8D20, + 0x08B27825, 0xD9400960, 0x710E7076, 0x24A220CA, + 0x0DA57EF0, 0x740C23A4, 0x234A708D, 0xC80811C0, + 0x03012005, 0xB80C8D00, 0x20057825, 0x00030F80, + 0x088200D8, 0x41C10960, 0x1CFF238D, 0x180C2456, + 0x06C00DCE, 0xC18040E2, 0x716C734C, 0xFFAF0F02, + 0x1400718C, 0x26553009, 0xD8071801, 0x10C82E41, + 0x2006B923, 0x244A038B, 0x708D71C0, 0x088020A8, + 0x13002901, 0xB8C06C75, 0x02C62800, 0x209F8D00, + 0x70C20803, 0x70016078, 0x22058840, 0xA8400182, + 0x29014C18, 0x71851000, 0x2800B8C0, 0x8D0002C2, + 0x0803209F, 0x631B70C2, 0x88606338, 0xA8407A65, + 0xF1B07702, 0x43428D40, 0x018C41C3, 0x08620003, + 0x240A0220, 0x70AD04C0, 0xC808DC07, 0x200578A5, + 0x00030F80, 0x0FDEF0D8, 0x702C0920, 0x1DFF248D, + 0x180D2556, 0x06C00D2A, 0x30100915, 0x20310B11, + 0x702C4042, 0x02E00F1E, 0x20431900, 0xC7DA4082, + 0x41C3C2E2, 0x12208000, 0x89208941, 0x02C1229F, + 0x0582219F, 0x621A6038, 0xB8C38A02, 0x002009D6, + 0x068D205F, 0x00802079, 0x0186209F, 0x2534651D, + 0x80001F80, 0xC6C20A7C, 0x0AEEC0F1, 0x716C0100, + 0xDA62E89D, 0x800140C3, 0xBA9F4E77, 0x8A208800, + 0x262F7825, 0x0026F005, 0x12340004, 0x208B0080, + 0xF40D8401, 0x01000A7A, 0x0AA2E889, 0xE8870100, + 0x00801230, 0x04032044, 0xC0D1BB24, 0x40607FE0, + 0x4508C2EA, 0xD8FA4110, 0x46284748, 0x05200B1E, + 0x22C1219F, 0x0020096A, 0x40C34010, 0x12208000, + 0x762C8800, 0x0582209F, 0x244ADA22, 0x70CC0400, + 0x20327022, 0x80010F83, 0x710C4E84, 0xB80278B8, + 0x0340200F, 0x7D0FBB86, 0x0AB2700C, 0x45A10060, + 0x0402202F, 0x0F33E008, 0x202F103E, 0x700C2007, + 0x724CD907, 0x708C706C, 0x0A9270AC, 0x260A0060, + 0x700C0400, 0xDA22762C, 0x244A43C1, 0x45A10380, + 0x00600A7A, 0x0F2F70CC, 0x700C107E, 0x724CD907, + 0x708C706C, 0x0A6670AC, 0x260A0060, 0x700C0400, + 0xDA22762C, 0x244A43C1, 0x45A103C0, 0x00600A4E, + 0x700C70CC, 0x724CD907, 0x708C706C, 0x0A3E70AC, + 0x260A0060, 0x700C0400, 0x724CD907, 0x708C706C, + 0x0A2A70AC, 0x264A0060, 0x700C0A00, 0x006009CE, + 0xC6CA712C, 0x800040C3, 0x7FE00462, 0x00051800, + 0x1E00700C, 0x901C7004, 0x7EE00480, 0xE08E4100, + 0xF707710C, 0x704E0E0B, 0x40410000, 0xE1A87EE0, + 0x7FE07CE0, 0x78E0700C, 0x45CBC2E4, 0x1A108000, + 0xE8049511, 0x10451D28, 0x00200872, 0x460840A1, + 0x800040C3, 0xB0C00462, 0x702C40A1, 0xFF6F0E82, + 0x700CDA20, 0xB513B514, 0xB511B512, 0xC6C440C1, + 0x800041C3, 0x91030462, 0x71109120, 0x7CE0700C, + 0xFFCF07B9, 0x800040C3, 0x90000462, 0xB8227FE0, + 0x800040C3, 0x7FE0046E, 0x78E08800, 0x0DBEC0F1, + 0x700C0060, 0x00600DC6, 0x0C12700C, 0x700C0060, + 0xFFCF0F56, 0x7EE0C0D1, 0xC1A4C3F6, 0x800043C3, + 0x8B280462, 0xE90770CD, 0x71C56949, 0x80812104, + 0x904FF5FC, 0x100E8BA3, 0xB0B30115, 0x01171004, + 0x01161002, 0x1028BD0A, 0x1000010B, 0x10240109, + 0x10120108, 0x10140107, 0x2B400106, 0x101012CB, + 0x90910104, 0x01051020, 0x011E100A, 0x011F1006, + 0x01101008, 0x01131016, 0x0111101A, 0x0114100C, + 0x01121018, 0x226D902E, 0x1C0C0300, 0xB9C33004, + 0xDA7F6A14, 0x24537825, 0x1C0A20C1, 0x256D3004, + 0x1C042300, 0x2D403004, 0x78252100, 0x1C02BA07, + 0x2A403004, 0x235321C0, 0x78442181, 0x29407905, + 0x78252380, 0x31812753, 0x30041C08, 0x21C02840, + 0x93E37844, 0x2E407905, 0x78253380, 0x02012D40, + 0x30041C00, 0x21846C17, 0x2004000C, 0x00000F80, + 0x78257C00, 0x01012C40, 0x04012144, 0x7905BC0C, + 0x01402F40, 0x08012084, 0x79058B4A, 0x01C02E40, + 0x7825780F, 0x12012840, 0x30041C0E, 0x1F802404, + 0x70000000, 0x000C2184, 0x782578A5, 0x1F812304, + 0x08000000, 0x29407825, 0x21441101, 0x79050401, + 0x21402E40, 0x08012084, 0x2F407905, 0x780F21C0, + 0x79FD7825, 0x30041C06, 0x0A6DEA08, 0x7CCF0071, + 0x641C8B09, 0x12140C57, 0x244A6912, 0x20057100, + 0x00100F81, 0xC0804000, 0x03C020A8, 0x050B1002, + 0x0F8D2105, 0x00009000, 0x050C1002, 0xBC107424, + 0x12CC2405, 0x4F98A580, 0x907E2053, 0xB323B9A0, + 0x710CF205, 0x02002006, 0x40C3AB0B, 0x1A308000, + 0x00710A15, 0x00051800, 0x60D88B09, 0x00031B08, + 0xAB09B8C2, 0xC7D67830, 0x4350C2EE, 0x09D74130, + 0x47080030, 0x2FC3208A, 0x800045CB, 0x70CD1A10, + 0x2448222F, 0x21140A1D, 0x20300B19, 0x90BE2753, + 0x700CF219, 0xA5077726, 0xA505A506, 0xF02EA504, + 0x90BE2753, 0x0A69F21F, 0x74E52070, 0xA5C6A5C7, + 0x0D8AA5C5, 0xA5C4FFEF, 0x20B00A49, 0x77264708, + 0x40A1F1E0, 0x0C1A702C, 0xDA20FF6F, 0xA048228C, + 0x00250046, 0x1D22732C, 0x21801404, 0xB5322038, + 0x0A21F00C, 0x40A12070, 0x0BF6702C, 0xDA20FF6F, + 0x20B00A3B, 0x20912142, 0xFFCF0D42, 0xF1C24708, + 0x74E5A5C3, 0xA5C1A5C2, 0xF01DA5C0, 0xA5C6A5C7, + 0xA5C4A5C5, 0x2104F017, 0x00002F80, 0x781DFFFE, + 0x203F090F, 0xB5327704, 0xE708B511, 0xB532F00B, + 0xFFEF0D0A, 0x702CB511, 0xA52068E4, 0xA522A521, + 0x78F0A523, 0x78E0C6CE, 0x4508C2E2, 0x0060096E, + 0x080C208A, 0x752CD809, 0xDA0CB813, 0x0008238A, + 0x45A1708C, 0x00200EB6, 0x700C70CC, 0x724C762C, + 0x244A736C, 0x45A10680, 0x00200EA2, 0x0EF270CC, + 0x700C03C0, 0x724C762C, 0x244A716C, 0x45A10680, + 0x00200E8A, 0x0EDA70CC, 0x700C03C0, 0x724C762C, + 0x244A706C, 0x45A10680, 0x00200E72, 0x700C70CC, + 0x095ED922, 0x704C0060, 0x752C700C, 0x238A744C, + 0x708C000E, 0x0E5645A1, 0x70CC0020, 0xD907D880, + 0x744CB893, 0x708C706C, 0x0E4270AC, 0x70CC0020, + 0xFFCF0CA6, 0x78107704, 0x78E0C6C2, 0x4508C2EA, + 0x70801600, 0x00088000, 0x00B1080D, 0x2280204A, + 0xF00574CD, 0x2240204A, 0x0C9672CD, 0x08AEFFCF, + 0x208A0060, 0x08B2080C, 0x706C0040, 0x4768D907, + 0xBF8F724C, 0x40E1708C, 0x0DF270AC, 0x70CC0020, + 0xD907700C, 0x706C704C, 0x70AC708C, 0x00200DDE, + 0x6F1570CC, 0x704C752C, 0x708CDB80, 0x0DCE45A1, + 0x70CC0020, 0x12002F40, 0x42C1D929, 0x708C706C, + 0x70CC45A1, 0x00200DB6, 0x40224110, 0x42C1D929, + 0x708C706C, 0x0DA645A1, 0x70CC0020, 0x30821204, + 0xD907700C, 0x708C706C, 0x0D9270AC, 0x70CC0020, + 0xD907700C, 0x706C704C, 0x70AC708C, 0x00200D7E, + 0x6F1670CC, 0x704C752C, 0x0004238A, 0x45A1708C, + 0x00200D6A, 0xD80870CC, 0xB898D92A, 0x706C42C1, + 0x45A1708C, 0x00200D56, 0xD84170CC, 0xB812D92A, + 0x706C42C1, 0x45A1708C, 0x00200D42, 0x700C70CC, + 0x744CD907, 0x708C706C, 0x0D3270AC, 0x260A0020, + 0x0FBE0400, 0x700C0000, 0x704CD907, 0x708C706C, + 0x0D1A70AC, 0x70CC0020, 0xD907D880, 0x706C704C, + 0x70AC708C, 0x00200D06, 0x0B6E70CC, 0x7704FFCF, + 0xC6CA7810, 0x40C3C0F1, 0x61A80000, 0x0000080E, + 0xFFCF0AE2, 0x7EE0C0D1, 0x0072081D, 0x1600714C, + 0x901C7101, 0xE9850484, 0x71447210, 0x2179F6B9, + 0xF0030000, 0xD90B700C, 0xFF6F066D, 0x78E0B912, + 0x082DC2E2, 0x43200072, 0x800045CB, 0x8D420462, + 0x28057810, 0x0B110081, 0x9500027F, 0xEA848D4B, + 0xF003714C, 0x0CE6704C, 0xB500FFCF, 0x78E0C6C2, + 0x70ADC0E6, 0xB0A2E2B3, 0xB0A7B0A1, 0x0302B0A6, + 0xB0A0002D, 0x24AD4468, 0x20241203, 0x00F50080, + 0x01090000, 0x01310000, 0x015B0000, 0x01850000, + 0x01A50000, 0x01B30000, 0x00B70000, 0x00BB0000, + 0x02CF0000, 0x00BD0000, 0x01AB0000, 0x01B30000, + 0x02BF0000, 0x01AF0000, 0x01C10000, 0x01C70000, + 0x00A10000, 0x02AB0000, 0x02A70000, 0x02A30000, + 0x029F0000, 0x029B0000, 0x02970000, 0x02930000, + 0x01AD0000, 0x01BB0000, 0x006F0000, 0x01C10000, + 0x01E90000, 0x01E90000, 0x01EB0000, 0x006F0000, + 0x017D0000, 0x01E90000, 0x01E90000, 0x01F10000, + 0x01F30000, 0x00570000, 0x00370000, 0x01F30000, + 0x01F70000, 0x01F70000, 0x01F70000, 0x01F90000, + 0x01F90000, 0x01FD0000, 0x020B0000, 0x02210000, + 0x000F0000, 0x021D0000, 0x021D0000, 0xB0A40000, + 0x0020021F, 0xDB78B0A3, 0x2453B063, 0xF0A600C3, + 0xB063DB38, 0x00832453, 0x0203F0A0, 0xBBC60020, + 0x02F270D4, 0x23530021, 0xBB24018C, 0x0E012384, + 0x2345B084, 0xF0F400C3, 0x2C406BF3, 0x2453008C, + 0x274400C4, 0x24841C0E, 0x24051001, 0x24050384, + 0x7B7B110C, 0x2384B084, 0x27440C01, 0x7B85120C, + 0xF0DEBB80, 0x2C406BF3, 0x2453008C, 0x274400C4, + 0x24841C0E, 0x24051001, 0x24050384, 0x7B7B110C, + 0x2384B084, 0x27440C01, 0x7B85120C, 0x01432345, + 0x6BF3F0C6, 0x008C2C40, 0x00C42453, 0x1C0E2744, + 0x10012484, 0x03842405, 0x110C2405, 0xB0847B7B, + 0x0C012384, 0x120C2744, 0x23457B85, 0xF0B00183, + 0xBB037C7B, 0x1C012484, 0x0C032344, 0xB083BC82, + 0x008C2C40, 0x00C42453, 0x10012484, 0x01032305, + 0xF03C7B85, 0x2453BB23, 0x2384018C, 0xB0840C01, + 0x03032345, 0x0E25F094, 0x02370011, 0x18080020, + 0xBB050104, 0x2384DC68, 0xB0830801, 0xDB28F026, + 0x70D4F060, 0x00010218, 0x018C2353, 0x23847B7D, + 0xB0840001, 0xF07CBB83, 0x01041808, 0x06051806, + 0xDB38F077, 0x2453B063, 0xF00F0083, 0x018C2353, + 0x23847B7D, 0xB0840001, 0x0C032345, 0xDB78F068, + 0x2453B063, 0xBB8600C3, 0xF063B064, 0x2C406BF3, + 0x2453008C, 0x274400C4, 0x24841C0E, 0x24051001, + 0x24050384, 0x7B7B110C, 0x2384B084, 0x27440C01, + 0x7B85120C, 0xF04CBB81, 0xF049DB58, 0xB083B084, + 0x7B7DF047, 0x00012384, 0xF041BB83, 0xF041B084, + 0x2384BB23, 0x23450C01, 0xF0390303, 0x01832453, + 0x7B7DF035, 0x00012384, 0x0C032345, 0x70D4F02F, + 0xDB40F51F, 0xDB60F006, 0xDB20F004, 0xDB50F002, + 0xF026B0A4, 0xF023DB38, 0x00832453, 0xF01FBB86, + 0xBB037C7B, 0x1C012484, 0x02032344, 0xBB807B85, + 0xBB03F015, 0x008C2C40, 0x00C42453, 0x0C032344, + 0x10012484, 0x01032305, 0xF0097B85, 0xF007DB40, + 0xF005DB68, 0x2384BB05, 0xB0640801, 0x091DB063, + 0x0A19041F, 0x22780C70, 0x230B0A03, 0xF4068180, + 0x00432553, 0xF003B065, 0x0939B0A5, 0xDB0D053F, + 0x057F0937, 0x0939DBD0, 0xDB0D05BF, 0x05FF0937, + 0x0939DB08, 0xDB80063F, 0x067F09B3, 0x0010238A, + 0x06BF09D3, 0x0004238A, 0x06FF09D3, 0xF010706C, + 0x0345180E, 0xB067F00C, 0xF00ADBD0, 0xB067BB08, + 0x180EF006, 0xF0040205, 0xDB80B067, 0x0909BB8C, + 0xB06704DE, 0x07550A13, 0x708F0E21, 0x00181000, + 0x0B21766C, 0x2242008F, 0x0B190843, 0x0A150094, + 0xE2A90AF0, 0xF414704C, 0x180C744C, 0xF0100105, + 0x00832941, 0x7A66724C, 0x01032144, 0x21447074, + 0x0B0D0303, 0x22CF0330, 0xB0460021, 0x049E090B, + 0x00C22245, 0x262FB046, 0x000AF046, 0x18040003, + 0x090B0045, 0xBA83033E, 0x090DB046, 0x0D09019F, + 0xC4C6005F, 0x00451800, 0xB067C4C6, 0xBB0A756C, + 0x2B41F1BF, 0xBB2B01CC, 0x1C012484, 0x0E012384, + 0x110E2405, 0x01C32345, 0xF17AB0C4, 0xDB58B084, + 0xB067F176, 0xBB08DB11, 0x238AF1AB, 0xB0670008, + 0xBB09DB09, 0x78E0F1A5, 0x0C1AC2E2, 0x45280020, + 0x05600886, 0x0EB2760C, 0x7704FF8F, 0x00200C8E, + 0x0C6E7810, 0x70B50000, 0xFFC20B3C, 0x78E0C6C2, + 0x0BF2C2E2, 0x45280020, 0x0560085E, 0x0C52760C, + 0x70B50000, 0xFFC20B20, 0x78E0C6C2, 0x800040C3, + 0x7FE0046F, 0x00431800, 0x46CBC2F4, 0x04628000, + 0x8E4D4050, 0x2180260A, 0x2140240A, 0x2100250A, + 0x43304270, 0x01B1092D, 0xEA144110, 0x8E008EA2, + 0x80BE2053, 0x7DBBF402, 0x0487212F, 0x0A8640A2, + 0x42820020, 0x23402002, 0xFFEF0B0A, 0xF0C94122, + 0x081D8E0A, 0x40620071, 0xFFAF0DB6, 0x20788E68, + 0xBB240000, 0xB870B806, 0xAE086078, 0x47CB7054, + 0x1A108000, 0x223E090F, 0x206120C0, 0xB8819710, + 0x090DB710, 0x9710235E, 0xB710B880, 0x0E699620, + 0x21532030, 0x08190080, 0x700C0131, 0xA706A707, + 0xA704A705, 0x0D866904, 0xB600FFAF, 0x42628E23, + 0x43428E04, 0x41227825, 0x00002079, 0x0540240A, + 0x40E1AE03, 0x0500250A, 0x0ABA70CC, 0x70ADFFEF, + 0xFFAF0D3E, 0x08C54062, 0x4FA80030, 0x41224020, + 0x43424262, 0x0540240A, 0x0500250A, 0xFFEF0A96, + 0xF05871CC, 0x01110829, 0x225F0911, 0x8E438E04, + 0x00010A09, 0xE80C9712, 0xA704700C, 0xA706A705, + 0x6904A707, 0xFFAF0D16, 0x9620B600, 0x09CBB9C2, + 0x40620130, 0x003109C1, 0x8E23700C, 0x8E044262, + 0x78254342, 0x20794122, 0x240A0000, 0xAE030540, + 0x250A40E1, 0x0A3E0500, 0x70CCFFEF, 0x96008E22, + 0x090F7404, 0xB600227E, 0xB8819712, 0x4062B712, + 0xFFAF0CAE, 0x204D2002, 0x4F28E813, 0x42624122, + 0x240A4342, 0x250A0540, 0x0A0A0500, 0x71CCFFEF, + 0x74049600, 0xFFAF0CDE, 0x8E02B600, 0x40A17D02, + 0xFFEF09C2, 0xF0234122, 0xA1A2A1A3, 0xA1A0A1A1, + 0x96008EA2, 0xB600E008, 0x23402017, 0x0072082B, + 0x15841F22, 0x1F2460B8, 0x77041085, 0xFFAF0C6E, + 0x2F057F10, 0x96001341, 0xFFAF0E92, 0xB600704C, + 0x22D1214F, 0x1F24F003, 0x8E0410C5, 0x0E32AE03, + 0x40220620, 0x0C2AC6D4, 0x4308FF8F, 0x41224F28, + 0x43424262, 0x0540240A, 0x0500250A, 0xFFEF0986, + 0x960070CC, 0x0B357404, 0xB6001030, 0xFF8F0C1E, + 0x40E18EA2, 0x42624122, 0x240A4342, 0x250A0540, + 0x09620500, 0x71CCFFEF, 0x20029600, 0x74042341, + 0x8E02B600, 0xF10A4910, 0x20028E02, 0x0D13200D, + 0x0BEA1052, 0x40A1FF8F, 0xFFEF090A, 0x09934122, + 0x9712A2DE, 0xB712B880, 0x78E0F1C3, 0xC1ABC3E6, + 0x45284748, 0xC0804608, 0x0A66702C, 0xDA2AFF2F, + 0x41838E00, 0x8E01B103, 0x8E02B104, 0x8E03B10B, + 0x103E0F0B, 0x1C0AB10C, 0x0F0B3344, 0x1C1A105E, + 0x0C1A3344, 0xC080FFAF, 0x78E0C7C6, 0x800040C3, + 0x7FE00466, 0x00031800, 0x800041C3, 0xB1000462, + 0xB1037FE0, 0x800040C3, 0x7FE00466, 0x00431800, + 0x800043C3, 0xB30419E4, 0xB303D858, 0x01802153, + 0x2253B30C, 0xB30D0040, 0x800044CB, 0xB3050462, + 0xB308781D, 0x783DB300, 0x0140206C, 0xB8839440, + 0xB30BE208, 0x03B54060, 0xB440FFAF, 0xC1A4C3E8, + 0x800046CB, 0x47480462, 0x45289640, 0x00812253, + 0x700C4010, 0xC042C043, 0x091FC041, 0xC0400131, + 0x800041C3, 0xA1001A20, 0xA102A101, 0x6A04A103, + 0xFFAF0AFA, 0x8E02B600, 0x781B70F5, 0x080F780F, + 0x20CA2031, 0x0D090062, 0x45081005, 0x100E2D05, + 0x781078C9, 0x26C27510, 0x78D01061, 0x8004208C, + 0xD908F792, 0xB80AD81F, 0xB2074283, 0x08002059, + 0x0892B203, 0xC0800920, 0x107C2680, 0x208C78D0, + 0xF7328FC3, 0xF388262F, 0x2E40F212, 0x20041300, + 0x00000F80, 0xB8887000, 0xB88BB889, 0x30041C06, + 0x20046E17, 0x00000F80, 0xF0057C00, 0x1C06700C, + 0x1C0E3005, 0xC0803004, 0x0920084A, 0xC7C8D908, + 0x800041C3, 0x19020462, 0x7FE00043, 0x78E0A90C, + 0x70041E00, 0x049C901C, 0x78E07EE0, 0xC1A8C3E6, + 0x47284648, 0x24404508, 0x702C3080, 0xFF2F08E2, + 0x6E13DA1E, 0x2044BE0E, 0x42830400, 0xB203B20B, + 0x1F802605, 0x2C580000, 0x2753B200, 0x68371180, + 0xB20C7825, 0x11802553, 0x78256837, 0x78FDB204, + 0x0140206C, 0x2605B883, 0xB8071001, 0xC0807905, + 0x0FD2B228, 0xD91008E0, 0x78E0C7C6, 0x1E00710C, + 0x901C7004, 0x7EE00480, 0xB9025020, 0x0F812105, + 0x0488901C, 0xB1007FE0, 0xB9025020, 0x0F812105, + 0x048C901C, 0xB1007FE0, 0x4708C2E8, 0x20846A15, + 0x204F0001, 0x204F06D0, 0x2148068E, 0x77040040, + 0x68A17810, 0x400270F5, 0x038120CA, 0x704CD907, + 0x708C706C, 0x0B7670AC, 0x70CCFFEF, 0x1D3F258C, + 0x78E0C6C8, 0x256FC2E8, 0x46081743, 0x10D01500, + 0x20402040, 0x7314780F, 0x002500F0, 0x0D1E70ED, + 0x42C10880, 0x00842280, 0xE8188A60, 0x10C21500, + 0x780F6A01, 0x00F408D5, 0x2A446B01, 0xB8220081, + 0x0FC02049, 0x10002615, 0x0A999081, 0x242F00B2, + 0x90200045, 0xF0497180, 0x20B2082D, 0x20812844, + 0x170B1682, 0x240A6B01, 0x20A87000, 0x26150300, + 0x908110C0, 0x12C40C41, 0x0B3D9000, 0x77641004, + 0xF01B700C, 0x700CE3BF, 0x1682F717, 0xDC40170B, + 0x240A7C62, 0x20A87300, 0x261503C0, 0x94A110CC, + 0x12C40D15, 0x0B119480, 0xE3BF1324, 0x20CA7164, + 0xF0030FE1, 0x60384060, 0x7B0FAA00, 0x17021682, + 0xF749E3C0, 0x96017E75, 0x0084080B, 0x0A3D9600, + 0x242F0005, 0xD8C80045, 0x022041C3, 0xF0130003, + 0x792D7933, 0x1E824C31, 0x9000105C, 0x10240C0F, + 0x0C0B7A30, 0x0A151084, 0xD8C80005, 0x021F41C3, + 0x0F0E0003, 0xDF070140, 0xC6C840E1, 0x0DA2C2F2, + 0x451001A0, 0x704E4410, 0x800047CB, 0x0AA91222, + 0xD82520B5, 0x8820B89F, 0x7825881B, 0x048E0895, + 0x1A0D8FC0, 0x7DCF3482, 0x08898F01, 0x40C30344, + 0x12D98000, 0x08798800, 0x40A2036E, 0x085641A1, + 0x1A0B0760, 0x43103358, 0x0865700E, 0x0B5D2295, + 0x210A242E, 0x1A0C2500, 0x40C33418, 0x28F00000, + 0x221A7A1B, 0x211A2001, 0xB8222082, 0x623A78AA, + 0x40026219, 0x0184209A, 0x70C36038, 0x1A3C8000, + 0xFFEF0E76, 0x34581A0D, 0x3082120D, 0x00002078, + 0x3603120B, 0x021E41C3, 0x0B6E0003, 0x120CFF2F, + 0x71363604, 0xF5DB712E, 0xF1D17106, 0xF1BD71C5, + 0xF1AF7146, 0x78E0C6D2, 0x1CFCC2FA, 0xC1A8B6C8, + 0xD8254318, 0x1600B89F, 0x80007091, 0x44D31222, + 0x00489004, 0x24428820, 0x881B2210, 0x20787825, + 0x204000C0, 0x16000055, 0x80007080, 0x08E11223, + 0x40C30444, 0x12D98000, 0x08D18800, 0x212F046E, + 0x0F920447, 0x40630720, 0x23182940, 0x706E4118, + 0x34EE09B3, 0x22002B40, 0x200570AD, 0xC8080601, + 0x69127905, 0x20054230, 0x90040F96, 0x215A0320, + 0xC7802A00, 0x800041C3, 0x7FB4C004, 0x04C02015, + 0x603278B4, 0x11A06119, 0x20340101, 0x80000F80, + 0xB740BEC4, 0x1C08B722, 0x25053004, 0x68D21480, + 0x15002605, 0x00E009D6, 0xB7059000, 0x140E2605, + 0x00E009CA, 0xB7079600, 0x160071A5, 0x0DB32100, + 0x1C129564, 0x40A23004, 0x062009E6, 0x706CC180, + 0x2305C485, 0x14020480, 0xB8021501, 0x20057164, + 0xB2200502, 0x04012005, 0x0BEB9401, 0xB1008564, + 0x70801600, 0x00EE8000, 0x141CE885, 0x1E003100, + 0x71662004, 0xA2540B4D, 0xF18F7126, 0x1404C0A8, + 0xC6DA341B, 0xC1A3C3F8, 0xD8254018, 0x1600B89F, + 0x8000708D, 0x16001222, 0x80007092, 0x88200187, + 0x881B7056, 0x242122CA, 0x20787825, 0x204000C0, + 0x16000053, 0x80007080, 0x08DB1223, 0x40C30344, + 0x12D98000, 0x08CB8800, 0x79AF036E, 0x07200E76, + 0x2D404003, 0x47101316, 0x0FB1700E, 0x2840242E, + 0x702E2200, 0x05812005, 0x2105C808, 0x25050015, + 0xC1812440, 0x260568D2, 0x90041F8F, 0x0B960048, + 0x97000260, 0x1F8E2605, 0x00409004, 0x0B869600, + 0xC1820260, 0x30821409, 0x30811405, 0x0483223D, + 0x0480213D, 0xC022786B, 0xE810F410, 0x08022254, + 0x2154C321, 0x77040801, 0x1C097764, 0xC0623082, + 0x1C05C361, 0xF0033042, 0x792FC321, 0x0007252F, + 0x262FC140, 0x272F0087, 0x740C00C7, 0x41C34222, + 0x0007025A, 0x0C4A43A1, 0x240A0160, 0x0CF60400, + 0xC0810160, 0x0CEEB700, 0xC0820160, 0x2140B600, + 0x086F2040, 0x712E84E4, 0x08537106, 0x71A5A254, + 0xC7D8F191, 0x88606038, 0xA8607B44, 0x0083104B, + 0x184B7B44, 0x109600C2, 0x7B440083, 0x00C21896, + 0x008310E1, 0x7FE07A64, 0x008218E1, 0x2482C3F4, + 0x250A3306, 0x230A2180, 0x40702100, 0x45284650, + 0x248A4410, 0x24407001, 0x218A3011, 0xC0800FC7, + 0x014020A8, 0x1804B021, 0x18000015, 0xD8FF0005, + 0x301C1C82, 0x38002456, 0x000042D3, 0x47CB0A3C, + 0x1A3C8000, 0x00300D89, 0x07C31802, 0x1481251F, + 0x0184228A, 0x2F80241F, 0x28F00000, 0x2184209F, + 0x70026038, 0x0B9260F9, 0xC080FEEF, 0x088008AE, + 0x003008DB, 0x1600DD3F, 0x80007080, 0x080F0001, + 0x1600009F, 0x8000708D, 0x08920120, 0x24560880, + 0x24003843, 0x00003F81, 0xA901010C, 0x712C40A1, + 0x02E00EBE, 0x148A704C, 0x248A370D, 0x708D7001, + 0x20A8C080, 0x10020340, 0x10020503, 0x4A710502, + 0x71247270, 0x24C079AC, 0xF0501046, 0x20842180, + 0xA3440E9D, 0x20900B0F, 0x20510B13, 0x101F0D0B, + 0x0D0BF005, 0x71A5101F, 0x70CDF1F4, 0x94050EFB, + 0x20310D11, 0x16802500, 0x0080101C, 0x10000E4B, + 0x0880081A, 0x1482251A, 0x241F7014, 0x00002F81, + 0x708D28F0, 0x800040C3, 0x61591B3E, 0x229A42C1, + 0x623A0184, 0x6059F206, 0x14829161, 0x4B343701, + 0x620A62F9, 0x20801100, 0x0306242F, 0xC0804A13, + 0x00600F96, 0x71C5C280, 0x248AF1D2, 0x708D7001, + 0x20A8C080, 0x10020300, 0x10020502, 0x49530501, + 0x71647150, 0x10C624C0, 0xC7D47890, 0x4008C0E6, + 0x7001248A, 0x70CD70ED, 0x07C020A8, 0x000044CB, + 0x7D9B28F0, 0x1300201F, 0xBC227D6A, 0x60B87C2A, + 0x4448609D, 0x1184249F, 0x44CB659D, 0x1A3C8000, + 0x71E57DF5, 0x64BC6590, 0x4C159481, 0x25407410, + 0x26C0104B, 0x78D012C6, 0x78E0C4C6, 0x78E07EE0, + 0x70851E00, 0x0088900C, 0x78E07EE0, 0x0921C0F1, + 0x271400A5, 0x0ACE000C, 0x40A00160, 0x0AC6B40A, + 0x40C00160, 0x2740B40C, 0xF00C0200, 0x01600AB6, + 0xB40A4060, 0x01600AAE, 0xB40C4080, 0x04802740, + 0xC0D19000, 0x1F1C7FE0, 0x78E00004, 0x08EDC3F4, + 0xC1A40071, 0x47CB712E, 0x12228000, 0x20F509D3, + 0x0447202F, 0x00900813, 0x0051081B, 0x70811600, + 0x00258000, 0x1600F005, 0x80007081, 0x09AF0040, + 0x0D1A00D1, 0x0EEE01C0, 0x706E0600, 0x20B50B9F, + 0x0DB64062, 0x702C00A0, 0x20408FA0, 0x8F010A94, + 0x03440887, 0x13122D40, 0x2205C808, 0xC1802510, + 0x04002005, 0x04C22116, 0x46CBB802, 0x00009004, + 0x78C57AB4, 0x0B5F9000, 0xB2002071, 0x034021F4, + 0x422279B4, 0x9124716C, 0x603844A1, 0x042241C3, + 0x78100006, 0x0002252F, 0x01D62841, 0x01552553, + 0x260A740C, 0x093A0580, 0x270A0160, 0x2E400540, + 0x20052180, 0xC8080541, 0x04822005, 0x04002005, + 0xB802BA02, 0x22057E05, 0x90040F82, 0xB22000A8, + 0x71A5B620, 0x7166F1BD, 0x7126F1B2, 0x0E46F198, + 0x0C6A0600, 0x730C01E0, 0x78E0C7D4, 0x41C3C2F0, + 0x000001CF, 0x016008EA, 0x43D3740C, 0x12228000, + 0x208E1300, 0x800142D3, 0x22164D44, 0x1301238D, + 0x76102080, 0x002D0120, 0x23802216, 0xCC2290E0, + 0x702EE819, 0x40F144B1, 0x21041400, 0x42C1740C, + 0x01D041C3, 0x08AA0003, 0x43220160, 0x25001402, + 0x20087126, 0x27092010, 0xCC22100F, 0xA00409DD, + 0x40F1F002, 0x41C3740C, 0x000201D1, 0x088242E1, + 0x43020160, 0x740C7702, 0x41C37FFD, 0x000201D2, + 0x1310274E, 0x232F42E1, 0x08660408, 0x41700160, + 0x2E406F14, 0x20051343, 0x29402010, 0x20052100, + 0xC80803DF, 0x2300718C, 0x00000F8C, 0x726D1000, + 0x903842C3, 0x0C0F0000, 0x208A0031, 0x208A1C15, + 0x20051415, 0xB9021001, 0x1016218A, 0x0C0D7945, + 0x91200031, 0x1815218A, 0x000C2184, 0x2105708C, + 0x210507CF, 0xB9021001, 0x794572AC, 0x912070CC, + 0x000C2184, 0x20472005, 0x02012600, 0x001E2105, + 0x30C12605, 0x7945B902, 0x2605B1E0, 0xB9023301, + 0xB1E07945, 0x02412600, 0x00062105, 0x00C12605, + 0x7945B902, 0x01C41900, 0x03012605, 0x71CCB902, + 0x258D7945, 0x1900093F, 0x238C01C4, 0xE5081FFE, + 0xF16F71C5, 0x06000CEE, 0x78E0C6D0, 0x014422AA, + 0x010421AA, 0x800040C3, 0xA0410450, 0xA0207FE0, + 0x700026F4, 0x0F608000, 0x78E07EE0, 0x803C2042, + 0x012220E8, 0x0040212F, 0x7FE06909, 0x78E07810, + 0x4010C2E8, 0x4568730C, 0x0AD24648, 0x472801E0, + 0x800040C3, 0x88001138, 0x1600E810, 0x80007080, + 0x08190001, 0xD80F00FF, 0x42E14102, 0x708C43C1, + 0x08A00C16, 0xC6C845A1, 0x4102D80F, 0x43C142E1, + 0x08A00A6A, 0xC6C844A1, 0xEA06C0E6, 0x248A76AD, + 0xF005100F, 0x248ADD07, 0x2278100E, 0xBA060002, + 0x2204E23F, 0x7984004F, 0x7C0479B9, 0x2C0169D6, + 0x66FE1340, 0x0E176836, 0x61581064, 0x76107810, + 0x108D24C0, 0x6698F703, 0xC8084834, 0xB8027865, + 0x0F802005, 0x3C009004, 0xC4C6B080, 0x093EC2E2, + 0x099E02C0, 0x450802E0, 0x02A00D66, 0x609860BC, + 0x00412044, 0x780F6038, 0x07012089, 0x30021A04, + 0x78E0C6C2, 0x4008C2E6, 0x800040C3, 0x08151221, + 0x88401071, 0x70831600, 0x00408000, 0xF2957074, + 0x1030080D, 0x100C2078, 0xF0038865, 0xEC848863, + 0xF0038886, 0xC8088884, 0xDD787034, 0x0C0F706D, + 0x25CA10E5, 0x70CD1822, 0x2178F01F, 0x655D0001, + 0x70CDB903, 0x00462140, 0x03012B40, 0x7180240A, + 0x702D61B9, 0x69F27905, 0x030020A8, 0x13C12105, + 0x10102180, 0xB99CB992, 0x9120B99F, 0x038E2108, + 0x71647391, 0xB802F7AA, 0x0343236F, 0x0F802005, + 0x00209004, 0x730C9080, 0x05091302, 0x100C2479, + 0x210C8B20, 0x00009F80, 0x20CA0C7F, 0x723400AD, + 0x23CA7C9B, 0x718510E1, 0x2300DDFF, 0x7C3D130B, + 0x2E01E407, 0x7461130C, 0x208A641C, 0x20CA0FC7, + 0x78C40341, 0x00002079, 0x2356641C, 0x10000940, + 0x609800C0, 0x2048780E, 0xCA070003, 0x0813E80F, + 0x12210231, 0x0C17370C, 0x00001F80, 0x08176815, + 0x0C130251, 0x00001F81, 0x09177196, 0xBB620111, + 0x210CF007, 0x00009F80, 0x23C22156, 0x202F0066, + 0x242F0200, 0x785500C8, 0x007541C3, 0x70C30003, + 0x04588000, 0x6B09B060, 0x43017810, 0xFEEF0A7A, + 0x03C0207C, 0x40C3C6C6, 0x04588000, 0x90207855, + 0xC6C6B021, 0xC80843E3, 0x2005B802, 0x90080F80, + 0x90000014, 0x02A00F96, 0x2044B8C3, 0x781D0041, + 0x7B006038, 0x1CFCC2FA, 0x2482B6C8, 0xD98E3805, + 0xB99F70AD, 0xC551DA80, 0x11F88900, 0xC552808E, + 0x8908C047, 0xC553702C, 0xC044C554, 0xFEAF0D32, + 0x3E002455, 0x702CC098, 0x0D26DA80, 0xC557FEAF, + 0x14002644, 0xC54D720E, 0xC54FC54E, 0xC549C550, + 0xC54BC54A, 0xC556C54C, 0xC007C046, 0x807E2053, + 0x4DC8F212, 0x7825C808, 0x79B6C191, 0x06200BAE, + 0x1600714C, 0x8000708B, 0x16001223, 0x80007082, + 0xF02D1222, 0x708B1600, 0x12238000, 0x70821600, + 0x12228000, 0x10A40B47, 0x1F012554, 0x7825C808, + 0x68324448, 0x13832C40, 0x7200244A, 0x70CD7B25, + 0x048020A8, 0x24556D16, 0x671F3E0F, 0x671F6C14, + 0x12802E40, 0x7FD47865, 0x71C5B892, 0xB89FB89C, + 0xB7009000, 0x71857471, 0x0B47F7A6, 0x6D3610A4, + 0x611B6A14, 0x1F412554, 0x7825C808, 0x2A4068D2, + 0xC098038F, 0x244A7FC5, 0x60797200, 0x20A8700C, + 0x27050340, 0x2080100C, 0xBC920010, 0xBC9FBC9C, + 0x19029480, 0xE3100314, 0x71447271, 0xC006F7A9, + 0x4DDAE889, 0x7825C808, 0x79B6C189, 0x06200AEE, + 0xC004714C, 0x013E0815, 0xC8084DD8, 0xC18D7825, + 0x0ADA79B6, 0x714C0620, 0x227E208D, 0xC09871AD, + 0x3B1B2440, 0x08002054, 0xC042700F, 0x3E002455, + 0x30191408, 0x08002054, 0xC045C043, 0x30161408, + 0x140CC696, 0x24543013, 0x7EB43B92, 0x23522214, + 0x3B172440, 0x77B171ED, 0x1600F2F6, 0x80007085, + 0x16001223, 0x8000708C, 0xC0061222, 0x700DE8B8, + 0x03240D67, 0x2454702D, 0x25023B0B, 0x23140300, + 0x231413CB, 0x27143307, 0x20402304, 0x702D0046, + 0x1702700D, 0x762C0500, 0x01200C56, 0x4408DA40, + 0x1402B600, 0x762C0500, 0x01200C46, 0x1B00DA40, + 0x222F1004, 0x9E200206, 0x1B00B680, 0x780E1004, + 0x22087902, 0x9E200048, 0x212F4910, 0x268D0246, + 0x210808FF, 0x202F0009, 0xF0910206, 0xC0056C34, + 0x00482000, 0x2014C096, 0xC09703D0, 0x03DE2014, + 0x20442600, 0x30472100, 0x20462300, 0x702D706D, + 0x03240DF9, 0x11802B40, 0x2053C007, 0xF218807E, + 0x2016C091, 0x78F60341, 0x030121F4, 0x030020F4, + 0xB826B926, 0x20441A00, 0x30041E00, 0x21411200, + 0x212F4910, 0x210802C6, 0xF019000B, 0x7200244A, + 0x420143C0, 0x04C020A8, 0x05001202, 0x1A00B826, + 0x13022004, 0xB8260500, 0x30041E00, 0x21411200, + 0x212F4910, 0x210802C6, 0x214A000B, 0x250A2200, + 0x240A2100, 0x140221C0, 0x762C2500, 0x01200B72, + 0xB600DA40, 0x1502762C, 0x0B662500, 0xDA400120, + 0x20041800, 0x9E00790E, 0x212F7822, 0x218D0246, + 0x21082B7F, 0xC0040009, 0x013E083D, 0x3D112440, + 0x2116762C, 0xDA402340, 0x01200B36, 0x030020F4, + 0x2116B600, 0x762C23C0, 0x0B26DA40, 0x20F40120, + 0x18000300, 0x790E2004, 0x78229E00, 0x0246212F, + 0x00092108, 0x04042440, 0x04072740, 0x04062640, + 0x14082040, 0xF1867185, 0x0B66780E, 0x44000000, + 0x00200B5E, 0x0246202F, 0x202F4110, 0xC1880607, + 0x611942A1, 0x190043E1, 0xC1950442, 0x41C36038, + 0x0003038E, 0x01021800, 0x09E6740C, 0x40300120, + 0x2401204F, 0x42A1740C, 0x09D643E1, 0x240A0120, + 0x71070440, 0x203F2680, 0x203F2380, 0x22172742, + 0x77E570F5, 0xC005F501, 0x303F2180, 0x003F2080, + 0x321B2342, 0x77A570B5, 0xFFE205D4, 0xC135C045, + 0x70801600, 0x12208000, 0xD841E803, 0xD826F002, + 0x1408B89F, 0x700E3015, 0x1801712E, 0x14550052, + 0xA8203081, 0xA829C128, 0x30811421, 0xC006A82A, + 0x00172079, 0x34001C04, 0x34001C00, 0x30141408, + 0x3B182454, 0x3B962454, 0x34532014, 0x24562614, + 0x273971ED, 0x704E1440, 0x05C02006, 0xB8E070CD, + 0x1600F4CB, 0x8000708C, 0x16001222, 0x80007092, + 0x20141223, 0xC00333CE, 0x700D70AD, 0x25006C34, + 0x24002044, 0x20002049, 0x74520046, 0x002D015A, + 0xC00778AE, 0x807E2053, 0xC091F23F, 0x2016762C, + 0xDA400440, 0x012009DA, 0x030020F4, 0x43CB4700, + 0xFFFF0000, 0x3000264A, 0x0200254A, 0x20041E00, + 0xC1986F16, 0x6C146119, 0x762C6038, 0x078020F4, + 0x012009AE, 0x212FDA40, 0x264002C8, 0x258D305E, + 0x21090CBF, 0xB600000B, 0x081DC004, 0xC08D013E, + 0x78F6762C, 0x098ADA40, 0x20F40120, 0x23090300, + 0xB600100B, 0x02C6212F, 0x01C6202F, 0x79AE7822, + 0x000D2108, 0x274AF020, 0x260A0200, 0x250A3240, + 0x15020180, 0x762C0500, 0x01200956, 0x4308DA40, + 0x35001602, 0x094A762C, 0xDA400120, 0x02C6222F, + 0x4A31790E, 0x278D7AAE, 0x22080BFF, 0xB600004D, + 0x22C41E00, 0x14600F83, 0x1200234A, 0x0240250A, + 0x0100270A, 0x05001702, 0x0916762C, 0xDA400120, + 0x20041B00, 0x1502762C, 0x09060500, 0xDA400120, + 0x790EB600, 0x21401300, 0x212F7822, 0x238D0206, + 0x21081B3F, 0xC0040008, 0x013E083F, 0x3D0B2440, + 0x2316762C, 0xDA401440, 0x012008D6, 0x030020F4, + 0x13CB2316, 0x20041B00, 0xDA40762C, 0x012008C2, + 0x130023F4, 0x790EB600, 0x21401300, 0x212F7822, + 0x21080206, 0x24400008, 0x21400404, 0x26401409, + 0x71850406, 0x090AF153, 0x42100000, 0x00200902, + 0x0206202F, 0x202F4608, 0xC1800407, 0x45CB6119, + 0x00030392, 0xC181A9C0, 0x41A16038, 0x04821800, + 0x4222740C, 0x0F8A43E1, 0x240A00E0, 0x254F0480, + 0x740C1401, 0x43E14222, 0x00E00F76, 0x248044C1, + 0x7106203F, 0x77E570F5, 0xC003F50D, 0x203F2580, + 0x003F2080, 0x77267036, 0xFFE205F4, 0xC221C043, + 0x70801600, 0x12208000, 0xD943E803, 0xD928F002, + 0x1405B99F, 0x19013080, 0x19010092, 0x14060012, + 0x19013080, 0x19010012, 0xC0200492, 0x00121901, + 0x30801401, 0x1402A900, 0xA9013080, 0x2480A9C2, + 0x14043805, 0xC6DA341B, 0x40D3C2EA, 0x0C0C902C, + 0x21111000, 0x2D0D2040, 0x214F71ED, 0xB5E02100, + 0x180070CD, 0x40C32004, 0xA48007BF, 0x10151D04, + 0x1DF0702C, 0x1DF093C4, 0x0AFA9384, 0xB5E004A0, + 0xE8069502, 0x04A00A62, 0xF1FCD80A, 0xB5DEB5C0, + 0xB5DEB5FE, 0x24441800, 0x78E0C6CA, 0x70811600, + 0x00088000, 0x00720813, 0x7810B907, 0x77046038, + 0x00412804, 0x7813F006, 0x28057810, 0x79130040, + 0x782E7FE0, 0x0B32C2E6, 0x45080820, 0x16007014, + 0x80007080, 0x74CD0160, 0x11E226CA, 0x0EF2E805, + 0x712CFFAF, 0x1600F009, 0x80007080, 0xB8E20001, + 0x20CA700C, 0x7F1003E1, 0x40E141C1, 0x716C42A1, + 0x70AC708C, 0x00600A9E, 0x700C71CC, 0x42A1702C, + 0x0DCE716C, 0x708C08E0, 0x41C140E1, 0x706C42A1, + 0x70AC708C, 0x00600A7E, 0x710C71CC, 0x42A1702C, + 0x0DAE716C, 0x708C08E0, 0x78E0C6C6, 0x40D3C2F4, + 0x12228000, 0x20911000, 0x46304550, 0x0A942040, + 0x23122940, 0x20801001, 0x046408AF, 0x25132205, + 0x2005C808, 0x47CB04C0, 0x00009004, 0x41C3B802, + 0x000303EC, 0x422278E5, 0x740C90C0, 0x265343C1, + 0x0DCE1144, 0x23AD00E0, 0x0D230982, 0x740C2030, + 0x03ED41C3, 0x0DBA0000, 0x160000C0, 0x80007080, + 0xB8060008, 0x100D2E09, 0x0E0DF00B, 0x26402030, + 0xF007180D, 0x18340E0B, 0x264270AD, 0x2553180D, + 0x25AD114E, 0x0D111982, 0x740C2030, 0x03EE41C3, + 0xF00B0002, 0x20100E0D, 0x03EF41C3, 0xF0050002, + 0x03F041C3, 0x42A10002, 0x00E00D66, 0x6D1643C1, + 0x20082296, 0xC8087E05, 0x04C02005, 0xB8027126, + 0xB7C07F05, 0x0A8EF1A8, 0xC6D405C0, 0x800140C3, + 0x88204E81, 0x70801600, 0x00728000, 0x20447824, + 0x7FE00800, 0x00002078, 0x70801600, 0x008A8000, + 0x7FE0B8C1, 0x00402078, 0x800141C3, 0x89204E89, + 0x70801600, 0x00928000, 0x20447825, 0x7FE00800, + 0x78E0B825, 0x800141C3, 0x89204E77, 0x70801600, + 0x00628000, 0x20847825, 0x7FE00001, 0x78E0B826, + 0x70801600, 0x008E8000, 0x7FE0B8C1, 0x00002078, + 0x70801600, 0x00968000, 0x04002044, 0xB8247FE0, + 0xB7C81CF4, 0x087F4200, 0x1C040065, 0x78523001, + 0x6038700D, 0xB8224340, 0x71044140, 0x7000240A, + 0x20A84308, 0x810005C0, 0xC0427104, 0xC001C402, + 0xC0416098, 0x236FA160, 0x8100003F, 0x00210B0D, + 0xC002718D, 0xA1004409, 0x74247464, 0x240A4089, + 0x20A872C0, 0x82000340, 0xC102C042, 0x7822C001, + 0xC002C041, 0x1A047704, 0xEC0D0010, 0x031041C3, + 0x0C4E0001, 0xD80A00E0, 0x41C3700C, 0x00000311, + 0xC001F00E, 0xC201E810, 0x031241C3, 0x0C320001, + 0xD80A00E0, 0x41C3700C, 0x00000313, 0xFE8F092A, + 0xF008710C, 0xD80AD9C5, 0x00E00C16, 0x700CB912, + 0x341F140C, 0x78E07EE0, 0xB7C81CF4, 0x087F4200, + 0x1C040065, 0x78523001, 0x6038700D, 0xB8224340, + 0x71044140, 0x7000240A, 0x20A84308, 0x810005C0, + 0xC0427104, 0xC001C402, 0xC0416098, 0x236FA160, + 0x8100003F, 0x00210B0D, 0xC002718D, 0xA1004409, + 0x74247464, 0x240A4089, 0x20A872C0, 0x82000340, + 0xC102C042, 0x7822C001, 0xC002C041, 0x1A047704, + 0xEC0D0010, 0x031541C3, 0x0B960001, 0xD80A00E0, + 0x41C3700C, 0x00000316, 0xC001F00D, 0xC201E80F, + 0x031741C3, 0x0B7A0001, 0xD80A00E0, 0x700CD963, + 0x0876B913, 0x710CFE8F, 0x41C3F008, 0x00000319, + 0x00E00B5E, 0x700CD80A, 0x341F140C, 0x78E07EE0, + 0xE18F714C, 0x0FC7238A, 0x22CA7A38, 0xB80E00C1, + 0x0F812005, 0x02EC9004, 0x0240224F, 0x00051900, + 0xB100B140, 0x7FE0B140, 0x00051900, 0x7FE0720C, + 0x00C420AB, 0x2482C3EC, 0x41303204, 0x740C4210, + 0x021241C3, 0x45880000, 0x0B064668, 0x474800E0, + 0x3605120C, 0x120B740C, 0x41C33604, 0x00040213, + 0x3603120D, 0x00E00AEA, 0x3082120D, 0x71001600, + 0x000A8000, 0x007E0815, 0x41C3D8C8, 0x00020214, + 0x0ACE42C1, 0x43A100E0, 0x24407752, 0x27CC3010, + 0xF2039442, 0x0FE640F1, 0x701407C0, 0x7EC0706D, + 0x1FC7208A, 0x9FC0234C, 0x002D006C, 0xE0BF78D0, + 0x002D0052, 0x22C12215, 0xEC259181, 0x211578CE, + 0x90612000, 0x9000EB1F, 0x994078A2, 0x2048780E, + 0x79100000, 0x20157230, 0x20CA22C1, 0x4BB2008A, + 0x7B8E7A4E, 0x0FC72289, 0x2209B100, 0x781000C2, + 0x7A50B141, 0x00A4081B, 0x1902D8FF, 0xB1000005, + 0x2015F007, 0x180222C0, 0x18000005, 0x71650204, + 0xF1CA71C5, 0xA3C0200C, 0x7001248A, 0x02A220E8, + 0x25001002, 0x10141F02, 0x25001002, 0x10141F02, + 0xC7CC700C, 0x1CFCC2FA, 0xC1A8B6C8, 0x31401C04, + 0x41C34520, 0x28F00000, 0x42504078, 0x0042201F, + 0xC0177B3B, 0x009B2D41, 0x1C1C786C, 0x44C33100, + 0x1A3C8000, 0x00962440, 0x31C01C00, 0x31801C14, + 0x00972000, 0x30191460, 0x25802700, 0xC000C042, + 0xD8406849, 0x00952801, 0x800040C3, 0x10B71222, + 0x43500081, 0x00861000, 0x8821C143, 0x222FC144, + 0xC0040187, 0x01DC7210, 0xC003000D, 0x80802011, + 0x221FF2E6, 0x00000F90, 0x225F0A3C, 0xC0020281, + 0x029E265E, 0x2700700D, 0x20002414, 0xC0012010, + 0x21112400, 0xC0467834, 0x9240204C, 0x002D01A0, + 0x3787272F, 0x702D700C, 0x702C706C, 0x436870CD, + 0xF005262F, 0x800043C3, 0x0044C444, 0x44EB0024, + 0x100E249F, 0x092B641C, 0x646B1030, 0x68A9EB95, + 0x12C7242F, 0x4B977BAF, 0x7BCF7C2F, 0x7B7B7B82, + 0x03E50B17, 0x706C702D, 0x46A94161, 0xEB05F006, + 0x4300712D, 0x4361F002, 0xF1DB7104, 0x1030091F, + 0x7ECF782F, 0x12C7242F, 0x7E02DD7F, 0x7EDB7D82, + 0x20CA75D1, 0x21CA030D, 0x70A202CD, 0x8002208C, + 0x41A2F784, 0x0FC12187, 0x7D2F4709, 0x1184279A, + 0x7D0AC000, 0x308021F4, 0x7782702D, 0x03CC2400, + 0x1C8060B8, 0xC005101C, 0x248AE824, 0x27007001, + 0x80001F8B, 0x20A81B40, 0x40E30740, 0x14CC2901, + 0x000E209F, 0x7C8F643C, 0x609845A8, 0xB8816068, + 0x700C7314, 0x40A0F203, 0x271570AD, 0x7125124C, + 0x110E2400, 0xB60074C2, 0x1B00B4A0, 0xF05016C4, + 0x7001248A, 0x0400270A, 0x1440230A, 0x020120A8, + 0x290145EB, 0x259F14C0, 0x6038100E, 0x708D7F0F, + 0x606E65F8, 0xEE2540A0, 0x1180275F, 0x40C3651D, + 0xC1448000, 0x10B00E11, 0x0E1760BC, 0x444A1071, + 0xF0176510, 0x94816510, 0x160C2402, 0x60BEF011, + 0x96816515, 0x160C2402, 0x7F104CB0, 0x22029602, + 0x7ED0200E, 0x20CA76F1, 0x24CA034E, 0x7D90148D, + 0x10040D23, 0xED07C507, 0x25F4C506, 0x60B8120D, + 0x7E1064BC, 0x7DC27D90, 0x0D0B71A5, 0x708D1155, + 0x1B0440A0, 0x71251014, 0x03141F04, 0x21842180, + 0x21842080, 0x26407105, 0xF130305E, 0xF11171C4, + 0x1404C0A8, 0xC6DA341B, 0x4130C2EA, 0xFFEF0AE6, + 0x0D154508, 0x401011F5, 0x203278AD, 0x80000F89, + 0xF00A0D80, 0x41C3700C, 0x00010087, 0xFE6F0CAA, + 0x702D42A1, 0x900446CB, 0x6D0A02D4, 0x01750821, + 0x294096E0, 0x27041289, 0x00001F80, 0x2005C3FF, + 0x1E000240, 0x90077004, 0xC6CAFED4, 0x800040C3, + 0x10B71222, 0x21540086, 0x88612F08, 0x240B2140, + 0x45CB8880, 0x00009004, 0x36071208, 0x83040BDF, + 0x032E0E59, 0x13042C40, 0x7240244A, 0x20A870AC, + 0x25050980, 0x20050100, 0x220501C2, 0xB90202C1, + 0x912079A5, 0x20300817, 0x2205B927, 0xBA020202, + 0x92407AA5, 0x0182226D, 0xB9E06159, 0x21C74121, + 0xB90A03E2, 0x1F8F2704, 0xC3FFFFFF, 0x2556B802, + 0x7F250805, 0xB0E078C5, 0xF1D27185, 0x226FC2E2, + 0x44CB0443, 0x04988000, 0x8A6084A7, 0x7D6C8406, + 0x0001231C, 0x810212FE, 0x231A61B9, 0x219A000D, + 0x40A1041F, 0x141F259A, 0x041F209C, 0x61197BBD, + 0x20798C10, 0x2447004C, 0x799817C0, 0x00002B01, + 0x7905706C, 0xFE6F0892, 0x13002D00, 0x78E0C6C2, + 0xC1A1C3E6, 0x000F2315, 0x260A4008, 0x97013080, + 0x703070AD, 0x002E0120, 0x97204328, 0x21CC7171, + 0x01148005, 0x2B400026, 0x258A1407, 0x27050FC3, + 0x772D0207, 0x334E2616, 0x9E609E01, 0x00E2082B, + 0x0240260A, 0x7A7079AF, 0x40E07B10, 0x00E00C6A, + 0x30C42440, 0x210C4600, 0x14039000, 0x26CA3080, + 0x25090245, 0x9E030005, 0x082D9E62, 0x210A00E2, + 0x79AF1180, 0x7B107A70, 0x0C3E40E0, 0x244000E0, + 0x410830C4, 0x8000260C, 0x30801403, 0x118521CA, + 0x00052509, 0xE5C071A5, 0xFFC5079C, 0x45CB9720, + 0xFFFF0000, 0x02C5091B, 0x0B179701, 0x20021025, + 0x7A1002C0, 0x10402302, 0x20097810, 0xD840008D, + 0x3703121D, 0x02002002, 0x201A780C, 0x204000C1, + 0x780A1040, 0x2509786C, 0x210C0203, 0x20CA9000, + 0x70300245, 0x000521CA, 0x0008208A, 0x02C22002, + 0x7A4CCC1C, 0x71507A0C, 0x004522CA, 0x1FC1204E, + 0x2309792F, 0x16000043, 0x80007081, 0xB9E0000E, + 0xF409705C, 0x10412340, 0x782C792C, 0x20CA7210, + 0x41C30085, 0xFFFF00FF, 0x657D7030, 0x000521CA, + 0x7D25B908, 0xC7C640A1, 0x1200C0E6, 0x70AD3087, + 0x47CB706C, 0x113A8000, 0x0B69710D, 0x2B4001E5, + 0x235A0386, 0x702D0A0E, 0x704C706D, 0xB0A167D8, + 0x0A47B0A0, 0x26050255, 0x21050241, 0x90040F81, + 0x91200200, 0x0A157C2F, 0x28000321, 0x9020130C, + 0x0081210F, 0xF00DB020, 0x71249021, 0xB902B021, + 0x0F0F2184, 0x61F961D9, 0x02C41902, 0x7425B180, + 0x71447165, 0x9020F1DF, 0xB9897164, 0xF1CFB020, + 0x78E0C4C6, 0xC1A1C3E6, 0x16004608, 0x80007100, + 0x4528000A, 0x0980206D, 0x0817E808, 0x080D0050, + 0x1A0000D1, 0xF00700C3, 0x00831A00, 0x1A00F003, + 0x24400043, 0x244030C0, 0x0E123081, 0x42C101E0, + 0xC7C6E802, 0x30821402, 0x308C1403, 0x7B3D6459, + 0x10C12615, 0x91E0AD60, 0x61F99121, 0xB521793D, + 0x7C3D6399, 0x13012615, 0x91E0AD84, 0x61F99121, + 0xB523793D, 0x793D6359, 0xAD287E35, 0x96219640, + 0x793D6159, 0xC7C6B525, 0xC1A2C3E4, 0x45084628, + 0x30011C04, 0xFEAF0E3A, 0x30011C00, 0xD907D841, + 0xDA08B813, 0x708C706C, 0x0FA270AC, 0x70CCFEEF, + 0x742C700C, 0xFF2F0A8A, 0xC080714C, 0x09E241A1, + 0x734CFF2F, 0x700C4508, 0x0A76742C, 0x714CFF2F, + 0xD907706C, 0x744C4060, 0x708CB892, 0x0F6E70AC, + 0x70CCFEEF, 0xD907D880, 0xDA08B893, 0x708C706C, + 0x0F5A70AC, 0x70CCFEEF, 0xFE8F0DBE, 0xB600B802, + 0xC7C440A1, 0x2044781B, 0xD8E40181, 0x7FE07839, + 0x78E0B8C1, 0x01422053, 0x206DA941, 0x20AD0182, + 0x605801C1, 0xA9007FE0, 0x43E3C1A1, 0xFFEF0FEA, + 0xC020C180, 0x30811401, 0x6038B806, 0x74877B20, + 0x1CFCC2FA, 0x2482B6C8, 0x1CC83B06, 0x40383080, + 0x30001CC0, 0x1CC4700C, 0x1C403000, 0x1CFC3018, + 0x1CF83000, 0x1CF43000, 0x14C83000, 0x1CA03000, + 0x20843000, 0x1CA00004, 0x14A03000, 0x1C8C3010, + 0x148C30C0, 0x1CE43001, 0x28413180, 0x1CE02200, + 0x1CAC3140, 0x09AA3100, 0x401000E0, 0x70911600, + 0x000D8000, 0x30001CEC, 0x02A00FBA, 0x46084003, + 0x702CC808, 0x2005B802, 0x90380F80, 0x90E00008, + 0x3F802400, 0x01040000, 0xFE2F0B46, 0x148CDA50, + 0xB8A03000, 0x30001C98, 0x22002144, 0x000D2078, + 0x30001498, 0x00910811, 0xFF8F0E3A, 0x30001CC4, + 0xF004710C, 0x00C00986, 0x30001CBC, 0x40037DC4, + 0x02A00F62, 0x33401CD4, 0x30011498, 0x00B1092D, + 0x24012144, 0x71001600, 0x00148000, 0x04110819, + 0x07800F86, 0x0832E888, 0x701407C0, 0x1CA4710C, + 0xF40B3000, 0xF007700C, 0x00002052, 0x00012178, + 0x1CA47824, 0x148C3000, 0xBFC13000, 0x00002078, + 0x07A00F56, 0x30001C9C, 0x300214C0, 0x024541C3, + 0x148C0005, 0x240A3003, 0x1CD80600, 0x740C3000, + 0x300614AC, 0x00A00A7A, 0x0400250A, 0x300014D4, + 0x00102079, 0x30402042, 0x081B7D0F, 0x1CB001F5, + 0x14B03000, 0xB8C63000, 0x0050080B, 0x300014A0, + 0x1600E88A, 0x80007080, 0xB8E00107, 0x1C94700C, + 0xF2073000, 0x05800B96, 0x1C94710C, 0x27793000, + 0xDA7D1000, 0x30001CB4, 0x148C708E, 0x41DB3000, + 0xC1448000, 0x0080207C, 0x30001CB8, 0x20402040, + 0x30001CCC, 0x3000149C, 0x0F80201F, 0x51E00000, + 0x30001CF0, 0x800070C3, 0x1CD01B3C, 0x14B03000, + 0xB8C63000, 0x00012A01, 0x11C0257C, 0x1CE87824, + 0x2A013000, 0xB8C00340, 0x800045CB, 0x1CDC1221, + 0x14983000, 0x20783000, 0x1CA80080, 0x72963000, + 0x00260702, 0xB89FD825, 0x881B8820, 0x710C7905, + 0x05002800, 0x200FB802, 0x7E2B050E, 0x002106D4, + 0x0D0A730C, 0x1D000120, 0x148C1502, 0x24553001, + 0x14E03F42, 0x24553004, 0x14A43FC3, 0x202F3005, + 0x43180507, 0x01600CB2, 0x300614D4, 0x300014A0, + 0x00002079, 0x100115BB, 0x30001C90, 0x14904063, + 0x0A623002, 0x14900320, 0x14D83003, 0x7FCF3000, + 0x3003148C, 0x3F452455, 0x30061490, 0x14CCC182, + 0x42033007, 0x093E44E1, 0x43F10060, 0x300014AC, + 0x14A870AE, 0xC3823001, 0x35441C0A, 0x300214E8, + 0x02200C8E, 0x30431C0C, 0x300014A4, 0xC808E839, + 0x15B8700D, 0x15021086, 0x8DE11089, 0x78EF68D2, + 0x1004095F, 0x002E0E57, 0x038C2840, 0x7240244A, + 0x70EC7CC5, 0x20A8706C, 0x205F0600, 0x24000501, + 0x00003F82, 0x623A015C, 0x02812F40, 0x22147985, + 0x210501CB, 0x90040F81, 0x91200320, 0x633B71E4, + 0x10441B00, 0x3F812400, 0x01540000, 0x78707914, + 0x02402845, 0x02041A12, 0x71E5B100, 0x14B0F1D1, + 0x08173000, 0x14A801D5, 0x14DC3001, 0x20053000, + 0xF207807E, 0x1498F00D, 0x08173000, 0x16000090, + 0x80007080, 0x2044000B, 0x2D410815, 0x0C9B2155, + 0x0D972011, 0x70ED2030, 0x310B1412, 0x3108140E, + 0x12C02002, 0x31071410, 0x00072700, 0x15B8C808, + 0x15021085, 0x8DC11084, 0x00862840, 0x0C6B7BCF, + 0x0D6300C4, 0x2B4000EE, 0x704C0389, 0x11892105, + 0x0501235F, 0x3F802400, 0x015C0000, 0x02750A45, + 0x20146038, 0x2A400081, 0x20050280, 0x20050240, + 0x90040F80, 0x90000320, 0x02CC2000, 0x1325080D, + 0x1900B100, 0xF00C01C4, 0x710C1600, 0x013A8000, + 0x0325080B, 0xB1E07882, 0xB100F002, 0xF1DA7144, + 0x71C5B0E9, 0x14B8F1CC, 0x14B43001, 0x790B3000, + 0x8DE1F233, 0x8D027EEF, 0x0384085F, 0x800040C3, + 0x880012D9, 0x03AE084F, 0x094A41C1, 0x14C80660, + 0x43083000, 0x13002E40, 0x244AC107, 0x79057280, + 0x7825C808, 0x6872702C, 0x054020A8, 0x104E0B25, + 0x150C265F, 0x3F822400, 0x01040000, 0x2940645C, + 0x7A650282, 0xBA927C34, 0xBA9FBA9C, 0xB4409240, + 0x71E57124, 0xDA23F1D0, 0xBA0A4023, 0xFDEF0F82, + 0x14D8702C, 0xE8093000, 0x40C3702C, 0xBE248000, + 0xFDEF0F6E, 0x1412DAA0, 0x14103112, 0x0A4D310E, + 0x210A23A5, 0x140D2500, 0x70143080, 0x000102E4, + 0x108B15B8, 0x8D218D42, 0x31031410, 0x7050782F, + 0x000D03C2, 0x102E0B21, 0x7240244A, 0x0F80201F, + 0x0A3C0000, 0x020020A8, 0x300C14D0, 0x2080641C, + 0xB4600184, 0xF1EC7124, 0x31171414, 0x20162479, + 0x2E812185, 0x2A162640, 0x900740D3, 0x14ACC29C, + 0x08A13000, 0x14980010, 0x08133000, 0x79CF00B1, + 0x0F324063, 0x734CFE6F, 0xC808F044, 0x108815B8, + 0x108B1502, 0x8D016852, 0x0B55790F, 0x084D1044, + 0x2940106E, 0x0D3B038C, 0x7C452030, 0x0501215F, + 0x3F832400, 0x015C0000, 0x7240244A, 0x633B702D, + 0x038020A8, 0x12812940, 0x024F23F4, 0x67DF7985, + 0x21057125, 0x90040F81, 0xB1E00320, 0x2405F006, + 0x90041F81, 0xB1C03F20, 0xF1D87104, 0x000440C3, + 0x0A8293E0, 0x702C0420, 0x300114B8, 0x300014B4, + 0xF208790B, 0x70801600, 0x001D8000, 0xF4D0B8E0, + 0x1C0AC808, 0xB8023384, 0x0F802005, 0xC0049007, + 0x00051800, 0x7014C022, 0xF217C082, 0x3101140E, + 0x3F432455, 0x30051490, 0x3FC42455, 0x300614A8, + 0xC1404263, 0x3001148C, 0x4003C041, 0x02200ED2, + 0x3007149C, 0x148CF012, 0x24553001, 0x14C03F45, + 0x704C3003, 0x300414BC, 0x30061490, 0x30071494, + 0x09C6C040, 0x40030060, 0x300014C4, 0xF2917014, + 0x30001494, 0x0F247014, 0x1C1C0561, 0x710C3580, + 0x012009D6, 0x40034162, 0x0FC24162, 0x704C0020, + 0x08C1C022, 0xC0820030, 0x24051800, 0xE81CCA00, + 0x2940702C, 0x228A0380, 0x20050004, 0x90040F80, + 0xB04002F8, 0x7200244A, 0x0010228A, 0x020020A8, + 0x00832005, 0x00102280, 0x00051B00, 0xCA007124, + 0x800409D3, 0x3101140E, 0x1490C082, 0x24553005, + 0x14A83F43, 0x24553006, 0x149C3FC4, 0x42633007, + 0x4003C041, 0x0E1AC140, 0x732C0220, 0x43C3702C, + 0x4FA08001, 0x0945CA00, 0x29400025, 0x700D038B, + 0x0833700C, 0x71ED0255, 0x30021494, 0x70547F18, + 0x900442C3, 0xF20702F8, 0xBC0A630C, 0x12CC2405, + 0x2305F003, 0x7A85120C, 0x10102080, 0x7104B2E0, + 0xE309F1E9, 0xF1E07124, 0x1800D820, 0xF0102004, + 0x300314C0, 0x300414BC, 0x3F452455, 0x4003C040, + 0x704C732C, 0x08C270CC, 0x71EC0060, 0x30001494, + 0x0AB87014, 0x14EC05C1, 0x40033002, 0x00200ECE, + 0x700C4162, 0x012008D2, 0x1C1C4162, 0x76E23440, + 0x705278D0, 0xFFCE05CA, 0xFFCF056F, 0x108B15B8, + 0x8D827FD0, 0x796F8D61, 0x06587191, 0x0B41FFCD, + 0x2400104E, 0x00003F80, 0x20F40154, 0x16000042, + 0x80007080, 0x6058011B, 0xD81170F1, 0x1600F7CA, + 0x80007080, 0x4A10011C, 0xD89170F1, 0x006B20CA, + 0x2105B90E, 0x90040F81, 0xB1003ED4, 0xF1DD7164, + 0x08C1C022, 0x140E0030, 0x8DE13113, 0x8D0279EF, + 0x006408E3, 0x40C34030, 0x12D98000, 0x08A18800, + 0x70CD042E, 0x1291275E, 0x0447202F, 0x01A00DE2, + 0x205F4210, 0x14CC2502, 0xC182300C, 0x248A7C09, + 0x623A7001, 0x923A7AD4, 0x41C3643C, 0x28F00000, + 0x2043241A, 0x201FB922, 0x14F02041, 0x627A3002, + 0x41C1623A, 0x0184219A, 0x2300623B, 0x80000F81, + 0x43681B3C, 0x708DB180, 0x078020A8, 0x300114D4, + 0x43627A8F, 0x62197A39, 0x218C704C, 0xF74C8002, + 0x215A4242, 0x229F0181, 0x623A000E, 0x06432234, + 0x92417223, 0x13012315, 0x71C37185, 0x1A3C8000, + 0xB141B160, 0x0E7571C5, 0x712692B4, 0xF1A871E5, + 0x3FC02455, 0x916A4183, 0x41629149, 0x240AC041, + 0x149C0540, 0x24003000, 0x00003F85, 0x14CC015C, + 0xC0403007, 0x300014AC, 0x00062078, 0xFFAF094A, + 0x149C4063, 0x40633001, 0x30021490, 0x300314C4, + 0x01A00A06, 0x300414E4, 0x300114B8, 0x300014B4, + 0xF234790B, 0x7EEF8DE1, 0x08618D02, 0x40C30384, + 0x12D98000, 0x08518800, 0x41C103AE, 0x06200CB6, + 0x300014C8, 0x2E404408, 0xC1071300, 0x7280244A, + 0xC8087905, 0x700C7905, 0x20A86952, 0x0C270580, + 0x265F100E, 0x24001503, 0x00003F81, 0x61790104, + 0x000321F4, 0x02812840, 0xB9927945, 0xB99FB99C, + 0x7104B160, 0xF1D171E5, 0x0A9EC082, 0x702C0020, + 0x300014D0, 0x20967186, 0x01070794, 0x1CD0FFEF, + 0x14943000, 0x70143000, 0x05C208A0, 0x3B062480, + 0x341B1404, 0x78E0C6DA, 0x4110C2EA, 0x70801600, + 0x00088000, 0x08114548, 0x462800B1, 0x2280204A, + 0xF00574ED, 0x2240204A, 0x088272ED, 0x208AFEEF, + 0x0EC1080C, 0x208A1275, 0x08B90144, 0x0923038E, + 0x706C2030, 0xFECF0872, 0xD907706C, 0x724C4060, + 0x708CB88F, 0x0DB670AC, 0x70CCFEAF, 0xD907F00C, + 0xDA184060, 0x708CB88F, 0x0DA270AC, 0x70CCFEAF, + 0xFECF0846, 0xD907700C, 0x706C704C, 0x45A1708C, + 0xFEAF0D8A, 0x704C70CC, 0x4648752C, 0xBE94DB80, + 0x40C1708C, 0x0D7645A1, 0x70CCFEAF, 0xD9296E13, + 0x706C42E1, 0x45A1708C, 0xFEAF0D62, 0x01C0264A, + 0x30821204, 0xD907700C, 0x708C706C, 0x0D4E45A1, + 0x70CCFEAF, 0xD907700C, 0x706C704C, 0x45A1708C, + 0xFEAF0D3A, 0x78DB70CC, 0x704C752C, 0x0004238A, + 0x45A1708C, 0xFEAF0D26, 0xD84170CC, 0xF03CD92A, + 0x20300921, 0x0FC2706C, 0x706CFE8F, 0x4060D907, + 0xB88F724C, 0x70AC708C, 0xFEAF0D02, 0xF00D70CC, + 0x4060D907, 0xB88FDA28, 0x70AC708C, 0xFEAF0CEE, + 0x0F9670CC, 0x700CFE8F, 0xDA08D907, 0x708C706C, + 0x0CDA45A1, 0x70CCFEAF, 0xD907700C, 0x706C704C, + 0x45A1708C, 0xFEAF0CC6, 0x704C70CC, 0x4040752C, + 0x0004238A, 0x708CB895, 0x0CB245A1, 0x70CCFEAF, + 0xD92BD841, 0x42E1B812, 0x708C706C, 0x0C9E45A1, + 0x264AFEAF, 0x700C01C0, 0x744CD907, 0x708C706C, + 0x0C8A45A1, 0x260AFEAF, 0x0F160400, 0x700CFE8F, + 0x704CD907, 0x708C706C, 0x0C7270AC, 0x70CCFEAF, + 0xD907700C, 0x706C704C, 0x70AC708C, 0xFEAF0C5E, + 0x0AC670CC, 0x7704FE4F, 0x78E0C6CA, 0x88A0C0E6, + 0x900743C3, 0xED07C2CC, 0x00051B00, 0x00051B04, + 0x248AF005, 0xB3801FC7, 0x1600B382, 0x80007083, + 0x23780008, 0x6B920103, 0x900743C3, 0xED16C2C0, + 0x1B04B380, 0x09130085, 0xDB1000F5, 0x26F47B2D, + 0x800070C3, 0x908810BC, 0x23CF7295, 0x1E000361, + 0x900770C4, 0xF007C29C, 0x1C0C2445, 0x1B04B380, + 0x43C30045, 0x12228000, 0x008B13B7, 0x8BC08BE1, + 0x0F417BCF, 0x0B3910C4, 0x201410EE, 0x091300CC, + 0xDD0A0070, 0x1C24E988, 0x75AD1285, 0x1C24F007, + 0xF0051145, 0x1C24DD0F, 0x09151005, 0x221400B5, + 0x130000C3, 0x0B0900C3, 0xB4B20013, 0xF1E271C5, + 0x78E0C4C6, 0x702CC0F1, 0x900742C3, 0x1E00C2C0, + 0x90077044, 0xB220FED4, 0x1E00B222, 0x90087044, + 0x800801E4, 0x2005B802, 0x90070F80, 0xB020C000, + 0x002009E2, 0x80441ADC, 0x01800C2A, 0x7EE0C0D1, + 0x46C8C2F2, 0x47084528, 0x416040C1, 0x21C0250A, + 0x2140220A, 0x2100200A, 0x0E364170, 0x43500060, + 0x40E14410, 0x704C41A1, 0x240A4322, 0x250A0400, + 0x46C10480, 0x0020085E, 0x0540270A, 0xEF0870CD, + 0x000040C3, 0x0C32FFFF, 0x712C05E0, 0x4102D840, + 0x70041E00, 0x01E49008, 0x42828508, 0x2005B802, + 0x90070F80, 0x1800C000, 0x1E000045, 0x90077384, + 0x099AC29C, 0x40620020, 0x41628D00, 0xFFEF0CDE, + 0xA5074202, 0x412240A1, 0xFFEF0E86, 0xC6D24242, + 0xC1A1C3F0, 0xD8314608, 0x4528A108, 0x210AC808, + 0xA9C02180, 0xAD24702C, 0x2140230A, 0x200AA526, + 0xB8022100, 0x20054270, 0x90380F80, 0x90E00008, + 0xA522B521, 0x07600C66, 0x11C41D10, 0x20F00A2B, + 0x0A31AD05, 0x204B2070, 0x0A35A140, 0x204B20B0, + 0x0A33A140, 0x204B2031, 0xF21DA140, 0x14811D18, + 0x14011D14, 0x204BF025, 0xF21AA140, 0xF020D828, + 0x1D18F218, 0x1D141401, 0xF01B1481, 0xD87AF217, + 0x700CF016, 0x022541C3, 0x0BEE0001, 0x4242FDEF, + 0x1D18F00F, 0x1D1414C1, 0xF00B1441, 0xF008D829, + 0x14411D18, 0x14C11D14, 0xD87BF003, 0x0A91A505, + 0x275320B5, 0xF244907E, 0x10310E85, 0x20112179, + 0x800047CB, 0x8FC01222, 0x0402202F, 0x22112140, + 0x20522279, 0x00542044, 0x08658F01, 0x40C30384, + 0x12D98000, 0x08558800, 0x7ACF03AE, 0x41424022, + 0x01600EBA, 0x089E4382, 0xC18001A0, 0x23802314, + 0x00C11000, 0x09C2C080, 0x21BF0360, 0x0CEE0FFF, + 0xE80D0040, 0x30801401, 0xF789E0C0, 0x003F2080, + 0x30021C01, 0x7104C020, 0xC080C060, 0x00200EF6, + 0x13902514, 0x2004182C, 0xF1D071C5, 0x78E0C7D0, + 0x42C3700C, 0x0000901C, 0x900741C3, 0xB200F800, + 0x00151984, 0x00041A44, 0x80151980, 0x191CB202, + 0x19040015, 0x19040015, 0x19080015, 0xB1000015, + 0x7FE0B102, 0x78E0B104, 0x4050C2EA, 0x082D4130, + 0x45080275, 0x000046CB, 0x2025FFFF, 0xF0310340, + 0xF008F015, 0xF006F016, 0xF01CF018, 0xF026F01E, + 0x000046CB, 0xF025A536, 0x41C3700C, 0x00010224, + 0xFDEF0AC6, 0x70CD42A1, 0xDEFFF01B, 0xF019BE08, + 0x000046CB, 0xF015AAAA, 0x000046CB, 0xF011B2B2, + 0x000046CB, 0xF00D8241, 0x800040C3, 0x88C10104, + 0xBE088820, 0xF0057E25, 0x000046CB, 0x70165A3C, + 0x0A26DFAA, 0x27CA0760, 0xE8061021, 0x708F1600, + 0x01068000, 0x08E96D0B, 0x26040155, 0x00001F81, + 0xB928FF00, 0x42E178CF, 0x0B8A43E1, 0x240A05E0, + 0x16000440, 0x80007080, 0x72140008, 0x901C41C3, + 0x40C30000, 0xF8009007, 0x1900F406, 0x18000005, + 0xF0060005, 0x00451900, 0x00451800, 0x12300DA7, + 0x0D59D8FF, 0x0D551110, 0x0DF111D0, 0xD9441031, + 0x901C40C3, 0x45CB0044, 0xF8849007, 0x00851800, + 0x90951D80, 0x804418C0, 0x0EC64002, 0x1D0005E0, + 0x700C1105, 0x901F41C3, 0x7AD0C00C, 0xB518B516, + 0xB51A4340, 0xB1004440, 0xB1024540, 0xB504712C, + 0x02200DE6, 0xC6CAB506, 0x900745CB, 0x1D04F830, + 0x704C13D4, 0x0FC7208A, 0x0388242F, 0x722CB540, + 0x700CB502, 0x250A706C, 0x0DBE0100, 0x47480220, + 0x1C012542, 0x901F40C3, 0x1900C00C, 0x1D500085, + 0xB0E013C4, 0xB1E4B0E2, 0xC6CAB1E6, 0x90500D1F, + 0x45CBF199, 0xF8209007, 0x13D41D04, 0x10151D04, + 0x1D08700E, 0x7AD01014, 0x13D41D04, 0x901F47CB, + 0x1D00C004, 0x25421404, 0xB5021C11, 0xB700D844, + 0x722C700C, 0x44404340, 0x0D5E4540, 0x19000220, + 0x1D502105, 0x1F081404, 0x1F0C1404, 0x19081404, + 0x190C2404, 0xC6CA2404, 0x70051E00, 0xF8049007, + 0x78E0C6CA, 0x1CFCC2FA, 0xC1BFB6C8, 0x47084338, + 0xC08B70CE, 0xDA50702C, 0x31C01C00, 0x2140200A, + 0x31801C08, 0x31001C04, 0x1C28C348, 0x0C123580, + 0x1C24FDAF, 0xC8083580, 0x308D237C, 0x2005B802, + 0x90380F80, 0x90000008, 0x2079B8C1, 0x6F0B000E, + 0x039C7514, 0x71F50026, 0x00400A66, 0x25044610, + 0x0B0F1395, 0x712F3070, 0x21CA70D6, 0x47CB3541, + 0x12228000, 0x25802504, 0x300E14B8, 0x71148F60, + 0x202F8F41, 0x223C058A, 0x25CA00C1, 0x78252021, + 0x003F081B, 0x40614368, 0x7104790F, 0x10412614, + 0x00051924, 0x0AF5790F, 0x23788045, 0x737730C0, + 0x1618E009, 0xC0431017, 0xC044700C, 0x026120CA, + 0x8605C044, 0x9608C045, 0x30300969, 0xC808C047, + 0x12C0200A, 0x108717B7, 0x05C02005, 0x10861701, + 0x212F6892, 0x0E4D0207, 0x0F450044, 0x2940006E, + 0x215F0383, 0x7B850289, 0xC203700C, 0x00850831, + 0xEA88C202, 0x06822100, 0x0082121C, 0x0080081D, + 0x02422000, 0x7D54C58B, 0x02822840, 0xBA927A65, + 0xBA9FBA9C, 0xB5409240, 0xF1E97104, 0xF1DB7105, + 0x40CB7377, 0x0F000000, 0x20002552, 0x102120CA, + 0x800040DB, 0xC04612D9, 0x02C7222F, 0x08678F01, + 0x10000084, 0x085B3080, 0x2A4000AE, 0xC0050303, + 0x02012305, 0x900444CB, 0x79050000, 0x7905C808, + 0x208D20F4, 0x7985B902, 0xC106B1A0, 0xB040210B, + 0x2305F20B, 0x210505C1, 0x78250201, 0x7C05B802, + 0x208020F4, 0x0D1BB400, 0x26142030, 0x23051080, + 0x903605C3, 0x208020F4, 0xFEEF0B52, 0x7165C201, + 0x0C12F1CC, 0x8F610540, 0x0B458F20, 0x7A2F0044, + 0x2A407124, 0x2614038B, 0x2305108C, 0x90041F80, + 0x900002D4, 0x20849492, 0xBC0A040E, 0x204F7885, + 0x2305000C, 0x90041F80, 0xB0803ED4, 0x7854C089, + 0x208220F4, 0x782FB040, 0x80050BC7, 0xFEAF09BE, + 0x09CAD8C8, 0x960EFEAF, 0x248A702E, 0xC0082002, + 0xFE6F0D42, 0x1700712C, 0x8F211093, 0x24C7202F, + 0xA040200C, 0x002D0152, 0x0FCF228A, 0x30801000, + 0x84002011, 0x2440F29F, 0xC507390B, 0x140123F4, + 0x140B2314, 0x30B50B37, 0xB9C6653D, 0x6038C007, + 0x8002208C, 0x2555F796, 0x0D2D180D, 0x1B002030, + 0x26141344, 0xC2011400, 0x23032840, 0x23059036, + 0x0A8A05C3, 0x78B0FEEF, 0x1B00F006, 0xF0351344, + 0x13441B00, 0x119E0D63, 0xE82FC001, 0x180D2554, + 0x20300D1F, 0x13441B00, 0x14002614, 0x23032840, + 0x05C32305, 0x9036714C, 0xFEEF0A52, 0x0E3B78B0, + 0x28402031, 0xD90F238C, 0x1F802405, 0x02D49004, + 0x26149060, 0x90521400, 0xB0327946, 0x0F802304, + 0xC3FF0000, 0x7905B90A, 0x1F802405, 0x3ED49004, + 0x1300B020, 0x2840110D, 0xC8082302, 0xC0057A05, + 0x41C37845, 0x3C009004, 0x7825B802, 0xC006B0A0, + 0xB000210B, 0x2205F208, 0x6A1205C2, 0x13007825, + 0xB0201101, 0x23802840, 0x0F802005, 0x26FC9004, + 0x01121000, 0xC002C504, 0xE88E7AAF, 0x02110A09, + 0xE89CC000, 0xE888C000, 0x26802000, 0x0080101C, + 0x00000A29, 0xE8098E04, 0x11041602, 0x0447232F, + 0x4102C000, 0xC000F006, 0x0448242F, 0x706C4102, + 0x04A00C7A, 0x0480250A, 0xC00371A5, 0x09BB79AF, + 0x71668004, 0x40C3F153, 0xC2EC9007, 0xB0407126, + 0x21FD248D, 0x00051800, 0x3010095D, 0x108B17B7, + 0x7C4F8F40, 0x03040951, 0x132E0B49, 0x13002C40, + 0x128D245F, 0x05C32005, 0x7865C808, 0x68D2706C, + 0x0B31C003, 0xC0020005, 0x2400E887, 0x101C1680, + 0x0B1D0080, 0x63BF0000, 0x20F4C08B, 0x2B4003CF, + 0x78C50280, 0xB89CB892, 0xB0E0B89F, 0xF1EA7164, + 0xF1D97144, 0x1404C0BF, 0xC6DA341B, 0xFFC1046C, + 0xFFCF046F, 0x0F812032, 0x0E9C8000, 0x02150809, + 0xF0037933, 0x7FE0B9C2, 0x78E0782D, 0x78E07EE0, + 0x70C51E00, 0x0088900C, 0x78E07EE0, 0x0926C0F1, + 0x0862FD8F, 0x4608FD8F, 0x4528CA09, 0x09807014, + 0xC1A10361, 0xC040C086, 0x70801600, 0x00128000, + 0x10240E0D, 0x0D5E40A1, 0xC1000720, 0x7014CA09, + 0x07010A10, 0xDC247487, 0xFD8F009B, 0xC1A2C3E8, + 0x45284050, 0x41C34200, 0x00010361, 0xFFEF0FB2, + 0xED23750C, 0x70CD704C, 0x7100244A, 0x4040702C, + 0x024020A8, 0x20F4C380, 0x7B34200C, 0x712460B8, + 0x1406B380, 0x750C3106, 0x31041402, 0x036241C3, + 0x14040005, 0x0F7A3105, 0x1400FFEF, 0x71C53103, + 0x0AC97AD0, 0xC7C88344, 0x02550A15, 0x215FE808, + 0x621A0240, 0x0F822232, 0x4FA08001, 0x40407FE0, + 0x88008821, 0x7FE0B807, 0x78E06038, 0x88008821, + 0x7FE0B806, 0x78E06038, 0x216C791D, 0x20530142, + 0x20840141, 0x60380001, 0x60587FE0, 0x00432801, + 0x2B007A69, 0x78220041, 0x7FE0621A, 0x78E07850, + 0x215FC0E4, 0x44CB0A03, 0x113A8000, 0x647970CD, + 0x639291A1, 0x0E257A04, 0x23151365, 0x61990381, + 0x790B9122, 0x79DBF208, 0x00412314, 0x91236199, + 0x0042220F, 0xF1F171C5, 0xC4C47850, 0xC1A4C3F2, + 0x70931600, 0x00048000, 0x02E341C3, 0x0EC20000, + 0x740CFFEF, 0x800145CB, 0x6DCB4E77, 0x19152554, + 0x02200CC6, 0x40C140C1, 0x05600F66, 0x40C1D90B, + 0x05600F5E, 0x40C1D911, 0x0A7ED912, 0xDAEFFEAF, + 0x0F4E40C1, 0xD9120560, 0x0F4640C1, 0xD9290560, + 0x05600BEA, 0x0BE640C1, 0x40A20560, 0x800140C3, + 0x0BDA4F0A, 0x42100560, 0x800140C3, 0x0BCE4F55, + 0x41100560, 0x10C01603, 0x8E3670ED, 0x800040D3, + 0x8E4D1220, 0x23C218B8, 0x23C41800, 0x017E0A11, + 0x238018BC, 0x00120809, 0x011E0933, 0x092F7905, + 0xB88601BF, 0x154BAD00, 0xB8861080, 0x10021D4B, + 0x10801596, 0x1D96B886, 0x15E11002, 0xB8861080, + 0x10021DE1, 0x07200862, 0xC808710C, 0x40C36832, + 0x0504901C, 0xB1E07905, 0x10C3276F, 0x804518A4, + 0x773541C3, 0x8F009400, 0x80822044, 0x001E40C3, + 0x45088480, 0x104125CA, 0xE9098F38, 0x02E541C3, + 0x0DCE0000, 0xD80AFFEF, 0x7054F047, 0x0BEB41C3, + 0x20CAC200, 0x09DE0041, 0x702C03A0, 0x70801600, + 0x000D8000, 0x00BE080B, 0x09DED840, 0x0D960700, + 0x40C3FFCF, 0x019B8000, 0x10FF8820, 0x20058080, + 0xF21A807E, 0x201A782A, 0x000F0F80, 0x09CA4240, + 0x702C03A0, 0xC8094200, 0x010421AA, 0x09237912, + 0x23AA0085, 0x08FF0104, 0x20AA80C4, 0x50320144, + 0xF0097A22, 0x097E40A1, 0x702C03A0, 0x621AF00D, + 0x21AAC80A, 0x090F0104, 0x23AA00A5, 0x08F70144, + 0x20AA80C0, 0x16000104, 0x80007080, 0xB8E0000D, + 0x06C20F78, 0x03C008CE, 0x800045CB, 0x8D001138, + 0x0010088B, 0x08878F00, 0x0DE200DF, 0x0EF20080, + 0x8D00FDCF, 0x704C708E, 0x8F00E806, 0x02002044, + 0x00022078, 0x0B4A700C, 0xD908FE6F, 0x081F8D01, + 0x704C00B4, 0xE8078D00, 0x20448F00, 0x20780200, + 0x700C0002, 0xFE6F0B2A, 0x8D00702C, 0xE807704C, + 0x20448F00, 0x20780200, 0x700C0002, 0xFE6F0B12, + 0x8D00D90A, 0x8F00E806, 0x02002044, 0x00142078, + 0x702CD808, 0xFE6F0AFA, 0x8D004282, 0x8F00E80E, + 0x02002044, 0x00022078, 0x40C3F009, 0x8480001E, + 0x03A008B2, 0xF00F702C, 0x700C704C, 0xFE6F0AD2, + 0x0C42D996, 0x700C0580, 0xFE2F0F82, 0x0CC2712C, + 0x160000C0, 0x80007080, 0x081502FE, 0xD95D003E, + 0x0C5ED80A, 0xB913FFEF, 0x07400AFA, 0x0BE2C080, + 0x235305A0, 0xC08020D3, 0x00A008BE, 0x40C1D91C, + 0xC280702C, 0x708CDBFF, 0x07600BD2, 0x0B5A70AD, + 0x0BBE0000, 0xC08005A0, 0x089EC080, 0xD91000A0, + 0x0896C080, 0xD91C00A0, 0x712C40C1, 0xDBFFC280, + 0x07600BAA, 0x40C1708C, 0x04E00E4E, 0x40C1D90B, + 0x04E00E46, 0x40C1D911, 0x04E00E3E, 0x40C1D912, + 0x04E00E36, 0xCA0ED929, 0x10050D2F, 0x2B02235F, + 0x1F812532, 0x04788000, 0x7AB561CB, 0x720271A5, + 0x2132AA68, 0xAA6A0483, 0x05432132, 0x04412132, + 0xAA2BAA69, 0x0CEAF1EA, 0xD96EFE8F, 0x11C5B99F, + 0x19018480, 0x21400012, 0x21400EC2, 0x12010683, + 0xA9000480, 0x04801201, 0x00121B01, 0x04801205, + 0x1201AB00, 0xA9010480, 0x04801201, 0x1201A902, + 0xAB010480, 0x04801201, 0x1276AB02, 0x1A8B0480, + 0x12018012, 0x43400480, 0x000A1B79, 0x04801201, + 0xAC006B85, 0x121D6C25, 0x19010480, 0x12010012, + 0x1A560480, 0x12010002, 0xAB010480, 0x04801201, + 0x1211AC01, 0x19010480, 0x12010012, 0x1A430480, + 0x8A000002, 0x8A01AB02, 0x8A02AC02, 0x197CE227, + 0x12010012, 0x19010480, 0x12010012, 0x19010480, + 0x12010012, 0x19010480, 0x12010012, 0x19E70480, + 0x12018012, 0x19050480, 0x12010012, 0x19050480, + 0x12010012, 0x19050480, 0x12010012, 0x19010480, + 0x12010012, 0x21420480, 0xAB0003C3, 0x028C2142, + 0x04801201, 0xAC0069AD, 0x04801201, 0x1201AD00, + 0x19010480, 0x12010012, 0xAB010480, 0x04801201, + 0x1201AC01, 0xAD010480, 0x04801201, 0x1201A900, + 0xAB020480, 0x04801201, 0x1201AC02, 0xAD020480, + 0x04801201, 0x1201A901, 0x19F30480, 0x8A008002, + 0x800219F8, 0x19FD8A01, 0x8A028002, 0x1600A902, + 0x90387101, 0x12260034, 0x080D8080, 0x704C01BF, + 0xF011B9A0, 0x70801600, 0x01648000, 0x013F0817, + 0x1600B980, 0x80007080, 0xB8E6001F, 0x22CA724C, + 0x1E000061, 0x903B7044, 0xC808C034, 0x2005B802, + 0x903B0F80, 0xB040C008, 0x78E0C7D2, 0x40C3C5E1, + 0x12228000, 0x706C88A1, 0x704C8880, 0xCA00702C, + 0x00050921, 0x03040909, 0x10450D0F, 0x0F802205, + 0x3ED49004, 0x7124B060, 0x000072C3, 0xF1F14000, + 0x78E0C4C2, 0x1C00DC3F, 0x7C0F0302, 0x080DB830, + 0x4C3100A5, 0xF00A4852, 0x00250B09, 0xF0064872, + 0x704C7831, 0x00021C00, 0xCC1D792C, 0x0003211A, + 0x221ACC1C, 0x782C0081, 0x60787FE0, 0x44CBC0F1, + 0x01078000, 0x42008C60, 0x003F0B2D, 0x0B29710C, + 0x700C007F, 0x7234B9A0, 0xFEC20C9C, 0x40C3F40B, + 0x4E778001, 0x9081145B, 0x78258800, 0x207A780D, + 0x78440000, 0x7EE0C0D1, 0x71001600, 0x00068000, + 0x0F80203C, 0x0C800000, 0x78E07EE0, 0x06C3216F, + 0xB8E68900, 0x7CE0700C, 0x20448907, 0x7FE00200, + 0x78E0B823, 0x4528C2E4, 0xFDEF0B26, 0xEE1E4608, + 0x05800926, 0xD925700C, 0xDB86704C, 0x45A1708C, + 0xFE2F0C8A, 0x700C70CC, 0x704CD926, 0x708CDB86, + 0x0C7A70AC, 0x70CCFE2F, 0xD910700C, 0xFE2F0F62, + 0x08D2714C, 0xF00C0580, 0x10452553, 0xD919D880, + 0xDB86744C, 0x0C56708C, 0x70CCFE2F, 0x0BFE700C, + 0x712CFE2F, 0x40C3EE87, 0x75300000, 0x03600D06, + 0xC6C4D91E, 0x0C46C0F1, 0x730C0060, 0x800040C3, + 0x88001138, 0x1600E810, 0x80007080, 0x08190001, + 0x098A00DF, 0x710C0080, 0xFFEF0F6E, 0x0902D90F, + 0xF00600C0, 0x0F62700C, 0xD90FFFEF, 0x7EE0C0D1, + 0x4430C2F0, 0xFEEF0BA2, 0x46CB4110, 0x12DC8000, + 0x43108620, 0x800140C3, 0x88E04E77, 0x0442202F, + 0x70901600, 0x00628000, 0x704CB8C0, 0x0976706C, + 0x42100260, 0x900745CB, 0x0A0AC17C, 0x1D000520, + 0x0A3E1005, 0x708CFDCF, 0x4080752C, 0xB895714C, + 0x0004238A, 0x0440250A, 0xFE2F0BA2, 0xD88070CC, + 0xB892D90F, 0x706CDA20, 0x0500240A, 0x0440250A, + 0xFE2F0B8A, 0x700C70CC, 0xFE2F0B32, 0x2705712C, + 0x78ED140F, 0x20310B0F, 0x10451D00, 0x00120807, + 0x8620C6D0, 0x00022084, 0x01C32841, 0x09064042, + 0x42620260, 0x78E0C6D0, 0x0B62C2E6, 0x730C0060, + 0x72ED70CD, 0xB89FD825, 0x881B8820, 0x710C7905, + 0xB80278D8, 0x0380200F, 0xF259782B, 0x712C7D0F, + 0x056009EE, 0x09AA40A1, 0x0AF2FDCF, 0xE00C0140, + 0x7A0F752C, 0xB813D809, 0x0008238A, 0x45A1708C, + 0xFE2F0B0A, 0x269F70CC, 0x700C12C1, 0xDA22762C, + 0x03C0244A, 0x70CC45A1, 0x1F8E2632, 0x4E838001, + 0xFE2F0AEA, 0x11C3264F, 0x002D40C3, 0x0BB6C6C0, + 0x712C0360, 0x700C7910, 0xFE2F0DC6, 0x700C704C, + 0xDA22762C, 0x244A43C1, 0x45A103C0, 0xFE2F0ABE, + 0x700C70CC, 0xDA08752C, 0x000E238A, 0x45A1708C, + 0xFE2F0AAA, 0xD88070CC, 0xB893D907, 0x706C744C, + 0x70AC708C, 0xFE2F0A96, 0x700C70CC, 0xFE2F0A3E, + 0x40A1712C, 0x0560094A, 0x278D702C, 0x71CD17BE, + 0x78E0C6C6, 0xB7C81CF4, 0xC181C808, 0x1C08714C, + 0x0DEA3001, 0x1C0404A0, 0x41C33001, 0x0000036B, + 0xFFAF0EFE, 0x700C750C, 0x0F36712C, 0xC281FFAF, + 0x341F140C, 0x78E07EE0, 0xB7C81CF4, 0x70C3C181, + 0x00400100, 0x1C08714C, 0x0DB23001, 0x1C0404A0, + 0x41C33001, 0x0000036A, 0xFFAF0EC6, 0x700C750C, + 0x0EFE712C, 0xC281FFAF, 0x341F140C, 0x78E07EE0, + 0x4030C2EA, 0x70AD4110, 0x00FA76B5, 0x097B000D, + 0x740C203E, 0x00E541C3, 0x0E960001, 0x42A1FFAF, + 0xDF0770CD, 0x800040C3, 0x88600485, 0x800040C3, + 0x10001220, 0x244A008B, 0x708D7200, 0x20A8DA07, + 0x40610540, 0x209F6D35, 0x27060803, 0x70021388, + 0x2E416119, 0x667E10C0, 0x28016108, 0xB8C00200, + 0x77447858, 0x7A8F7C05, 0x00E641C3, 0x0E420001, + 0x740CFFAF, 0x9004268C, 0xFFC507AC, 0x740CD9E7, + 0xFFAF0E2E, 0x097BB910, 0x740C207E, 0x00E841C3, + 0x0E1E0001, 0x42A1FFAF, 0xDF0770CD, 0x800040C3, + 0x88600485, 0x800040C3, 0x10001220, 0x244A008B, + 0xDA077200, 0x20A8708D, 0x40610540, 0x209F6D35, + 0x27060803, 0x70021388, 0x2E416119, 0x667E10C0, + 0x28016108, 0xB8C00200, 0x77447858, 0x7A8F7C05, + 0x00E941C3, 0x0DCA0001, 0x740CFFAF, 0x9004268C, + 0xFFC507AC, 0x740CD975, 0xFFAF0DB6, 0x71A5B911, + 0xC6CAF184, 0xC1A2C3F6, 0x46504170, 0xC1814730, + 0x30C22440, 0x01600A82, 0x30832440, 0x000040C3, + 0x211A28F0, 0x14022011, 0x232F3094, 0x46CB2000, + 0x1B3C8000, 0x308D1403, 0x23640C9F, 0x0F0679AF, + 0x40E20560, 0x704E4510, 0x24AE0D85, 0x261F474A, + 0x251A24C1, 0x00001F80, 0x279A0A3C, 0x71221184, + 0x671F6038, 0x06E00A76, 0x13D02600, 0x20851002, + 0x13842734, 0x21061004, 0x2D41E808, 0x740C0085, + 0x00A741C3, 0xF0060005, 0x41C3740C, 0x000500A8, + 0x0D1E42A1, 0x4342FFAF, 0x18002659, 0x1600671F, + 0x80007080, 0x0819000B, 0x40E1007F, 0x00200BCA, + 0x40E1712C, 0x00200BC2, 0xF00A702C, 0x090240E1, + 0x712C0020, 0x08FA40E1, 0x702C0020, 0x0A7D7146, + 0x71A5A294, 0xC7D6F1B2, 0xC1BFC3EA, 0x47084548, + 0x702CC08B, 0x0CEADA50, 0x4668FD2F, 0x10B10F29, + 0x41C3750C, 0x00010365, 0xFFAF0CB6, 0xC08B42C1, + 0x0D9E702C, 0x704C04A0, 0xD909700C, 0xFFAF0CE2, + 0xC7CAC28B, 0xC046700C, 0xC044C045, 0x30041C28, + 0x750CC049, 0x41C3EF12, 0x00010368, 0xFFAF0C82, + 0x255442C1, 0x25001F42, 0x01001F8C, 0x25400020, + 0x4D5A1A03, 0xF00F712C, 0x036641C3, 0x0C620001, + 0x42C1FFAF, 0x148C2540, 0x14022540, 0xD9094D48, + 0xC040DBC8, 0x000940C3, 0x70AD0001, 0x37102440, + 0x30112440, 0xC047C241, 0x4083C442, 0xC343B030, + 0xC08BB031, 0x0C4A702C, 0xDA50FD2F, 0x24011104, + 0x1002C808, 0x7825250E, 0x0AF2C18B, 0x42C104A0, + 0x41C140A1, 0xFFAF0C4A, 0x71A5C28B, 0x91140DD7, + 0x90110F63, 0x00000CF2, 0x78E0C7CA, 0x1CFCC2FA, + 0x2482B6C8, 0x20143F05, 0x22550042, 0x922A0800, + 0x30401CE8, 0x1CEC9228, 0x92263040, 0x30401CF0, + 0x1CF49224, 0x92223040, 0x30401CF8, 0x1CFC9220, + 0x922C3040, 0x30581C40, 0x1C41922E, 0x92303058, + 0x30581C42, 0x1C439232, 0x92343058, 0x30581C44, + 0x1C459236, 0x92383058, 0x30581C46, 0x1C47923A, + 0x923C3058, 0x30581C48, 0x1C49923E, 0x12403058, + 0x1C4A0101, 0x12443058, 0x1C4B0101, 0x12483058, + 0x1C4C0101, 0x124C3058, 0x1C4D0101, 0x12503058, + 0x1C4E0101, 0x12543058, 0x1C4F0101, 0x12583058, + 0x1C500101, 0x125C3058, 0x1C510101, 0x12603058, + 0x1C520101, 0x12643058, 0x1C530101, 0x12683058, + 0x1C540101, 0x126C3058, 0x1C550101, 0x12703058, + 0x1C560101, 0x12743058, 0x1C570101, 0x12783058, + 0x1C580101, 0x127C3058, 0x1C590101, 0x90203058, + 0x30581C5A, 0x1C5B9022, 0x90243058, 0x30581C5C, + 0x1C5D9026, 0x90283058, 0x30581C5E, 0x01061014, + 0x01091018, 0x0108101C, 0x010B1020, 0x90F490D2, + 0x909890B6, 0x905C907A, 0x1040903E, 0x10440119, + 0x10480118, 0x104C0117, 0x10500116, 0x10540115, + 0x10580114, 0x105C0113, 0x10600112, 0x10640111, + 0x10680110, 0x106C011F, 0x1070011E, 0x10740105, + 0x10780104, 0x107C0107, 0x2455011B, 0x18643800, + 0x186006C0, 0x185C01C0, 0x18580100, 0x18540140, + 0x18500780, 0x184C07C0, 0x18480400, 0x18440440, + 0x18400480, 0x183C04C0, 0x18380500, 0x18340540, + 0x18300580, 0x182C05C0, 0x18280600, 0xA0290640, + 0x00A541C3, 0xA0480040, 0xA086A067, 0xA0E4A0A5, + 0x1808A0C3, 0x180402C0, 0x18000200, 0x145E0240, + 0x1C7C3600, 0x14FC3180, 0xC05E3002, 0x3600145D, + 0x300314F8, 0x300414F4, 0x145CC05D, 0x14EC3600, + 0x14F03006, 0xC05C3005, 0x3600145B, 0x300714E8, + 0x145AC05B, 0xC05A3600, 0x36001459, 0x1458C059, + 0xC0583600, 0x36001457, 0x1456C057, 0xC0563600, + 0x36001455, 0x1454C055, 0xC0543600, 0x36001453, + 0x1452C053, 0xC0523600, 0x36001451, 0x1450C051, + 0xC0503600, 0x3600144F, 0x144EC04F, 0xC04E3600, + 0x3600144D, 0x144CC04D, 0xC04C3600, 0x3600144B, + 0x144AC04B, 0xC04A3600, 0x36001449, 0x1448C049, + 0xC0483600, 0x36001447, 0x1446C047, 0xC0463600, + 0x36001445, 0x1444C045, 0xC0443600, 0x36001443, + 0x1442C043, 0xC0423600, 0x36001441, 0x1440C041, + 0xC0403600, 0xFFAF094A, 0x2480740C, 0x14043F05, + 0xC6DA341B, 0x1CFCC2FA, 0xC1BCB6C8, 0x20557834, + 0x90580801, 0x01051158, 0x01071160, 0x9054C259, + 0x01061168, 0x01041018, 0x9050C25A, 0x01161010, + 0x01171008, 0x1038C25B, 0x10400108, 0x10480119, + 0x10500118, 0x10580115, 0x10600114, 0x10680113, + 0x10700112, 0x10780111, 0x1100011B, 0x9164010B, + 0x91EC9148, 0x91B491D0, 0x911C9198, 0x01101140, + 0x011F1148, 0x011E1150, 0x01091170, 0x01011178, + 0x31801C58, 0x31C01C54, 0x31401C50, 0x3005146C, + 0x30061468, 0x30071464, 0x41C3C158, 0x001F00A6, + 0x740CC050, 0x42E2C24B, 0x43C2C34A, 0x32401C5C, + 0x37801C4C, 0x37C01C48, 0x34001C44, 0xC54EC44F, + 0xC74CC64D, 0x32C01C24, 0x36C01C20, 0x34401C1C, + 0x34801C18, 0x34C01C14, 0x35001C10, 0x35401C0C, + 0x36001C08, 0x36401C04, 0xFFAF0856, 0x32001C00, + 0x1404C0BC, 0xC6DA341B, 0xC1A2C2F2, 0x70901600, + 0x00048000, 0x20D02053, 0x710C702E, 0x70AE724E, + 0x1600E807, 0x80007080, 0xE8890025, 0x1600F040, + 0x80007080, 0x08810040, 0x251F0010, 0x00002F8D, + 0x706E7000, 0x23002B40, 0x60BE70AC, 0xC808728E, + 0x03812005, 0x0300255F, 0x0F802030, 0x05B88000, + 0xB8027825, 0xB89FB89C, 0x20539000, 0x205300C6, + 0x274C0107, 0x26CE8400, 0xB8250026, 0x00C12053, + 0x02340909, 0x7813B8C2, 0x41C3C141, 0x0008006A, + 0x750CC040, 0x43A24202, 0xFF6F0FB6, 0x04C0240A, + 0x25FF248D, 0x716671AC, 0xA1940B9D, 0x228D700C, + 0x71AE2EBE, 0x800040C3, 0x880012D9, 0x046E087D, + 0x724E708E, 0x2414710C, 0x2800244E, 0xBE0C050F, + 0x45CB706E, 0x05D08000, 0x7F0B8D04, 0xC808F227, + 0x03812005, 0x78258500, 0xB89CB802, 0x9000B89F, + 0x00C62053, 0x01072053, 0x8400274C, 0x002626CE, + 0x2053B825, 0x090B00C1, 0xB8C20234, 0xC1417813, + 0x006B41C3, 0xC0400008, 0x4202750C, 0x240A4322, + 0x0F2E0500, 0x250AFF6F, 0x716604C0, 0xA1B40BAD, + 0x228DE50C, 0x718E22BF, 0x097D7126, 0xC0A2A114, + 0x78E0C6D2, 0xC1B7C3EC, 0x41C3D840, 0x0000036D, + 0x88A0B89F, 0x809110E5, 0xFF6F0EF6, 0x2105750C, + 0x700E2351, 0xE58770AD, 0x00260162, 0x20C02178, + 0x10B50D0D, 0x1208704E, 0xF009360E, 0x0D0F704E, + 0x70CD10B0, 0x360E1208, 0xC083744E, 0x0EE2702C, + 0xDA50FCEF, 0x800041C3, 0x89011222, 0x08E38980, + 0x742C0324, 0x29007882, 0x732C048F, 0x049F2900, + 0x2900722C, 0x712C049E, 0x04852900, 0x40C36821, + 0x12D98000, 0x00841000, 0x7040240A, 0x903843C3, + 0x20A80000, 0x0CA905C1, 0x2C40032E, 0x26F01347, + 0x8000734B, 0x270510F8, 0xC2830387, 0x11C02305, + 0x03012215, 0x2300B802, 0x78651146, 0x17892300, + 0x23009000, 0xB10017C8, 0x01C02605, 0x7865B802, + 0xB1089000, 0x11C02105, 0x7865B802, 0xB1109000, + 0x11C02005, 0x7865B802, 0xB1189000, 0x7894710C, + 0x00012214, 0x2005B80C, 0x23050382, 0x23001080, + 0xB80213CB, 0x90007865, 0x2605B100, 0xB8020080, + 0x90007865, 0x2105B108, 0xB8021080, 0x90007865, + 0x2005B110, 0xB8021080, 0x02C22205, 0x90007865, + 0x6A12B118, 0x90007865, 0x00041940, 0x750C7185, + 0x036E41C3, 0x42A10001, 0xFF6F0DC6, 0x6E3470CD, + 0x6038C083, 0x01071008, 0x01061006, 0x01041002, + 0x01051004, 0x90459060, 0x90079026, 0x42C1C240, + 0x41C3C141, 0x0009036F, 0x0D96C042, 0x750CFF6F, + 0x0ECF71C5, 0x71A59154, 0x68C1F14F, 0x41C3750C, + 0x00010370, 0xFF6F0D7A, 0x70AD4202, 0x209F4002, + 0x20140401, 0x40C30341, 0xBF648000, 0x6113603A, + 0x123C750C, 0x41C30106, 0x00050371, 0x01051228, + 0x01041214, 0xFF6F0D4A, 0x71A542A1, 0x92540DD1, + 0x20402040, 0x83A408B9, 0xC7CC710E, 0x094AC2E6, + 0x702CFEEF, 0x800046CB, 0x8EE01222, 0x09418E21, + 0x204003E4, 0xC8080A8D, 0x78A57AEF, 0x2A406832, + 0x78250380, 0x03F141C3, 0xB8920004, 0xB89FB89C, + 0x750C9060, 0x23534460, 0x0CF60145, 0x24ADFF6F, + 0x71E50982, 0x79EF8E01, 0x804508CF, 0x78E0C6C6, + 0xC1B4C3E2, 0x360D1208, 0x702CC080, 0xFCEF0CF2, + 0xD9DBDA50, 0x0CCA750C, 0xB912FF6F, 0x12032585, + 0x40A1C180, 0x04600B96, 0x700CDA09, 0x0CF2D909, + 0xC280FF6F, 0x78E0C7C2, 0x78E07EE0, 0xA023702C, + 0xA021A022, 0xA0207FE0, 0x4200C2E8, 0x780F7704, + 0x004C41C3, 0x207C0001, 0x098E00C0, 0x4050FD2F, + 0x901C41C3, 0x42C301C8, 0x12228000, 0x20B00821, + 0xDC25706C, 0x0831BC9F, 0x8C002071, 0xB162B100, + 0x9201B178, 0xD83FB200, 0xF00CB806, 0x1600B160, + 0x80007080, 0xB1020040, 0x9202B178, 0xD83FB200, + 0xF011B110, 0x8C1BB100, 0xB178B102, 0x20049110, + 0x00000F80, 0xB110FFBE, 0xAA008A02, 0xAA018A05, + 0x0F16B170, 0x400204E0, 0x78E0C6C8, 0x40C37014, + 0x048A8000, 0x1600F207, 0x90387101, 0xB9800030, + 0x9020F003, 0x1E00B9A0, 0x903B7044, 0x7FE0C030, + 0x78E0B020, 0x4528C2E4, 0xFD6F0DC6, 0xEE154608, + 0x762CC808, 0x746CDA22, 0x0B80244A, 0x70CC45A1, + 0x2005B802, 0x90070F80, 0x1800C004, 0x0F1E0045, + 0x700CFDAF, 0x700CF013, 0xDA22762C, 0x244A706C, + 0x45A10B80, 0xFDAF0F06, 0xC80870CC, 0x2005B802, + 0x90070F80, 0x1800C004, 0x700C0005, 0xFDAF0E9E, + 0xC6C4712C, 0x4628C2E4, 0x21534508, 0x710C0142, + 0xFCEF0F3E, 0xBE23702C, 0x16022644, 0x8540655D, + 0x85017A06, 0xA5407826, 0xC6C4A501, 0x70801600, + 0x00018000, 0x7CE0B8E0, 0x900F41C3, 0x704CC068, + 0x04C02150, 0xB040B140, 0x900840C3, 0xB0400068, + 0x804519D8, 0x804518A8, 0x18007FE0, 0x78E000C5, + 0x03C32841, 0x03C12840, 0x28417B25, 0x21440341, + 0x28410081, 0x7B2500C2, 0x02C12841, 0x01012144, + 0x00012284, 0x28417B25, 0x21440241, 0x7B250201, + 0x01C12841, 0x04012144, 0x28417B25, 0x21440141, + 0x79650801, 0x79456875, 0x22847A1D, 0x23840002, + 0x79450010, 0x22847A1B, 0x79450004, 0x22846853, + 0x79450008, 0x7B25704C, 0xBA8B6837, 0x23057944, + 0x2840004C, 0x795B0243, 0x28407964, 0x7C2502C3, + 0x79646A32, 0x10432405, 0x03412840, 0x78246A13, + 0x7FE07B05, 0x78E07870, 0xC1A4C3FA, 0x00582053, + 0x800045CB, 0x207811DA, 0x4138308F, 0x15464510, + 0x40E11081, 0x219F4030, 0x42D30582, 0x4E748001, + 0x02C1209F, 0x140E2714, 0x46D3706E, 0x02249004, + 0x2FC7248A, 0x41C36038, 0x0504901C, 0x100C7042, + 0xC8080097, 0x2005B802, 0x1A000042, 0x19A40045, + 0x20058045, 0x90070F81, 0x2005C090, 0x90040F80, + 0x90000090, 0xB100B888, 0x0B3F66A8, 0x28402025, + 0x78F62100, 0xE0247062, 0x294060A9, 0x21050391, + 0x18002580, 0x0E060504, 0x740C02E0, 0x22012640, + 0x21057166, 0x18002040, 0x69040504, 0x04402005, + 0x00051800, 0x2D40F1E2, 0xD9102080, 0x05512005, + 0x303009AF, 0x0A9A4042, 0x404204C0, 0x0FA6D910, + 0xDA410260, 0xD9104042, 0xFDEF0DAE, 0x0FBEDAF3, + 0x208AFDAF, 0x0D820C12, 0x700C0160, 0xFD4F0B7A, + 0x40C36829, 0x04888000, 0x0520099A, 0x40C3B020, + 0x13880000, 0x02E00DBE, 0x09C2D90C, 0x40420500, + 0x0F62D90D, 0xDA400260, 0x05200916, 0xC080C080, + 0xFFEF0DF6, 0xC080D910, 0xFFEF0DEE, 0x41E1D90D, + 0x219F4002, 0x704C02C1, 0x0582209F, 0x708CC380, + 0x611970AC, 0x0447202F, 0x06A00E2E, 0x40427142, + 0x0D36D910, 0xDAF3FDEF, 0xD9104042, 0x02600F16, + 0x4042DA61, 0x0D22D910, 0xDA7FFDEF, 0x0D1AF00E, + 0xDAF3FDEF, 0xD9104042, 0x02600EFA, 0x4042DA61, + 0x0EF2D910, 0xDA800260, 0x70451E00, 0x04C4901C, + 0x800040C3, 0x88001220, 0xDA40E803, 0xDA25F002, + 0x209F41E1, 0x219F0582, 0xBA9F02C1, 0x00931200, + 0x70426038, 0xFD6F0ACA, 0x00941010, 0x000009AE, + 0x050008C6, 0x0447222F, 0x0806D810, 0x4182FDEF, + 0x742C700C, 0xFDAF0F1A, 0x0B27714C, 0x710C20F1, + 0x30812079, 0x24847838, 0xB8022282, 0x21412485, + 0x0040200F, 0x7A0F4182, 0xFDAF0FD6, 0x700CD810, + 0x0EEED920, 0x714CFDAF, 0x0BA2700C, 0x712CFDAF, + 0xFD4F0A6E, 0x01600C52, 0x084A700C, 0x700C0500, + 0xFDAF0B8A, 0xD914702C, 0x000040C3, 0x0C961388, + 0x441002E0, 0xE81866A8, 0x2840706E, 0x78F62100, + 0xE0247062, 0xD88060A9, 0x052009EA, 0x29404130, + 0x71662391, 0x2F812105, 0x02309004, 0x66A8B100, + 0xA0040BDB, 0x0C5E4082, 0xD90C02E0, 0x00400882, + 0x0500085A, 0x000340C3, 0x0C4AD090, 0x702C02E0, + 0x05200812, 0x21D5274F, 0xE81866A8, 0x2840706E, + 0x78F62100, 0xE0247062, 0x40A260A9, 0x05200996, + 0x29404130, 0x71662391, 0x2F812105, 0x02309004, + 0x66A8B100, 0xA0040BDB, 0x40C3D90C, 0x13880000, + 0x02E00C02, 0x66A84410, 0x254FE819, 0x706E2215, + 0x21002840, 0x706278F6, 0x60A9E024, 0x095640A2, + 0x41300520, 0x23912940, 0x21057166, 0x90042F81, + 0xB1000230, 0x0BDD66A8, 0x4082A004, 0x02E00BC6, + 0x66A8D90C, 0x702EE825, 0x21002840, 0x702278F6, + 0x60A9E024, 0x0006208A, 0x0520091A, 0x2B404330, + 0x24052394, 0x90042F81, 0xB1000224, 0x02E00B6E, + 0x208A740C, 0x08FE0006, 0x41620520, 0x2F812405, + 0x022C9004, 0x7126B100, 0x09C166A8, 0x40C3A004, + 0xD0900003, 0x02E00B6E, 0x4042702C, 0x0460098A, + 0x0F6AD910, 0xC7DA04C0, 0x40D3C2F8, 0x01E8901C, + 0x000040C3, 0x10000FFF, 0x10102112, 0x18102111, + 0x18002005, 0xC8082004, 0x2005B802, 0x900C0F80, + 0x90400020, 0x800040C3, 0x8800121E, 0x0201204F, + 0x1E006058, 0x901C7044, 0x20420508, 0x160000D5, + 0x80007080, 0x70140114, 0xD93DF281, 0xB910750C, + 0xFF2F0EDE, 0x47CB70CD, 0x01188000, 0x45CB8F40, + 0x0001003E, 0x0ECA750C, 0x41A1FF2F, 0x10562740, + 0x1401254F, 0x20821600, 0xFF2F0EB6, 0x2640750C, + 0x71AD2057, 0x20821700, 0x750CBD96, 0xFF2F0EA2, + 0x274241A1, 0x254F10D4, 0x14001401, 0x0E922082, + 0x750CFF2F, 0x20532440, 0x1441254F, 0x20821300, + 0x0E7E750C, 0x4038FF2F, 0x204F6FA9, 0x8D403401, + 0xFF2F0E6E, 0x710C750C, 0xE808722D, 0x70801600, + 0x00258000, 0xF037E887, 0x70801600, 0x00408000, + 0xC808E835, 0x13812E40, 0x7180244A, 0x008B2840, + 0x0A4020A8, 0x03DE208A, 0x201143E2, 0x40A18380, + 0x4062F40F, 0x11300E1B, 0x0E1343C2, 0x40621330, + 0x12F00E0F, 0x0E2743C2, 0x40821151, 0x210543E1, + 0x884002C8, 0x20058B00, 0x90001F8C, 0xB40001C0, + 0x1F802005, 0x01B49000, 0x71C5B040, 0x000071C3, + 0xDE074000, 0x10FF218D, 0x45CB700C, 0x11388000, + 0x108015E6, 0x27C12D42, 0x7824B802, 0x1E0070A2, + 0x901C7004, 0x40C30510, 0x2AF80000, 0x02E009E6, + 0x1800702C, 0x18102484, 0x15E62444, 0x781D1080, + 0x7704B8A0, 0xC6D8AD01, 0x0AC2C2E8, 0x40100640, + 0x700C71ED, 0x900F45CB, 0xD940C298, 0x73C41E00, + 0xC028900F, 0x02E009AE, 0x1E00B5E0, 0x902F73C4, + 0x0A62CC40, 0x700C03A0, 0x02E0090E, 0x1D00D810, + 0x16001005, 0x9018710E, 0x08150018, 0x26842030, + 0x1E001C07, 0x901B73C4, 0xF02EC000, 0x901B45CB, + 0x264FC018, 0x702C1280, 0x096AB500, 0x208A02E0, + 0x702C0A0F, 0x000F40C3, 0x095A4240, 0x1DEC02E0, + 0x160093C4, 0x90187101, 0x1DE8004C, 0xB9C493C4, + 0x90051DEC, 0x70801600, 0x00048000, 0x08002044, + 0x78C5B804, 0xC808B500, 0x2005B802, 0x90180F80, + 0xB0200024, 0x800041C3, 0x89001220, 0x0582209F, + 0x000111BC, 0x88216038, 0x00DF090D, 0x21538834, + 0xF20480FE, 0x04C00E2A, 0x70451E00, 0xC0B49027, + 0x78E0C6C8, 0xC1A3C3FA, 0x2140260A, 0x3100210A, + 0x40584770, 0x71344530, 0x002D0136, 0xC8084210, + 0x800047CB, 0xB8021222, 0x0F802005, 0x01909038, + 0x08159000, 0x1600025E, 0x80007080, 0x701400F3, + 0x0001024E, 0x208A70D4, 0x218A003E, 0x0C9E2001, + 0x21CAFD2F, 0x8FA02002, 0x00132079, 0x22132340, + 0x75308F21, 0x000D01A6, 0x800040C3, 0x880012D9, + 0x036E08CB, 0x0E137AAF, 0x40622030, 0x0C8E41A2, + 0x43420060, 0x0A92F004, 0x40400020, 0x234E2714, + 0x20700A25, 0x0A4FB600, 0x212F2031, 0xF2138348, + 0x0050099F, 0x009009A3, 0x00D1093B, 0x800041C3, + 0xF01C014A, 0x8348222F, 0x41C3F209, 0x014C8000, + 0x41C3F008, 0x01478000, 0x41C3F010, 0x014B8000, + 0x0083227C, 0x21CA7074, 0x80000F81, 0x0A0D014D, + 0x41C300D4, 0x014E8000, 0x00901100, 0x70811600, + 0x000D8000, 0x017E0937, 0x0DFAC182, 0x22140040, + 0x20002340, 0x80000F94, 0x0D6A0470, 0x140904A0, + 0x08133080, 0xC1220874, 0x001E090F, 0x20431C00, + 0x09FDF005, 0x1C00801E, 0x96202003, 0x24402000, + 0x2108780F, 0x49100001, 0x71A5B600, 0x41C3F192, + 0x01488000, 0x41C3F1D2, 0x01498000, 0x2550F1CE, + 0x08BF2000, 0x708D00B1, 0x800045CB, 0x0EC31222, + 0x73B62030, 0x20C82578, 0x126124CA, 0x12482040, + 0xFD2F0B7A, 0x12892C40, 0x108615B7, 0x15014700, + 0x8D60108B, 0x018C7371, 0x0E7F000D, 0x2B4000EE, + 0xC8080301, 0x47CB7905, 0xFFFF0000, 0x04812105, + 0x69B270CD, 0x42814021, 0x02050A43, 0x00310F11, + 0x06812300, 0x0081111C, 0x00400A2B, 0x20B10D13, + 0x03412005, 0x0F812105, 0x01E89004, 0x2505F005, + 0x90041F81, 0x912000A8, 0x210871F1, 0x27CA038E, + 0x20801045, 0x71440010, 0x66FEF1E0, 0x20C22714, + 0x268C79DD, 0x21809002, 0x21CA003F, 0xB2200025, + 0x30C22014, 0x7164B220, 0x8FA0F1BE, 0x700CF080, + 0x03A341C3, 0x0FC20001, 0x42A2FCAF, 0x4042F07A, + 0x714CC180, 0xC441716C, 0x00A009EA, 0x4042C440, + 0x714CC180, 0x00A009DE, 0x8D01706C, 0x08D58D40, + 0x784200A4, 0x2A922240, 0xC8086821, 0x7040240A, + 0x078020A8, 0x03012A40, 0x79057142, 0xB992B902, + 0xB99FB99C, 0xC1809180, 0x008321F4, 0x6479BCC5, + 0x08032142, 0x7930E120, 0x2714E1C0, 0x23CA2081, + 0xB1600025, 0x30812014, 0xB1607144, 0x8F21F042, + 0x097D8FA0, 0x49B00364, 0x40C36841, 0x12D98000, + 0x240A8880, 0x40A17080, 0x20A8DAC1, 0x0C0D0240, + 0x2714102E, 0xB3402003, 0xF02A7104, 0x800040C3, + 0x880012D9, 0x034E0847, 0x234027F4, 0x00600C26, + 0xCA05C182, 0xC082E805, 0x02200D4E, 0x16004123, + 0x80007080, 0x0819000D, 0x2214017E, 0x20322340, + 0x80000F81, 0x0D320470, 0xC0820220, 0x0A86C082, + 0x2014FF2F, 0x8F21334E, 0x71A5B600, 0x834509B1, + 0x78E0C7DA, 0x2840C2E2, 0x4200038C, 0x1F812405, + 0x0AB09004, 0x70EC9100, 0x0003204F, 0xB8A0B160, + 0x2A40B100, 0xC8080301, 0x69127905, 0x0F802005, + 0x0AB49004, 0x0B1D9060, 0x46600175, 0x208040C0, + 0x7825080A, 0xB892B802, 0xB89FB89C, 0x01071000, + 0x1F802405, 0x03549004, 0x16009000, 0x80007101, + 0x090D0006, 0x00000F84, 0x781D0A6B, 0x211F7910, + 0x20020180, 0xB80601C0, 0x00402805, 0x0804218A, + 0x0008252F, 0x7D104910, 0x01442053, 0x11832D41, + 0x039D41C3, 0x092A0006, 0x740CFF2F, 0xC6C240A1, + 0x01822053, 0x01C120AD, 0x7FE0A941, 0x78E0A900, + 0xC1A4C3F0, 0x40C34410, 0x12208000, 0x202F8820, + 0x41300502, 0xD940E903, 0xD925F002, 0x2044B99F, + 0x89000053, 0x00F1080F, 0x20002352, 0x04E0092E, + 0x09AA712C, 0x40C3FFCF, 0xC3500000, 0x02A00CF6, + 0x46CB732C, 0x11DA8000, 0x04E008BA, 0x244F2314, + 0x21122940, 0x67C870AD, 0x10250D2B, 0x24C02216, + 0xE02460B8, 0x208A60C9, 0x0A3A0004, 0x403004E0, + 0x23902840, 0x200571A5, 0x90042F81, 0xB1000230, + 0x45CBF1EB, 0x13880000, 0x0CAA40A1, 0xD90C02A0, + 0x04C008AA, 0x702CC808, 0xB802700E, 0x0F802005, + 0x0504901C, 0x00051800, 0x02A00C8A, 0x45CB40A1, + 0x4E748001, 0x091A40A1, 0xD91004A0, 0xD91040A1, + 0xFDAF0C36, 0x40A1DACF, 0x0C2ED910, 0xDAFFFDAF, + 0x04A00FCE, 0xC080C080, 0xFFAF0CAE, 0x4062D910, + 0x2582219F, 0x02C1209F, 0xC380704C, 0x70AC718C, + 0x60B97022, 0x06600CF2, 0x40C34082, 0x36B00000, + 0x02A00C32, 0x67C8D90A, 0x2216E812, 0x700224C0, + 0xE0247106, 0xB80E60C8, 0x0F812005, 0x02309004, + 0xB88C700C, 0x67C8B100, 0xA00408E3, 0x0A2A40A1, + 0xD9100420, 0x6832C808, 0x0F802105, 0xC0909007, + 0x0F812105, 0x00909004, 0x21049120, 0x00000F81, + 0xB020FEFF, 0x02A00B52, 0xC7D0D814, 0x46CBC2E8, + 0x01E8901C, 0x96A89620, 0x25464030, 0xB6081C00, + 0x0F802105, 0x0C300000, 0x1600B600, 0x80007080, + 0xE8360114, 0x750CD945, 0xFEEF0F86, 0xC808B910, + 0x726D702C, 0x710C68F2, 0x1600E807, 0x80007080, + 0xE8880025, 0x1600F020, 0x80007080, 0xE8200040, + 0x7180244A, 0x060020A8, 0x03802940, 0x800042C3, + 0x78E519AC, 0x004C22F4, 0x0F832005, 0x01C09000, + 0xE21CB380, 0x0F832005, 0x01B49000, 0x004022F4, + 0xB3007124, 0x238DD907, 0x700C16BF, 0x901C40C3, + 0x18000508, 0x18080005, 0x40C30005, 0x2AF80000, + 0x02A00B32, 0x1E00702C, 0xB6A81404, 0x78E0C6C8, + 0x1CFCC2FA, 0xC1A7B6C8, 0xD9894528, 0x4608B910, + 0xC344D8C8, 0xFEEF0EEA, 0xD8C8C243, 0xD98BED04, + 0xF004B910, 0xB911D945, 0xFECF0ED6, 0xC18640A1, + 0x35C22440, 0x00A00BB2, 0x35832440, 0xEE05D8C8, + 0xB910D98D, 0xD923F003, 0x0EB6B912, 0xC006FECF, + 0x008E45CB, 0x41A10001, 0xD8C8C041, 0xFEEF0EA2, + 0x1417C201, 0x254F3080, 0xC0401401, 0x0E92D8C8, + 0xC200FEEF, 0x30801416, 0x009046CB, 0x41C10001, + 0xD8C8C042, 0xFEEF0E7A, 0xC203C202, 0x1401264F, + 0xFEEF0E6E, 0xDD20D8C8, 0x144F264F, 0xD8C8BD9F, + 0x0E5E41E1, 0x1501FEEF, 0x8D401482, 0x1401274F, + 0xFEEF0E4E, 0x15F6D8C8, 0x264F9082, 0xD8C8148F, + 0xFEEF0E3E, 0x15F741E1, 0x274F9082, 0x0E321401, + 0xD8C8FEEF, 0xBF918D44, 0x0E26D8C8, 0x41E1FEEF, + 0x274F8D5F, 0x0E1A1401, 0xD8C8FEEF, 0xD8C8BE93, + 0x0E0E41C1, 0xDA0AFEEF, 0x1401264F, 0x0E02D8C8, + 0x744CFEEF, 0xD8C8D94D, 0xFEEF0DF6, 0xC001B911, + 0x01427014, 0x704E002C, 0x47D3C000, 0x0A3C0000, + 0x05C2201F, 0x20C12F40, 0x46D3C004, 0x1A3C8000, + 0x0059201F, 0x20902640, 0x22007223, 0x20000595, + 0xC1002090, 0x7110C002, 0x002D00F0, 0x2540230A, + 0x240AC600, 0xC0032400, 0x04A00F3A, 0x431879CF, + 0x0BC1702E, 0xD8C8346E, 0x4342C204, 0x009B41C3, + 0x44C10004, 0xFEEF0D8A, 0x0440250A, 0xD8C8D927, + 0xFEEF0D7E, 0x70ADB912, 0x34C0200A, 0x1704478A, + 0xD8C81503, 0x35021004, 0x009D41C3, 0x0D620003, + 0x44A1FEEF, 0xE5C071A5, 0xDD4FF7B3, 0xBD11D8C8, + 0xFEEF0D4E, 0x254F41A1, 0x0D461401, 0xD8C8FEEF, + 0xD8C8752C, 0xFEEF0D3A, 0x221AB915, 0x00002F81, + 0x261A28F0, 0x452A15C0, 0x1184259A, 0x800047CB, + 0x71231B3E, 0x0A466038, 0x651D0620, 0x260065EB, + 0x65FD2341, 0x07021180, 0x11041502, 0xBB22E807, + 0x41C3D8C8, 0x000300A1, 0xD8C8F005, 0x00A241C3, + 0x0CEE0003, 0xD9A3FECF, 0x0CE6D8C8, 0xB910FEEF, + 0x23807126, 0x093F2184, 0x2480A2B4, 0xC0022184, + 0x07267610, 0x71C5FFE5, 0x000040C3, 0x250028F0, + 0x20002015, 0x71462010, 0x220CC001, 0x06F6A000, + 0xD929FFCB, 0x0CAAD8C8, 0xB912FEEF, 0x1404C0A7, + 0xC6DA341B, 0xC1A2C3F0, 0x40C34310, 0x12258000, + 0x800041D3, 0x88000025, 0x11004748, 0x4628208C, + 0x30021C03, 0xC181710C, 0x30C22440, 0x00A0095A, + 0x30C32440, 0x30121404, 0x10C02478, 0x20087104, + 0x084F0490, 0x44102072, 0x0B1170AD, 0x740C2030, + 0x00AA41C3, 0xF0050003, 0x00A941C3, 0x42A10003, + 0x0C3E43A1, 0x44C1FEEF, 0x15250D11, 0x41C1700C, + 0x0E8642E1, 0x43A1FF2F, 0x14A30D11, 0x41C1710C, + 0x0E7642E1, 0x43A1FF2F, 0x0DC371A5, 0x11E59404, + 0x081FA080, 0x4062003E, 0x42C1702C, 0xFFEF0D06, + 0x406243E1, 0x42C1712C, 0xFFEF0CFA, 0xC7D043E1, + 0x2482C3F2, 0x42203608, 0x740C4210, 0x021741C3, + 0x0BDE0001, 0x4450FEEF, 0xC1804042, 0xFE2F0EEA, + 0x35C22440, 0x003108B5, 0xC0864708, 0x00200902, + 0xC0204142, 0xC2864182, 0x0D1A4342, 0x4110FE2F, + 0x70CD4510, 0x70ED454A, 0x200A706E, 0xE7C02440, + 0x9500F755, 0x0505081F, 0x0C1B9501, 0x78CF2025, + 0xC2864182, 0xFE2F0CEE, 0x0B0B4342, 0x43102005, + 0xE60840D1, 0xE708E520, 0x74EDF1EB, 0x2000740C, + 0x4508200E, 0xE0BF78CF, 0x4182F70A, 0x0CC6C286, + 0x4342FE2F, 0x20050B09, 0x40D14310, 0x234E2002, + 0xE0BF78CF, 0x4182F70A, 0x0CAAC286, 0x4342FE2F, + 0x20050B09, 0x40D14310, 0x91350DC7, 0x0B1D78BD, + 0x230C2030, 0x1A82A540, 0x21CA251C, 0x22802402, + 0x70ED2084, 0x24421A00, 0xC7D240E1, 0x4010C2E8, + 0xB8226901, 0x20494528, 0x46CB0FCF, 0x00020218, + 0x41C1740C, 0x0AFA42A1, 0x43E1FEEF, 0x23C02015, + 0x90419060, 0x00E50A13, 0x1401264F, 0x0AE2740C, + 0x74ADFEEF, 0x4002F00A, 0x2080627A, 0xA8A00084, + 0x70AD785D, 0x201C1882, 0xC6C840A1, 0x2155C0E6, + 0x248A0F8E, 0x708D7001, 0x238A704C, 0x20A80FC7, + 0x20160280, 0x7144008F, 0xB762B783, 0xB760B781, + 0x2115716D, 0x234002CC, 0x94401048, 0x0D3794A1, + 0x211510A5, 0x93A00203, 0x0A119341, 0x20160364, + 0xB2A002C2, 0xB2619361, 0x910214FC, 0x910314FE, + 0x00A40B65, 0x02C32016, 0x14FEB340, 0xB3419102, + 0x2016F02A, 0x774402CD, 0x9340B541, 0x232F7144, + 0x14FC1088, 0x71449102, 0x22097A50, 0xB54002C2, + 0x1086232F, 0x23099C40, 0x77441082, 0x9441B540, + 0xB5427144, 0x77449341, 0x14FE7B50, 0x77449102, + 0x22087A50, 0xB54300C2, 0x9C417B4E, 0x00822308, + 0xB5437144, 0x9FF4086F, 0x1200230A, 0x91619140, + 0x00A50B17, 0x91427744, 0x0B3B9163, 0xB0400084, + 0xB0419143, 0xB041F017, 0x71449142, 0x7B4EB040, + 0x23099940, 0x77440082, 0x9141B040, 0xB0427144, + 0x77449143, 0x7B4EB043, 0x23089941, 0x71440082, + 0x9642B043, 0x010311FE, 0x00A50B1B, 0x96407744, + 0x010311FA, 0x00840B41, 0x11FAB740, 0xB7210101, + 0xB741F01A, 0x71449640, 0x7B4EB740, 0x23099E42, + 0x77440082, 0x11FEB740, 0x71440102, 0x11FAB742, + 0x77440102, 0x7A4EB743, 0x014111FE, 0x00412208, + 0xB7237124, 0x7F80244A, 0x034020A8, 0x09159024, + 0x00000F81, 0x218AFFFF, 0x180A0FC7, 0xB0240005, + 0xC4C6E008, 0x1CFCC2FA, 0x1600B6C8, 0x8000708F, + 0x46CB1222, 0x1A3E8000, 0x2100270A, 0x41584078, + 0x46104338, 0x10912642, 0x70801600, 0x12238000, + 0x01507710, 0x40C3000D, 0x12D98000, 0x20118800, + 0xF29E83C0, 0x091370AD, 0x27003031, 0x101C1680, + 0x75100080, 0x0D0BF290, 0x70171271, 0x248AF28C, + 0x70EC7001, 0x706D700D, 0x70CC702D, 0x20A8706C, + 0x40C30D00, 0x28F00000, 0x261F791B, 0x231F2002, + 0xB8223041, 0x615978EC, 0x40A1611A, 0x0184209A, + 0x20156058, 0x213401C0, 0x60D0200C, 0x03250829, + 0xEB174050, 0x02C7222F, 0x0207212F, 0x222F4953, + 0x212F0187, 0x79420247, 0x23CA7170, 0x20CA1189, + 0xF0071249, 0x26CA7074, 0x210A01C1, 0x203D11C0, + 0x71E40303, 0x02C7212F, 0x0207202F, 0x212F4832, + 0x202F0187, 0x78220247, 0x23CA7050, 0x20CA118A, + 0x222F124A, 0x232F22C7, 0x23002207, 0x0F472480, + 0x242F2030, 0x0D762002, 0xE80D05C0, 0x209A40A1, + 0x70020184, 0x05002015, 0x20012134, 0x782260D0, + 0x2302F003, 0x120B2480, 0x252F3086, 0x253F0006, + 0x41C30180, 0x00050237, 0x43E142C2, 0xFC6F0D1A, + 0x40A144A1, 0x0184209A, 0x20102000, 0x18002656, + 0x0D2A7002, 0x180005E0, 0xE80E0502, 0x25002015, + 0x213460D1, 0x60382000, 0x2000791D, 0x80002F80, + 0xB0201B40, 0xE58A71A5, 0xFFC506CE, 0xF15671E5, + 0x341B1404, 0x78E0C6DA, 0x7034C2E6, 0x03012A40, + 0x79654608, 0x47CBC808, 0x00409004, 0x27C07825, + 0x28401222, 0xE688008B, 0x404846C1, 0x026126CA, + 0x000045CB, 0x702DFFFF, 0x706C708D, 0x01A50B37, + 0x0E137890, 0x20001275, 0x101C1680, 0x0B1F0080, + 0x21050000, 0x78E512C0, 0xFEEF0842, 0x79B09000, + 0x004D2009, 0x20087990, 0x2180004C, 0x71641010, + 0x79B0F1E6, 0x781D6038, 0x78E0C6C6, 0x44CBC0E6, + 0x12228000, 0x108814B7, 0x14008CE1, 0x0F9B1086, + 0x08931184, 0x244A11AE, 0x265A7280, 0x20A8028B, + 0x446900C1, 0x800045CB, 0x249AC144, 0x2432100E, + 0x80001F89, 0x0927C444, 0x659E10F0, 0x10B00915, + 0x7135659E, 0x702D70EC, 0x2434F417, 0xF0131347, + 0x13472434, 0x11091602, 0x2434F00F, 0x16021347, + 0xDD801109, 0x21029682, 0x7D8211C4, 0x03450C0B, + 0x218A4781, 0x21001002, 0x211411CC, 0x7E9D02CD, + 0x018C20F4, 0xB58064DC, 0x02CD2214, 0x018C20F4, + 0xB58074E0, 0x02CD2314, 0x018C20F4, 0x74217165, + 0x71C4B580, 0xC4C6F1B5, 0x706CC0F1, 0x2240DC3F, + 0x248A008B, 0x18007001, 0xA9800003, 0x01C020A8, + 0x15081304, 0x10110809, 0xF0037164, 0x2280A860, + 0x248A0F83, 0x20A87001, 0x12FC01C0, 0xEB858503, + 0x89807785, 0xA980F002, 0x7B8F8840, 0xCA0B4B51, + 0x44207110, 0xF649700C, 0x021D41C3, 0x0E520003, + 0xD8C9FEAF, 0xC0D1760C, 0x78E07EE0, 0x7002248A, + 0x20A8706C, 0x41000480, 0x0182235A, 0x000E219A, + 0x41C3623A, 0xC1448000, 0x61596234, 0x090D9121, + 0x71640305, 0xD8807FE0, 0x786F7FE0, 0xF717E1FF, + 0x7A22DA80, 0x7080240A, 0x044020A8, 0x215A4200, + 0x229A0183, 0x635B000E, 0x800042C3, 0x6354C144, + 0x9241627A, 0x03040A09, 0xD9807124, 0x78307FE0, + 0x01422053, 0xA941B826, 0xA9007FE0, 0xC1A3C3EC, + 0x700C4210, 0x458B4130, 0xB504B505, 0x018D41C3, + 0xB5030000, 0x0DBAB502, 0x740CFEAF, 0x4122710C, + 0x32822440, 0x00200F26, 0x31832440, 0x4122700C, + 0x0F1AC282, 0xC3810020, 0x3140140A, 0x2042D980, + 0x40C38443, 0x12208000, 0x23CA9582, 0x8840002C, + 0xE411E4EE, 0x24CA95E4, 0x1406104D, 0x7E703110, + 0x740C7D90, 0x018E41C3, 0x43420007, 0x45C1718C, + 0x0400260A, 0x0D5A47E1, 0xC540FEAF, 0x13840D1B, + 0x23E40817, 0x27CC7512, 0xF7599385, 0x41224042, + 0x43E1704C, 0x4042F00D, 0x704C4122, 0x44A143E1, + 0xFCAF0B4A, 0x404270AC, 0x704C4122, 0x240A43C1, + 0x0B3A0400, 0x71ACFCAF, 0x0E15C7CC, 0x0DEB13C5, + 0x40429424, 0x704C4122, 0xF00F43C1, 0x14250D13, + 0x41C3740C, 0x0000018F, 0xFE8F0CF6, 0x4042C7CC, + 0x704C4122, 0x44A143E1, 0x78E0F1E5, 0x800042C3, + 0x24AA0450, 0x21AA1144, 0x82610104, 0x200E8200, + 0xA2008040, 0x90C12403, 0xA2217FE0, 0x1CFCC2FA, + 0xC1B6B6C8, 0x800046CB, 0x8EA01222, 0x780F4310, + 0x714CC180, 0x1C04706C, 0x24403001, 0x0BE63019, + 0x1C000020, 0x23403001, 0x23402A18, 0x09D62A9B, + 0x255F03A0, 0x16001251, 0x272F1092, 0x8E011487, + 0x03E40885, 0x2F412354, 0x33CD21F4, 0x41C3740C, + 0x000103EA, 0xFEAF0C6A, 0x2F4042A1, 0xC8081315, + 0x26C12505, 0x900447CB, 0x78250000, 0xB802708E, + 0x2440270A, 0x902078E5, 0x01502153, 0xE5207502, + 0x2348262F, 0x05C7222F, 0x7854C082, 0x03EB41C3, + 0x43020004, 0xB0A04440, 0x0C26740C, 0x250AFEAF, + 0x71860580, 0x0507202F, 0x827408DD, 0x250571E6, + 0xC8082601, 0x21007825, 0xB8022511, 0x78E57146, + 0xF1BDB0A0, 0x7825C808, 0x714CC182, 0x708C706C, + 0x06200D7E, 0xC0B670AC, 0x341B1404, 0x78E0C6DA, + 0xD820C2E2, 0x900745CB, 0x1D00C40C, 0x0F6A1045, + 0x1D000220, 0xD8201005, 0x02200F5E, 0x10451D00, + 0x10051D00, 0x78E0C6C2, 0x803C2042, 0x42C3F208, + 0x12EA8000, 0x010020A8, 0x00521A14, 0x06200475, + 0x78E0712C, 0x2482C3EA, 0x45083212, 0x38802455, + 0x0BAE702C, 0x228AFC2F, 0x710C0010, 0xB80278B8, + 0x00200E42, 0x0350200F, 0x00200E46, 0x07912040, + 0x8E82208C, 0xDEFE70ED, 0x0E36F705, 0x20540000, + 0x740C088E, 0x040841C3, 0x714C0002, 0xFEAF0B52, + 0x120843A1, 0xC084360D, 0x800041C3, 0x0B4A1042, + 0xDA78FC2F, 0x0BC6C084, 0xD9780620, 0x1E00D80F, + 0x900773C4, 0x0FDEC29C, 0xD90FFDAF, 0x212F78CF, + 0x0FA60447, 0x222F0160, 0x25050407, 0x00011F90, + 0x45CB002A, 0x12228000, 0x8D208D01, 0x00640829, + 0xB90E7822, 0x28407104, 0x240A2082, 0x20A87000, + 0x22050300, 0x71C30040, 0x40000000, 0xB89FB89C, + 0x00051800, 0xD80F70CD, 0xFDAF0F8A, 0x700CD90F, + 0xFCEF0DDA, 0x8D01712C, 0x77108DE0, 0x002D006C, + 0x106D26C0, 0x712C78E2, 0x26046861, 0x00001F82, + 0x2653FFF8, 0xBA231080, 0x71C57918, 0x70C0240A, + 0x090020A8, 0x13032F40, 0x73C026F4, 0x048C8000, + 0x2F407865, 0xB802120C, 0x0F802005, 0x02DC9004, + 0x010B1000, 0x38802455, 0x70756098, 0x8C00605C, + 0x004220C5, 0x7826F402, 0x04032305, 0x6B12AC00, + 0xB89C71E5, 0xB0C0B89F, 0x03400F9A, 0x087B78D0, + 0x00008F84, 0x8DC00800, 0x8D01700E, 0x03A408DD, + 0x41C3740C, 0x00010409, 0xFEAF0A36, 0x702E42C1, + 0xAFDF218C, 0x002D00B6, 0x218B740C, 0x1C0CA803, + 0x1C083400, 0xF4123400, 0x28002156, 0x21822941, + 0x0F802004, 0xFFC00000, 0x41C3B826, 0x0002040A, + 0x09FE6869, 0x740CFEAF, 0x70CCDF08, 0xC282706C, + 0x627A708D, 0x00892653, 0x7100244A, 0x200A736D, + 0x1A001440, 0x20A80003, 0x2E400500, 0x24551200, + 0x61193881, 0x10C02841, 0x61087105, 0x02402801, + 0xB8C07125, 0x02C02800, 0x7C057765, 0x00862652, + 0x71647426, 0x177F278D, 0x140DAA80, 0x140B3087, + 0x140C3085, 0x140A3086, 0xC2223084, 0x30831409, + 0x3081140E, 0x3080140F, 0x41C3C140, 0x0008040B, + 0x097EC041, 0x740CFEAF, 0x41C3F1A4, 0x0000040C, + 0xFE8F096E, 0xF19371C5, 0x78E0C7CA, 0x082E43E3, + 0x20780000, 0x16000001, 0x80007080, 0x08110008, + 0x217800B1, 0xB8020000, 0x7B007404, 0x00002178, + 0x7204781B, 0x78E07B00, 0x800040C3, 0x88201220, + 0x219F8841, 0x229F0582, 0x10BC02C1, 0x60380000, + 0x8A03621A, 0x86002044, 0x02002078, 0x20CA7FE0, + 0x78E000A1, 0x244AC5E1, 0x706C71C0, 0x702C704C, + 0x900C44CB, 0x20A80240, 0x21050280, 0x7424030D, + 0x651D95A0, 0x7144AD40, 0x70811600, 0x00408000, + 0x244AE90E, 0x704C71C0, 0x028020A8, 0x1381244F, + 0x74447945, 0x61199120, 0x7164A967, 0x78E0C4C2, + 0x4310C2F2, 0x4570710C, 0x42304450, 0xFCAF0A92, + 0x04CD2800, 0x10512553, 0xD90B700C, 0x706C704C, + 0x250A708C, 0x0BF60440, 0x70CCFCEF, 0xD9FF700C, + 0xFCEF0EDE, 0x6D12704C, 0x200F762C, 0xDA2204C0, + 0x700C7E0F, 0x20300D1D, 0x244ADB40, 0x45C10A00, + 0xFCEF0BCA, 0xD88070CC, 0x744CD919, 0xF00CDB83, + 0x0940244A, 0x0BB645C1, 0x70CCFCEF, 0xD919D880, + 0xDB81744C, 0x250A708C, 0x0BA20440, 0x70CCFCEF, + 0x0B4A700C, 0x712CFCEF, 0x0BCE700C, 0xB88B0220, + 0x000040C3, 0x0C4E9C40, 0xD9080220, 0x20300D0B, + 0xD92640C1, 0xD923F002, 0xFE8F0F7A, 0x800047CB, + 0x8FA01222, 0x082B8F01, 0x79AF0344, 0x0C4E4062, + 0x403000A0, 0x4002E809, 0x0F9A742C, 0x42620360, + 0x23412214, 0x8F01B100, 0x71A57510, 0x0D0DF7AF, + 0x40C12030, 0xF003D927, 0x0F3AD924, 0x8FA0FE8F, + 0x0B7D8F61, 0x7EAF0364, 0x0C124062, 0x41C100A0, + 0x40C1E834, 0x0F5E742C, 0x42620360, 0x22F4B808, + 0x22142341, 0x78252342, 0x1600B200, 0x80007101, + 0x218C0006, 0xF70581C3, 0x00451A00, 0x7810F004, + 0x0095080D, 0x000040C3, 0xF009FFFF, 0x70811600, + 0x00088000, 0x2905B911, 0xB2000000, 0x0D117B10, + 0x740C2030, 0x035941C3, 0xF0050002, 0x035A41C3, + 0x0F5E0002, 0x42A1FE6F, 0xF1C471A5, 0x0B298FA0, + 0x79AF0364, 0x00A00B96, 0xE88B4062, 0x103F0D0D, + 0x23402214, 0xF0049021, 0x810110FE, 0x8F61B020, + 0xF1EF71A5, 0x0B438F40, 0x0C3F0084, 0x23782030, + 0x0D0F2000, 0x20782030, 0x48AC0000, 0x489CF002, + 0x68614B50, 0x7825C808, 0x70C0240A, 0x20A86892, + 0x2A400340, 0x22F40380, 0x78852081, 0xB8927144, + 0xB89FB89C, 0x08CAB020, 0x700CFC8F, 0x744CD90C, + 0x708C706C, 0x0440250A, 0xFCEF0A32, 0x700C70CC, + 0x764CD907, 0x708C706C, 0x0A2270AC, 0x268AFCEF, + 0x700C0FC3, 0x744CD910, 0x708C706C, 0x0440250A, + 0xFCEF0A0A, 0xD88070CC, 0x764CD907, 0x708C706C, + 0x09FA70AC, 0x268AFCEF, 0x700C0FC3, 0xFCEF099E, + 0x0832712C, 0xC6D203C0, 0xC1A4C3EA, 0x45484668, + 0x41104030, 0x0F9770ED, 0x244A11F5, 0x40C37200, + 0x12208000, 0x20300935, 0x704C8820, 0x20A8706C, + 0x40200540, 0x209F6F95, 0x70020803, 0x2B41641C, + 0x640C00C0, 0x01802344, 0x01C02047, 0x102E0C3B, + 0xE212C080, 0xF029E312, 0xDA7EDBFE, 0x050020A8, + 0x6F954020, 0x0803209F, 0x641C7002, 0x00C02B41, + 0x2344640C, 0x20470180, 0x0C1901C0, 0xC080102E, + 0xBB72BA72, 0x41C3F011, 0x00020183, 0xF00878F4, + 0x003E2380, 0x41C378F4, 0x00020184, 0x740CB040, + 0xFE6F0DEE, 0x71E542E1, 0x1400F1B7, 0x244A3100, + 0xC28071C0, 0xB600B500, 0x038020A8, 0x05011202, + 0x090B9560, 0xB52000C5, 0x080B9600, 0x40200045, + 0x78E0B620, 0x78E0C7CA, 0xE808702C, 0x8002222F, + 0x6119B8C0, 0xF5FC4040, 0x78307FE0, 0x71001600, + 0x02909008, 0x78E07EE0, 0x0872C2E2, 0x08C6FD8F, + 0x4508FDAF, 0x70811600, 0x001C8000, 0xE80CE906, + 0xD87DED8B, 0xF019B807, 0xED8CE80B, 0x000040C3, + 0xF0134650, 0x40C3ED0A, 0x4A380000, 0xED0AF00D, + 0x000040C3, 0xF0095208, 0x000040C3, 0xF0052EE0, + 0x000040C3, 0x097E36B0, 0x742C0220, 0xC6C2780F, + 0x800040C3, 0x051D12DC, 0x8000FC6F, 0x45CBC2E4, + 0x12208000, 0x8D218D00, 0x0582209F, 0x02C1219F, + 0x100215BC, 0x60386058, 0xB8248801, 0xFC6F0EE6, + 0x058E205F, 0x00832079, 0x8D418D00, 0x0582209F, + 0x02C1229F, 0x100115BC, 0x0285239F, 0x60586038, + 0x63DB8803, 0xD80AB8E5, 0x022120CA, 0x2332631B, + 0x80000F80, 0xC6C407E0, 0x40C3C2E2, 0x12208000, + 0x88418820, 0x0582219F, 0x02C1229F, 0x000010BC, + 0x621A6038, 0xB8C38A02, 0xFC6F0E8A, 0x038D205F, + 0x00812079, 0x800040C3, 0x219F0646, 0x61B90483, + 0x60386112, 0x621A9001, 0xC6C27850, 0x4568C2E8, + 0x4050DB7F, 0x44604220, 0x248AE983, 0x8D850FC7, + 0x11041D06, 0xEA14E80E, 0x70811600, 0x01468000, + 0x40C3E91E, 0x01408000, 0xB5268861, 0xF0158820, + 0x1D08710C, 0xB8901001, 0xC6C8A503, 0x20100831, + 0x71011600, 0x01428000, 0x40C3E92E, 0x01388000, + 0xB5269062, 0xB5249020, 0xF031B565, 0x11041D0A, + 0x10051D08, 0x1D0CEC2A, 0xF0291085, 0x71011600, + 0x01448000, 0x40C3E918, 0x013E8000, 0x10FC9060, + 0xB5268100, 0xB504B565, 0x70801600, 0x000B8000, + 0x017E082B, 0x8008238C, 0x10051D08, 0x238AF78F, + 0xF1DC0FC7, 0x0FC7238A, 0x11041D0A, 0x10051D08, + 0x1D0CEC04, 0xF0031205, 0x41C3B506, 0x00030227, + 0xFC2F08D6, 0x00C0243D, 0x1104150C, 0x0400250A, + 0x95059544, 0x1D0E4851, 0x29081104, 0x78220101, + 0x022841C3, 0xB5050004, 0x0BA67B10, 0x740CFE6F, + 0x78E0C6C8, 0x084BC5E1, 0x712D00B5, 0x2078DD25, + 0xBD9F0008, 0x8D8D700C, 0x10F00C0F, 0x2444716D, + 0x20521040, 0x7015000B, 0x20CA8D80, 0xA90002C1, + 0x10002900, 0x7C0BAA00, 0x700C712C, 0xAB20F207, + 0x800041C3, 0x702D1220, 0x4021A900, 0xDD40C4C2, + 0x00882078, 0x700CBD9F, 0x0C118D8D, 0x716D10F0, + 0x10402444, 0x000B2052, 0x8D807015, 0x02C120CA, + 0x2900A900, 0xAA001000, 0x722C7C0B, 0xF5E1710C, + 0x78E0F1E5, 0x00700821, 0x7DE07014, 0x70801600, + 0x00258000, 0x00C02078, 0xA1007104, 0x800040C3, + 0xF0151224, 0x70801600, 0x00408000, 0x0050080F, + 0x00D10811, 0x00811900, 0x1900F006, 0xF0040041, + 0x00011900, 0x800040C3, 0x88201226, 0x8801AA20, + 0xAB007FE0, 0x0883C2E2, 0x45080030, 0x71021600, + 0x00148000, 0x00CF41C3, 0x0AB60001, 0xD8FFFE6F, + 0x08676D09, 0x120D01D5, 0x120B3083, 0x120C3604, + 0x20253605, 0xF0080000, 0xF010F00B, 0xF018F013, + 0xF024F01B, 0x41C3700C, 0x000300D0, 0x700CF022, + 0x00D141C3, 0xF01E0003, 0x41C3700C, 0x000300D2, + 0x700CF018, 0x00D341C3, 0xF0140003, 0x41C3700C, + 0x000300D4, 0x120BF00E, 0x41C33082, 0x000400D5, + 0xFBEF0F56, 0xC6C2700C, 0x41C3700C, 0x000300D6, + 0x43804260, 0xFBEF0F42, 0x0140240A, 0x78E0C6C2, + 0x000043CB, 0x242F28F0, 0x201F12C0, 0x7B8A02C0, + 0x108B2B41, 0x02C1211F, 0x0184229F, 0x60386078, + 0x42C36058, 0x1A3E8000, 0x08012256, 0x78356029, + 0x61116A2A, 0x48326050, 0x71447030, 0x002522CA, + 0x78507FE0, 0x1CFCC2FA, 0xC1A6B6C8, 0x16004608, + 0x80007100, 0x4528000A, 0xC3414358, 0x781DC043, + 0x87812044, 0xC045710C, 0xC042D810, 0x090DF207, + 0x700C00B1, 0xF003C045, 0x208AC142, 0xB6010004, + 0xAE00D820, 0x081FC003, 0xD8C8007E, 0x8D409561, + 0x021A41C3, 0x121C0004, 0x09963705, 0x121DFE6F, + 0x8D003704, 0xC2014363, 0x95E14210, 0x0AE641E1, + 0x41F1FDAF, 0xC0034010, 0x007E081D, 0x9561D8C8, + 0x41C38D40, 0x0004021B, 0x0400240A, 0xFE6F0962, + 0x0400250A, 0x7014C002, 0x7216F2BC, 0x00250174, + 0xC002746E, 0x70CE8DE0, 0xB82295A1, 0x1410C044, + 0x22003015, 0x240A24C0, 0x210A2440, 0x20533400, + 0x22020150, 0x0D1124C0, 0x20531521, 0x0F1B0151, + 0x70EE1460, 0x4022C201, 0x0A7A4182, 0x4363FDAF, + 0x15210D0B, 0x0F254710, 0xC2011400, 0x41824002, + 0xFDAF0A62, 0x0F154363, 0x081F2005, 0x47100664, + 0x220A474A, 0xF00B2400, 0xA640270C, 0x148627CA, + 0x244622CA, 0x270AF743, 0x24002640, 0x240224C0, + 0x205324D1, 0x21530218, 0x77522211, 0x944125CC, + 0x0D21F405, 0x700E1621, 0xC201F01B, 0x41224042, + 0xFDAF0A12, 0x40104363, 0x25CC7752, 0xF2119601, + 0x4042C201, 0x09FE4103, 0x4363FDAF, 0x20050813, + 0x05E40819, 0x2600210A, 0x4010458A, 0x200CF00A, + 0x25CAA5C0, 0xF7461506, 0x2500210A, 0x25C0200A, + 0x26610817, 0x30141410, 0xF547262F, 0x2542F204, + 0xF0032054, 0xC003708E, 0x007E082D, 0x2507252F, + 0x41C3D8C8, 0x0007021C, 0x434242C2, 0x0440240A, + 0x0400250A, 0x0400260A, 0x04C0270A, 0xFE6F0832, + 0x35401C00, 0x08178E00, 0x0D170481, 0x96012010, + 0x0440080F, 0x2500250A, 0x0DFDF012, 0x1410A011, + 0x202F3015, 0x431084C2, 0x716EF404, 0x2500250A, + 0x00012079, 0x2005C005, 0xF20C807E, 0xC00271C6, + 0xA000260C, 0x14441E02, 0xFFE506AA, 0x14821E00, + 0xC0A64002, 0x341B1404, 0x78E0C6DA, 0x44CBC0E6, + 0x12D98000, 0x8C204028, 0x7100244A, 0x70AD70CD, + 0x20A8708D, 0x091B0240, 0x7185030F, 0x000075C3, + 0x702C8000, 0x900345CB, 0x706DC000, 0x6892F015, + 0x10812800, 0x79647D85, 0x1F8C2505, 0x00009038, + 0x25059480, 0x903B1F8D, 0x2406C000, 0x7C6410CF, + 0x2C0179E5, 0x0C43108B, 0xB5200031, 0x708C1600, + 0x00258000, 0x1600EC88, 0x8000708C, 0xEC140040, + 0xBE0CDE07, 0x28007E05, 0x6E52108C, 0x22057C64, + 0x90000F81, 0x91200000, 0x0F8D2205, 0xC0009003, + 0x79857966, 0x4061B520, 0x78E0C4C6, 0x1CFCC2FA, + 0xC1ADB6C8, 0x4210C71D, 0x70801600, 0x00148000, + 0x21C0200A, 0x41384150, 0x700F70EE, 0x31801C2C, + 0x31401C04, 0x31001C28, 0x013E081B, 0x1600C349, + 0x80007080, 0x080F001E, 0x710F003F, 0x05400C5A, + 0x97C44018, 0x20C02242, 0x0175082F, 0x0D8297A1, + 0xE815FE4F, 0x800040C3, 0x88411222, 0x0A1F8800, + 0x790F0004, 0x27147104, 0x19241041, 0x790F05C4, + 0x80450AF3, 0x0ADBF003, 0x2178A050, 0xD80930D2, + 0x30F10911, 0xD80AC040, 0x3240234A, 0xF003C040, + 0x0842706F, 0x0E360380, 0xD8C8FCAF, 0xFCAF0E3E, + 0x7056970E, 0x900446D3, 0x40C33DD0, 0x01D09004, + 0x200226CA, 0x3031080D, 0x2004258A, 0x2002258A, + 0x2538C01C, 0x704E1393, 0x800044D3, 0xC04C1222, + 0x30002150, 0x40C3C045, 0x28F00000, 0x2001211F, + 0x201F781B, 0x60382000, 0x4063C043, 0x0184209F, + 0x6038C103, 0x0F812000, 0x1A3C8000, 0x800070C3, + 0xC0481A3E, 0xC042720C, 0x30802178, 0xC1477204, + 0x710CC046, 0x45CBC044, 0xC2CC9007, 0x20300A1D, + 0x0FC7208A, 0x732EB500, 0x15C41D04, 0x0819C005, + 0x97C800B1, 0xF009BE07, 0x712E70CD, 0x15C41D00, + 0xF003B502, 0x1400BE08, 0x14012090, 0x202F208B, + 0x0B930407, 0x43A21024, 0x70811600, 0x12D98000, + 0x002E097F, 0x10012714, 0x038B2840, 0x1F822305, + 0x3ED49004, 0xB90A9132, 0x04412105, 0xC109B220, + 0x000021F4, 0x30300829, 0x0A1960D8, 0x79102030, + 0x08002155, 0x0FCF218A, 0x8FCF208C, 0xF009F7C8, + 0x8002218C, 0xF785702C, 0x003E2080, 0x23054100, + 0xB0201580, 0xE815CC20, 0x712CD840, 0x15C41D00, + 0x03E009E6, 0x15C41D04, 0x70801600, 0x00088000, + 0xD8407414, 0x20CAD944, 0x1DF40041, 0x71069004, + 0xCC20F1B5, 0xC106E827, 0x20032D01, 0x00412800, + 0x1400633B, 0x0B3F2081, 0x16001044, 0x80007088, + 0x782F12D9, 0x102E0827, 0x2005B80E, 0x90040F82, + 0x9200029C, 0x05C41A00, 0x0F8C2004, 0x1FFE0000, + 0xB80DCC20, 0xBC807C05, 0x7124B280, 0x0BD7782F, + 0x78709005, 0xFCAF082E, 0x7076702C, 0x14B7F26F, + 0x14012088, 0x8F05208B, 0x208E1400, 0x268AE82E, + 0x7BCF0FC7, 0x10C40BC5, 0x10CE084D, 0x0F82231F, + 0x0A3C0000, 0xC008C407, 0x621A645C, 0xC1004063, + 0x00450835, 0xE988C101, 0x06812300, 0x0081111C, + 0x00400819, 0x7001248A, 0x41404189, 0x018020A8, + 0x00151904, 0x11941904, 0x11842480, 0x01842280, + 0xF1E77104, 0xF1D771C5, 0x128D265F, 0x7ACF7563, + 0x10840B69, 0x10AE085F, 0x416344A9, 0x0957C000, + 0xC0010005, 0x2200E887, 0x101C0680, 0x09410080, + 0x788F0000, 0x7002248A, 0x000E209F, 0x0F832000, + 0xC1448000, 0x20A8C00C, 0x1B0201C0, 0x1B040014, + 0x225F0015, 0x60F80500, 0x3030080D, 0x18347834, + 0xF0060FC5, 0x23F4C30A, 0xB07A0083, 0x71247185, + 0xE50AF1D6, 0xF1CD71C5, 0x0A7E706E, 0x1400FC4F, + 0x14012090, 0x262F2080, 0x08771407, 0x714E03A4, + 0x70801600, 0x12D98000, 0x03AE0863, 0x13912E40, + 0xC000456B, 0x10050D57, 0xE888C001, 0x16802600, + 0x0080101C, 0x10000D43, 0x12802D40, 0x20CA7337, + 0x20050021, 0x20050440, 0x90040F80, 0xC10B01D0, + 0x0FF87034, 0x9000FD61, 0x1502265F, 0x7034C104, + 0x800041C3, 0x7AB4BE24, 0x6159F204, 0xF005B100, + 0x19506159, 0x71A50004, 0x7106F1D5, 0xC102F1C3, + 0xC1427724, 0x702C7034, 0xFFE2056E, 0x1400C144, + 0x202F2091, 0x200C2447, 0x012EA000, 0x1600000D, + 0x80007081, 0x211112D9, 0xF28D8400, 0x2295215E, + 0xC000466B, 0x010A7610, 0xC0010006, 0x2000E887, + 0x101C2680, 0x0EA10080, 0x205F1000, 0x40C32501, + 0xBE248000, 0x03832114, 0x6315607A, 0x01121250, + 0xE82E8F05, 0xDB3F9724, 0x48319701, 0x29049707, + 0x78300001, 0x023E41C3, 0x42000002, 0x000120BC, + 0xFBEF0816, 0x201F4350, 0x00002F81, 0xC0030A3C, + 0x40C16119, 0x0184209A, 0x21156119, 0x200004C0, + 0x80000F81, 0x70C31A3C, 0x1A3E8000, 0x23650A33, + 0x0FC7228A, 0x05C41800, 0xF016B140, 0x23640A29, + 0x79D461F9, 0x082D911A, 0x00000F81, 0x2200FFFF, + 0xE0FF2340, 0x1934F70A, 0x700C05C4, 0xB1A0F00A, + 0x04841800, 0xF1A771C5, 0x2080781D, 0xB11A003F, + 0x78109728, 0x75104D12, 0x0480200E, 0x23832500, + 0x004B2A04, 0x28047C6F, 0x23CA0040, 0x7A101025, + 0x02C8212F, 0x80640AD1, 0x215F4081, 0x209F0181, + 0x6119000E, 0x800040C3, 0x6038C144, 0xB0219721, + 0x90609721, 0x00C50907, 0x7165B020, 0x1401F1EA, + 0x71262080, 0xC0ADF167, 0x341B1404, 0x78E0C6DA, + 0x47CBC2FA, 0x12228000, 0x240A8FC0, 0x250A2180, + 0x260A2140, 0x47702100, 0x41384058, 0x8F014110, + 0x03840899, 0x800040C3, 0x880012D9, 0x03AE0889, + 0x1105704E, 0x700E2080, 0x27F4E883, 0x265A2390, + 0x11051293, 0xE81D2080, 0x000040C3, 0x791B28F0, + 0x3002211F, 0x3041201F, 0x78CCB822, 0x611A6159, + 0x209A4042, 0x621A0184, 0x800040C3, 0x60591A3C, + 0x91016215, 0x0345081B, 0x700C70AD, 0x0B82F009, + 0x4062FF6F, 0x40624508, 0xFF6F0BA6, 0x60B941A1, + 0x24C22614, 0x7502793D, 0x71467102, 0x2514B220, + 0xB1A024C1, 0x04012000, 0x24C02414, 0x0A977166, + 0xB020A2B4, 0xF1B571C5, 0x78E0C6DA, 0x800041C3, + 0x89011222, 0x71108920, 0x07CD20E0, 0x29407822, + 0x71040382, 0x7000240A, 0x030020A8, 0x0F812205, + 0x01D09004, 0x72C39100, 0x40000000, 0xB100E020, + 0x78E07EE0, 0x0343236F, 0x800041C3, 0x93000458, + 0x208CDA08, 0xD8088059, 0x02A520CA, 0x9300B100, + 0x8059208C, 0x20CAD808, 0xB10102A5, 0x208C9300, + 0xD8088059, 0x02A520CA, 0x9300B102, 0x8059208C, + 0x02A522CA, 0xB1437FE0, 0xC1A2C3EE, 0x42104728, + 0x0C0D2055, 0x0D124020, 0x702CFD6F, 0x40424010, + 0x090E702C, 0xDACAFBAF, 0x208A71CD, 0xB5C20016, + 0x20041AC2, 0x0C15208A, 0x1600B500, 0x80007080, + 0x20440009, 0x710C8091, 0x00A120CA, 0x22431AC6, + 0x03200A1A, 0x20021AC9, 0x22408D24, 0xADC82403, + 0x200D2178, 0x424240E1, 0x71AC708C, 0xFEEF0BDA, + 0x12C546A1, 0x22402081, 0x22402202, 0x40E12603, + 0x71AC708C, 0xFEEF0BC2, 0x47CB46A1, 0x12228000, + 0x8F018FC0, 0x03840841, 0x238D2214, 0x0C9AC180, + 0x9500FD6F, 0x0C929504, 0xC181FD6F, 0x0BBAC080, + 0x712C0120, 0xFE2F090E, 0xB500C080, 0x0BAAC081, + 0x712C0120, 0xFE2F08FE, 0xB504C081, 0x76108F01, + 0xF7A471C5, 0x05000CE2, 0x70148FC0, 0x2040740C, + 0x20CA2413, 0x204001E2, 0x1AC72491, 0x8F012002, + 0x03A4085F, 0x13102E40, 0x265A70AD, 0x2D401503, + 0x22051202, 0xC8080402, 0x41C37A05, 0x00009004, + 0x04402205, 0x04C22205, 0xB8027342, 0x78257BB4, + 0x01051000, 0x1B206A12, 0x78250144, 0x01041000, + 0x1B70740C, 0x41C30104, 0x000401C7, 0x0FD242C1, + 0x43A1FDEF, 0x0DB771A5, 0x71C59254, 0xC7CEF1D1, + 0x40C3C0F1, 0x12208000, 0xC8088880, 0x7885BC0C, + 0x0F802005, 0x0FD80003, 0x05200F3A, 0xC808702C, + 0x6C127C05, 0x0F802005, 0x0364900C, 0x7FE0C0D1, + 0x00051800, 0xD9FFD838, 0x1803B89F, 0x18FC0052, + 0x18018042, 0x18160052, 0x18010052, 0xA8200052, + 0x7FE0A823, 0x78E0A824, 0xD9FFD83A, 0x1803B89F, + 0x18FC0052, 0x18018042, 0x18160052, 0x18010052, + 0xA8200052, 0x7FE0A823, 0x78E0A824, 0x200AC2E8, + 0x47682100, 0x45284648, 0x0135080B, 0xBA0E4200, + 0x0A0FF00D, 0x700C03F1, 0xBA0EDA1F, 0x41C3F008, + 0x00010030, 0xFB8F0C22, 0xBA92704C, 0x900040C3, + 0x22053A90, 0x74040001, 0x2205B1A0, 0x74040001, + 0x2205B1C0, 0x74040001, 0xB1E07845, 0x04041800, + 0x78E0C6C8, 0x4110C2EE, 0x230A4040, 0x220A2140, + 0x45682100, 0xFEAF0BAE, 0x46084030, 0xFEAF0BA6, + 0x470840A1, 0xFEAF0B9E, 0x45084042, 0xFEAF0B96, + 0x09214062, 0x092D2090, 0x09472050, 0x42222031, + 0x901C42C3, 0x41C3006C, 0xF8A89007, 0xF011B2C0, + 0x901C42C3, 0xB2C000EC, 0x900741C3, 0xF009F928, + 0x901C42C3, 0xB2C000AC, 0x900741C3, 0xB2E2F8E8, + 0xB102B1A0, 0x84041AD4, 0x840419D8, 0x41C3C6CE, + 0x0001002F, 0xFBAF0B72, 0xC6CE700C, 0x45CBC5E1, + 0x006C901C, 0x10141D04, 0x900744CB, 0x1D3CF8A8, + 0x1C041054, 0x1C3C1094, 0x1D0410D4, 0xB5201014, + 0x10941C04, 0xB51EB460, 0x10441D40, 0x1C40B45E, + 0xC4C210C4, 0x1600C2E2, 0x90307100, 0x45CB0200, + 0x4FC48001, 0x1A11DAB0, 0x206D3003, 0x40C30081, + 0x04A88000, 0x40A1A820, 0xFB6F0E26, 0x42C3702C, + 0xFFFC7FFF, 0x10802504, 0x2000B822, 0x00050F81, + 0x12688000, 0x20790600, 0x1A680000, 0x1A090058, + 0xC6C23002, 0x0FBAC3EC, 0xC1A1FBEF, 0x800040D3, + 0x205410D4, 0x70CD280F, 0x254270AD, 0x08111700, + 0x160001D5, 0x80007080, 0xE8130131, 0x14032532, + 0x1700700C, 0x762C1084, 0x254A704C, 0x08FE03C0, + 0x70CCFC6F, 0xD922700C, 0xFC6F0BE6, 0x71A5704C, + 0x98F40DCB, 0x700C71E5, 0xFC6F0892, 0xDD25712C, + 0xBD9F714E, 0x702C722E, 0x8D40720E, 0x7A058D1B, + 0x20402A00, 0x200FB802, 0x7F4B004F, 0x0E6AF21B, + 0x40C10060, 0x0F3AE817, 0x252FFBCF, 0x700C03C7, + 0x704C762C, 0x244ADBD0, 0x08A20300, 0x70CCFC6F, + 0xD922700C, 0xFC6F0B8A, 0x700C704C, 0xFC6F083E, + 0x208D712C, 0x712C277F, 0x25FF218D, 0xD98271CD, + 0xB99F70CD, 0x800047CB, 0x712E1220, 0x04801101, + 0x0140206C, 0x0E002045, 0x8900C060, 0x0140206C, + 0x0E002045, 0x30021C01, 0x206C8901, 0x20450140, + 0x1C020E00, 0x89023002, 0x0140206C, 0x0E002045, + 0x30021C03, 0x790F700C, 0x00B50979, 0xE906AF00, + 0xE8888D1B, 0xF034710C, 0x70148D00, 0xF230700C, + 0x20402900, 0xFEAF0826, 0x0E96780F, 0x702CFBCF, + 0x8D60720E, 0x7B058D1B, 0x20402900, 0x200FB802, + 0x7A6B0042, 0x8F60F20F, 0x252FC080, 0x704C0087, + 0x0440244A, 0x787470CC, 0x700C602B, 0xFC2F0FDE, + 0x208D762C, 0x712C2A7F, 0xD922700C, 0xFC6F0AC2, + 0x700C704C, 0xFC2F0F76, 0x8F00712C, 0xF1C57104, + 0xFE6F0FCA, 0xB7C0730C, 0x78E0C7CC, 0x0FDEC0F1, + 0x208A00E0, 0x7910041F, 0x0A96700C, 0x704CFC6F, + 0x7EE0C0D1, 0x4508C2E2, 0xB813D841, 0x744CD907, + 0x708C706C, 0x0F8670AC, 0x70CCFC2F, 0xFC4F0A2A, + 0xD90740A1, 0x706C744C, 0x70AC708C, 0xFC2F0F6E, + 0x09FE70CC, 0x40A1FC4F, 0x744CD907, 0x708C706C, + 0x0F5A70AC, 0x70CCFC2F, 0xD907D880, 0x744CB893, + 0x708C706C, 0x0F4670AC, 0x70CCFC2F, 0x78E0C6C2, + 0x800042C3, 0x8A401225, 0x0042223C, 0x16007854, + 0x80007082, 0x22110121, 0x21448000, 0x20F90040, + 0x7FE00022, 0x002120F8, 0x4608C2E4, 0x800040C3, + 0x88001225, 0x203C4528, 0x0CAE0040, 0x41C10060, + 0x710C7014, 0x038120CA, 0xFFE10FB8, 0xC6C441A1, + 0x0927682B, 0x71140175, 0x71011600, 0x00148000, + 0x210B710C, 0x00008F80, 0xF2034008, 0x782D7EE0, + 0x207A7FE0, 0x700C0000, 0xF1FAF3F0, 0x4220C0F1, + 0x2144B923, 0xBAC50601, 0x81006119, 0xFB6F0F3E, + 0xB8C08121, 0x7FE0C0D1, 0x00002078, 0x2482C3EC, + 0x45083708, 0x087AC087, 0x41A1FF2F, 0xC18240A1, + 0xFD2F0E46, 0x31C22440, 0xC7CCE802, 0x30801407, + 0x00B00811, 0x080F72CD, 0x704E00F0, 0xF00370CD, + 0x702E714E, 0xC080C182, 0x42A179D5, 0xFFAF091A, + 0x080FC387, 0xC7200444, 0x14024110, 0x76523110, + 0xF63277C5, 0xA03009C7, 0x1D82750C, 0x2580141C, + 0x700C1084, 0xC7CCADE0, 0xC1A2C3E6, 0x70AD4708, + 0x800146CB, 0xC5414D7C, 0x0071080D, 0xD864C540, + 0xF066B600, 0xB606D8C8, 0x080FF062, 0xE8890050, + 0xB808D87F, 0xD87FF003, 0xC040B810, 0xD9FFF006, + 0x0FA6700C, 0xB910FB6F, 0x10710F0D, 0x26F44E1C, + 0xF0041340, 0x034020F4, 0x0882B802, 0x7810FC6F, + 0xD907D841, 0xDA08B813, 0x708C706C, 0x0DCE70AC, + 0x70CCFC2F, 0x742C700C, 0xFC6F08B6, 0xC080714C, + 0x080E41E1, 0x724CFC6F, 0xD914700C, 0xFC6F08A2, + 0x706C714C, 0x4060D907, 0xB892744C, 0x70AC708C, + 0xFC2F0D9A, 0x160070CC, 0x80007080, 0x0811000C, + 0x700C003E, 0x087AD914, 0x714CFC6F, 0xD907D880, + 0xDA08B893, 0x708C706C, 0x0D7270AC, 0x70CCFC2F, + 0xFBCF0BD6, 0x13412614, 0x10710F0F, 0xB1016849, + 0xB14C71A5, 0xB107F004, 0xB15271A5, 0x90B40D3F, + 0xC7C678B0, 0x702CC2E4, 0x4508DA4B, 0xFB6F0A02, + 0x090E2055, 0x704CD95A, 0x1104B99F, 0xAD010480, + 0x04801104, 0x1104AD02, 0xAD030480, 0x04801104, + 0x1104AD0A, 0xAD0B0480, 0x04801104, 0x1104AD0C, + 0xAD0D0480, 0x04801104, 0x1104AD0E, 0xAD0F0480, + 0x04801104, 0x1104AD10, 0xAD110480, 0x04801104, + 0x1104AD12, 0xAD130480, 0x04801104, 0x1104AD14, + 0xAD150480, 0x04801104, 0x1104AD16, 0xAD180480, + 0x04801104, 0x1104AD19, 0xAD1A0480, 0x04801104, + 0x1104AD1B, 0xAD1C0480, 0x04801104, 0x1104AD1E, + 0xAD1F0480, 0x04801104, 0x10021D20, 0x04801104, + 0x10021D21, 0x04801104, 0x10021D22, 0x04801104, + 0x10021D25, 0x04801104, 0x10021D28, 0x04801108, + 0x10021D29, 0x10821D2E, 0x04801104, 0x10021D3A, + 0x04801104, 0x10021D45, 0x04801104, 0x10021D46, + 0x04801104, 0x10021D47, 0x84801179, 0x10021D48, + 0x0080118B, 0x10021D49, 0x0080118F, 0x10021D4A, + 0x04801104, 0x10021D4C, 0x04801104, 0x10021D4D, + 0x04801104, 0x10021D4E, 0x04801104, 0x10021D55, + 0x04801104, 0x10021D56, 0x04801104, 0x10021D57, + 0x04801104, 0x10021D58, 0x04801104, 0x10021D59, + 0x04801104, 0x10021D5A, 0x04801104, 0x10021D5B, + 0x04801104, 0x10021D5C, 0x04801104, 0x10021D5D, + 0x04801104, 0x10021D5E, 0x04801104, 0x10021D5F, + 0x04801104, 0x10021D60, 0x04801104, 0x10021D61, + 0x04801104, 0x10021D63, 0x04801104, 0x10021D64, + 0x04801104, 0x10021D65, 0x04801104, 0x10021D66, + 0x04801104, 0x10021D67, 0x04801104, 0x10021D69, + 0x04801104, 0x10021D6A, 0x04801104, 0x10021D6B, + 0x04801104, 0x10021D6C, 0x04801104, 0x10021D6D, + 0x04801104, 0x10021D70, 0x04801104, 0x10021D73, + 0x04801108, 0x10021D74, 0x10821D79, 0x04801104, + 0x10021D85, 0x04801104, 0x1104AE00, 0x1D910480, + 0x11041002, 0x1D920480, 0x11791002, 0x1D938480, + 0x118B1002, 0xAE040080, 0x0080118F, 0x10021D95, + 0x04801104, 0x10021D97, 0x04801104, 0x1104AE08, + 0x1D990480, 0x11041002, 0xAE100480, 0x04801104, + 0x10021DA1, 0x04801104, 0x10021DA2, 0x04801104, + 0x10021DA3, 0x04801104, 0x1104AE14, 0x1DA50480, + 0x11041002, 0x1DA60480, 0x11041002, 0x1DA70480, + 0x11041002, 0xAE180480, 0x04801104, 0x10021DA9, + 0x04801104, 0x10021DAA, 0x04801104, 0x10021DAB, + 0x04801104, 0x1104AE1C, 0x1DAE0480, 0x11041002, + 0x1DAF0480, 0x11041002, 0x1E200480, 0x11041002, + 0x1DB10480, 0x11041002, 0x1DB20480, 0x11041002, + 0x1E240480, 0x11041002, 0x1DB50480, 0x11041002, + 0x1DB60480, 0x11041002, 0x1DB70480, 0x11041002, + 0x1E280480, 0x11041002, 0x1DBB0480, 0x11041002, + 0x1DBE0480, 0x11081002, 0x1DBF0480, 0x1E341002, + 0x11041082, 0x1E400480, 0x11041002, 0x1DDB0480, + 0x11041002, 0x1E4C0480, 0x11041002, 0x1DDD0480, + 0x11791002, 0x1DDE8480, 0x118B1002, 0x1DDF0080, + 0x118F1002, 0x1E500080, 0x11041002, 0x1DE20480, + 0x11041002, 0x1DE30480, 0x11041002, 0x1E540480, + 0x11041002, 0x1DEB0480, 0x11041002, 0x1E5C0480, + 0x11041002, 0x1DED0480, 0x11041002, 0x1DEE0480, + 0x11041002, 0x1DEF0480, 0x11041002, 0x1E600480, + 0x11041002, 0x1DF10480, 0x11041002, 0x1DF20480, + 0x11041002, 0x1DF30480, 0x11041002, 0x1E640480, + 0x11041002, 0x1DF50480, 0x11041002, 0x1DF60480, + 0x11041002, 0x1DF70480, 0x11041002, 0x1DF90480, + 0x11041002, 0x1DFA0480, 0x11041002, 0x1DFB0480, + 0x11041002, 0x1E6C0480, 0x11041002, 0x1DFD0480, + 0x11041002, 0x1DFF0480, 0x25561002, 0x11041800, + 0xA8600483, 0x238043A1, 0x11040044, 0xAB000480, + 0x04801104, 0x1104AB01, 0xAB020480, 0x04801104, + 0x1104AB05, 0xAB080480, 0x04801108, 0xAB4EAB09, + 0x04801104, 0x1104AB1A, 0x1B250480, 0x11040002, + 0x1B260480, 0x25560002, 0x11041940, 0xA8400482, + 0x1B288900, 0x89040002, 0x00021B29, 0x1B2A8908, + 0xC6C40002, 0x1CFCC2FA, 0x256FB6C8, 0x8D001243, + 0x017E084F, 0x42C3C1AE, 0x00349018, 0x05001204, + 0x800041C3, 0x1902018C, 0x12040014, 0x19020500, + 0x12040014, 0x19020500, 0x12E00014, 0xB1008500, + 0x6872C808, 0x00802305, 0xB1039000, 0x03002242, + 0x90007865, 0x6A0CB101, 0x90007865, 0xC08CB102, + 0x800041C3, 0x0D320635, 0x764CFB2F, 0x0DAEC08C, + 0x762C0520, 0xD9258D00, 0xB99FB8C3, 0x70041E00, + 0x022C9008, 0x42C38900, 0x01C8901C, 0x891BB200, + 0x11F4B202, 0xE8968080, 0x03000C56, 0x2042C805, + 0xF210803C, 0x20A8700C, 0x20050380, 0x90040F82, + 0x9220028C, 0x000070C3, 0x21444000, 0xB2200301, + 0x902C41C3, 0x91000C98, 0x78259122, 0x001E0815, + 0x71001600, 0x00068000, 0x0F84080D, 0x0C810000, + 0xFC8F0DAA, 0x00000BB6, 0x70801600, 0x011D8000, + 0x0AFAE807, 0xC0AE0300, 0x341B1404, 0x1600C6DA, + 0x80007080, 0x701400F3, 0x00010370, 0x702E700C, + 0x1E00B88C, 0x90077444, 0x43DBC3E8, 0xC83C9007, + 0x70041E00, 0xC3649007, 0x40DBC808, 0x00009000, + 0x20056892, 0x00010F80, 0x24050027, 0x90041F83, + 0x9340083C, 0x16C12405, 0x0F822204, 0xFF780000, + 0x01822285, 0x2405B140, 0x90071F82, 0xC04BC09C, + 0x2005B802, 0xC2450600, 0x9040C048, 0xBAA0C005, + 0x1600B040, 0x90047100, 0xB8A00AB0, 0x70041E00, + 0xCAB09007, 0x20459300, 0xB1A0014D, 0x70801600, + 0x00088000, 0x01002079, 0x2040B802, 0x2B40030B, + 0x0F861240, 0x20960120, 0xC8080208, 0x47CBBDA0, + 0x12228000, 0x22056852, 0xB1A006C1, 0xB7209721, + 0x0F812205, 0x08249004, 0x34401C0C, 0x34401C08, + 0x34401C04, 0x793B9120, 0x0F872184, 0x231F7124, + 0x21551041, 0xC1460DC1, 0x0F812205, 0x01909038, + 0xC14A9120, 0xB962C181, 0x702CC149, 0x202FC144, + 0x28402447, 0x20052312, 0x68520480, 0x900440C3, + 0x22050A80, 0x74040001, 0x43839120, 0x2205B322, + 0x91200001, 0xB3237404, 0x00012205, 0x74049120, + 0x2205B324, 0x91200001, 0xB3257404, 0x208A7A05, + 0x92200FCF, 0x2840B307, 0xB3262380, 0x0F8E2005, + 0x0AB09004, 0x9600C047, 0x0001204F, 0xB8A0B620, + 0xC007B600, 0x0F802005, 0x03549004, 0x090BC10A, + 0x9000027F, 0x140C781D, 0x7D103107, 0x3106140A, + 0x1404740C, 0x41C33103, 0x0007005A, 0x31051408, + 0x14064202, 0x240A3117, 0x0AF605C0, 0xC540FDAF, + 0x16D5255F, 0x30141424, 0x702F706E, 0x29012D85, + 0x15562502, 0x23552500, 0x21001402, 0x71021600, + 0x00068000, 0x0A11791B, 0x00000F85, 0x0D2D0C80, + 0xF0201045, 0x03440925, 0x30100915, 0x21011400, + 0x0D197822, 0x08152002, 0xF0140582, 0x05C0200E, + 0x20020D09, 0x058308EF, 0x2179D95D, 0x0F9A3100, + 0xB910FB2F, 0x72867127, 0xB17409B1, 0x756E7166, + 0x2205C808, 0x00012F86, 0x2005020F, 0x20050481, + 0xB9020180, 0x2105B802, 0x90040F81, 0x19000AB4, + 0xD99C04C4, 0x70441E00, 0xC3649007, 0x2005C10B, + 0x21050600, 0xB9020481, 0x060B2105, 0x11091300, + 0x1001214F, 0x10441B00, 0x256C90A0, 0xB9801041, + 0x0DC6B020, 0xC0060120, 0x10002150, 0x1B00BDA0, + 0xC8081004, 0x01812005, 0x2105B902, 0xB1A00601, + 0x214F9620, 0xB6400002, 0xB620B9A0, 0x04812005, + 0x2105B902, 0x90040F82, 0xC1070ABC, 0x0F812105, + 0x03589004, 0xB2209120, 0x080D8F23, 0x218C2065, + 0xF4118FC3, 0x20610815, 0x8F258F44, 0x72304150, + 0x21CAC104, 0xF00A006D, 0x2084080F, 0x080B8F25, + 0x71262045, 0x712CF003, 0xC104C144, 0xF3117034, + 0x706EF003, 0xC108F196, 0x91A0B802, 0x254FC105, + 0xB1401002, 0x06C12005, 0x0F802005, 0x083C9004, + 0x266C90C0, 0xB8801040, 0x0D1EB100, 0xC0060120, + 0xBDA0C005, 0xB0A0BEA0, 0xB802C808, 0x06C12005, + 0x8FA0B1C0, 0x8F017AAF, 0x04CA7210, 0x40C3FFCD, + 0x12D98000, 0x08418800, 0x2A4000AE, 0x2405038C, + 0x90041F80, 0x90600354, 0x2353C808, 0xB8020201, + 0x20057885, 0x90380F8C, 0x9400021C, 0x0F802004, + 0xFE000000, 0x41C37825, 0x00020062, 0x0922B400, + 0x740CFDAF, 0xF1D871A5, 0x800041C3, 0x9100018A, + 0x8701113E, 0xF7877110, 0xFC8F0C2A, 0x04807014, + 0x0463FFC1, 0x78E0FFCF, 0xC808C2E6, 0x21056832, + 0x90070F80, 0x2105C83C, 0x90040F81, 0x9120083C, + 0x0F812104, 0xFF780000, 0x01812145, 0x1600B020, + 0x80007087, 0x0E5A0005, 0x710C0320, 0x47CB712D, + 0x0084900C, 0x0F9574CC, 0x1F000030, 0x700C1244, + 0x01200CD2, 0x702C742C, 0x901840C3, 0xB7200008, + 0x02441800, 0x824418FC, 0x70441E00, 0x0C40902C, + 0x804418F8, 0x009840C3, 0x0CAA9680, 0x46280120, + 0x47CBD833, 0x08009008, 0x45CBB700, 0x02889008, + 0x0C06D820, 0xB5C00120, 0x900743CB, 0x1D58C11C, + 0x208A9244, 0x1B000010, 0x1B001145, 0x234F1184, + 0x1B0014CB, 0x1B001145, 0x1D001184, 0x0BDA1085, + 0x1D580120, 0x700C9384, 0xB5C0D920, 0x01200C56, + 0x1B0CB7C0, 0xF0659244, 0x01200BBE, 0x46CB740C, + 0x00189018, 0x950016F0, 0x2004702C, 0x00000F80, + 0x1E00FDFF, 0x901B7004, 0x40C3C018, 0x4240000F, + 0xB7204528, 0x4708B620, 0x70441E00, 0x0C40902C, + 0x90441EFC, 0x90441EF8, 0x01200C0A, 0x10C51E04, + 0x78FD720D, 0x0BFE702C, 0x1E040120, 0x702C1204, + 0x009840C3, 0x0BEE9680, 0xB6A20120, 0x900843CB, + 0x47C301E0, 0xC11C9007, 0x12441B00, 0x1F00D833, + 0x47CB0145, 0x08009008, 0x01841F00, 0x04C7274F, + 0x1A8E2355, 0x01451F00, 0x01841F00, 0x760CB700, + 0x01200B26, 0x700CB6A0, 0x000041C3, 0x1B002710, + 0x0BA21204, 0x1E000120, 0x700C1204, 0x1B00D920, + 0xB6A01344, 0x01200B8E, 0x1F0CB7A0, 0x0CB68244, + 0x710C01E0, 0x01200AF2, 0x46CBD878, 0xC11C900F, + 0x14CF2650, 0x1E00710C, 0x1E001185, 0x1F001105, + 0x08D61185, 0x1F0000E0, 0x0EF21105, 0x208AFDCF, + 0x45CB0D07, 0x03E09008, 0x0B4AD920, 0x1D000120, + 0x700C1045, 0x1EB2B88C, 0xD820101C, 0x101D1F84, + 0x01200AA6, 0x10051D00, 0x78E0C6C6, 0x78E07EE0, + 0x78E07EE0, 0x16007A1B, 0x80007080, 0x7859001C, + 0x7FE07839, 0x78E0B8C0, 0x2079C2F0, 0x43500050, + 0x45CB4728, 0x11DA8000, 0x03200ECA, 0x204E2014, + 0x66A8704E, 0x20250A2B, 0x20166F14, 0x70420400, + 0x60A9E024, 0x084ED880, 0x41300360, 0x23912940, + 0x21057146, 0x90042F81, 0xB1000230, 0x40C3F1EB, + 0x4E200000, 0x01200ABE, 0x66A8702C, 0x21D3234F, + 0x702EE82B, 0x20166F14, 0x70220400, 0x60A9E024, + 0x08124062, 0x42300360, 0x23942A40, 0x2F812405, + 0x02309004, 0x0A66B100, 0x740C0120, 0x2FC7228A, + 0x2F802405, 0x02249004, 0x04841800, 0x01200A4E, + 0x2405740C, 0x90042F80, 0x1800022C, 0x71260484, + 0x09B566A8, 0xD90CA004, 0x000040C3, 0x0A561388, + 0x44100120, 0xE81A66A8, 0x2213234F, 0x6F14704E, + 0x04002016, 0xE0247042, 0x406260A9, 0x03200FA6, + 0x29404130, 0x71462391, 0x2F812105, 0x02309004, + 0x66A8B100, 0xA0040ADB, 0x0A1A4082, 0xD90C0120, + 0xE82666A8, 0x6F14702E, 0x04002016, 0xE0247022, + 0x208A60A9, 0x0F6E0006, 0x42300320, 0x23932A40, + 0x2F812305, 0x02249004, 0x09C2B100, 0x740C0120, + 0x0006208A, 0x03200F4E, 0x23054142, 0x90042F81, + 0xB100022C, 0x66A87126, 0xA00409BF, 0x000340C3, + 0x09C2D090, 0x702C0120, 0x03000DC2, 0x78E0C6D0, + 0x1CFCC2FA, 0x2482B6C8, 0x702C3211, 0xFCEF099A, + 0x1207C045, 0xC0443091, 0xC051700C, 0xC04FC050, + 0xC04DC04E, 0xFF2F082E, 0x47CBC04C, 0x12228000, + 0x40108F61, 0x0B338F20, 0x750C0064, 0x70801600, + 0x000C8000, 0x700CB8E3, 0x2100F208, 0x101C0680, + 0x20780080, 0xB8080000, 0x70422614, 0x048C8000, + 0xB2007124, 0xC205F1E9, 0x03F246CB, 0x0D220001, + 0x41C1FD6F, 0xFDEF0FEA, 0x45CBC005, 0x01268000, + 0x264F8D40, 0x0D0A1401, 0x740CFD6F, 0x214A7036, + 0x8D003480, 0x33E121CA, 0xF491B8E0, 0x712EC005, + 0x41C3C204, 0x000103F5, 0x20002900, 0x0CE268D2, + 0x740CFD6F, 0x712CC004, 0xFC6F0EC6, 0x0D9E704C, + 0x0EAEFE0F, 0x0CB2FB4F, 0x0C8A0300, 0x700C0300, + 0xFBAF0FCA, 0x1600712C, 0x80007082, 0x22780008, + 0x68210080, 0x71001600, 0x0510901C, 0x2044C047, + 0x20002040, 0x1E002003, 0x901C7044, 0x0A0F0510, + 0x218A00B0, 0x218A0048, 0xC0050090, 0x1010260F, + 0x2340C808, 0xB802078E, 0x0F822005, 0x04F8901C, + 0x0F802005, 0x04F4901C, 0x714CB220, 0x712CB020, + 0x71001600, 0x0508901C, 0xB887C048, 0x70041E00, + 0x0508901C, 0xFC6F0E3A, 0x0C62C004, 0x4210FB4F, + 0x000040C3, 0x08B2FFFF, 0x41000320, 0x208A7056, + 0xD9FF0FC7, 0x0EA6711C, 0x710C02E0, 0x70801600, + 0x000C8000, 0x00DF080D, 0x74441E00, 0xC2D49007, + 0x1E00D80F, 0x901F7085, 0x1E00C040, 0x90077085, + 0x08B2F880, 0xD90FFCAF, 0x0240093A, 0x0A9278CF, + 0x212F0060, 0x8D000407, 0x00FF0821, 0x1410C092, + 0x0205301B, 0x23400020, 0xD9FD3A9B, 0x0BD2D80A, + 0xB912FD6F, 0x00000425, 0x0BE6702C, 0x228AFAEF, + 0xC3050010, 0x714C740C, 0x03F941C3, 0x1C2C0002, + 0x0BAE3FC1, 0x1C28FD6F, 0x8FA03FC1, 0x1410700E, + 0x2340301B, 0x232F3A9B, 0x238C0408, 0x00A68FDF, + 0xC808000D, 0x20058FC1, 0x689206C0, 0x13640E23, + 0x13802D40, 0xB8927885, 0xB89FB89C, 0xC28AEB85, + 0x7AB49020, 0x1800B220, 0x71A50404, 0x08A6F1F0, + 0xD80F0240, 0xFCAF080E, 0x700CD90F, 0xFBAF0E5E, + 0x8F01712C, 0x085B8FA0, 0x78A20364, 0x6821714C, + 0x2F832004, 0xFFF80000, 0x20802053, 0x7A18BB23, + 0x7040240A, 0x20A843A9, 0x26F40740, 0x800072C0, + 0x6832048C, 0x13802B40, 0x2B407825, 0x20051201, + 0x90040F80, 0x908002DC, 0x6038C092, 0x60797095, + 0x20C58900, 0xF4030082, 0x71657846, 0x7106A900, + 0x700EF1AB, 0x08DD8F01, 0x42A10364, 0x03FA41C3, + 0x0ADE0001, 0x740CFD6F, 0x09B9702E, 0x00002F85, + 0x218B0800, 0x1C0CA803, 0x1C083400, 0xF4123400, + 0x28002156, 0x21822941, 0x0F802004, 0xFFC00000, + 0x41C3B826, 0x000203FB, 0x0AA66869, 0x740CFD6F, + 0x70CCDB08, 0xC48270CD, 0x64DC700C, 0x00892653, + 0x7100244A, 0x200A736D, 0x1C001440, 0x20A81003, + 0x2D4004C0, 0xC2921201, 0x2841623A, 0x710510C1, + 0x29016229, 0x71250241, 0x2900B9C0, 0x776502C1, + 0x26527825, 0x74260086, 0x238D71C5, 0xAC0007FF, + 0x3087140D, 0x3085140B, 0x3086140C, 0x3084140A, + 0x1409C222, 0x140E3083, 0x140F3081, 0xC1403080, + 0x03FC41C3, 0xC0410008, 0xFD6F0A26, 0xF1A7740C, + 0x03FD41C3, 0x0A1A0000, 0x740CFD6F, 0xF19471A5, + 0x08318F20, 0x78220064, 0xC8086861, 0x06C02005, + 0x70C0240A, 0x20A86852, 0xC08A0380, 0x004320F4, + 0x03802940, 0x71247845, 0xB89CB892, 0xB060B89F, + 0x02000F22, 0x03FE41C3, 0x09D60000, 0x740CFD6F, + 0x42D3700C, 0x00009000, 0x202FC046, 0xC0498648, + 0x1600F2F2, 0x80007080, 0x0817000C, 0x700C00FE, + 0xFBAF0CBA, 0xD80F712C, 0xFC6F0E5A, 0x700CD90F, + 0xFBAF0CAA, 0x8FC0712C, 0x76108F01, 0x002D01AA, + 0x2440D80F, 0x27143C17, 0x17002397, 0x70142100, + 0x2614F4C9, 0x80007395, 0x2E40048C, 0x24401301, + 0x15003E11, 0x21052100, 0x00010F98, 0x200500B7, + 0x21050600, 0xB80206C1, 0x23912114, 0x04802005, + 0x2490224F, 0xC8089040, 0x78254350, 0x20841900, + 0x2005B802, 0xC0902010, 0x21141000, 0x03962014, + 0x21001600, 0x0B3FE80E, 0x740C2031, 0x03FF41C3, + 0x42C10002, 0x091A4382, 0x1F00FD6F, 0xF0932045, + 0x20110B23, 0x7014CA07, 0x20CAD812, 0xC10903E1, + 0x00610813, 0x740C702C, 0xFD6F08F6, 0x710CB99A, + 0x2453C046, 0x24AD214D, 0x740C2982, 0x040141C3, + 0x42C10004, 0x44A14382, 0xFD6F08D6, 0x04C0250A, + 0x20812440, 0x20056916, 0xCA070353, 0xD8227014, + 0x072120CA, 0x004508C3, 0x08B3C006, 0x16000010, + 0x80007080, 0x29090008, 0xF2518014, 0x040241C3, + 0x089E0000, 0x740CFD6F, 0xD90FD80F, 0xFC6F0D46, + 0x23441800, 0x02000DCE, 0x41C3740C, 0x00030403, + 0x706C42C1, 0xFD6F087A, 0x160044A1, 0x80007080, + 0x0817000C, 0x700C00FE, 0xFBAF0B72, 0xD80F712C, + 0xFC6F0D12, 0x700CD90F, 0xFBAF0B62, 0x1500712C, + 0x20052100, 0xB8020600, 0x04802005, 0x19009000, + 0xE8132004, 0x21842C40, 0x2405740C, 0x41C30344, + 0x00030404, 0x438242C1, 0xFD6F0826, 0x21041800, + 0x20451F00, 0x740CF017, 0x040541C3, 0x42C10003, + 0x080E706C, 0x44A1FD6F, 0x41C343B1, 0x00000406, + 0xFAEF0D06, 0x1800700C, 0x110024C4, 0x1E002100, + 0x71C52004, 0x0C9EF12A, 0xD90FFC6F, 0x02200D26, + 0xF10D7727, 0x1E00C007, 0x901C7004, 0xC0080510, + 0x70041E00, 0x0508901C, 0xFE4F0816, 0x702CC004, + 0xFC6F09AE, 0x41C3704C, 0x00000407, 0xFD2F0FB2, + 0x0A7E750C, 0xC005FDEF, 0x32112480, 0x341B1404, + 0x78E0C6DA, 0xC1A4C3E8, 0x800046CB, 0x8EA11220, + 0x40D371ED, 0x4E748001, 0x40027014, 0x7FB8D912, + 0x083EF209, 0x400202C0, 0x0D4AD912, 0xDA800060, + 0x09B6F003, 0x0EFA0240, 0xC08002E0, 0x0BDAC080, + 0xD912FDEF, 0x259F8E00, 0x209F12C1, 0x704C0582, + 0x708CC380, 0x6F12651D, 0x250078E5, 0x0A7E1401, + 0x780F04A0, 0x000040C3, 0x0B5A4E20, 0x702C00E0, + 0x78E0C7C8, 0x2482C3F2, 0x44103104, 0x702CC081, + 0xFAAF0F3E, 0x0004228A, 0x800045CB, 0x8D401220, + 0x20502479, 0x22102040, 0xA0432442, 0x41C3750C, + 0x00030150, 0xFD2F0EFA, 0x0400240A, 0x24408DA0, + 0xC8083081, 0x7D05BD0C, 0xFCAF0A82, 0x46084082, + 0x1F802505, 0x00D90003, 0x0E6AD940, 0x43100460, + 0x02200BBE, 0x1402BE68, 0x7FD03102, 0x41E14082, + 0x0BEA41F1, 0x4250FB2F, 0xD955E806, 0x0BBA700C, + 0xB912FAEF, 0x22002840, 0x7D0570CD, 0x800047CB, + 0x25050484, 0x00031F95, 0x7DD000D8, 0x9FC3258C, + 0x40A2F712, 0x04600E1E, 0x0B7641A1, 0x40820200, + 0x0BAA4122, 0x4242FB2F, 0x61B9C181, 0x8F00A900, + 0xF1ED661E, 0x0DFE40A2, 0x702C0460, 0x20802B40, + 0xB89C70AD, 0x0B4AB89F, 0xB0A00220, 0x015741C3, + 0x0E4E0000, 0x740CFD2F, 0x21C22042, 0x41C3740C, + 0x00020158, 0xFD2F0E3A, 0x8F804302, 0x7200244A, + 0x706C704C, 0x030020A8, 0x659EC081, 0x224E60A9, + 0x714401C0, 0x290045C9, 0x7B050000, 0x41C37A6F, + 0x00010159, 0xFD2F0E0A, 0x268C740C, 0x45C99004, + 0xD9ADF6A5, 0x0DFA740C, 0xB911FD2F, 0x700C8F40, + 0x8FC3208C, 0xC181F707, 0x70346109, 0x008120C0, + 0x2080F3F8, 0x7E0E003F, 0x9004268C, 0x41C3F688, + 0x0000015B, 0xFAEF0AD2, 0xF009700C, 0x41C3740C, + 0x0001015C, 0xFD2F0DBA, 0x40C342C1, 0x01258000, + 0x6D2988A0, 0x0114090B, 0x180074AD, 0x740C0103, + 0x015D41C3, 0x0D9A0001, 0x42A1FD2F, 0x740CBD05, + 0x015E41C3, 0x0D8A0001, 0x42A1FD2F, 0x780E4EB0, + 0x78E0C7D2, 0xC1A4C3E2, 0x800145CB, 0x40A14E74, + 0x02A00E2E, 0x40A1D910, 0x0B3AD910, 0xDA410060, + 0xD91040A1, 0xFBEF0942, 0x40A1DAF3, 0x02A00E12, + 0x40A1D929, 0x0932D929, 0xDA1FFBEF, 0x0E0240A1, + 0xD90B02A0, 0xD90B40A1, 0xFBEF091E, 0x40A1DAF0, + 0x02A00DEE, 0x40A1D912, 0x0AFAD912, 0xDA080060, + 0xD91240A1, 0xFBEF0902, 0x0CA6DAF8, 0xC08002E0, + 0x0986C080, 0xD910FDEF, 0x097EC080, 0xD929FDEF, + 0x0976C080, 0xD90BFDEF, 0x096EC080, 0xD912FDEF, + 0x0966C080, 0x732CFDEF, 0x095EC080, 0xD911FDEF, + 0x0956C080, 0xD912FDEF, 0x70801600, 0x01318000, + 0x0071080D, 0x0942C080, 0xD913FDEF, 0x702C40A1, + 0xDBFFC280, 0x04A00C56, 0x40C3708C, 0x4E200000, + 0x00E008D2, 0x40A1702C, 0x02200EEE, 0x40A1D929, + 0x02200EE6, 0x40A1D90B, 0x02200EDE, 0xC7C2D912, + 0xC1A2C3EC, 0x800145CB, 0x41304D64, 0xD8644010, + 0x254070CD, 0xB5001312, 0xC640C641, 0x731478CF, + 0x000D00F0, 0x20100919, 0x00D00829, 0x0050081F, + 0x00900829, 0xD87FE896, 0xF01EB808, 0x00D0082D, + 0x00500831, 0x0090080D, 0xD87FE898, 0xF014B810, + 0x7F0040C3, 0xF0107F7F, 0x7F7F40C3, 0xF00C007F, + 0x700CD989, 0xF00EB911, 0x007F40C3, 0xF0047F7F, + 0xB818D87F, 0xF008C040, 0x41C3700C, 0x00000119, + 0xFACF0916, 0x15001502, 0x0A02B802, 0x7810FBAF, + 0xD907D841, 0xDA08B813, 0x708C706C, 0x0F4E70AC, + 0x70CCFB6F, 0x742C700C, 0xFBAF0A36, 0xC080714C, + 0x098E4102, 0x724CFBAF, 0xD914700C, 0xFBAF0A22, + 0x706C714C, 0x4060D907, 0xB892744C, 0x70AC708C, + 0xFB6F0F1A, 0x160070CC, 0x80007080, 0x0811000C, + 0x700C003E, 0x09FAD914, 0x714CFBAF, 0xD907D880, + 0xDA08B893, 0x708C706C, 0x0EF270AC, 0x70CCFB6F, + 0xFB0F0D56, 0x7704B500, 0x20141A02, 0xF18871C5, + 0x78E0C7CC, 0x4608C2E8, 0x70801600, 0x000C8000, + 0x47284050, 0x8E00204B, 0x40C3F2B7, 0x12208000, + 0x20812078, 0x219F8800, 0x209F02C1, 0x61190582, + 0x0F8F2132, 0x4E868001, 0xFB0F0D26, 0xD907706C, + 0x744C4568, 0x708CBD9A, 0x70AC40A1, 0xFB6F0E8E, + 0x43E170CC, 0x238540A1, 0x762C0201, 0x244A744C, + 0x250A0480, 0x0E760400, 0x70CCFB6F, 0xD90740A1, + 0x706C744C, 0x70AC708C, 0xFB6F0E62, 0x0FC1268A, + 0xFB8F0906, 0x13C0254F, 0x744CD907, 0x708C706C, + 0x0E4A70AC, 0x70CCFB6F, 0xD90740A1, 0x706C744C, + 0x70AC708C, 0xFB6F0E36, 0x03C0264A, 0xD9077EBD, + 0x744C40C1, 0x708C706C, 0x0E2270AC, 0x70CCFB6F, + 0xD90740A1, 0x706C744C, 0x70AC708C, 0xFB6F0E0E, + 0x0FC3268A, 0xD90740C1, 0x706C744C, 0x70AC708C, + 0xFB6F0DFA, 0x40A170CC, 0x744CD907, 0x708C706C, + 0x0DEA70AC, 0x268AFB6F, 0x40C10FC3, 0x744CD907, + 0x708C706C, 0x0DD670AC, 0x70CCFB6F, 0xD90740A1, + 0x706C744C, 0x70AC708C, 0xFB6F0DC2, 0x0FC3268A, + 0x1480254F, 0x744CD907, 0x708C706C, 0x0DAE70AC, + 0x71CCFB6F, 0xFB8F083A, 0xD90740A1, 0x706C744C, + 0x70AC708C, 0xFB6F0D96, 0x40A173CC, 0x744CD907, + 0x708C706C, 0x0D8670AC, 0x268AFB6F, 0x40A10FC1, + 0x744C762C, 0x244A43E1, 0x250A0480, 0x0D6E0400, + 0x70CCFB6F, 0xD90740A1, 0x706C744C, 0x70AC708C, + 0x0FC0264A, 0x0BDAF03F, 0x700CFB0F, 0x744CD907, + 0x708C706C, 0x0D4670AC, 0x70CCFB6F, 0xFB4F0FEA, + 0xD907706C, 0x724C4568, 0x708CBD99, 0x70AC40A1, + 0xFB6F0D2A, 0x700C70CC, 0x42C1D907, 0x708C706C, + 0x0D1A70AC, 0x70CCFB6F, 0xBD2D740C, 0x712CB892, + 0x43A142E1, 0x70AC708C, 0xFB6F0D02, 0x6D1370CC, + 0xDA0CD907, 0x708C706C, 0x0CF270AC, 0x71CCFB6F, + 0xFB4F0F7E, 0xD907700C, 0x706CDA10, 0x70AC708C, + 0x0CDA70CC, 0xD880FB4F, 0x744CD907, 0x708C706C, + 0x0CCA70AC, 0x70CCFB6F, 0x78E0C6C8, 0x4510C2F4, + 0x71001600, 0x0508901C, 0x20534330, 0xF4098196, + 0x03E641C3, 0x094A0000, 0x740CFD2F, 0x265F71CE, + 0x2E4020CF, 0x710C2094, 0x200E241F, 0x93A50FFD, + 0x0B0E7104, 0x740CFB0F, 0x03E741C3, 0x09220001, + 0x42C2FD2F, 0xFB4F0F22, 0x2280265F, 0x704CD907, + 0x708C706C, 0x770470AC, 0x2007212F, 0x0C5E700C, + 0x260AFB6F, 0x6F010440, 0x7B0F702C, 0x0986D807, + 0x704C0020, 0x000045CB, 0x232F12C8, 0xD81D0580, + 0x426241A1, 0x0020096E, 0xD81E4270, 0x426241A1, + 0x00200962, 0xD81F4342, 0x426241A1, 0x00200956, + 0xD8204342, 0x704C41A1, 0x0020094A, 0x78F24342, + 0x661E702C, 0x7BCFD807, 0x093A704C, 0x40700020, + 0xD907700C, 0x706C704C, 0x70AC708C, 0xFB6F0BEE, + 0x0440260A, 0x20402242, 0x262FD907, 0x700C0007, + 0x706C744C, 0x0BD6708C, 0x70ACFB6F, 0x710CDD08, + 0x082A41C2, 0x4262FBAF, 0x41C2700C, 0xFBAF081E, + 0x258C4262, 0x700C1DFF, 0xDA5CD907, 0x708C706C, + 0x70CC70AC, 0xFB6F0BA6, 0x708C71CE, 0x458874CD, + 0xBD8CBE92, 0xD92E40C1, 0x43A142A2, 0x0B8E70AC, + 0x70CCFB6F, 0xD92F40C1, 0x43A142A2, 0x70AC708C, + 0xFB6F0B7A, 0x6D1370CC, 0x744CD907, 0x708C706C, + 0x0B6A70AC, 0x71CCFB6F, 0x0540202F, 0x0C8D2054, + 0x2580241F, 0x08FD46CA, 0x71C68364, 0xD907700C, + 0x706C704C, 0x70AC708C, 0xFB6F0B42, 0x0440260A, + 0x1500261E, 0x704C702C, 0x671F78A2, 0x7B0F6F01, + 0x00200862, 0xDD25D807, 0xBD07D81D, 0x41A14262, + 0x00200852, 0xD81E4342, 0x426241A1, 0x00200846, + 0xD81F4342, 0x426241A1, 0x0020083A, 0xD8204342, + 0x704C41A1, 0x0020082E, 0xD8074342, 0x704C702C, + 0x00200822, 0x700C4302, 0x704CD907, 0x708C706C, + 0x0ADA70AC, 0x260AFB6F, 0x0D660440, 0xC6D4FB4F, + 0x4648C2E8, 0x40104728, 0x6B09EB0F, 0x68A1780F, + 0x4102700C, 0x43E1704C, 0x45C1708C, 0xFB6F0AAE, + 0x258C70CC, 0xC6C81E3F, 0x4050C2E8, 0x47CB4528, + 0x04988000, 0x8703E81B, 0xE8877104, 0x71001600, + 0x025C9004, 0x720CA703, 0x900746CB, 0x0B1EC25C, + 0x1E0000A0, 0x16001005, 0x80007080, 0x2053000C, + 0xF223817E, 0x90051ECC, 0xC808F021, 0x46CB70AD, + 0xC3EC9007, 0x21056832, 0x903B0F80, 0xB0A0C02C, + 0x268079C5, 0xD8141939, 0x0A7EB1A0, 0xB6A000A0, + 0x90451E2C, 0x93441ED8, 0x93441ED4, 0xB6068703, + 0x93441EE0, 0x1ECCC6C8, 0x740C9344, 0x900746CB, + 0x0ABAC224, 0xB6A000A0, 0x10051E08, 0x20300819, + 0x90051E58, 0x20710823, 0x1E00700C, 0x90077285, + 0xF010C254, 0xB802C808, 0x0F802005, 0xC3EC9007, + 0x00451800, 0x41C3F006, 0x0000034D, 0xFA8F0B8A, + 0x74041E00, 0xC2509007, 0xB802C808, 0x0F802005, + 0xC02C903B, 0x00851800, 0x78E0C6C8, 0xC1A2C3F2, + 0xB99FD925, 0x1C068900, 0x891B3002, 0x30021C07, + 0x800040C3, 0x88201224, 0x8822C161, 0x30421C05, + 0x88038821, 0x30421C02, 0xFEAF0896, 0x30021C03, + 0x70ED4110, 0x218121AD, 0x0FA9714E, 0x2A001465, + 0x70CD23D5, 0x0E99C806, 0x24401005, 0x60C83180, + 0xA000250B, 0x2714F242, 0x700E1380, 0x20142A00, + 0x30802440, 0x03932032, 0x60CDC081, 0x0B6D78AF, + 0x78CF2024, 0xFF6F0EF2, 0x6E3479EF, 0x800042C3, + 0xE81311DE, 0x20402040, 0x03C32116, 0x6D817910, + 0x61596179, 0x03021920, 0x0408212F, 0x61596179, + 0x03421920, 0x232FF016, 0x79F60408, 0x16006179, + 0x80007080, 0x240B0121, 0x6D01A000, 0xF2066159, + 0x00021920, 0xF005A9A0, 0x1920A900, 0x40020342, + 0x204072A5, 0xF1CC0050, 0xF1B671C5, 0xF1AF71E5, + 0x78E0C7D2, 0xDB24C2E6, 0x800042C3, 0xBB9F1224, + 0x00031A00, 0xE0078B00, 0x00C12841, 0x69898B1C, + 0xE80FAA81, 0x791DC805, 0x70801600, 0x003F8000, + 0xB9C6E007, 0xAA22B823, 0x68C96038, 0x4689F003, + 0x12B5AA22, 0x788F008D, 0xAAC37104, 0x7000240A, + 0x20A8770C, 0x71040180, 0x100D250F, 0x42C378CF, + 0x12D98000, 0x0064081B, 0x7822AAA0, 0x240A7104, + 0x20A87000, 0x250F0180, 0x7124104D, 0x70ADAAA0, + 0x800044CB, 0x0D4311DA, 0x408910B5, 0x706D70CD, + 0x0B3179AF, 0x70751095, 0x20CA4060, 0x80000F82, + 0x88E0003F, 0xFF6F0DE2, 0xE80578CF, 0xB8236F07, + 0x4F1FF003, 0x1802B824, 0x71C51012, 0xF1EB7165, + 0x71A57185, 0xC6C6F1E1, 0x0A22C0F1, 0xC0D10100, + 0x700C7FE0, 0xE9058840, 0x001F0A0B, 0xBAE07EE0, + 0x88217DE0, 0xF78AE1C0, 0x20E07354, 0x218007CD, + 0xA821003F, 0xF0086A21, 0x7CE07054, 0x08012154, + 0x6A29A821, 0xA8207FE0, 0x0443216F, 0x11FE8940, + 0x229F8101, 0x790C041F, 0x00802905, 0x71047FE0, + 0x2482C3F4, 0x16003302, 0x80007080, 0xB8C30004, + 0x800047CB, 0x205F1220, 0x41C30B16, 0x0000013F, + 0x2700702E, 0x18081580, 0x0C360001, 0xD80AFCEF, + 0xFF8F0EB6, 0x800042D3, 0x202F1138, 0x24400448, + 0x24403181, 0x08823142, 0x2440FEAF, 0x701431C3, + 0x1407F4E3, 0x0F763080, 0x1A00FD6F, 0x14052043, + 0x712C3080, 0xFDAF0966, 0x70AD4310, 0x712C4062, + 0x0F62704C, 0x1A00FFAF, 0x14062342, 0xC1823080, + 0x716C724C, 0x0A0A708C, 0x4010FAAF, 0x702CC083, + 0xFA6F0BEE, 0x258ADA80, 0x708E2002, 0x8F2070CD, + 0x0507222F, 0x0CD64062, 0xC540FF6F, 0xC1804002, + 0x716C724C, 0xFAAF09DA, 0x1401708C, 0x20533080, + 0xF20681BE, 0x60D8C083, 0x00431800, 0x258D7186, + 0x71C52A7F, 0x740C8F60, 0x014141C3, 0x0B820002, + 0x4202FCEF, 0xDE8070AD, 0x41C3C083, 0x00010142, + 0x0B6E60AA, 0x740CFCEF, 0x1E3F268D, 0x41C371A5, + 0x00000143, 0xFCEF0B5A, 0x248A740C, 0x77AD7002, + 0x776D700C, 0x20A8776C, 0xC1830740, 0x610977B5, + 0xE0FFF207, 0xE914F202, 0x6829E906, 0xE98FF005, + 0xF00E4508, 0x2302D97F, 0x49B210CC, 0x25CA7291, + 0x21CA10CC, 0x43A102CC, 0x77AD4328, 0x77747104, + 0x77B5F404, 0xF404DE7F, 0x46694568, 0x41A18F60, + 0x21B94EB0, 0x207F0FFF, 0x78240100, 0x014541C3, + 0x0FF60002, 0x4202FA6F, 0x41C366B8, 0x00030146, + 0x00942844, 0x42A1740C, 0x0AD643C1, 0x240AFCEF, + 0x8F200500, 0x843E2105, 0x26144620, 0x70022040, + 0x180860F8, 0xF20B0502, 0x2011081D, 0x00510E19, + 0x75021E00, 0x004E8000, 0x1E00F013, 0x80007502, + 0xF00F0033, 0x20510813, 0x00110E0F, 0x75021E00, + 0x00348000, 0x1E00F005, 0x80007502, 0x242F004F, + 0x250A0507, 0x245F0400, 0x20540140, 0x78300C81, + 0x02822845, 0x209E4040, 0x60380DBF, 0x014741C3, + 0x7B100005, 0xFCEF0A5A, 0x4062750C, 0x0946702C, + 0x1A00FDEF, 0x71262043, 0x0448202F, 0x061E7414, + 0x40C3FFC5, 0x12D88000, 0x00431800, 0x78E0C7D4, + 0x88606038, 0xA8607B45, 0x0083104B, 0x184B7B45, + 0x109600C2, 0x7B450083, 0x00C21896, 0x008310E1, + 0x7FE07A65, 0x008218E1, 0x2482C3EA, 0x266F3206, + 0xC0801243, 0xFF2F0812, 0x10901600, 0x800140C3, + 0x88404E77, 0x7A058813, 0x30811403, 0x30801416, + 0x78477825, 0x01BE080B, 0x0C2E700C, 0x256F03C0, + 0x150016C3, 0x081110C0, 0xC0800032, 0x0DAAD913, + 0xDAF3FB6F, 0x3BC02456, 0xFD6F0D16, 0x20D02053, + 0x3BC02456, 0x02A00946, 0xC080D90B, 0xDA45D910, + 0xFFEF0F72, 0x30112440, 0x3BC02456, 0x02A0092E, + 0x2456D946, 0x09263BC0, 0xD94702A0, 0x3BC02456, + 0x02A0091A, 0x2456D948, 0x09123BC0, 0xD94902A0, + 0x3BC02456, 0x02A00906, 0xCA0ED94A, 0x47CB704C, + 0x12208000, 0x00050A31, 0x2B01205F, 0x0F832232, + 0x04788000, 0x79557322, 0x673F7144, 0xAB208F28, + 0x1B968F2A, 0x8F290042, 0x00421B4B, 0x1BE18F2B, + 0xF1E70042, 0x3BC22456, 0x712CC080, 0x08BEDBFF, + 0x708C0460, 0xD910C080, 0xFB6F0CFE, 0x8D00DABC, + 0x005E0815, 0x08118E00, 0xC080017F, 0x0ED6D910, + 0xDA40FFEF, 0x02A0088A, 0x3BC02456, 0x3BC02456, + 0xFD6F0D66, 0xC027D910, 0x017F0819, 0xD91CC080, + 0xFFEF0EB2, 0x2456724C, 0x0D4E3BC0, 0xD91CFD6F, + 0x3BC22456, 0x702CC080, 0x0862DBFF, 0x708C0460, + 0x080F8D00, 0x8E00005E, 0x0ADCB8E5, 0x08A2FEC1, + 0x0A8EFCCF, 0x8D00FACF, 0xF29EB8E1, 0xB8E58E00, + 0x096AF49A, 0x0882FD8F, 0xD8100280, 0x0FC2D940, + 0xDA0FFB2F, 0x762C700C, 0xFB2F0ED6, 0x8F20714C, + 0x0582219F, 0x100017BC, 0x88216038, 0x00DF090D, + 0x20538814, 0xF23580FE, 0x2400702C, 0x00003F80, + 0x087E012C, 0xDA4BFA6F, 0x3A002456, 0x02A00816, + 0x00831800, 0x0B56700C, 0x712CFB2F, 0xFACF0A22, + 0x02800826, 0x752C700C, 0xFB2F0E86, 0x40C3714C, + 0x3A980000, 0x00600C4E, 0x0D0A742C, 0x710C0120, + 0x3F802400, 0x012C0000, 0x02800966, 0x000340C3, + 0x0C320D40, 0xD9080060, 0x01200D5A, 0xD810710C, + 0x0F2E702C, 0xDA0FFB2F, 0x762C700C, 0xFB2F0E42, + 0x700C714C, 0x704CD932, 0x708C706C, 0x0B3E73AC, + 0x70CCFB2F, 0xD933700C, 0x706CDA20, 0x73AC708C, + 0xFB2F0B2A, 0x700C70CC, 0x0E16762C, 0x714CFB2F, + 0xD938D811, 0xFB2F0EEA, 0x700CDA0F, 0x0E02D907, + 0x714CFB2F, 0xD930700C, 0x706C704C, 0x73AC708C, + 0xFB2F0AFA, 0x700C70CC, 0x704CD931, 0x708C706C, + 0x0AEA73AC, 0x70CCFB2F, 0x762C700C, 0xFB2F0DD2, + 0x0F42714C, 0x700C0240, 0xFB2F0A82, 0x0FC2712C, + 0xF027FD8F, 0xDA20D825, 0x706CB89F, 0x70CC708C, + 0x881B8820, 0xD90B7825, 0x00452053, 0xFB2F0AAE, + 0x700C700C, 0x724CD928, 0x708C706C, 0x0A9E73AC, + 0x70CCFB2F, 0xD907700C, 0x706CDA1E, 0x70AC708C, + 0xFB2F0A8A, 0x700C70CC, 0xFB2F0A32, 0x702C712C, + 0x70441E00, 0xC200901F, 0x70801600, 0x00968000, + 0x011E0815, 0xB802C808, 0x0F802005, 0xC0049007, + 0x00451800, 0x900840C3, 0xB02001B8, 0x1CC3266F, + 0x8E00B036, 0xF01AE89E, 0x1600E908, 0x80007080, + 0xE88B0040, 0xF011710C, 0x70801600, 0x00258000, + 0x700C7014, 0x710CF209, 0x0A327838, 0x780FFD6F, + 0xFB8F0986, 0x68218F00, 0x792FAF20, 0x809409CD, + 0xFD6F0A1A, 0x70AD730C, 0x8E20B7A0, 0x0C82E984, + 0x8E200240, 0x900740C3, 0xB0A0C2CC, 0xE989B0A2, + 0x71001600, 0x00108000, 0x09F07114, 0x0F820242, + 0x08DAFF0F, 0xC7CAFD8F, 0x78E07EE0, 0x7FE0700C, + 0x00C420AB, 0x1CFCC2FA, 0xC1A2B6C8, 0xC8084608, + 0x006E41C3, 0xB8020002, 0x0F802005, 0x200C900C, + 0x78BD90A0, 0x70901600, 0x00048000, 0x004F2044, + 0x10432544, 0x42E1D80A, 0xFCAF0E36, 0x20534078, + 0xC04020C0, 0xC200EF8A, 0x006F41C3, 0x0E220001, + 0xD80AFCAF, 0x000003E5, 0xB802C808, 0x0F802005, + 0x140C9000, 0x30310821, 0x01131000, 0x10C02D41, + 0x1AC125AD, 0x0F832084, 0x60B8742C, 0x0380205A, + 0xF004E038, 0x732CD870, 0x6038710E, 0x1E007017, + 0x90037404, 0x1E00D878, 0x90077404, 0x02F4F87C, + 0xC0410022, 0x02EC70D5, 0x710C0021, 0x01000AA6, + 0x45CBC808, 0xC400900F, 0x14CE2550, 0xB802726D, + 0x03412005, 0x190078C5, 0x180002C4, 0x099E02C4, + 0xD81E0060, 0x36091208, 0x702E700D, 0x70CC71EC, + 0x00100F11, 0x70801600, 0x00258000, 0xF053E888, + 0x70801600, 0x00408000, 0x001008A7, 0x00052752, + 0x3000264A, 0x33002E40, 0x70C0704C, 0x200572EF, + 0x0E090244, 0xEAB830D1, 0x31310E17, 0x8080270B, + 0x1600F207, 0x80007081, 0x095D0025, 0x0E1B0050, + 0x220B3131, 0xF2098140, 0x70811600, 0x00408000, + 0x0051090F, 0x2678F020, 0x794B3141, 0x215AF41C, + 0x41C32503, 0x12E08000, 0x71266A94, 0x43C36179, + 0x0FF10000, 0x43C3B166, 0x05248000, 0x1908639A, + 0x82E30003, 0x22058241, 0xA1E40102, 0x6462A141, + 0xA1407A05, 0x31FF278D, 0x2640714C, 0x0E79305E, + 0x46C3B194, 0x70000000, 0x193E238D, 0x40C370EC, + 0x12D98000, 0x00841000, 0x43C371CC, 0x05448000, + 0x022E0C6B, 0x72AC700C, 0x00072E00, 0x02002014, + 0x244AB80C, 0x20057180, 0x4308025F, 0x3000264A, + 0x088020A8, 0x310C2E40, 0x89086399, 0x8000270B, + 0x215AF218, 0x40C32502, 0x12E08000, 0x60587126, + 0x000042C3, 0xB0460FF1, 0x81218143, 0x07C12105, + 0x01821808, 0x6461A021, 0x02C12105, 0xA020A044, + 0x305E2640, 0x04BF258D, 0x7105710C, 0x91140895, + 0x41C34022, 0x00010069, 0x024120BC, 0xFA6F094A, + 0x21424222, 0x42D3A03C, 0x12E48000, 0x2344F20B, + 0x22402042, 0xD9F12140, 0x014020A8, 0x1814A822, + 0x706D0092, 0x79EDDFF1, 0xFE2F0862, 0x71654022, + 0x14310B11, 0x702C4022, 0x01A00A56, 0x706DDA10, + 0x7F0D6F01, 0x94120FE3, 0x702C4022, 0x01A00A42, + 0x21424261, 0xF20DA03C, 0x2006710C, 0x224004C1, + 0x20A82140, 0x180201C0, 0x181403C3, 0x706D0052, + 0x4022DF0F, 0xFE2F0816, 0x716541E1, 0x14310B11, + 0x712C4022, 0x01A00A0A, 0x706DDA10, 0x7F0D6F09, + 0x9C3F278C, 0x4022F62F, 0x09F6712C, 0x426101A0, + 0x2030098F, 0x230A708E, 0x702F3440, 0x350F215A, + 0x23D32200, 0x20D51308, 0x23F10D1F, 0x20D61309, + 0x14822730, 0xDB0F740C, 0x006441C3, 0x0B720003, + 0x240AFCAF, 0x268C0580, 0xF40DAC7F, 0x14822730, + 0x43A2740C, 0x006541C3, 0x0B560003, 0x248AFCAF, + 0x26000C7F, 0x27302540, 0x28441482, 0x13040097, + 0x252F2080, 0xE80705C5, 0x41C3740C, 0x00040066, + 0x740CF005, 0x006741C3, 0x43A20004, 0xFCAF0B22, + 0x0580240A, 0x238D7127, 0x1B06313F, 0x402225C2, + 0x04200BE2, 0xC808702C, 0x2005B802, 0x78C50341, + 0x05041900, 0x05041800, 0x0120084A, 0xC808710C, + 0x7D05B802, 0x1D007E05, 0x1E001045, 0xF0061045, + 0x74041E00, 0xC02C9003, 0x0260083E, 0x4008710C, + 0x00200ECA, 0x45CBD80D, 0xE008900F, 0x255070CD, + 0xB5C014CB, 0x13841B00, 0x00200E4E, 0x1D00C001, + 0x08231404, 0x1B003031, 0xC8081404, 0x40C36832, + 0xC400900F, 0x00022105, 0x7825B8B3, 0xB0C0B2C0, + 0x40C3F00C, 0xC02C9003, 0xB8AFB0C0, 0x70451E00, + 0x802C9001, 0x00451800, 0x1E0070CD, 0x90037384, + 0x1E00D878, 0x90077384, 0x0FCEF87C, 0x40010220, + 0x45CBD820, 0x03E09008, 0x00200DEE, 0x10451D00, + 0x0DE6D820, 0xB5C00020, 0xD80AC200, 0x007041C3, + 0x0A3E0002, 0x4303FCAF, 0x1404C0A2, 0xC6DA341B, + 0x1CFCC2F8, 0x2482B6C8, 0x44303902, 0xB910D9AB, + 0x30001C84, 0x4670740C, 0xFCAF0A16, 0xD9204550, + 0x89A0B99F, 0x11002553, 0x8961A900, 0x01002353, + 0xA9017BA5, 0x813E2353, 0x808C11F7, 0x11002453, + 0x800219F7, 0x808211F8, 0x01002253, 0x800219F8, + 0x1901F405, 0x19000043, 0x7A850043, 0x813E2253, + 0x19F8F405, 0x19F78043, 0x0E1D8043, 0x740C2030, + 0x20710E23, 0x09BAD92B, 0xB912FCAF, 0x712E700F, + 0xF01070EE, 0x09AAD9AD, 0xB910FCAF, 0x710F70EE, + 0xD957F007, 0xFCAF099A, 0x71EEB911, 0x722E700F, + 0xBD9FDDEE, 0x15328DC0, 0x70D5109B, 0x0ECA40D1, + 0x23CA03A0, 0x1C8C3022, 0xE8123000, 0x740CD9AF, + 0xFCAF096E, 0xD825B910, 0x8840B89F, 0x00412244, + 0xA8204250, 0x274488FB, 0xA83B1041, 0x740CD90B, + 0xFCAF094E, 0x8D00B914, 0x120C4182, 0x20793085, + 0x14840006, 0x42A23000, 0x0D8A43C2, 0x240AFBEF, + 0x160006C0, 0x80007080, 0x081B000B, 0xD9B1003E, + 0x091E740C, 0xB910FCAF, 0x41A240E2, 0xFDAF0C7A, + 0x20054203, 0x148C35C0, 0x1C883001, 0x78253000, + 0x0051085F, 0xE8AD8D00, 0x740CD959, 0xFCAF08F2, + 0x2479B911, 0x40E22003, 0x42A2702C, 0x0440240A, + 0x01200EBE, 0x46084370, 0x40E2E88A, 0x42A2712C, + 0x0EAE4362, 0x240A0120, 0x46080440, 0x740CD9B3, + 0xFCAF08BE, 0x40E2B910, 0x0C1E41A2, 0x4203FDAF, + 0xFE2F0DE6, 0x709640C1, 0xFB2209A4, 0x0F1740A2, + 0x740C2030, 0x089AD92D, 0xB912FCAF, 0x04800AE6, + 0xD9B5F057, 0xFCAF088A, 0x120CB910, 0x24793081, + 0x20782003, 0x40032004, 0x04A00806, 0xCA0C42A2, + 0x060A212F, 0x00002078, 0x084D7825, 0xD840003F, + 0xB89F700E, 0x88C0722E, 0x808010E5, 0x0E237E05, + 0x4002142E, 0x70931600, 0x00048000, 0xFBEF0C5A, + 0x4200712C, 0x4162700C, 0xFCEF0B62, 0x218D4302, + 0x710E2C7F, 0x740CD95B, 0xFCAF0826, 0x09DEB911, + 0x40A2FB2F, 0x0343206F, 0x10C29020, 0x09330700, + 0x0C2F0004, 0x16002011, 0x80007100, 0x09230188, + 0x0E9E0005, 0x2005FC8F, 0x08170600, 0xD9B70071, + 0x0FEE740C, 0xB910FC6F, 0xFB2F0ABE, 0x8D0040A2, + 0xF47C7114, 0x7014CA06, 0x700CF278, 0x20300C15, + 0x30001C90, 0xFC8F0E6A, 0x710CE804, 0x30001C90, + 0x708E1600, 0x12228000, 0x16007DCF, 0x80007080, + 0x08C51223, 0x40C30344, 0x12D98000, 0x08B58800, + 0x40A2036E, 0x0260092E, 0x702E41A1, 0x30001CA0, + 0x300014A0, 0x046E0897, 0x706E720C, 0x30001C94, + 0xB89FD825, 0x881B8820, 0x710C7905, 0x04C02800, + 0x200FB802, 0x782B04C0, 0x1490F231, 0x40C33010, + 0x28F00000, 0x231F791B, 0x201F2002, 0xB8222041, + 0x436278AA, 0x6219623A, 0x209A4022, 0x704C0184, + 0x41E26038, 0x800070C3, 0x1C981A3C, 0x24793000, + 0x1C9C2000, 0x14983000, 0x0B623000, 0x149C0460, + 0x14983004, 0x41E23000, 0x3004149C, 0x0B4E714C, + 0x43620460, 0x710E7016, 0x1494F3D3, 0x716E3000, + 0x08817704, 0x1C948031, 0x71263000, 0xA2940965, + 0xF19C71C5, 0x0100099A, 0x3000148C, 0x026E7014, + 0x0C0A0001, 0x24790380, 0x1C05200E, 0x40633002, + 0x42C141E2, 0xFE2F0A3A, 0xD917C380, 0x0EC2740C, + 0xB913FC6F, 0x30001488, 0x256FE81A, 0x700C1243, + 0x10901500, 0xFBEF0AC2, 0x4200712C, 0x4102700C, + 0xFCEF09CA, 0x8DA0706C, 0x0AAE710C, 0x712CFBEF, + 0x700C4200, 0x09B641A1, 0x716CFCEF, 0x2744DD40, + 0xBD9F1080, 0xAD0070F6, 0x20802244, 0x90021DE5, + 0x09DAF27E, 0x710CFD2F, 0x800046CB, 0x8E221B3C, + 0x140C714C, 0x782A3100, 0x61199620, 0x0EB6710C, + 0x21ADFA6F, 0x40C30883, 0x25788000, 0x140C8842, + 0x7A2A3101, 0x710C9020, 0x724C6159, 0xFA6F0E96, + 0x088321AD, 0xFD2F0996, 0x40C3720C, 0x2FB48000, + 0x140C8842, 0x7A2A3101, 0x710C9020, 0x714C6159, + 0xFA6F0E72, 0x088321AD, 0x800040C3, 0x884239F0, + 0x3101140C, 0x90207A2A, 0x6159710C, 0x0E56724C, + 0x21ADFA6F, 0x09560883, 0x730CFD2F, 0x3085120C, + 0x14844182, 0x42A23000, 0x708C43C2, 0xFBEF0A26, + 0xD9B971CC, 0xB910740C, 0x0DC6ADE0, 0x1DE5FC6F, + 0x40C39482, 0x12228000, 0x008810B7, 0x88608841, + 0x01007350, 0x0835000D, 0x244A10EE, 0x700C7280, + 0x050020A8, 0x209A68A1, 0x231A0184, 0x00000F81, + 0x60380A3C, 0x800041C3, 0x603C442C, 0x60D860D1, + 0x8802B420, 0x40A1AC02, 0xF1E47164, 0x3085120C, + 0x14844182, 0x42A23000, 0x708C43C2, 0x09B671CC, + 0x700EFBEF, 0x740CD95D, 0xADE0B911, 0xFC6F0D52, + 0x94821DE5, 0x3081120C, 0x42A24003, 0x0CD243C1, + 0x708C0460, 0x212FCA0C, 0x2078060A, 0x78250000, + 0x001F0845, 0x15E58DE0, 0x72AD9080, 0x0F237F05, + 0x4002142E, 0x708E1600, 0x00048000, 0xFBEF092A, + 0x4200712C, 0x41C1700C, 0xFCEF0832, 0x258D4302, + 0x710E1C7F, 0x740CD9BB, 0xFC6F0CF6, 0x0EAEB910, + 0x40A2FAEF, 0x0343206F, 0x10C29020, 0x09390700, + 0x0C350004, 0x16002011, 0x80007100, 0x09290188, + 0x0B6E0005, 0x2005FC8F, 0x081D0600, 0xD92F0071, + 0x0CBE740C, 0xB912FC6F, 0xFAEF0F8E, 0xF00440A2, + 0x04400F02, 0x30001488, 0x256FE819, 0x700C1243, + 0x08B68DC0, 0x712CFBEF, 0x710C4200, 0x0FBE41C1, + 0x706CFCAF, 0x710C8DA0, 0xFBEF089E, 0x4200712C, + 0x41A1710C, 0xFCAF0FA6, 0x2480716C, 0x14043902, + 0xC6D8341B, 0x68614200, 0x7054CA08, 0x20AA7B19, + 0x081700C4, 0x23CA003F, 0x720C0021, 0x00C420AB, + 0x20AB710C, 0x0B1100C4, 0x16000415, 0x901C7100, + 0xF01B0490, 0x010420AA, 0x0A1B7A12, 0x24AA00E5, + 0x21AA1144, 0x08FF0104, 0x4B508044, 0x114424AA, + 0x6078F002, 0x010421AA, 0x20E17110, 0x22AA07C6, + 0x0CF50144, 0x7EE09080, 0x0443226F, 0x8A004300, + 0x0A0F239A, 0x00802079, 0x12FE6822, 0x78398100, + 0x70002E05, 0x4240000F, 0xFFEF077D, 0x00002B05, + 0x0826C0F1, 0x0F720000, 0xC0D1FFCF, 0x78E07EE0, + 0x4328C0F1, 0x00200812, 0x7071702C, 0x7FE0C0D1, + 0x02C520CA, 0x0343226F, 0x000370D3, 0x92600D41, + 0x0F8628C5, 0x86A00001, 0x00C620DA, 0x052628C5, + 0x00C520DA, 0x0F8528C5, 0x8480001E, 0x69818A62, + 0x71046078, 0x00C02805, 0x800043C3, 0x8B601138, + 0x12FBEB0D, 0x0A178082, 0x43C300DF, 0x121E8000, + 0xEA058B40, 0x8B817A2C, 0x74107C4C, 0x20CA7FE0, + 0x78E0030D, 0x0DBAC2EE, 0x2053FDCF, 0x206D00C1, + 0x50160900, 0x43D3782A, 0x003F8000, 0x13005015, + 0x13012080, 0xE9112081, 0x029741C3, 0x083A0000, + 0x2079FA2F, 0xCA140000, 0x20811300, 0x206CB802, + 0x61190080, 0xD953F011, 0x00002078, 0xFA2F081A, + 0x1600B913, 0x80007081, 0xC8060024, 0x0091080B, + 0x781DC805, 0x7A2F5015, 0x807E2153, 0x00832A41, + 0x23C0BA23, 0x21530062, 0x1A028080, 0x22C03002, + 0xD80A0062, 0x029941C3, 0x1A010002, 0x0AD230C2, + 0x1A00FC6F, 0x226F3082, 0x41C320C3, 0x0006029B, + 0x20801200, 0xD87FB8E2, 0x01E220CA, 0x30021A03, + 0x1205D80A, 0x12002486, 0x120C2107, 0x120A2085, + 0x13012104, 0x0A9A2083, 0x121FFC6F, 0x121F2082, + 0xB8E02080, 0xDE66F2AB, 0x02A447CB, 0xBE9F0005, + 0x41E1D80A, 0x948616FC, 0x948516FC, 0x10841600, + 0x908316FC, 0x908216A6, 0xFC6F0A66, 0x2640BAC3, + 0x8E6C160D, 0x10861500, 0x1401274F, 0x908515FC, + 0x15F8D80A, 0x16A69084, 0x0A469082, 0xBAC3FC6F, + 0x14102540, 0x10008D64, 0x274F2086, 0x10FC144D, + 0xD80AA085, 0xA08410F8, 0x16A641A1, 0x0A229082, + 0xBAC3FC6F, 0x240F2040, 0x20831004, 0x14861710, + 0x1401254F, 0x908517EC, 0x17E8D80A, 0x16A69084, + 0x09FE9082, 0xBAC3FC6F, 0x948617FC, 0x1700D80A, + 0x41C31085, 0x000502A8, 0x908417FC, 0x17F84030, + 0x16A69083, 0x09DA9082, 0xBAC3FC6F, 0x150D2740, + 0x15008F68, 0x204F1086, 0x15FC2401, 0xD80A9085, + 0x908415F8, 0x908216A6, 0xFC6F09B6, 0x2540BAC3, + 0x8D64140F, 0x10861700, 0x2441204F, 0x908517FC, + 0x17F8D80A, 0x16A69084, 0x09969082, 0xBAC3FC6F, + 0x120D2740, 0x15008F64, 0xD80A1084, 0x908216A6, + 0x02AB41C3, 0x097A0003, 0xBAC3FC6F, 0x10861510, + 0x2481204F, 0x1085150C, 0x1508D80A, 0x8D641084, + 0x908216A6, 0xFC6F095A, 0x151CBAC3, 0xD80A1085, + 0x10841518, 0x02AD41C3, 0x8D740004, 0x908216A6, + 0xFC6F093E, 0x121FBAC3, 0xB8E12080, 0xDE67F2A8, + 0x02AE45CB, 0xBE9F0005, 0x41A1D80A, 0x948616FC, + 0x948516FC, 0x14841618, 0x908316E4, 0x9082168D, + 0xFC6F090E, 0x16FCBAC3, 0x254F9486, 0x16001401, + 0xD80A1085, 0x908416FC, 0x908316F8, 0x90821691, + 0xFC6F08EE, 0x2640BAC3, 0x8E68150D, 0x10861500, + 0x15FCD80A, 0x41C39085, 0x000502B0, 0x908415F8, + 0x16914030, 0x08CA9082, 0xBAC3FC6F, 0x140F2540, + 0x17008D64, 0x204F1086, 0x17FC2401, 0xD80A9085, + 0x908417F8, 0x90821691, 0xFC6F08A6, 0x2740BAC3, + 0x8F64140D, 0x10861500, 0x2441204F, 0x908515FC, + 0x15F8D80A, 0x41309084, 0x90821691, 0xFC6F0882, + 0x2540BAC3, 0x8D64140F, 0x10861700, 0x2401214F, + 0x908517FC, 0x17F8D80A, 0x16919084, 0x08629082, + 0xBAC3FC6F, 0x140D2740, 0x15088F64, 0x204F1486, + 0x15F4248F, 0xD80A9085, 0x908415F0, 0x169141E1, + 0x083E9082, 0xBAC3FC6F, 0x10841500, 0x15FCD80A, + 0x41C39083, 0x000302B5, 0x90821691, 0xFC6F0822, + 0x1510BAC3, 0x274F1086, 0x150C1441, 0xD80A1085, + 0x10841508, 0x16918D64, 0x08069082, 0xBAC3FC6F, + 0x1085151C, 0x1518D80A, 0x41C31084, 0x000402B7, + 0x16918D74, 0x0FEA9082, 0xBAC3FC2F, 0x20801301, + 0xF2ABB8E0, 0xD80ADE68, 0x41C3BE9F, 0x000502B8, + 0x16FC4030, 0x16FC9486, 0x16009485, 0x16FC1084, + 0x16A49083, 0x0FBA9082, 0xBAC3FC2F, 0x160F2640, + 0x17008E6C, 0x204F1086, 0x17FC2401, 0xD80A9085, + 0x908417F8, 0x908216A4, 0xFC2F0F96, 0x2740BAC3, + 0x8F64140D, 0x10861500, 0x2441204F, 0x908515FC, + 0x15F8D80A, 0x41309084, 0x908216A4, 0xFC2F0F72, + 0x2540BAC3, 0x8D64140F, 0x14861710, 0x2401214F, + 0x908517EC, 0x17E8D80A, 0x16A49084, 0x0F529082, + 0xBAC3FC2F, 0x948617FC, 0x2481204F, 0x10851700, + 0x17FCD80A, 0x40309084, 0x908317F8, 0x908216A4, + 0xFC2F0F2E, 0x2740BAC3, 0x8F68150D, 0x10861500, + 0x2401204F, 0x908515FC, 0x15F8D80A, 0x16A49084, + 0x0F0E9082, 0xBAC3FC2F, 0x140F2540, 0x17008D64, + 0x204F1086, 0x17FC2441, 0xD80A9085, 0x908417F8, + 0x908216A4, 0xFC2F0EEA, 0x2740BAC3, 0x8F64120D, + 0x10841500, 0x16A4D80A, 0x41C39082, 0x000302BF, + 0xFC2F0ECE, 0x1510BAC3, 0xD80A1086, 0x1085150C, + 0x02C041C3, 0x15080005, 0x8D641084, 0x908216A4, + 0xFC2F0EAE, 0x151CBAC3, 0xD80A1085, 0x10841518, + 0x02C141C3, 0x8D740004, 0x908216A4, 0xFC2F0E92, + 0x1301BAC3, 0xB8E12080, 0xDE69F2AA, 0x02C245CB, + 0xBE9F0005, 0x41A1D80A, 0x948616FC, 0x948516FC, + 0x14841618, 0x908316E4, 0x9082168B, 0xFC2F0E62, + 0x16FCBAC3, 0x254F9486, 0x16001401, 0xD80A1085, + 0x908416FC, 0x908316F8, 0x9082168F, 0xFC2F0E42, + 0x2640BAC3, 0x8E68150D, 0x10861500, 0x02C447CB, + 0x15FC0005, 0xD80A9085, 0x908415F8, 0x168F41E1, + 0x0E1E9082, 0xBAC3FC2F, 0x14102540, 0x10008D64, + 0x274F2086, 0x10FC1401, 0xD80AA085, 0xA08410F8, + 0x9082168F, 0xFC2F0DFA, 0x2040BAC3, 0x10042411, + 0x11002083, 0xBF912086, 0xA08511FC, 0x11F8D80A, + 0x41E1A084, 0x9082168F, 0xFC2F0DD6, 0x2140BAC3, + 0x1104240D, 0x15002083, 0x274F1086, 0x15FC1401, + 0xD80A9085, 0x908415F8, 0x9082168F, 0xFC2F0DB2, + 0x2540BAC3, 0x8D64140F, 0x14861708, 0x02C845CB, + 0x17F40005, 0xD80A9085, 0x908417F0, 0x168F41A1, + 0x0D8E9082, 0xBAC3FC2F, 0x10841700, 0x17FCD80A, + 0x41C39083, 0x000302C9, 0x9082168F, 0xFC2F0D72, + 0x1710BAC3, 0x254F1086, 0x170C1441, 0xD80A1085, + 0x10841708, 0x168F8F64, 0x0D569082, 0xBAC3FC2F, + 0x1085171C, 0x1718D80A, 0x41C31084, 0x000402CB, + 0x168F8F74, 0x0D3A9082, 0xBAC3FC2F, 0x71001600, + 0x02009030, 0xB82271ED, 0x10002706, 0x30021A08, + 0x21001200, 0x0F85082B, 0x0A6B0000, 0x244AC808, + 0x68527200, 0x20A8700C, 0x22050340, 0x70C30001, + 0x40000000, 0x0F812105, 0x004C9038, 0x0BAAB1E0, + 0x46CBFE0F, 0xC1DC901F, 0x1443256F, 0x73C41E00, + 0x04A0901C, 0x73C41E00, 0xC294900B, 0x10051E00, + 0x41C3740C, 0x000102CE, 0xFC2F0CC6, 0x0BD68D40, + 0x8D00FAAF, 0x02CF41C3, 0x0CB60000, 0x750CFC2F, + 0x120AB6F2, 0x08152100, 0x16000050, 0x80007080, + 0xB8E40004, 0x010109F4, 0x70801600, 0x01148000, + 0x0CEC7014, 0x16000182, 0x80007080, 0x205300F4, + 0xF20B80FE, 0x813E206C, 0x208CF207, 0xF7068FC2, + 0x1A20B825, 0xC6CE301C, 0x301D1A20, 0x78E0C6CE, + 0x0E3EC2E2, 0x40C3FA0F, 0x0BB80000, 0xFFEF0886, + 0x252F702C, 0xF20D9007, 0xD907700C, 0x706C704C, + 0x73AC708C, 0xFA6F0F96, 0x258C70CC, 0xD8801E3F, + 0x704CD907, 0x708C706C, 0x0F8273AC, 0x70CCFA6F, + 0x0F2A700C, 0x712CFA6F, 0x78E0C6C2, 0x1CFCC2FA, + 0x2482B6C8, 0xC0413C09, 0x70C01600, 0x001F8000, + 0x00320817, 0x0E06DE51, 0xC0010020, 0x3C092480, + 0x341B1404, 0x740CC6DA, 0x0BE6BE13, 0x41C1FC2F, + 0x3F002456, 0x70901600, 0x12238000, 0x708D1600, + 0x12228000, 0x0BEA702C, 0xDA90F9AF, 0x3A802456, + 0x0BDE702C, 0xDA90F9AF, 0x70921600, 0x001F8000, + 0x21402244, 0x1401264F, 0xF9EF08AE, 0x01402079, + 0x20402244, 0x20912244, 0x2244C044, 0xC0432100, + 0x0442242F, 0x740CC303, 0x41C3C204, 0x0003028A, + 0xFC2F0B7E, 0xC808BB22, 0x2005B802, 0x90380F80, + 0x90000008, 0xB8C2C049, 0x0050080D, 0x80B10871, + 0xF003720C, 0xC045710C, 0xC04278BB, 0x2014710C, + 0x226D0400, 0x41C32902, 0x0001028B, 0x740CC048, + 0x0B3E70ED, 0x4450FC2F, 0x01A00B2E, 0xC001C001, + 0x01E00CC2, 0x2F4079EF, 0x45101310, 0x0DCB70AD, + 0x2D40236E, 0x275A120E, 0x26051500, 0x726E140E, + 0x78B4704E, 0x800170C3, 0x18004DAC, 0x43420405, + 0x238C2200, 0x0201239F, 0xC8084CAA, 0x1488275A, + 0x42C37905, 0x00009004, 0x2455B902, 0x79453C0B, + 0x10CB2300, 0x01061100, 0x2300C18C, 0x6179120B, + 0x14032440, 0x134B2314, 0x71017865, 0x1B00B802, + 0x78451184, 0x100079B4, 0x740C0105, 0x01441900, + 0x028C41C3, 0x42420005, 0x0AA643E1, 0x44A1FC2F, + 0x20510C41, 0x000040C3, 0x271A0A3C, 0xB8021001, + 0x2000221F, 0x40A16119, 0x0184209A, 0xC8086119, + 0x210078C5, 0x80000F82, 0xB8021B40, 0x800071C3, + 0x20056D20, 0x90040F80, 0x90000320, 0xB100B200, + 0x2BFE238D, 0x71A5714E, 0x92540D37, 0x0F2371E5, + 0x244A9114, 0xD8987140, 0x903B43DB, 0x20A8C000, + 0x20050200, 0x740406C1, 0x00C51900, 0x20B10C11, + 0x20412478, 0x000047CB, 0xF00586B0, 0x000047CB, + 0x2940265C, 0xE90520C0, 0x000147CB, 0x20523694, + 0xC04A0100, 0xFCAF0DFA, 0xDE25700C, 0xBE9F716E, + 0x029040DB, 0xC8080005, 0x2005B802, 0x903B0F80, + 0x0B11C008, 0x228A2071, 0x18002802, 0xF0060045, + 0x2902228A, 0x01451800, 0x30171428, 0xC808708E, + 0x7140244A, 0x20A84242, 0x22050440, 0xE2100001, + 0x2105B902, 0x210506C3, 0x903B0F81, 0x1B00C004, + 0x190005C4, 0x160005C4, 0x80007080, 0x08110001, + 0xDD6400BF, 0x708D1600, 0x01208000, 0xE88BC003, + 0xD80FC201, 0x716C742C, 0x70AC44A1, 0xFB6F0DD6, + 0xC00470CC, 0xC201E88A, 0x742CD80F, 0x44A1706C, + 0x0DC270AC, 0x70CCFB6F, 0x70AE720C, 0xC047C046, + 0x8E3B8E00, 0x710C7905, 0x05402800, 0x200FB802, + 0x782B0540, 0x740CF2A6, 0x028D41C3, 0x42620003, + 0x093E43E2, 0x240AFC2F, 0x16000540, 0x80007091, + 0x16001222, 0x80007080, 0x210C1223, 0x0124A000, + 0x40C3000D, 0x12D98000, 0x20118800, 0xF2888440, + 0x0AA2C001, 0x212F01E0, 0x700E0447, 0x2448262F, + 0xC00BC04B, 0x042E08F3, 0x1408252F, 0xE8ABC004, + 0xE8B4C003, 0x41C240A2, 0x7F6042A1, 0x4118706C, + 0x4103740C, 0x43A24222, 0x0400240A, 0x05C0250A, + 0xFC2F08CE, 0x0640260A, 0x41C240A2, 0x7F6042A1, + 0x4508716C, 0x3401204F, 0x4222740C, 0x240A43A2, + 0x250A0400, 0x08AA05C0, 0x46A1FC2F, 0x164D2509, + 0x40A2F01F, 0x42A141C2, 0x706C7F60, 0x740C4508, + 0x028E41C3, 0xF00C0005, 0x41C240A2, 0x7F6042A1, + 0x4508716C, 0x41C3740C, 0x0005028F, 0x43A24222, + 0x0400240A, 0x05C0250A, 0xFC2F0866, 0x43A246A1, + 0x248C215A, 0x0201239F, 0x3A802456, 0x60986078, + 0x04012014, 0x3F002456, 0x91406078, 0x03650A17, + 0x20146098, 0x42A10400, 0x1800B1A0, 0x40E205C4, + 0x20F4F003, 0xC2400400, 0x0008272F, 0x41C3740C, + 0x00070292, 0x432242A2, 0x0400240A, 0x05C0250A, + 0xFC2F080E, 0x710646A1, 0xA254080B, 0xF16B7126, + 0x71AEC007, 0x70147704, 0xF54CC047, 0x274C71E6, + 0x061EA800, 0x8E00FFC5, 0x79058E3B, 0x2800710C, + 0xB8020500, 0x0500200F, 0xF24C782B, 0x70901600, + 0x12228000, 0x70801600, 0x12238000, 0x04240877, + 0x40C34082, 0x12D98000, 0x08678800, 0x212F042E, + 0x09420407, 0xC00101E0, 0x2495205A, 0x70AD4610, + 0x236E0E49, 0x2500210A, 0x3A802456, 0x2201219F, + 0x70A27022, 0x034020F4, 0x700CE88A, 0x029341C3, + 0x42820003, 0x0C824302, 0x44A1F9AF, 0x2500205A, + 0x200078B4, 0x80010F81, 0x24564DAC, 0x70223F00, + 0x20F470A2, 0xB1000340, 0x0DB971A5, 0x71069254, + 0xC301F1C2, 0x000042C3, 0x0D9EBA68, 0x414203E0, + 0x718EC006, 0x08537704, 0xC0468031, 0x230CC005, + 0x0536A000, 0x7166FFE5, 0xC00170CD, 0x01E008B6, + 0x2E4079CF, 0x43101311, 0x0B7970AD, 0x2D40236E, + 0x704C1210, 0x24502005, 0x4340724E, 0x148C265A, + 0x0201239F, 0x3C002455, 0x04082200, 0x900447CB, + 0x20400000, 0x44A11481, 0x20006078, 0xC808030B, + 0x23F47905, 0xB9021349, 0x190079E5, 0x20400244, + 0x78251401, 0x029441C3, 0xB8020005, 0xC08C7F05, + 0x43C16078, 0x24F4641C, 0xB7001340, 0x24F4740C, + 0x0EAE1345, 0x23F4FBEF, 0x228D1346, 0x714C247F, + 0x0D8B71A5, 0x71C59254, 0x91140E73, 0x0882C001, + 0x712C03A0, 0x7A0FC008, 0x780FC002, 0x00040A29, + 0x6832C808, 0xB8C4C002, 0x7825B80E, 0x0F832005, + 0x00089038, 0xB300C009, 0x7104C002, 0x780FC042, + 0x80050AE5, 0x70801600, 0x01648000, 0xF42BB8E6, + 0x70801600, 0x001F8000, 0x00FF0839, 0x41C3740C, + 0x00000295, 0xFBCF0E3A, 0x256FC201, 0xD80F1A43, + 0x716C742C, 0xFF6F0BFE, 0x12051D00, 0xD80FC201, + 0x0BF2742C, 0x706CFF6F, 0xB88FD808, 0xF00BB500, + 0x029641C3, 0x0E0A0000, 0x740CFBEF, 0xFAEF0F7A, + 0x020DC001, 0x78E0FFCF, 0x1CFCC2FA, 0xC1BFB6C8, + 0xC8084410, 0x2005B802, 0x90380F80, 0x90000008, + 0x1600C043, 0x80007080, 0xC1030164, 0xC046B9C2, + 0x800040C3, 0x88601222, 0x00700911, 0x72348841, + 0x00220320, 0xF003720C, 0xC044710C, 0xC00671AD, + 0x780D7D54, 0xC0497F7B, 0x88002044, 0xF40EC047, + 0x7140244A, 0x20A8D898, 0x20050280, 0x903B0F81, + 0x7404C000, 0x00C51900, 0x01600D7E, 0xD8254082, + 0x33C7232F, 0x712FB89F, 0x881B8820, 0x20787825, + 0x710400C0, 0x78AFC048, 0x202FC041, 0xC0043647, + 0x02347013, 0x40820025, 0x752CC808, 0x2005B802, + 0x903B0F80, 0x0815C008, 0xC1453071, 0xDEA0712C, + 0x730CB020, 0xF009C040, 0x01451800, 0xDEA4740C, + 0x760CC040, 0x70ADC045, 0x7510C008, 0x000601F2, + 0x2578C007, 0x20791017, 0x27040000, 0x20782017, + 0x27043040, 0x0F1F2017, 0x244A2071, 0xD8987140, + 0x024020A8, 0x0F812005, 0xC000903B, 0x19007404, + 0x08DE0005, 0x710CFCAF, 0x30041400, 0x2347262F, + 0x218AD8C8, 0x43820004, 0x000042C3, 0x250ABA68, + 0x70CC0580, 0x02A0083E, 0xC0064250, 0x800140D3, + 0x08434DAC, 0x244000FF, 0x74AE3B13, 0x2400210A, + 0x41224062, 0xF96F0CB2, 0x2340DA14, 0x258D2513, + 0x21402EBF, 0x14142511, 0xD8C83004, 0x0004218A, + 0x43824242, 0x0580250A, 0x02600FFA, 0xC28B70CC, + 0x42C3F004, 0xBF648000, 0x244A746C, 0x20A87280, + 0x100002C0, 0x12022101, 0x60380500, 0x1802781D, + 0x238C2014, 0x084A0D7F, 0x700CFCAF, 0x0E424082, + 0x702C0360, 0x706E70F6, 0xF28570AE, 0x7140244A, + 0x20A8D998, 0x21050280, 0x903B0F80, 0x7424C000, + 0x04C41800, 0xF07773AE, 0x244AC808, 0x20057140, + 0x41C10342, 0x038020A8, 0x00402205, 0xB802E110, + 0x0F832005, 0xC000903B, 0xC042700C, 0x00051B00, + 0x30041400, 0x142440C1, 0xD9103006, 0x0FFF26BF, + 0x000042C3, 0x43822950, 0x02600F5A, 0x0580250A, + 0x2540203C, 0x26C0200A, 0xC001C04A, 0x04040895, + 0x212FC002, 0x20790402, 0xB9C60000, 0x00922840, + 0x0D524082, 0x702E01A0, 0x230C2840, 0x24055020, + 0x43C11342, 0x00482205, 0x20412044, 0x010B2140, + 0x22C50955, 0x04AE0849, 0x10C12005, 0x903842C3, + 0xB9020000, 0x00892105, 0x11061100, 0x270BC10A, + 0xF216A040, 0x29812140, 0xB9027985, 0x26537A25, + 0x091D00C1, 0x120003F1, 0x0F150107, 0x274000F0, + 0x19000041, 0xB2201184, 0x10051900, 0x7126E310, + 0xF1D87146, 0x7106C002, 0x00002052, 0xF1B7C042, + 0x202F7166, 0x0D1524C7, 0x71A5A405, 0x05CFF106, + 0x7127FFEF, 0x03600D1A, 0xC001712C, 0x06C40827, + 0x6852C808, 0x11002753, 0xB80E71E5, 0x20057845, + 0x90380F81, 0xC0030008, 0x79EFB100, 0x08E9C001, + 0x16008045, 0x80007080, 0x08590164, 0x1600019F, + 0x80007080, 0x083B001F, 0x740C00FF, 0x028641C3, + 0x0ADE0000, 0x256FFBCF, 0xD80F1A43, 0x4282742C, + 0x08A2716C, 0x1D00FF6F, 0xD80F1205, 0x4282742C, + 0xFF6F0892, 0xD808706C, 0xB500B88F, 0x41C3F00A, + 0x00000287, 0xFBEF0AAA, 0x0C1E740C, 0x4082FAEF, + 0x1404C0BF, 0xC6DA341B, 0x200AC2F6, 0x80010F80, + 0x20A78000, 0x200A0849, 0x80010F80, 0x20A78000, + 0x200A0949, 0x80010F80, 0x20A77000, 0x200A0809, + 0x80010F80, 0x20A77000, 0x200A0909, 0x00080F80, + 0x20296000, 0x206F0000, 0x100020C3, 0x701420C0, + 0x000B072C, 0x800047CB, 0x8F00019A, 0x1600E886, + 0x80007080, 0xE812019B, 0x00C420AA, 0x003F0811, + 0x20AB720C, 0x710C00C4, 0x00C420AB, 0x010420AA, + 0x20AA5031, 0x50320144, 0x19C3266F, 0x70451E00, + 0x0080900C, 0x903045CB, 0x16EF03B8, 0x0D4E9481, + 0x950002E0, 0x000041D3, 0x0E962503, 0x1E00FC6F, + 0x0E961444, 0x41C30080, 0x00000325, 0xFBEF09E2, + 0x0D2ED80A, 0x40C3FA0F, 0xA6350000, 0x902446CB, + 0xB60020A8, 0x0304208A, 0xD80AB602, 0x032741C3, + 0x09BE0001, 0x4222FBEF, 0xD80A9542, 0x41C39560, + 0x00050328, 0x910415FC, 0x71051600, 0x03B89008, + 0xFBEF099E, 0x910615F8, 0xFDCF0B6E, 0xB802C808, + 0x0F802005, 0x002C9008, 0xCA079020, 0x01B5081B, + 0x00CC2184, 0x8084218C, 0x41C3F407, 0x00000329, + 0xF96F0E76, 0xCC1E700C, 0x08139620, 0x700C0060, + 0x032A41C3, 0x0E620000, 0xCC1FF94F, 0x08139622, + 0x700C0060, 0x032B41C3, 0x0E4E0000, 0x1600F94F, + 0x80007080, 0xB8E00185, 0x00C20C54, 0x1243256F, + 0x800042D3, 0x8D001138, 0x9566B8C3, 0x1A00B814, + 0x0B1A2043, 0x50300160, 0xFDCF098E, 0xFDCF09AE, + 0xBBE0C808, 0xB8024170, 0x0F802005, 0x003C900C, + 0x01141000, 0x1E00F28D, 0x90087045, 0x0DD60288, + 0x710C0020, 0x70801600, 0x00198000, 0x1600E893, + 0x80007080, 0x080D000D, 0x8D00005E, 0x011E0817, + 0xE8898F00, 0x70801600, 0x019B8000, 0x0E947014, + 0x0D66FA41, 0x0B42FF4F, 0xD933FECF, 0x08B2740C, + 0xB914FBEF, 0xFE0F0B22, 0xF9CF0A86, 0x742C700C, + 0xFA2F0EEE, 0x700C704C, 0xFA2F0BA2, 0x0DE6712C, + 0x700C0020, 0x70801600, 0x000D8000, 0x005E080D, + 0xB8E48D00, 0x01410F30, 0x1A43266F, 0xFBEF09A2, + 0x10451E00, 0xFB0F0B06, 0xFECF0A06, 0x01000E4E, + 0x233E0939, 0xD80A70ED, 0x033341C3, 0x08520000, + 0xBF8CFBEF, 0x70801600, 0x01848000, 0x20CA7014, + 0x1A0B0321, 0x08123002, 0xB6E0F9AF, 0xB80CD809, + 0x0DCAB600, 0xD80D0020, 0x03400C2E, 0xF9CF0A02, + 0x000040C3, 0x0C4E3A98, 0x702CFF6F, 0xD907780F, + 0x02022048, 0x706C700C, 0x70AC708C, 0xFA2F0B5E, + 0x700C70CC, 0xFA2F0B06, 0x0DC6712C, 0x710CFA4F, + 0x20031A00, 0xB600B88F, 0x00200D82, 0x0B3E700C, + 0x710CFC6F, 0x207E092B, 0x41C3D80A, 0x000002F1, + 0xFB8F0FCE, 0x1A43266F, 0x0A2E710C, 0x1E0001A0, + 0x720C1085, 0xB600B88F, 0x00200D52, 0x095D710C, + 0xD9BB20BE, 0x0FAAD80A, 0xB912FBAF, 0xFBCF0FAE, + 0x1A43266F, 0xFAEF0ABE, 0x11051E00, 0x41C3E80F, + 0x000002ED, 0xFBAF0F8A, 0x09EED80A, 0xD80901A0, + 0xB88F740C, 0x750CB600, 0x41C3F00E, 0x000002EE, + 0xFBAF0F6E, 0x09D2D80A, 0x700C01A0, 0xB88F740C, + 0x720CB600, 0x00000CF6, 0x000042D3, 0x21044000, + 0xF215A495, 0x02EF41C3, 0x0F460000, 0xD80AFBAF, + 0x1A43266F, 0x09A2D80C, 0x1E0001A0, 0x730C1484, + 0xB600B80E, 0x00200CC6, 0x2144D814, 0xF205A216, + 0x02E008EA, 0x0939710C, 0xD80A21BE, 0x02F741C3, + 0x0F0E0000, 0xDF40FBAF, 0xFD8F0FA2, 0x1A43266F, + 0xB6E0D80B, 0x01A00962, 0x30431A06, 0xB88FD840, + 0x0C8AB600, 0x760C0020, 0x30031A06, 0xF445262F, + 0x00030096, 0xF98F0EF6, 0xFAEF09FA, 0xE8094710, + 0x02F941C3, 0x0ECA0000, 0xD80AFBAF, 0x266FF03D, + 0xD95F14C3, 0x10931600, 0x0EB6B913, 0xD80AFBAF, + 0x12CF2640, 0xB700D880, 0xA0002351, 0x090AD80D, + 0x20CA01A0, 0x8E0002A1, 0x00BF0843, 0x218A70F6, + 0xD8FF0FC7, 0xFAEF0802, 0xCA0A703C, 0xD825E897, + 0xB89F706E, 0x88C072EE, 0x7E05881B, 0x14EE0E19, + 0x0A864062, 0x712CFB2F, 0x42008D20, 0x098E700C, + 0x4362FC2F, 0x2D3F278D, 0xD880716E, 0xB700B88F, + 0x00200BEA, 0x0D67D80A, 0x16002010, 0x80007080, + 0x08510164, 0xD92F013F, 0x0E36D80A, 0xB914FBAF, + 0x1A43266F, 0xF9AF0E46, 0x14841E00, 0x218A7014, + 0xD8FF0FC7, 0xFFAF0A0A, 0x730C703C, 0xB600B80E, + 0x00200BAA, 0x8D20D814, 0x704C700C, 0xFC2F092E, + 0x8D20706C, 0x714C700C, 0xFC2F0922, 0xF007716C, + 0xD80AD9CD, 0xFBAF0DEA, 0x096DB912, 0xD80A22BE, + 0x02FA41C3, 0x0DDA0000, 0x278AFBAF, 0x0DEE1010, + 0x4210F98F, 0x70801600, 0x01638000, 0xFA6F0E42, + 0x266F712C, 0x41421A43, 0x02600EFA, 0xD821B6E0, + 0xB600B80A, 0xE895CA0A, 0x70EDD825, 0x724EB89F, + 0x88DB8820, 0x0E157E25, 0x40E113EE, 0xFB2F09AA, + 0x0EAA712C, 0x41E1FBEF, 0x2DFF228D, 0x0B1E71ED, + 0xD80E0020, 0x2051092D, 0x70801600, 0x00198000, + 0x1600E897, 0x80007080, 0xE893011D, 0x033541C3, + 0x0D5E0000, 0xD80AFBAF, 0x01600FBE, 0xF009D808, + 0x213F0909, 0xF003710C, 0x0F3E700C, 0x09710140, + 0x704E213E, 0x20801000, 0x370E1223, 0x0D4EB8E2, + 0x22CAF9AF, 0x278A23E1, 0xE8831FC7, 0x0E51DFFF, + 0xD80A117E, 0x02FD41C3, 0x0D160000, 0x208AFB8F, + 0x266F0404, 0xB6001A43, 0x4142720C, 0x00200AEA, + 0x083242E1, 0xE80DFACF, 0x02FE41C3, 0x0CF20000, + 0x740CFBAF, 0x4142730C, 0x00200ACE, 0x40C342E1, + 0x81100000, 0x0A76B600, 0xD8160020, 0x20300EAD, + 0x40C3704E, 0x01888000, 0x103F9020, 0x70308700, + 0xF786700C, 0x00000F5A, 0x00002052, 0x30021A05, + 0x0E7A700C, 0x1A0C02A0, 0xCA053482, 0x700CE806, + 0x02A00E6A, 0x30431A0C, 0x20801000, 0x370E1223, + 0x0CAAB8E2, 0x22CAF9AF, 0x278A23E1, 0xE8831FC7, + 0x0E0DDFFF, 0x0F9E119E, 0xE808FA8F, 0xD80A732C, + 0xFBAF0C6E, 0xF022B918, 0x02FF41C3, 0x0C620000, + 0xD80AFBAF, 0x0204208A, 0x1A43266F, 0x710CB600, + 0x0A364142, 0x42E10020, 0x000040C3, 0xB6000908, + 0x4142700C, 0x00200A22, 0x40C342E1, 0x81080000, + 0x09CAB600, 0xD8180020, 0x227E0951, 0x41C3D80A, + 0x00000301, 0xFBAF0C1A, 0x2008228A, 0xF9AF0C2E, + 0x208F1000, 0x0F764010, 0x730CFC2F, 0x700CBFE2, + 0x1A43266F, 0x03E120CA, 0x0CE24102, 0x1E000220, + 0xD8411484, 0xB600B809, 0xE885CA0A, 0xFBEF0CCA, + 0x097A8D00, 0xD8090020, 0xE829CA0A, 0x70EDD825, + 0x720EB89F, 0x88DB8820, 0x0E297E25, 0x40E113EE, + 0xFAEF0FD6, 0x8D20712C, 0x710C4200, 0x0EDE43E1, + 0x4250FBEF, 0x700C8D20, 0x0ED24242, 0x43E1FBEF, + 0x2B7F208D, 0x0C8271ED, 0x8D00FBEF, 0x70801600, + 0x00008000, 0x0EACB8E5, 0x0982FC02, 0x0923FECF, + 0x8D002050, 0x0C012044, 0x0C100913, 0x017F0809, + 0xF003700C, 0x0C4A710C, 0x0ED202C0, 0x0CBE0100, + 0xC8080080, 0x2005B802, 0x900F0F80, 0x1800C03C, + 0x08DE0504, 0x700C0160, 0x00000DF6, 0xD80AD967, + 0xFBAF0B3E, 0x0E96B913, 0x700CFC2F, 0x02A00F6A, + 0x700CD807, 0x00C420AB, 0xF0007FFF, 0x02800C82, + 0x4308C2E6, 0x730C71AD, 0x900F46CB, 0x0EAAC028, + 0xB6A0FF2F, 0x900847CB, 0x97000288, 0x0B3DB8A1, + 0xB7001031, 0x900F41C3, 0x40C3C298, 0x3FFF0000, + 0x19E8B1A0, 0x20508004, 0x40C30341, 0xC2249007, + 0x1600B020, 0x80007082, 0x2253000C, 0xF205817E, + 0x00051804, 0xB022F002, 0xFF2F0E5E, 0xD81FD80D, + 0x135C1FAC, 0xFF2F0E52, 0x10051E00, 0x78E0C6C6, + 0x4308C2E4, 0xFF2F0E42, 0x70ADD81F, 0x900846CB, + 0x740C03E0, 0xFF2F0E32, 0x1654B6A0, 0x206C9700, + 0xB8810040, 0x10300B0B, 0x901C1E54, 0x700CC6C4, + 0x900F41C3, 0xB88CC280, 0x40C3B100, 0xC2249007, + 0xB0A2B0A0, 0xC6C4B1AC, 0x4608C2E4, 0x70801600, + 0x00128000, 0x8203208C, 0x02AE0E8C, 0x0EFA40C1, + 0x0BDE0040, 0x0B26FECF, 0xCA110080, 0x800145CB, + 0x25164FC4, 0x0B4A1000, 0xB0C0FAEF, 0x30821211, + 0xA5017D56, 0x0F0A6A01, 0x1A11FAAF, 0x0C663002, + 0xC6C40280, 0x1CFCC2FA, 0x2482B6C8, 0x41583304, + 0x4310C141, 0x702CC08E, 0xF92F0A26, 0x708EDA50, + 0x35001C34, 0x35001C30, 0x35001C2C, 0xFBEF087E, + 0x35001C28, 0x21350B27, 0x2353C042, 0x730C20C1, + 0x21787839, 0xB8C000DB, 0x202FC043, 0x26F004C5, + 0x80007000, 0xC04410C4, 0x700CF007, 0xB890706F, + 0x4063C044, 0x2350C043, 0x21842000, 0xC0473004, + 0x46D3720C, 0x12218000, 0x800047D3, 0xC045C144, + 0x458AD825, 0x718EB89F, 0x881B8820, 0x2C007905, + 0xB8022340, 0x0350200F, 0xA040200B, 0x00210408, + 0x0CEA730C, 0x1E00FC2F, 0xC0042342, 0x0E2A78A5, + 0xC04602A0, 0xC8084110, 0x7825C106, 0x208916B8, + 0x20881602, 0x008B2840, 0x20811601, 0x1064086D, + 0x096540A1, 0x2940106E, 0x215A0380, 0x2005050C, + 0xC78E02C0, 0x7280244A, 0x0F832005, 0x00009000, + 0x679F700C, 0x080020A8, 0x30310911, 0x06822100, + 0x0082121C, 0x0080082F, 0x30300B0B, 0x02422079, + 0x2078F003, 0xEA8F0242, 0x0271080D, 0x9340C68E, + 0xF009B749, 0x02822840, 0x7A65669E, 0x92407E14, + 0x7104B640, 0xF1CC7124, 0x3005140C, 0xC28C4162, + 0x708CC38A, 0xFC6F0C12, 0x40C370CC, 0x12DC8000, + 0x21798020, 0x40A13002, 0x09CA4340, 0x4250FE2F, + 0x30300B73, 0x1407262F, 0x0CCE710C, 0x41C1FC2F, + 0x00800A0A, 0x38812455, 0xDA084022, 0x44C14362, + 0x3C052440, 0x0480260A, 0x089A71EC, 0x2455FB6F, + 0xDA23388F, 0xBA0A40E2, 0xF92F08A6, 0xC301702C, + 0x1408D808, 0x41623004, 0x2440704C, 0x260A3C05, + 0x70EC0480, 0xFB6F0C52, 0x2455C740, 0x082A3880, + 0x702CFB6F, 0x0C72700C, 0x41C1FC2F, 0x00C00E3E, + 0x2455F029, 0x40223881, 0x4362DA08, 0x244044C1, + 0x260A3C05, 0x71EC0480, 0xFB6F083A, 0x388F2455, + 0x40E2DA23, 0x084ABA0A, 0x702CF92F, 0xD808C301, + 0x30041408, 0x704C4162, 0x3C052440, 0x0480260A, + 0x0BF670EC, 0xC740FB6F, 0x38802455, 0xFB2F0FCA, + 0x1601702C, 0x16022091, 0x210C2080, 0x025CA000, + 0x40C3000D, 0x12D98000, 0x20118800, 0x02468440, + 0x29400021, 0xC0062315, 0x05402005, 0xC049700E, + 0x2280215A, 0x0917C048, 0x21003031, 0x101C2680, + 0x200C0080, 0x0214A000, 0x0B0D0001, 0x20793030, + 0xF0042240, 0x22402078, 0x02007014, 0xC2080002, + 0x229A7202, 0x2232000E, 0x80000F83, 0xEB14C444, + 0x00700B2B, 0x05C02234, 0x0B1772E2, 0x922100F1, + 0xDE809282, 0x4E924913, 0x00A20B17, 0x42104291, + 0xF0074628, 0x70CD704E, 0xDE80F003, 0x215A4210, + 0xC08E2501, 0xC007603A, 0x040F22F4, 0x00B1080F, + 0xC08C4058, 0x044020F4, 0x0812F00A, 0x40E1FBAF, + 0xC08C4708, 0xFBAF0806, 0x044020F4, 0x4F10661E, + 0x20024EF1, 0x72760480, 0x20CA4608, 0x26CA0045, + 0x0B411046, 0x12082030, 0x0BB73609, 0x28402071, + 0x47CB220B, 0x00009000, 0x154B2305, 0x124B2305, + 0x1F812305, 0x006A0001, 0xB90261B9, 0x03C82105, + 0x1F812305, 0x00680001, 0xB90261B9, 0xF0787F25, + 0x220B2840, 0x900042C3, 0x23050000, 0x7BD0154B, + 0x124B2305, 0x23057810, 0x00011F81, 0x61B90068, + 0x7F4569F2, 0x21099720, 0x230500CE, 0x00011F81, + 0x61B9006A, 0x2105B902, 0x10000088, 0x21091101, + 0x23050000, 0xB9021341, 0x0F822105, 0x00489004, + 0x0F812105, 0x00409004, 0x16009240, 0x80007083, + 0x0B8D00EF, 0x91200030, 0xB9C6BAC6, 0x21CC72D1, + 0x005E838D, 0x0A59000D, 0x4A760065, 0x0B2DF029, + 0x210520B1, 0x28401541, 0x43C32202, 0x00009000, + 0x21057945, 0x00010F82, 0x62BA0060, 0x0F812105, + 0x00630001, 0xF00EBA02, 0x0F822105, 0x00190001, + 0x7AB4B981, 0xBA02B985, 0x43C3B990, 0x00009000, + 0xB2C07A65, 0xB90261B9, 0xF0277965, 0x621C4976, + 0xF705E4FE, 0xE4FF611C, 0x090FF78A, 0x228700A5, + 0x4A700FC1, 0x2187F004, 0x49700FC1, 0x1F812305, + 0x006C0001, 0x42C361B9, 0x00009000, 0xB7C0B902, + 0xB1C07945, 0x1F812305, 0x006E0001, 0x180061B9, + 0xB9021004, 0xB1007945, 0x41C3C009, 0x00009000, + 0x340320F4, 0x02402005, 0x2270080D, 0x2840B802, + 0x78452282, 0xB0607825, 0x204C7106, 0x05DAA280, + 0x05A7FFC5, 0x7126FFEF, 0x20110B1D, 0x71001600, + 0x00C49004, 0x0002204F, 0x900741C3, 0xB140C0C4, + 0xB100B8A0, 0x7704C005, 0x03D87014, 0xC045FFE2, + 0x33042480, 0x341B1404, 0x78E0C6DA, 0x70801600, + 0x000D8000, 0x08002044, 0xB8257FE0, 0xC1A4C3E4, + 0x70CDDD37, 0x1501BD9F, 0xC0621480, 0x14801501, + 0x30021C09, 0x14801501, 0x30021C0A, 0x14801501, + 0x30021C0B, 0x14801501, 0x1501C063, 0x1C0D1480, + 0x15013002, 0x1C0E1480, 0x15143002, 0x1C0F1480, + 0xC0823002, 0x022141C3, 0x60CB0002, 0x0D02740C, + 0x42C1FB6F, 0x0EEF71C5, 0x15019214, 0xC0601480, + 0x14801501, 0x30021C01, 0x14801501, 0x30021C02, + 0x14801501, 0x30021C03, 0x14801501, 0x8D00C061, + 0x30021C05, 0x1C068D01, 0x8D023002, 0x1C0770AD, + 0xC0803002, 0x022241C3, 0x60AB0002, 0x0CB2740C, + 0x42A1FB6F, 0x0DEF71A5, 0xC7C49214, 0x46CBC2E6, + 0x04628000, 0x800045CB, 0x08131A20, 0x470802FF, + 0x20539600, 0xF41180BE, 0x950AF00D, 0xB50AB880, + 0x20538E00, 0xF20780BE, 0xA503700C, 0xA501A502, + 0x0E22A500, 0x262FF94F, 0x0008F3C5, 0xC6C60004, + 0x20538E00, 0xF20780BE, 0xA503700C, 0xA501A502, + 0x0E02A500, 0xC6C6F94F, 0x46A8C2EA, 0x40704788, + 0x0CDA4548, 0x4130FB6F, 0x2281215F, 0x25CAE589, + 0x60381221, 0x229F7A0F, 0x2200000E, 0x20000400, + 0x80000F81, 0x8960C444, 0x0B1D710C, 0x78B800F0, + 0x00700B3F, 0x0B5178CB, 0x78CB00B0, 0x78CBEB83, + 0xC6CAF22C, 0xF3FF78CB, 0x2180205F, 0x40C3621A, + 0xC1448000, 0x9340621B, 0x78429301, 0x93027C10, + 0x7A504F12, 0x10850C1B, 0xB300B3E1, 0xF3EBF009, + 0x2180205F, 0x70C36058, 0xC1468000, 0x1900B0E0, + 0xC6CA0083, 0x205FF5DF, 0x19002180, 0x605800C3, + 0x800070C3, 0xF00AC148, 0x2180205F, 0x00431900, + 0x70C36058, 0xC1448000, 0xC6CAB0E0, 0xC1A6C3F2, + 0x44104530, 0xF2B27014, 0x230A70ED, 0x25142500, + 0x244023D2, 0x21143511, 0x120023D1, 0x20532100, + 0x19010141, 0x702C2042, 0x1900B826, 0x0EBA2002, + 0x4022FE6F, 0x21001204, 0x34102440, 0x23D02014, + 0x01412053, 0x20421801, 0xB826702C, 0x20021800, + 0xFE6F0E96, 0x40224002, 0x0DB24102, 0x724C0060, + 0x2100120A, 0x7EF4C683, 0x01412053, 0x712CAE21, + 0xAE00B826, 0xFE6F0E72, 0x120E40C1, 0xC5822100, + 0x20537DF4, 0xAD210141, 0xB826712C, 0x0E5AAD00, + 0x40A1FE6F, 0x41A140C1, 0x00600D72, 0x1101724C, + 0xE0C02080, 0xD940F704, 0xF0044910, 0x003F2080, + 0x31812440, 0xA90061F9, 0x20801001, 0xF705E0C0, + 0x4910D940, 0x2080F003, 0xC181003F, 0xA90061F9, + 0xE0C08E01, 0xD940F704, 0xF0044910, 0x003F2080, + 0x30812440, 0xA90061F9, 0xE0C08D01, 0xD940F704, + 0xF0044910, 0x003F2080, 0x63F9C380, 0x238D71E5, + 0xA900227E, 0x7500240A, 0x708D70AD, 0x704C706D, + 0x054020A8, 0x30802440, 0x22086088, 0x13010001, + 0x21080480, 0x24400002, 0x60883180, 0x10012308, + 0x6088C081, 0x21087185, 0x270A000B, 0xC3830540, + 0x32042440, 0x35052440, 0x34062440, 0x24147BB4, + 0x25140344, 0x26140345, 0x78AF0346, 0xFA2F0812, + 0x71A54161, 0x95040DDB, 0x78E0C7D2, 0x1CFCC2FA, + 0x2482B6C8, 0x1C473D08, 0xC0413058, 0x36001447, + 0x30981C48, 0x800042C3, 0x1C081224, 0x08293100, + 0x1C490070, 0x144730D8, 0xE89F3600, 0x70801600, + 0x00258000, 0x00C02078, 0x00971200, 0xC0407104, + 0xF0118A01, 0x70801600, 0x00408000, 0x00412078, + 0x00971202, 0x7314C140, 0x20CAC000, 0xC04000A1, + 0x1C468A03, 0xC2013018, 0x41C3740C, 0x000200BD, + 0xFB6F09AE, 0xC001C300, 0x02D07014, 0xD9200021, + 0x0BC3216F, 0x780A8900, 0x301C1A1C, 0x780A8901, + 0x301C1A1D, 0x7014C000, 0x0021052C, 0x40DB708E, + 0x0A3C0000, 0x2619271F, 0x394F2456, 0x33102440, + 0x800043DB, 0x27801A3C, 0x20801084, 0x706E2084, + 0x36D92100, 0x30181C45, 0x7001248A, 0x218AC083, + 0x1A0D0FC7, 0x20A834C2, 0xB0210180, 0x00151804, + 0x39402456, 0x248AD9FF, 0x228A7001, 0x18000FC7, + 0x1C8627C3, 0x1C88351C, 0x20A8305C, 0xB0410180, + 0x00151804, 0x25C0210A, 0x3F802400, 0x02280000, + 0x17C31F00, 0x00051800, 0x1446B022, 0x08CF3600, + 0xC0830464, 0x36001448, 0x0447212F, 0x01200A86, + 0x34581A0B, 0xC04270AE, 0x08A9C002, 0x211A054E, + 0x1A0C2600, 0x231A3558, 0x00002F92, 0x220028F0, + 0x40A22012, 0x0184209A, 0x20007042, 0x0ED606CD, + 0x40A10260, 0xF4E47014, 0x41C3740C, 0x000200CA, + 0x08AE4222, 0x43A2FB6F, 0x0CCA4062, 0x4122FD6F, + 0x24404608, 0xE8843316, 0x39562456, 0x02400DBE, + 0x700C7014, 0x800042C3, 0xF2101B3E, 0xC083EE03, + 0x2456F003, 0x10823940, 0x40A20701, 0x0184209A, + 0x60587042, 0x78229001, 0x219A41A2, 0x71420184, + 0xEE05614A, 0x20811000, 0x8F20F002, 0x242F4A33, + 0x40C20006, 0x0D3241A1, 0x42C2FA6F, 0xF4A87014, + 0x0D5971A6, 0x7126A294, 0x0D16F199, 0xC1010060, + 0x70CE7014, 0xC101F49D, 0x00600D06, 0x39402456, + 0xF4977014, 0x20821000, 0x41C3740C, 0x000200CB, + 0xFB6F080E, 0x37031488, 0x24348F40, 0x00003F83, + 0x41C3022C, 0x000200CC, 0xFB2F0FF6, 0x1446740C, + 0x080F3600, 0x71CE05E5, 0x36001445, 0x462BF079, + 0x25C0210A, 0x36001448, 0x0447212F, 0x01200966, + 0x34581A0B, 0x02600CF6, 0x4508C042, 0x0BE64062, + 0x4122FD6F, 0xE808ED05, 0x208D1000, 0xE806F00A, + 0xF006C083, 0xF0068FA0, 0x39402456, 0x070D1082, + 0x45D1704E, 0x0867C002, 0x740C04AE, 0x00CD41C3, + 0x42220002, 0x0F8A4342, 0x1A0CFB2F, 0x0CAE3498, + 0xE8070240, 0x0C6A40A2, 0x41A1FC6F, 0x40A2F005, + 0xFC6F0B82, 0xE8BC41A1, 0x0084208A, 0x00CE41C3, + 0x25320004, 0x740C2005, 0x43224262, 0xFB2F0F52, + 0x0480240A, 0xE80BCA06, 0x40A2C101, 0x36021447, + 0x0B7A4362, 0x14490320, 0x71463604, 0xA2B40A99, + 0x21842580, 0x02400C56, 0x2602211A, 0x231A7014, + 0x00002F81, 0x40C328F0, 0x1B3E8000, 0xF2056159, + 0xA8A06038, 0x6038F003, 0x1446B0A1, 0x76033600, + 0xA000210C, 0xFFE50720, 0xF1887126, 0x70D670CE, + 0x00210292, 0xC1007166, 0xA040230C, 0xFFE50588, + 0x37942196, 0x00000281, 0xB99F700E, 0x780A8900, + 0x301C1A1C, 0x780A8901, 0x301C1A1D, 0x36001449, + 0x0D5EE805, 0xE803FB4F, 0x41D3710E, 0x51E00000, + 0x20D82941, 0x2440201F, 0x2619271F, 0x800043DB, + 0xC7831A3C, 0x10842780, 0x20007023, 0x144606D9, + 0x270C3600, 0x0230A000, 0x708E002D, 0x36001448, + 0x05C7212F, 0x080E706E, 0x1A0B0120, 0x1C8C35D8, + 0x1C453018, 0x148C3658, 0x20113600, 0xF2ED84C0, + 0x7001248A, 0x218AC083, 0x704E0FC7, 0x34D81A0C, + 0x014020A8, 0x1804B021, 0xD8FF0015, 0x17C31F00, + 0x301C1C88, 0x08BDC000, 0x1C860030, 0x1445349C, + 0xC002360E, 0x2025082B, 0x34821A0D, 0x250A70AD, + 0x66B82400, 0x0AFA702C, 0x1A0D0060, 0x44103558, + 0xF4BF7014, 0xC00271A6, 0xA0240DEB, 0x71467522, + 0x000045D3, 0xC00028F0, 0xA0240ACB, 0x70AD76A2, + 0x0869C002, 0x1A0D2025, 0x220A3342, 0x0B0E2400, + 0x1A0D0260, 0x251A3498, 0x70141542, 0x2441221A, + 0x800040C3, 0x271A1B3E, 0x708D2603, 0x42626159, + 0x0184229A, 0x627A633B, 0x6059F206, 0x14889161, + 0x4B343701, 0x06C12200, 0x8F00620A, 0x0306242F, + 0xC0834A13, 0xFA6F0A82, 0x4410C283, 0xF4817014, + 0xC0027146, 0xA0040AAB, 0xC00071A5, 0x90040D95, + 0x740CD95F, 0xFB2F0D7A, 0x8F40B911, 0x41C3740C, + 0x000200BF, 0xFB2F0D6A, 0x37031488, 0x0A42C083, + 0x702C0060, 0x08CD4410, 0x70CE0031, 0x740C8F40, + 0x00C041C3, 0x0D4A0002, 0x1488FB2F, 0xD9C13703, + 0x0D3E740C, 0xB910FB2F, 0x08A1C000, 0x71CE0030, + 0x220A70AE, 0x1A0D2400, 0xC0023542, 0x20250A85, + 0x0487202F, 0x2F81251A, 0x28F00000, 0x221A5035, + 0x271A2440, 0x6038260E, 0x4062661E, 0x0184209A, + 0x0A2A661D, 0x75630260, 0x8F20E806, 0xFC6F09E2, + 0xF00740A1, 0x37011488, 0xFC6F08FA, 0x441040A1, + 0x4062E8A7, 0x00C241C3, 0x209A0004, 0x42A20184, + 0x240A43E2, 0x60D804C0, 0x0F852032, 0x1B3E8000, + 0xFB2F0CBE, 0xCA06740C, 0x1447E80A, 0x40A13602, + 0x36041449, 0x08E6702C, 0x43A20320, 0xF1BF7146, + 0xC00071A6, 0xA0040D6F, 0x30141404, 0x70CEF002, + 0x20110E0B, 0x1404F018, 0x14453014, 0x71663600, + 0x01842080, 0xA280234C, 0x30181C45, 0xFFE5060A, + 0x35001C04, 0x36192100, 0x05D771E6, 0x1C04FFEF, + 0x44103500, 0x0507202F, 0x3D082480, 0x341B1404, + 0x78E0C6DA, 0x1600C2EA, 0x8000708D, 0x40500008, + 0x0E1E4130, 0x4608F92F, 0xD907706C, 0xDA284768, + 0x708CBF8F, 0x70AC40E1, 0xF96F0F82, 0x0A2A70CC, + 0x700CF98F, 0xDA08D907, 0x708C706C, 0x0F6E70AC, + 0x70CCF96F, 0xD907700C, 0x706C704C, 0x70AC708C, + 0xF96F0F5A, 0x6F1670CC, 0x704C752C, 0x0004238A, + 0x45C1708C, 0xF96F0F46, 0x257870CC, 0x781B1080, + 0x20300845, 0xD92B68A2, 0x010040C3, 0x42A1000C, + 0x708C706C, 0x70CC45C1, 0xF96F0F22, 0x2F404010, + 0xD92B1240, 0x706C42A1, 0x45C1708C, 0xF96F0F0E, + 0x0440260A, 0xD92B4002, 0x706C42A1, 0x45C1708C, + 0xF00B70CC, 0x12402F40, 0x42A1D92B, 0x708C706C, + 0x260A45C1, 0x0EE60440, 0x700CF94F, 0x744CD907, + 0x708C706C, 0x0ED670AC, 0x70CCF96F, 0xF98F0962, + 0xD907700C, 0x706CDA30, 0x70AC708C, 0xF96F0EBE, + 0xC6CA70CC, 0x1600C2E2, 0x80007080, 0x083F0001, + 0x45CB001E, 0xC148900B, 0x10451D00, 0x800042C3, + 0x12FF0203, 0x8A008481, 0xB810B918, 0x12FF7825, + 0xB9088081, 0x12FE7905, 0x20058080, 0x0F1E8040, + 0x20CAFEAF, 0x1D0002A1, 0xC6C21005, 0x1600C2E4, + 0x80007080, 0x45CB001A, 0xC40C900F, 0x00510821, + 0x900F40C3, 0x1D00C1E4, 0x1D001045, 0x18001005, + 0x18000185, 0x0E820005, 0xD820FEAF, 0x0E7A750C, + 0x1D00FEAF, 0xD8201045, 0x900F46CB, 0x0E6AC1E4, + 0x1E00FEAF, 0x1D001185, 0x1E001005, 0xC6C41005, + 0xD841C2E2, 0x900845CB, 0xB50001E4, 0xFEAF0E4A, + 0xD840750C, 0xC6C2B500, 0xC1A4C3F4, 0x800045CB, + 0x15020150, 0xD97B1500, 0xB2004283, 0x1502B910, + 0xB2011500, 0x15001502, 0x1502B202, 0xB2031500, + 0x15001502, 0x9500B204, 0x9501B205, 0x9502B206, + 0x0A6EB207, 0x740CFB2F, 0x908015D7, 0x1210E804, + 0xF0043092, 0x3092120F, 0x710C702E, 0xE80872CE, + 0x70801600, 0x00258000, 0xF045E888, 0x70801600, + 0x00408000, 0x00100887, 0xC08070AD, 0x78B5700E, + 0x70ED728E, 0x044020F4, 0x2005781B, 0x00040F93, + 0x0A571000, 0x250A2030, 0x70CD2480, 0x1B00255A, + 0x1F852632, 0x04788000, 0x430242A1, 0x0440240A, + 0x201478D5, 0x70020440, 0x0F812000, 0x12288000, + 0x706278EF, 0xB89CB802, 0x8000B89F, 0x262FA900, + 0x41C30007, 0x0005007C, 0xFB2F09D6, 0x71C5740C, + 0x27BF258D, 0x248D71E5, 0x710E25FF, 0x0D8F71A5, + 0x700C9114, 0x2D7E268D, 0xC7D4712E, 0x4350C2F8, + 0x08854630, 0x44100030, 0x20002678, 0x220A70D6, + 0x781B24C0, 0x202222CE, 0x70AE68E9, 0x250D255A, + 0x800041C3, 0x652012E0, 0xB89CB802, 0x0B53B89F, + 0x10002030, 0x653D0118, 0x8D29702E, 0x20008D0B, + 0x40100497, 0x044A222F, 0x72624628, 0x0D4E4003, + 0x702CF8AF, 0x00412044, 0x10400E17, 0x20300E11, + 0x20402042, 0x20402040, 0xF003AD0D, 0x7126AD0C, + 0xA4E409D5, 0x23D02000, 0x15C21D0B, 0x248DAD29, + 0x71A6243F, 0x78E0C6D8, 0x47CBC2EE, 0x12228000, + 0x42508FA0, 0x1090251F, 0x70911600, 0x00048000, + 0x46084330, 0x20D12153, 0x08A58F01, 0x0E390344, + 0x0A99161F, 0x2D402030, 0x6E321380, 0x704C7905, + 0x0408202F, 0x20032314, 0xB80A784F, 0x78257144, + 0xB89CB892, 0x9000B89F, 0x784FB300, 0x84A408E5, + 0xF0347106, 0x7E06C808, 0x1F802604, 0xFFFE0FFF, + 0xFEFF70C3, 0x2843FFF0, 0xF2118100, 0x00D00823, + 0x00900817, 0x0071081F, 0x0CCA40C1, 0x41A1FD2F, + 0x710C7014, 0x720CF408, 0x700CF006, 0x730CF004, + 0x740CF002, 0x2B01215F, 0x8F037915, 0x0340203C, + 0x26447914, 0x60381040, 0x882660F8, 0x0408202F, + 0x20002314, 0xB0207106, 0xF1B071A5, 0x78E0C6CE, + 0x4410C2F8, 0x03952840, 0x1600785B, 0x80007096, + 0x2044008E, 0xD8E40182, 0x2C407859, 0xB8C12318, + 0x2F8E2505, 0x01C89004, 0x0F112054, 0x040F2040, + 0x01972140, 0x704E706E, 0x700E70AD, 0x26012205, + 0x7825C808, 0xA07E2653, 0x900441C3, 0xF20D0000, + 0xB80278E5, 0x90007825, 0x01C120AD, 0xB8647314, + 0x002D20CA, 0x2005F00C, 0xB8020440, 0x218A7825, + 0x90000FBF, 0x770CB8E6, 0x004120CA, 0x20022700, + 0xE810CA07, 0x02310811, 0x37011221, 0x0F800915, + 0x68150000, 0x02510811, 0x0F81090D, 0x71960000, + 0xF003BA86, 0xD808BA87, 0xFEAF0B4E, 0x2505B640, + 0x225624C0, 0x20052812, 0x90040F80, 0x900001CC, + 0x20102380, 0x2800B8C0, 0x71060400, 0xA2740871, + 0x78B07D05, 0x087E4182, 0x1E00FB2F, 0x780F1005, + 0x78E0C6D8, 0x2840C2E6, 0x4708038E, 0x2605D889, + 0x90041F8D, 0xB50001C8, 0xFEAF0AFE, 0x244AD808, + 0x708D7240, 0x702C704C, 0x20A8706C, 0x26050400, + 0x22801080, 0x20050010, 0x90040F80, 0x900001CC, + 0x7838B8C0, 0x7B057124, 0x41E17870, 0xFB2F0826, + 0x780FB580, 0x78E0C6C6, 0x014422AA, 0x010421AA, + 0x800040C3, 0xA04104B0, 0xA0207FE0, 0x45CBC0E6, + 0x12228000, 0x46008D60, 0x0A1B718D, 0x700C00B0, + 0x0241235F, 0x00710A13, 0xE108DE08, 0xD808DC09, + 0x4160F003, 0x150170CD, 0x4E12108B, 0x00492240, + 0x0B377D6F, 0x0E2F1344, 0xBD0E1024, 0x7240240A, + 0x20A84008, 0x7A2F0440, 0x26146199, 0x2840008F, + 0x7AA51282, 0x22057105, 0x90040F82, 0x924001D0, + 0x7164B740, 0xC4C6F1E6, 0x40C3C5E1, 0x04988000, + 0xE9AE8820, 0x00431800, 0xE82ACA00, 0x70AD712D, + 0x800144CB, 0x2D404FA0, 0x244A1381, 0x42817240, + 0x706D700D, 0x05C020A8, 0x02002105, 0x20057405, + 0x90040F83, 0x8A000200, 0x2900B300, 0x120112C3, + 0x71650480, 0x7825B80A, 0x0F802005, 0x02F89004, + 0x71A5B060, 0x0DC3CA00, 0xE4099024, 0x78E0C4C2, + 0xDC25C808, 0x43C3BC9F, 0x12248000, 0x2005B802, + 0x90070F81, 0xCC23C408, 0x8C00B100, 0x8B01E818, + 0x082D8B20, 0x78220064, 0x240A7104, 0x20A87000, + 0x40C30400, 0x049C8000, 0x004220F4, 0x03802940, + 0x20057124, 0x90040F80, 0xB040028C, 0x70148C1B, + 0x8B037CE0, 0x72108B42, 0x07CD20E0, 0x71047842, + 0x7000240A, 0x03C020A8, 0x800040C3, 0x20F4049C, + 0x2A400081, 0x71440380, 0x0F802005, 0x028C9004, + 0x7EE0B020, 0x21326038, 0x80000F82, 0xA8401880, + 0x0F822132, 0x18CB8000, 0x0082184B, 0x0F822132, + 0x19168000, 0x00821896, 0x0F812132, 0x19618000, + 0x18E17FE0, 0x78E00042, 0x4748C2E6, 0x00851101, + 0x46288861, 0x00841100, 0x88404508, 0x41C3740C, + 0x000500D7, 0xFAEF0D6A, 0x8E0046E1, 0x71108D20, + 0xF7C7F233, 0x03E50915, 0xAD006909, 0x0835F00F, + 0x770403C5, 0xF01FAE00, 0x0F1349F0, 0xAD001070, + 0x10900F1B, 0x10C01501, 0x8D01F005, 0x08002054, + 0x262FAD01, 0x0032F005, 0xD87F0003, 0xF015AD01, + 0x0F1378E2, 0xAE001070, 0x10900F1B, 0x10C01601, + 0x8E01F005, 0x08002054, 0x262FAE01, 0x000AF005, + 0xD87F0003, 0x8E60AE01, 0x00D841C3, 0x8D400003, + 0x09F644E1, 0x2238F8AF, 0xC6C600C0, 0x41C3C2E4, + 0x0000031A, 0xFAEF0CDA, 0x086ED80A, 0xD80AFEAF, + 0xF98F0D2E, 0x800141C3, 0x080A6800, 0x206FFA2F, + 0xE8880043, 0x031B41C3, 0x0CB60000, 0xD80AFAEF, + 0xFC0F0FCE, 0x43204200, 0x031C41C3, 0x0CA20001, + 0xD80AFAEF, 0xF98F0CFA, 0x000046CB, 0x45CB3420, + 0x34D80000, 0x13650E37, 0x41C3D80A, 0x0001031D, + 0xFAEF0C7E, 0x700C42A1, 0xFA2F0872, 0x460841A1, + 0x031E41C3, 0x0C6A0000, 0xD80AFAEF, 0x40A1D941, + 0xF9EF0FA2, 0x60DDB90A, 0x41C3F017, 0x0001031F, + 0xFAEF0C4E, 0x700C42C1, 0xF9EF0F8A, 0xD91941C1, + 0xB9154508, 0xFAEF0C3A, 0xD941D80A, 0x082E40C1, + 0xB90AFA2F, 0xED88651D, 0x032141C3, 0x0C220000, + 0xD80AFAEF, 0xFC0F0F3A, 0x800045CB, 0x85400448, + 0x0003223D, 0x223D8541, 0x71500040, 0x00C120CA, + 0x0F1EE885, 0xA521FC0F, 0x0F16A500, 0x4200FC0F, + 0x41C34320, 0x00010322, 0xFAEF0BE6, 0x1600D80A, + 0x80007080, 0x082F0004, 0x8501015E, 0x70148520, + 0x0F81213C, 0xF42C0001, 0xE98D79C0, 0x032341C3, + 0x0BBE0000, 0xD80AFAEF, 0x700CD9C9, 0xF8AF08BA, + 0xC6C4B912, 0x4010C2E8, 0x085AD80F, 0xD90FFA2F, + 0x0EAAD80F, 0x712CF92F, 0x800046CB, 0x8EA01222, + 0x1280255F, 0x0F8F2000, 0x4DFC8001, 0x085F8E01, + 0x40C30344, 0x12D98000, 0x084D8800, 0x79AF036E, + 0x00A00D02, 0x2D404002, 0x244A138B, 0x708D7280, + 0x20A8706C, 0x082B0680, 0x240500EE, 0x210512C1, + 0x90040F82, 0x210502DC, 0x90040F81, 0x924002E0, + 0x213D9120, 0x793B0081, 0x67796949, 0x2480A940, + 0x71641010, 0x71A5E70A, 0xC6C8F1D2, 0x084EC2E2, + 0x45080220, 0x1600E888, 0x80007080, 0x0811000B, + 0x40A100BF, 0x0220091E, 0xC6C240A1, 0xFCEF0FC2, + 0xC6C2702C, 0x1600C2E6, 0x8000708E, 0x47280008, + 0xF8EF0CCE, 0x700C4508, 0x744CD907, 0x708C706C, + 0x0E3A70AC, 0x70CCF92F, 0x10802678, 0x08DA781B, + 0x68C2F96F, 0x700CEF11, 0x724CD907, 0x708C706C, + 0x0E1A70AC, 0x74CCF92F, 0x752C704C, 0x238A4040, + 0xB8950004, 0x704CF01B, 0x4040752C, 0x0004238A, + 0x708CB895, 0x0DF645A1, 0x70CCF92F, 0xD92B74ED, + 0x42C1BF98, 0x706C40E1, 0x45A1708C, 0xF92F0DDE, + 0x40E170CC, 0x42C1D92B, 0x708C706C, 0x0DCE45A1, + 0x70CCF92F, 0xD92BD841, 0x42C1B812, 0x708C706C, + 0x0DBA45A1, 0x70CCF92F, 0xD907700C, 0x706C744C, + 0x70AC708C, 0xF92F0DA6, 0x0280264A, 0xD907706C, + 0x744C4060, 0x708CB88F, 0x0D9270AC, 0x70CCF92F, + 0xD907700C, 0x706CDA08, 0x70AC708C, 0xF92F0D7E, + 0x080E70CC, 0x700CF94F, 0x744CD907, 0x708C706C, + 0x0D6A70AC, 0x70CCF92F, 0x78E0C6C6, 0x2482C3F0, + 0x42103403, 0x38002455, 0x702C4330, 0xF86F0A12, + 0x40C3DA50, 0xF0B00000, 0xB415448B, 0x73044899, + 0xB409B42F, 0x0A812057, 0x000040C3, 0x1C66FF74, + 0x21573004, 0x1C5A09C0, 0xB86E3004, 0x30041C42, + 0xB41BB863, 0x000140C3, 0xC049F0BA, 0x710C686E, + 0xB88EDA07, 0x30841C5C, 0x30841C44, 0xB45C71AD, + 0x03422342, 0x40C3B408, 0xFFB50001, 0x2080C043, + 0xC2400339, 0x1C6ADA40, 0x20403084, 0xC05B0802, + 0x6843C258, 0xB4237704, 0x41C3C04F, 0xFE030000, + 0x70801600, 0x00088000, 0x00802079, 0x30441C4E, + 0x30041C40, 0xB41D702C, 0xC255B802, 0x000742C3, + 0xB417F004, 0xB42EC808, 0xB425B42B, 0x30441C70, + 0x30441C64, 0x30441C5E, 0x30441C58, 0x30441C52, + 0x30441C4C, 0x6B4BC252, 0x30441C46, 0x2005B43A, + 0x000E0F81, 0xC15EF00B, 0x09412254, 0xC3467825, + 0x30041C72, 0xC24CB830, 0x1C74702C, 0x700C3004, + 0x706C704C, 0xB4B0B4B6, 0xB4A4B4AA, 0x33441C68, + 0x33441C50, 0xB4B1B4B4, 0x30851C04, 0x30851C7C, + 0xFCEF0A7E, 0x33441C76, 0x000042C3, 0x700C5555, + 0x4340722C, 0x09E24440, 0x4540FCEF, 0x094EC080, + 0xD97E0260, 0x0D6ED80F, 0xD90FF9EF, 0x900741D3, + 0x1900F804, 0x47CB2105, 0x12228000, 0x6832C808, + 0x2105D880, 0x90070F82, 0xB200FC48, 0x0F822105, + 0xFC4C9007, 0x2105B200, 0x90070F82, 0xB200FC40, + 0x0F822105, 0xFC449007, 0x2D00B200, 0xB8021480, + 0x200F8F40, 0x8F01048E, 0x00A4082B, 0xBA0E7842, + 0x240A7104, 0x20A87000, 0x210503C0, 0x72C30080, + 0x40000000, 0x0F802005, 0x057C9004, 0xBB8A9060, + 0x0C62B060, 0x09DEFC0F, 0x242F0000, 0xD8552387, + 0x704CD955, 0x0E5E706C, 0x240A0060, 0x40820500, + 0xFFEF0D26, 0xD860702C, 0xF92F0B22, 0x208A712C, + 0x40D30FC7, 0xC2CC9007, 0x20041800, 0x20041804, + 0x71001600, 0x02C09004, 0x0C002045, 0xA00418F4, + 0xA34418F8, 0x8F008F81, 0x10240C43, 0x2840D9AC, + 0x244A0388, 0x706D7240, 0x20A8704C, 0x0B1305C0, + 0x20002031, 0x111C0681, 0x0A190081, 0x20050040, + 0x210512C1, 0x90040F81, 0x916001D0, 0xB160E320, + 0x10102380, 0x71047144, 0x46CBF1E0, 0x01068000, + 0xD8538E40, 0x0DCE4340, 0x240A0060, 0x8E000500, + 0x8FA0E81C, 0x08258F01, 0x8E000344, 0x00A00916, + 0x2D4079AF, 0x21051381, 0x90040F81, 0xB1003830, + 0x75108F01, 0xF7B371A5, 0x0FC7218A, 0x900740C3, + 0x1800F834, 0xB0220005, 0x0C5E4082, 0x712CFFEF, + 0x000042C3, 0x700CAC53, 0x4340722C, 0x085A4440, + 0x4540FCEF, 0x0BEED80F, 0xD90FF9EF, 0xDD2870CD, + 0x0A3AD808, 0x712CF92F, 0x108B1701, 0x0B578F00, + 0xD90F1024, 0x03892840, 0x7240244A, 0x708D700D, + 0x07C020A8, 0x20310B11, 0x06812000, 0x0081111C, + 0x10400C29, 0x12412005, 0x210570CD, 0x90040F82, + 0x210502DC, 0x90040F81, 0x924001D0, 0xEA069160, + 0x08032354, 0xB1604648, 0x10102080, 0x71047185, + 0x0B82F1D7, 0xD80FF9EF, 0x133F258C, 0x10002678, + 0x02DD41C3, 0x0BC20001, 0x4242F86F, 0x38002455, + 0x0F9E712C, 0x704CFFAF, 0x0ABE4042, 0x712CFA2F, + 0x0F002054, 0x38012455, 0x706C714C, 0x70AC708C, + 0x0260081E, 0x40C34588, 0xF8309007, 0x73441E00, + 0xC29C9007, 0xA34418F8, 0x73441E00, 0x0004901C, + 0x23441900, 0xB0A2B0A0, 0x0020080A, 0xC7D0B0A4, + 0xD820C2E2, 0x900B45CB, 0x09EEC280, 0x1D00FE6F, + 0x1D001045, 0xC6C21005, 0x1CFCC2FA, 0x2482B6C8, + 0x41DB3002, 0xC17C9007, 0x901C43D3, 0x190004A8, + 0x42103005, 0x20551B5C, 0xC8084338, 0x800041C3, + 0xDA6C04B8, 0x71AD702E, 0x2005B802, 0x180004C0, + 0x0E160045, 0xC085F82F, 0x702C700C, 0x0FA2704C, + 0x706CFCAF, 0x722C700C, 0x706C704C, 0x0F0A708C, + 0x70ACFCAF, 0x0E76C085, 0xD96C0220, 0xFACF0BC2, + 0x0A92D80F, 0xD90FF9EF, 0xFF8F0B1A, 0x40C3D90A, + 0x4E748001, 0x00200E8A, 0x40024010, 0x09AAD90A, + 0x704CF96F, 0xD90A4002, 0xFDEF0B8A, 0x4002DA59, + 0x00200E6E, 0x4002D92E, 0x098ED92E, 0x704CF96F, + 0x0E5E4002, 0xD9120020, 0xD9124002, 0xF96F097A, + 0x0D1EDAEF, 0xC0810060, 0x09FEC081, 0xD90AFB6F, + 0x09F6C081, 0xD92EFB6F, 0x09EEC081, 0xD912FB6F, + 0x800047CB, 0x41421220, 0x219F8F00, 0x704C02C1, + 0x0582209F, 0x708CC381, 0x2D006119, 0xB8021480, + 0x200F7102, 0x6D12048D, 0x7E0F78A5, 0x087E40C1, + 0x40D90220, 0x0F824002, 0xD90AFFAF, 0x0F7A4002, + 0xD912FFAF, 0x0F724002, 0xD92EFFAF, 0x700C7DAF, + 0x704C702C, 0x0B4E706C, 0x44A10060, 0x098A710C, + 0x712C0060, 0x0CB640A1, 0x702C01E0, 0x02D341C3, + 0x0CFE0000, 0x740CFAAF, 0x0802D860, 0x712CF92F, + 0xFC8F0B6E, 0x8F228F03, 0x00640829, 0x68417822, + 0x03802940, 0x7080240A, 0x030020A8, 0x0F812005, + 0x01D09004, 0x70C39140, 0x40000000, 0xB140BAC5, + 0x712C700C, 0xF8EF0FC6, 0x3FC11C00, 0x0966D80F, + 0xD90FF9EF, 0x0C5640A1, 0x712C01E0, 0x0FC7208A, + 0x900746CB, 0xB600C2CC, 0xB602D9B5, 0x1EF8D881, + 0xD8309004, 0x1EF4B912, 0x0C869004, 0x740CFAAF, + 0x40A1DDFF, 0x461045B1, 0x700C44B1, 0xF8EF0F7E, + 0x8F03712C, 0x08618F22, 0x70EE0064, 0x29407822, + 0x7104038C, 0x7000240A, 0x07C020A8, 0x2405C280, + 0x90041F80, 0x900002DC, 0x2079623A, 0x8A000003, + 0x7865781B, 0x2053AA00, 0x240580BE, 0x90041F80, + 0x904001D0, 0x2254F205, 0x71EE0802, 0x7124B040, + 0x000074C3, 0x14034000, 0xC5203096, 0x30951402, + 0x30941401, 0x08BED80F, 0xD90FF9EF, 0x41C3740C, + 0x000402D5, 0x438242A1, 0x0540240A, 0xFAAF0BF2, + 0x0580250A, 0x090B7126, 0x0F732E15, 0x41C3A011, + 0x000002D7, 0xF86F08E2, 0x20002778, 0x740CD95B, + 0xFAAF0BCE, 0x8F03B913, 0x082D8F22, 0x78220064, + 0x29406841, 0x240A0380, 0x20A87080, 0x20050380, + 0x90040F81, 0x914001D0, 0x000070C3, 0x22554000, + 0xB1400802, 0xB6A070AD, 0x0A16B6A2, 0x1EF4FCAF, + 0x700C9344, 0x00200D42, 0xD881712C, 0x02D941C3, + 0x1EF80000, 0x0B7A9004, 0x740CFAAF, 0x0E7ED840, + 0x712CF8EF, 0x712C4063, 0xFFAF0C56, 0x8F23724C, + 0x09238F02, 0x79020024, 0x240A7124, 0x20A87040, + 0x23F402C0, 0x23143001, 0x21803002, 0x7104003E, + 0x4042B220, 0xF9EF0F52, 0x48C8712C, 0x7825C808, + 0x714C4163, 0x708C706C, 0x02200CB6, 0xD92071AC, + 0x900740C3, 0xB0A0C29C, 0x22C1229F, 0x804418EC, + 0x834418EC, 0x73441E00, 0xC164900B, 0x93441EF8, + 0x30451900, 0xB802C808, 0x04C12005, 0xFFEF0C96, + 0x8F00B1A0, 0x209F704C, 0xC3810582, 0x7042708C, + 0x04012000, 0x01E00E16, 0xCA004003, 0x10250D31, + 0x138C2D40, 0x7240244A, 0x702C704C, 0x038020A8, + 0x2405716C, 0x7B381080, 0x0F802005, 0x02F89004, + 0x00102280, 0xB0607124, 0xF1E971A5, 0x30022480, + 0x341B1404, 0x78E0C6DA, 0x4408C0F1, 0x2084880B, + 0xAC0B01C2, 0xB8A38C01, 0x1600AC01, 0x800070C0, + 0x080F000D, 0x8C130012, 0x03002046, 0x0A8EAC13, + 0xE808F88F, 0xB8858C0D, 0x8C03AC0D, 0xAC03B887, + 0xF98F0D4A, 0x8C15E807, 0xAC15B8A5, 0xB8868C03, + 0xD840AC03, 0x10831C14, 0x8C0DAC10, 0xAC0DB8A4, + 0x20458C11, 0xAC110E00, 0x206C8C12, 0xAC120080, + 0x20448C1C, 0xAC1C0300, 0x10801429, 0xC0D1B8C4, + 0x1C297FE0, 0x78E01002, 0x40C3C5E1, 0x04988000, + 0xE9328820, 0xA840704C, 0x0A5DCA00, 0x2A400025, + 0x244A0381, 0x706C7240, 0x090020A8, 0x00802216, + 0x20006078, 0x80010F8D, 0x6B124FA0, 0x20057825, + 0x90040F80, 0x90800200, 0x0B13AD80, 0xB0600231, + 0x22008D80, 0x181C0680, 0x2B400302, 0x718D0280, + 0x7C787825, 0x20057164, 0x90040F80, 0xB08002F8, + 0xF1D47144, 0x78E0C4C2, 0xC1A2C3E6, 0x900042C3, + 0x92800184, 0x903841C3, 0x246C0184, 0x91601140, + 0x236CB200, 0xB1000140, 0x9202722D, 0xB8C891A2, + 0x704CB280, 0x44CBBDC8, 0x05A48000, 0xC241B160, + 0xB1014183, 0xC808B1A0, 0x10832415, 0x30062440, + 0x70AD720D, 0xF41C7AAB, 0x13412415, 0x7E0583C1, + 0x79C58123, 0x2105B902, 0x90030F8E, 0xB99CC000, + 0x91E0B99F, 0x134124F4, 0xC1817F26, 0x034B21F4, + 0x008126F4, 0x02C12900, 0xB62079E5, 0x193F208D, + 0x218D71AD, 0x714C16FF, 0x2042C805, 0xF20E803C, + 0xD99C700C, 0x028020A8, 0x0F822005, 0x03649004, + 0x000070C3, 0xB2204000, 0x9661468B, 0x41C3740C, + 0x00020071, 0x08EA96A0, 0x42A1FAAF, 0xDC7FC808, + 0x2553BC09, 0x68321202, 0x0F832105, 0x20289024, + 0x21059300, 0x90240F81, 0x7884202C, 0x008D2005, + 0x78849100, 0x7845B3A0, 0x740CB100, 0x007241C3, + 0x08AE0001, 0x9640FAAF, 0x78E0C7C6, 0xDC25C808, + 0x43C3BC9F, 0x12248000, 0x21056832, 0x90070F80, + 0x2105C408, 0x90040F81, 0x91200408, 0x305C1A23, + 0x0F812104, 0xFF9F0000, 0x8C00B020, 0x8B01E818, + 0x082D8B20, 0x78220064, 0x240A7104, 0x20A87000, + 0x29400400, 0x26140380, 0x80007042, 0x2005049C, + 0x90040F80, 0x9000028C, 0xB2007124, 0x70148C1B, + 0x8B037CE0, 0x71108B22, 0x07CD20E0, 0x71047822, + 0x7000240A, 0x03C020A8, 0x03802940, 0x70422614, + 0x049C8000, 0x0F802005, 0x028C9004, 0x71249000, + 0x7EE0B200, 0x45CBC2E8, 0x12228000, 0x40108DC0, + 0x085B8D01, 0x40C30384, 0x12D98000, 0x084B8800, + 0x79CF03AE, 0x0060097E, 0x44084002, 0x2E40C808, + 0x244A1382, 0x68327280, 0x702C7A25, 0x054020A8, + 0x104E0C25, 0x1500265A, 0x20007834, 0x80010F83, + 0x29404E24, 0x78450280, 0x0F802005, 0x03209004, + 0xB3009000, 0x71C57124, 0xC6C8F1D4, 0x706CC808, + 0x6852726D, 0xE808710C, 0x70801600, 0x00258000, + 0xF020E888, 0x70801600, 0x00408000, 0x7CE07014, + 0x7180244A, 0x058020A8, 0x03802B40, 0x800044CB, + 0x784519AC, 0x20057C74, 0x90000F81, 0x912001C0, + 0x0F802005, 0x01B49000, 0x7164B420, 0xB40E9000, + 0x238DDB07, 0x700C16FF, 0x78E07EE0, 0x21006038, + 0x80000F83, 0x88401880, 0x2100AB40, 0x80000F83, + 0x104B18CB, 0xAB400082, 0x0F832100, 0x19168000, + 0x00821096, 0x800071C3, 0xAB401961, 0x008010E1, + 0xA9007FE0, 0x2142EA1E, 0x7CE0803C, 0x064020A8, + 0x04831001, 0x04811001, 0x04821001, 0x7B25B908, + 0x04811001, 0x7945B908, 0x7965B910, 0xB99CB902, + 0x9120B99F, 0x00521801, 0x1801B928, 0xF0200052, + 0x803C2142, 0x072220E8, 0x04831001, 0x04811001, + 0x04821001, 0x7B25B908, 0x04811001, 0x7945B908, + 0x04821001, 0x7965B910, 0x2105B902, 0x90030F83, + 0x1001C000, 0xB9080481, 0xB3207945, 0x78E07EE0, + 0x7915793B, 0x0F802100, 0x04588000, 0xB0407FE0, + 0x40C34100, 0x12DA8000, 0xE8898800, 0x70801600, + 0x00088000, 0x01110807, 0x7FE0793B, 0x78E07830, + 0xE0C04100, 0xD840F704, 0xF0044831, 0x003F2180, + 0x782F7FE0, 0x24056892, 0x90071F80, 0x1800C2D4, + 0x40C30005, 0x12228000, 0x88608841, 0x20E07350, + 0x4A7007CD, 0x7104BB0E, 0x7000240A, 0x030020A8, + 0x10C02405, 0x000073C3, 0x20054000, 0x90040F80, + 0xB02002D4, 0x78E07EE0, 0x0443206F, 0x800042C3, + 0x8820121E, 0x0703219F, 0x810010FE, 0x01031A01, + 0x77046038, 0x00402805, 0xAA007FE0, 0xC1A4C3E4, + 0x800145CB, 0x46084E74, 0x40A17034, 0xF20BD912, + 0xFFCF0E8E, 0xD91240A1, 0xFDAF0B9A, 0x714CDA10, + 0x0806F004, 0x704CFF8F, 0x41C3C808, 0x0504901C, + 0x7825B802, 0xC080B040, 0x00200D36, 0x804519A4, + 0x0A16C080, 0xD912FB2F, 0x702C40A1, 0x43C1C280, + 0x01E00D2A, 0xC7C4708C, 0x70CDC0E6, 0x800042C3, + 0x1E001222, 0x90077384, 0x8AE1FED4, 0x1047232F, + 0x0F638A60, 0x2B4010E4, 0x238C038D, 0xF4169FC3, + 0x1F822505, 0x3ED49004, 0x023F091D, 0x2300B200, + 0x121C0682, 0xBA0A0082, 0x25057D45, 0x90041F82, + 0xB2C002D4, 0xF1E77164, 0x4028702D, 0x08F9704C, + 0x0AF59010, 0x202F8275, 0xF7499202, 0x124C2505, + 0x1F8C2405, 0x02D49004, 0x2180B400, 0x71441010, + 0xC4C6F1EF, 0x0FB2C2E2, 0x4408F92F, 0x1843256F, + 0x09679520, 0x41C30050, 0x12218000, 0x800043C3, + 0x0C1B0458, 0x894010F1, 0x15307B55, 0x93401081, + 0x9321E909, 0x00422208, 0x2450F005, 0x79551001, + 0x621B6172, 0x6852C808, 0x0F802205, 0x0034901C, + 0xC805B060, 0x803C2042, 0x700CF20D, 0x02C020A8, + 0x00012205, 0x000070C3, 0xB9924000, 0xB99FB99C, + 0x0E42B160, 0xC6C2FF8F, 0xC808C2E6, 0x120570AD, + 0x706C3608, 0x1202212F, 0x800046CB, 0x68920458, + 0x02250B51, 0x233DD940, 0xB99F024B, 0x20798900, + 0x23040002, 0x26F4908F, 0xF20613C2, 0x00D10817, + 0xF0079623, 0x808111E5, 0x00D1090B, 0x22089622, + 0x26140042, 0x716413C1, 0xB142B140, 0x13412405, + 0x75C3B992, 0x40000000, 0xB99FB99C, 0xF1DAB140, + 0x96219600, 0xF92F0ED2, 0x000C2108, 0x60985020, + 0x2105B902, 0x901C0F81, 0xB1000034, 0x78E0C6C6, + 0xC1A4C3E6, 0xC0804708, 0x00200B96, 0xC0804528, + 0xFB2F0876, 0x46CBD918, 0x4E748001, 0xD91840C1, + 0x0020096A, 0x78BD42E1, 0x800041C3, 0xB8C01220, + 0x209F8920, 0x704C02C1, 0x0582219F, 0x708CC380, + 0x6D126119, 0x61D978A5, 0x01A00F02, 0xC7C6780F, + 0x4528C2E4, 0xF86F0D9A, 0x700C4608, 0x724C762C, + 0x244A43C1, 0x45A10780, 0xF8AF0F02, 0x700C70CC, + 0x09EED922, 0x704CF8EF, 0x0EA2700C, 0x712CF8AF, + 0x78E0C6C4, 0x900742C3, 0xB200C2E4, 0xB2227FE0, + 0xC1A4C3E8, 0xC0804010, 0x0B064548, 0x47280020, + 0xAFC3208C, 0x800146CB, 0xF20C4E74, 0x28C02054, + 0xC080790F, 0xFAEF0FD2, 0x40C14030, 0xF02C4102, + 0x0FC6C080, 0xD946FAEF, 0x0FBEC080, 0xD947FAEF, + 0x0FB6C080, 0xD948FAEF, 0x0FAEC080, 0xD949FAEF, + 0x0FA6C080, 0xD94AFAEF, 0xD94640C1, 0x0020089E, + 0x40C142E1, 0x0896D947, 0x42E10020, 0xD94840C1, + 0x0020088A, 0x40C142E1, 0x0882D949, 0x42E10020, + 0xD94A40C1, 0x00200876, 0x79BD42E1, 0x800040C3, + 0x88001220, 0x209FB9C0, 0x704C0582, 0x02C1219F, + 0x708CC380, 0x6D126119, 0x61D978A5, 0x01A00E0E, + 0xC7C8780F, 0xDB1FC0F1, 0xC8084100, 0x2085BB0B, + 0xDA0B08C1, 0x0AEA708C, 0x4128FC2F, 0xC8084600, + 0x09012085, 0xDA0B4121, 0xFC2F0AD6, 0xC0D1718C, + 0x40C07FE0, 0xC8084100, 0x08C12085, 0x238ADA09, + 0x02BD0008, 0x708CFC2F, 0x184B6038, 0xA8400082, + 0x00821896, 0x18E17FE0, 0x78E00082, 0x45CBC2E2, + 0x04588000, 0x0FA2E806, 0x700CFFEF, 0xC6C2B504, + 0xFFEF0F96, 0xC6C29504, 0x4528C2E4, 0xF86F0C32, + 0x700C4608, 0x724C762C, 0x248A43C1, 0x45A10141, + 0xF8AF0D9A, 0x700C70CC, 0x0886D922, 0x704CF8EF, + 0x0D3A700C, 0x712CF8AF, 0x78E0C6C4, 0xDD25C2E2, + 0x901C41C3, 0xBD9F01C8, 0x1480151B, 0x15C6B100, + 0x0BD29480, 0xB102FF6F, 0x08359500, 0x00000F84, + 0xC8080C81, 0x40C36852, 0x0C50902C, 0x22059020, + 0x90240F8C, 0x9062201C, 0x71046917, 0xB4006B37, + 0x0F802205, 0x20209024, 0xB0207124, 0x78E0C6C2, + 0x4588C2EA, 0x47484668, 0x0BA64030, 0x4110F86F, + 0x800140C3, 0x88604E88, 0xBBC5700C, 0xDA22762C, + 0x0500244A, 0x0D0645A1, 0x70CCF8AF, 0x762C700C, + 0x4322DA22, 0x0840244A, 0x0CF245A1, 0x70CCF8AF, + 0x700CDA22, 0x4302762C, 0x45A14440, 0xF8AF0CDE, + 0x700C70CC, 0xDA22762C, 0x244A43E1, 0x45A107C0, + 0xF8AF0CCA, 0x700C70CC, 0xDA22762C, 0x244A43C1, + 0x45A10800, 0xF8AF0CB6, 0x700C70CC, 0xF8AF0C5E, + 0xC6CA712C, 0xD925C2E6, 0x8900B99F, 0x7F0589FB, + 0x000540C3, 0x0D6ECC60, 0x752CFDEF, 0xFE2F0CD6, + 0x0B0E4608, 0xBFC1F84F, 0xD90C700C, 0x706CDA20, + 0x45E1708C, 0xF8AF0C76, 0x40C370CC, 0x1D4C0000, + 0xFDEF0D42, 0x60DD722C, 0x262F700C, 0xD9070347, + 0x706C704C, 0x0C56708C, 0x70ACF8AF, 0x920D2D41, + 0x700CF20D, 0x704CD907, 0x708C706C, 0x0C3E70AC, + 0x268AF8AF, 0x258C0FC3, 0x700C1DFF, 0x744CD910, + 0x708C706C, 0x0C2645E1, 0x70CCF8AF, 0x0387262F, + 0xD907700C, 0x706C704C, 0x0C12708C, 0x70ACF8AF, + 0x920D2E41, 0x700CF20D, 0x704CD907, 0x708C706C, + 0x0BFA70AC, 0x268AF8AF, 0x258C0FC3, 0xD8801DFF, + 0x704CD907, 0x708C706C, 0x0BE270AC, 0x70CCF8AF, + 0x0B8A700C, 0x712CF8AF, 0x78E0C6C6, 0xA023772C, + 0xA021A022, 0xA0207FE0, 0x4628C2E4, 0x21534508, + 0x710C0142, 0xF7EF0C1A, 0xBE23702C, 0x16022644, + 0x8540655D, 0xA5007845, 0x78258501, 0xC6C4A501, + 0x700CC0F1, 0x0E8AD910, 0x714CF8AF, 0x702CD810, + 0xF8AF0E7E, 0x700C714C, 0x0E76D90A, 0x714CF8AF, + 0x7EE0C0D1, 0x752C700C, 0xF8AF0665, 0x78E0714C, + 0x0FAAC0F1, 0x208AF8AF, 0x40C30B04, 0x04888000, + 0xF8AF0FAA, 0x710C9000, 0x1E00702C, 0x901C7004, + 0x0B2204C4, 0x700CF8AF, 0x000040C3, 0x0C06C350, + 0xD90FFDEF, 0x7EE0C0D1, 0x901C41C3, 0x190004C4, + 0x11C00005, 0xE87F8100, 0x800519BC, 0x000040C3, + 0x03E11388, 0x702CFDEF, 0x4030C2F0, 0x41004508, + 0x800040C3, 0x88C01220, 0x02C1219F, 0x47CB40C1, + 0x4E758001, 0x0582209F, 0x67386119, 0x710C882F, + 0x080F78B8, 0xB8022030, 0x00D4216C, 0x2145F003, + 0x095E0154, 0x200FF86F, 0x087B0351, 0x40822030, + 0x12C1259F, 0x1582269F, 0x01012085, 0x2447222F, + 0x700C7B0F, 0xDA22762C, 0x0400244A, 0x250A65DD, + 0x67BE0480, 0x13D32532, 0x10901613, 0xF8AF0A9E, + 0x234470CC, 0xF20CA213, 0x700C65EB, 0xDA22762C, + 0x250A718C, 0x0A860480, 0x70CCF8AF, 0x20D02053, + 0x20B1080D, 0x08F87076, 0xF00DF841, 0x700C8E73, + 0xDA22762C, 0x0500244A, 0x0480250A, 0xF8AF0A5E, + 0x244F70CC, 0x252F2183, 0x7B6F0447, 0x762CD880, + 0x244ADA22, 0x0A460400, 0x70CCF8AF, 0x09EE700C, + 0x712CF8AF, 0x71001600, 0x00068000, 0x000070D3, + 0x41C3257F, 0x57300005, 0x000340C3, 0x20CAD090, + 0x0AE2004D, 0x702CFDEF, 0x78E0C6D0, 0x88945020, + 0x69528801, 0x0F812205, 0xC054900F, 0x00C0206D, + 0x0F832205, 0xC02C903B, 0x2205B100, 0x90070F81, + 0x2444C1F0, 0xBCC11300, 0x2478B100, 0x783B1001, + 0x2205B300, 0x90070F80, 0x7FE0C3EC, 0x78E0B020, + 0x215FC0E4, 0x44CB0A03, 0x113A8000, 0x647970CD, + 0x63959141, 0x0E237D04, 0x231510A5, 0x61990381, + 0x08139123, 0x79DB006E, 0x00412314, 0x91226199, + 0x71C57D25, 0x40A1F1F1, 0x78E0C4C4, 0x901C44CB, + 0x16000004, 0x90047102, 0x94203804, 0x900743C3, + 0xBAA0F804, 0x7A05B9A0, 0xB3407825, 0x7FE0B400, + 0x00051B04, 0xE81EC2E2, 0x740CD9BF, 0xFA2F0E02, + 0x700CB912, 0xD92572AD, 0x8940B99F, 0x7A25893B, + 0x7918712C, 0x210FB902, 0x794B0001, 0x09FAF206, + 0x712CF9AF, 0xFB8F091A, 0x1BFF258D, 0xC6C2710C, + 0x02FB41C3, 0x0DCA0000, 0xD80AFA2F, 0x1A43256F, + 0xFC2F0E5A, 0x14051D00, 0x081ED807, 0x1A060020, + 0xD8103043, 0x30031A06, 0xB500B88F, 0xFEAF0B3E, + 0xC6C2740C, 0xC1B6C3F6, 0xD8404608, 0x1000B89F, + 0x0ABA0095, 0x10E50160, 0x70148092, 0x20CAD80C, + 0x267C01A2, 0x1A0B1393, 0x2E013002, 0x00007380, + 0x20443679, 0x0E150051, 0x230411F1, 0x16002453, + 0x80007080, 0xE88D0161, 0x73146E0B, 0x000D0212, + 0x70801600, 0x01608000, 0x02067014, 0x0DC20001, + 0x712CF8EF, 0x23524708, 0x26792001, 0x782B11C0, + 0x708EDDFF, 0x0D46F407, 0xE805F80F, 0x1FC7258A, + 0x088A718E, 0x730CFAEF, 0x08336E0B, 0x26790135, + 0x26791141, 0x200410C0, 0x6E0D0050, 0x00B5082D, + 0x09A6702C, 0x70140140, 0x70801600, 0x01818000, + 0x21CA742C, 0xE88F01E2, 0xE687F00F, 0xE68CF2E5, + 0x00E10B50, 0xF00E40A1, 0x70801600, 0x01828000, + 0x1A0BE803, 0x78F03002, 0x430242A1, 0xFD8F0A96, + 0x1381267D, 0x20002178, 0x24952505, 0x00122105, + 0x70EE70AD, 0x800040D3, 0x72F61220, 0x00260124, + 0xA5C02511, 0x40E2F28B, 0x08AE4162, 0x1801F9AF, + 0x08B22342, 0x4610FBAF, 0x702CC082, 0xF7AF0CA2, + 0x0FEADA50, 0x730CFAAF, 0x13950ED3, 0x03802025, + 0xF024F019, 0xF063F027, 0xF061F061, 0xF05FF05F, + 0xF037F025, 0xF042F004, 0xF002F059, 0x79F078AF, + 0x0AF64282, 0x43C10020, 0x13500E9B, 0x12D00E8B, + 0x78AFF04D, 0xFF6F0DF6, 0x700CC182, 0xF8EF0D8A, + 0x710C712C, 0xF027712C, 0x08EE78AF, 0xC18201E0, + 0x08E2F03D, 0x78AF01E0, 0x78AFF039, 0x714CC180, + 0x0B52706C, 0x4110FBAF, 0xC1804022, 0x716C714C, + 0x30011C04, 0xFBAF0B3E, 0x30011C00, 0x78AFF027, + 0xFF6F09EE, 0x700C4182, 0xF8EF0D3E, 0x710C702C, + 0x0D36702C, 0xF01BF8CF, 0x70801600, 0x00098000, + 0x78AFB8E3, 0x0CFEF404, 0xF0070040, 0x428279F0, + 0x00200A66, 0x1600DB0B, 0x80007080, 0x080F017C, + 0xCC22001E, 0x1A227104, 0x730C301C, 0xFAAF0F0E, + 0x20031800, 0xE88BCA0A, 0x70811600, 0x00048000, + 0x40427BAF, 0xFA6F0EB6, 0x71A542C2, 0xF16F71E6, + 0x12D00E0B, 0x13500E13, 0x1600F00E, 0x80007080, + 0x0815017C, 0x1600001E, 0x80007080, 0xB8E60001, + 0xF8C20A6C, 0x70801600, 0x00018000, 0x0970B8E6, + 0x40C1F8E2, 0x70031E00, 0x000F8000, 0x1600C7D6, + 0x80007080, 0xE8070163, 0xF203E68D, 0x05F2E68A, + 0x1600FFC1, 0x80007080, 0xB8E20001, 0x05EB70ED, + 0x27CAFFEF, 0x0E4E13E1, 0x2079F90F, 0x28400000, + 0x16000256, 0x80007080, 0xE8040183, 0x30021A0B, + 0x23562605, 0xBD9FDDF4, 0x08338D00, 0x085A005F, + 0xE8150140, 0x02DF41C3, 0x0AE60000, 0x740CFA2F, + 0x10901500, 0x204F702C, 0x42C22040, 0x78F0AD00, + 0xFDAF08A2, 0x1D00726C, 0x78F01402, 0x42C2702C, + 0xFFEF05FD, 0x78E0726C, 0xC1A1C3F4, 0x43304550, + 0xFAEF081A, 0x70CD4210, 0x800040D3, 0x22531138, + 0x708E204D, 0x800047CB, 0x0B351220, 0x18002030, + 0x16002382, 0x80007080, 0x0825001B, 0x708E007E, + 0xFCEF0B56, 0x8F404042, 0x750C4410, 0x017741C3, + 0x43420003, 0xFA2F0A6A, 0x0500240A, 0x41624042, + 0x0DD2704C, 0x2578FCEF, 0x71561096, 0x000341C3, + 0xC80808D8, 0x082221D6, 0x8F207825, 0x7825B90C, + 0x016009D2, 0x7DD0D940, 0xE5FF708D, 0x002D00A8, + 0x11C0234A, 0x2005C808, 0x8F000301, 0x7825B80C, + 0x0F802005, 0x00D80003, 0x016009AA, 0x238D41A1, + 0x24561D3F, 0x0EFA180C, 0x40C2FECF, 0x734CC180, + 0x708C4362, 0xF7EF082A, 0x1400702E, 0x25553009, + 0xD8071803, 0x10C82D41, 0x2006BB23, 0x244A034B, + 0x20A871C0, 0x29010900, 0x29401440, 0xB8C02142, + 0x02CC2800, 0x209F8F00, 0x70A20803, 0x70016058, + 0x79858820, 0x2140A820, 0x29012200, 0x71261000, + 0x2800B8C0, 0x8F0002C1, 0x0803209F, 0x621A70A2, + 0x88406278, 0xA8207945, 0x800040C3, 0x88000484, + 0xF1AB661E, 0x7885C808, 0x0F802005, 0xF0D80003, + 0x01600912, 0x238D702C, 0x24561E3F, 0x0E62180C, + 0x4042FECF, 0x085E702C, 0x1800FB2F, 0x40822043, + 0x78E0C7D4, 0x2482C3F8, 0x46503617, 0x47104130, + 0x3F802400, 0x03800000, 0xDA78702C, 0xF7AF0962, + 0x30C01CD4, 0x2400702C, 0x00003F80, 0x09520308, + 0xDA78F7AF, 0x2400702C, 0x00003F80, 0x09420290, + 0xDA78F7AF, 0x300014D4, 0x0819704E, 0x700F02B1, + 0x70981600, 0x000C8000, 0x30012084, 0x31982841, + 0x300514D4, 0x42E2740C, 0x01D641C3, 0x43220005, + 0x0580240A, 0xFA2F08EA, 0x0600260A, 0x702C710C, + 0x05D32800, 0xF96F0CF2, 0x084B40E2, 0x1CD83031, + 0xC0823000, 0xFBEF0FC6, 0x14C841E2, 0x42C33101, + 0x00009038, 0x7905C808, 0x7945B902, 0x216D9120, + 0x14CA0A10, 0x78253101, 0x01D741C3, 0xB8020002, + 0x92007A05, 0x206D4202, 0x740C0A0D, 0xFA2F0892, + 0x14D443A1, 0x2B403000, 0x0F122093, 0x2079FA2F, + 0x1C5A034E, 0x16003018, 0x80007080, 0x206D0009, + 0x70140940, 0x30001CE0, 0x006120CA, 0x30001CE0, + 0x300014D4, 0x03510815, 0xB802C808, 0x0F802005, + 0xC234903B, 0x00451800, 0x0CFE7FDB, 0x230F0120, + 0x1CDC25D4, 0x24003000, 0x00003F80, 0x702C0218, + 0xF7AF084E, 0x45D3DA78, 0x12228000, 0x303008BD, + 0x1E00DA60, 0x90077484, 0x1E00C17C, 0x901C7045, + 0xC80804A8, 0x800041C3, 0xB8020EAB, 0x0F802005, + 0x0504901C, 0x00451800, 0x70C51E00, 0xC164900B, + 0xF76F0FF6, 0x3E402455, 0x3E402455, 0x01A0086E, + 0x710CD960, 0xFFAF0C52, 0x212F712C, 0x700C0507, + 0x09DA704C, 0x4330F9EF, 0xF82F0CF6, 0x43104062, + 0x20801501, 0x20821500, 0x00A408C3, 0x27407842, + 0x6821280C, 0x240AC808, 0x20A87040, 0x2A4007C0, + 0x24000301, 0x00003F83, 0x61990210, 0x79057B54, + 0xB992B902, 0xB99FB99C, 0xB3209120, 0x8005218C, + 0x003C238A, 0x00CD21C0, 0x3F832400, 0x02080000, + 0x71447B54, 0xF03BB320, 0x308714D1, 0x2507232F, + 0x308314CC, 0x3E412455, 0x04C0240A, 0x32052440, + 0x308214CF, 0x0580260A, 0xF9AF0F4A, 0x300014DC, + 0x308714D1, 0x3F812400, 0x01840000, 0x308314CD, + 0x04C0240A, 0x34052440, 0x0580260A, 0x308214CF, + 0xF9AF0FB2, 0x300014DC, 0x36001440, 0x30181C68, + 0x308014E9, 0x710CE80B, 0x34801CEC, 0x1C63B890, + 0x1CF03498, 0x1C643000, 0xBD083018, 0xE70D6E06, + 0x2447212F, 0x33581C5B, 0x22102840, 0x1C5D70AD, + 0x1C5E3018, 0x1C5C33D8, 0x145E3418, 0x75103600, + 0x000604A0, 0x3600145D, 0x790E78A2, 0x300014E0, + 0x00012908, 0xF048262F, 0x7017F4AD, 0x40C3F2AD, + 0x0E9C8000, 0x68346508, 0x212F7825, 0x0C4E0507, + 0x780FFFAF, 0xF86F0E36, 0x0E42D8C8, 0x202FF86F, + 0x150104C8, 0x1C602081, 0x15003498, 0x09352080, + 0x1C5F0024, 0x79023498, 0x240A7124, 0x20A87040, + 0x28400480, 0x21050381, 0x90040F82, 0x24003DD0, + 0x00003F81, 0x21F40208, 0x71040001, 0xB220E120, + 0xFECF0B92, 0x0AFED80F, 0xD90FF92F, 0x0086208A, + 0x900746CB, 0xB600C2C4, 0x096AD840, 0x712CF86F, + 0x20811501, 0x20801500, 0x00240931, 0x71247902, + 0x7040240A, 0x048020A8, 0x03812840, 0x3F832400, + 0x017C0000, 0x21057B14, 0x90040F82, 0x922001D0, + 0xB3207104, 0xB220E120, 0xFECF0B3A, 0x0AA6D80F, + 0xD90FF92F, 0x712CD882, 0x091AB600, 0xD840F86F, + 0x208E1500, 0x20801501, 0x03A40877, 0x0DAA78AF, + 0x4010F9CF, 0x13802E40, 0x0F8F2005, 0x01D09004, + 0x3F802400, 0x017C0000, 0x20F49720, 0x78220380, + 0x88012054, 0x0023000E, 0x26024420, 0x00007001, + 0xD840FFC0, 0x483142C1, 0x3F802400, 0x02180000, + 0x430278B6, 0xB02078D4, 0x01DC41C3, 0x0D820003, + 0x740CF9EF, 0x3F802400, 0x02100000, 0x038020F4, + 0x1501B700, 0x76102080, 0xFFE5079C, 0x0AA671C5, + 0x71A5FECF, 0x702CF143, 0x3F802400, 0x05880000, + 0xF76F0D6E, 0x702CDA50, 0x3F802400, 0x05380000, + 0xF76F0D5E, 0x702CDA50, 0x3F802400, 0x04E80000, + 0xF76F0D4E, 0x702CDA50, 0x3F802400, 0x04980000, + 0xF76F0D3E, 0x702CDA50, 0x3F802400, 0x04480000, + 0xF76F0D2E, 0x702CDA50, 0x3F802400, 0x03F80000, + 0xF76F0D1E, 0x14D4DA50, 0x08773000, 0x6D340371, + 0x3600145B, 0x254E7905, 0x20051300, 0x145C004B, + 0x78103601, 0xB80479A5, 0x36091208, 0x15007825, + 0x7E3B2081, 0x43C3710D, 0x00009038, 0x034F2940, + 0x20811501, 0x10482014, 0x13A40857, 0x124C2705, + 0x310214C8, 0x10082796, 0x14D871C5, 0x61593001, + 0xB9027985, 0xB1007965, 0x310214CA, 0x300114D8, + 0x79856159, 0x7965B902, 0x02C41900, 0x40C3F1E6, + 0x0E9C8000, 0x14D46508, 0x68343002, 0x212F7825, + 0x0A190507, 0x780F02B1, 0xFF8F0A12, 0x0886F003, + 0x268AFB4F, 0xF0051FC7, 0xFF8F089A, 0x14CCDE7F, + 0x24553081, 0xC2823E40, 0xF9AF0B56, 0x3E4F2455, + 0x300014DC, 0x14CCE825, 0x42E23081, 0x2440C382, + 0x14CF3604, 0x250A3080, 0x70CC0580, 0xC74170EC, + 0xFBAF0CEE, 0x2455C640, 0x41E23E40, 0x2400704C, + 0x00003F84, 0x24000588, 0x00003F85, 0x24000538, + 0x00003F86, 0x09BE04E8, 0xC386FBEF, 0x081AF024, + 0x14D00200, 0x222F3087, 0x14CC0507, 0x43223081, + 0x3604145A, 0x32052440, 0x308014CF, 0x0580260A, + 0xF9AF0FB6, 0x2400C740, 0x00003F81, 0x24000588, + 0x00003F82, 0x24000538, 0x00003F83, 0x0C6204E8, + 0xC086FB2F, 0x308114CD, 0x3F802400, 0x01840000, + 0x3F8F2400, 0x01840000, 0xF9AF0AA6, 0x14DCC284, + 0xE8283000, 0x308114CD, 0xC38442E2, 0x38042440, + 0x308014CF, 0x0580250A, 0x71EC70CC, 0x0C42C741, + 0xC640FBAF, 0x240041E2, 0x00003F80, 0x714C0184, + 0x3F842400, 0x04980000, 0x3F852400, 0x04480000, + 0x3F862400, 0x03F80000, 0xFBEF090A, 0xF025C388, + 0x01C00F66, 0x308714D0, 0x0507222F, 0x308114CD, + 0x145A4322, 0x24403604, 0x14CF3405, 0x260A3080, + 0x0F060580, 0xC740F9AF, 0x3F812400, 0x04980000, + 0x3F822400, 0x04480000, 0x3F832400, 0x03F80000, + 0xFB2F0BAE, 0x1501C088, 0x14CE2087, 0x15003084, + 0x74F0208C, 0xFFED058E, 0x245A706D, 0x24001286, + 0x00003F8F, 0x24000308, 0x00003F8E, 0x7FB60380, + 0x7F947EB6, 0x218A7E94, 0xD97F1FC1, 0x11250B6D, + 0x9040210C, 0x20310E11, 0x16802400, 0x0080101C, + 0x10000B55, 0x11882300, 0x3F802400, 0x05380000, + 0x020220F4, 0x3F802400, 0x04E80000, 0x020020F4, + 0x96004853, 0xB6006078, 0x3F802400, 0x04480000, + 0x020220F4, 0x3F802400, 0x03F80000, 0x020020F4, + 0x97407842, 0x7810621A, 0x02492009, 0x20097870, + 0xB7400041, 0xF1CC7165, 0x9700F745, 0x4121B600, + 0xF407F007, 0x96209700, 0x804408F5, 0x2400F1F9, + 0x00003F80, 0x78B60290, 0x71857894, 0xF1A3B020, + 0x30300847, 0x3E402455, 0x74841E00, 0xC164900B, + 0x6832C808, 0x901C40C3, 0x79050504, 0x04841900, + 0x18A4D920, 0x40C38484, 0xC17C9007, 0x00451800, + 0x74841E00, 0xFED49007, 0x005C1886, 0xFF2F0B96, + 0x049C1886, 0x09B2F005, 0x14CCF9AF, 0x15003081, + 0x40C3208F, 0x07070707, 0x30181C5F, 0x20801501, + 0x3F8E2400, 0x017C0000, 0x02507710, 0x41E2002D, + 0x70AD66FE, 0x708E714E, 0x70CE706E, 0x3600145D, + 0x790E78A2, 0x300014E0, 0x00012908, 0xF048262F, + 0x081DF434, 0x42E13030, 0x3F802400, 0x02180000, + 0x20F478B6, 0x210A03D0, 0xF01B2400, 0x3F802400, + 0x03800000, 0x41C378B6, 0x000401E5, 0x20F443A1, + 0x240003D1, 0x00003F80, 0x78B60290, 0x0440250A, + 0x03D020F4, 0x095A740C, 0x240AF9EF, 0x200C0400, + 0xF705A580, 0x0B21F410, 0xAEA02445, 0x260A718E, + 0x230A2400, 0x714E2440, 0x145E71A5, 0x0D813600, + 0xF00D9004, 0x20300C13, 0xA580200C, 0xA4C121CC, + 0x206122C0, 0x708EF3F2, 0x202FF1F0, 0x68290487, + 0x300014E0, 0x8E00790C, 0x783D7914, 0x7D0FAE00, + 0x300014D4, 0xF48AE08D, 0x41C3740C, 0x000301E6, + 0x43A142E1, 0xF9EF08EA, 0x04C0240A, 0x41C3740C, + 0x000201E7, 0x08DA42E1, 0x43A1F9EF, 0x37041222, + 0x01E841C3, 0x202F0003, 0x42E10100, 0x43A178F6, + 0x800170C3, 0xB0A04D44, 0xF9EF08B6, 0x14C8740C, + 0x2F403101, 0x12081348, 0x254E360B, 0x14D81306, + 0x23053000, 0x60381203, 0x3601145C, 0x46CB7865, + 0x00009038, 0x79A5B802, 0x01022E40, 0x7A2578C5, + 0x1F892000, 0x10000000, 0x2305B040, 0x14C8124C, + 0x14D83100, 0x60383001, 0xB8027885, 0xB04078C5, + 0x310014CA, 0x300114D8, 0x6D346038, 0x145B7865, + 0xB8023603, 0x01832305, 0x7B2578C5, 0x14CAB060, + 0x14D83101, 0x60383000, 0xB8027885, 0xB06078C5, + 0x70801600, 0x017C8000, 0x001F08AB, 0x70801600, + 0x00098000, 0x013F089F, 0x15CB2305, 0x903840C3, + 0x23051540, 0xBC02120C, 0x10012405, 0x2305B140, + 0xB9021241, 0x000D2105, 0x08002054, 0x79057C05, + 0xB460B540, 0xF037B160, 0xF9AF0FBE, 0x460840A1, + 0x300014D4, 0x02B1081F, 0x0837740C, 0xD8403030, + 0x01E941C3, 0x20020003, 0x740C04C4, 0x43A142E1, + 0x41C3F017, 0x000301EC, 0x43A142E1, 0xF9AF0FB2, + 0x04C0240A, 0x41C3740C, 0x000201ED, 0x740CF00F, + 0x01EA41C3, 0x42E10003, 0x240A43A1, 0x0F9204C0, + 0x740CF98F, 0x01EB41C3, 0x42E10002, 0xF9AF0F82, + 0x05AD43C1, 0x71E5FFEF, 0x3F802400, 0x017C0000, + 0x016009D2, 0x300214D4, 0x30310897, 0x0B7A40E2, + 0x702CF92F, 0x4210D939, 0x0F56B913, 0x740CF9AF, + 0x20901500, 0x24132240, 0x24922240, 0x1407272F, + 0x20801501, 0x03E40863, 0x13112F40, 0x275F70AD, + 0xC0821501, 0x43A142E1, 0x740C603E, 0x41C37EB4, + 0x000401C9, 0x11051620, 0xF9AF0F16, 0x11041670, + 0x12012D40, 0x2105C808, 0x43C30441, 0x00009004, + 0x71A57825, 0x04812005, 0x04C02005, 0x96306952, + 0xB8027A65, 0x7865B220, 0x11011670, 0x92740DB3, + 0x7106B020, 0x0C1EF1CC, 0x0CC2FE8F, 0xC7D8FF0F, + 0x1CFCC2FA, 0x2482B6C8, 0x40103D06, 0xDA78702C, + 0x3F802400, 0x013C0000, 0xC1504528, 0xC14EC14F, + 0xC14CC14D, 0xC14AC14B, 0xF72F0EC6, 0x2455C149, + 0x702C3C40, 0xF72F0EBA, 0x2455DA78, 0x702C3880, + 0xC548DA3C, 0xF72F0EAA, 0xC093C547, 0x0EA2702C, + 0xDA3CF72F, 0xC552712C, 0x70441E00, 0x04A8901C, + 0xC546C808, 0x6852C545, 0x0F802205, 0x0504901C, + 0x2205B020, 0x90040F80, 0x90000090, 0x0F832205, + 0xC0909007, 0xB888C042, 0x1600B300, 0x80007083, + 0x16000004, 0x80007080, 0x0811017C, 0x2205001E, + 0x903B0F80, 0xB020C234, 0x040E2900, 0x7FCFBBC3, + 0x40E1752C, 0xF9EF0D7E, 0x44D3C343, 0x12228000, + 0x208D1400, 0x35112440, 0x20801401, 0x03640841, + 0x160040E1, 0x80007080, 0x083112D9, 0x4002036E, + 0xFBEF0A12, 0xE81241A1, 0x742C78AF, 0xFEAF0D86, + 0x42004202, 0x23402114, 0x41C343A1, 0x000201A7, + 0x0DCEB040, 0x750CF9AF, 0xF1E071A5, 0xF9EF0D26, + 0x1400762C, 0x706F208D, 0x20801401, 0x0364084D, + 0x16006E12, 0x80007080, 0x083D12D9, 0x4002036E, + 0xFBEF09C2, 0xE81841A1, 0x20F4C085, 0x08290340, + 0x78AF0071, 0x0D2E742C, 0x4202FEAF, 0x750C4708, + 0x41C342E1, 0x000201A8, 0xF9AF0D76, 0x0F0943A1, + 0x716F11D1, 0xF1DA71A5, 0x78CF7E05, 0xF7EF09EE, + 0xC044C040, 0x060640C3, 0xC0510606, 0x2005C808, + 0x14B70400, 0xB8022097, 0x0F802005, 0x15409038, + 0x01181000, 0x1401D80D, 0x2084208F, 0xC041300C, + 0x20831400, 0x35C7212F, 0xDEC0C808, 0x040B2005, + 0x10C40F9B, 0x30EE0993, 0x2B40C591, 0x65690342, + 0x06002105, 0x4E31B904, 0x22057905, 0x284002C0, + 0x22960088, 0x20050008, 0x90381F80, 0xB0201540, + 0x20056568, 0xB8040601, 0x79054E10, 0x02C02205, + 0x42C36892, 0x15809038, 0x1F802405, 0x15409038, + 0x6568B020, 0x06012005, 0x4E10B804, 0x20057905, + 0xB0201080, 0x65687A85, 0x06012005, 0x4E10B804, + 0x702C7825, 0xC08DB200, 0xB0207874, 0x7874C08F, + 0xC08BB020, 0xB0207874, 0x7874C089, 0x30300B0B, + 0x1800B020, 0x71640045, 0x70CDF1B4, 0x1F802632, + 0x0E9C8000, 0x78256834, 0x08BAC100, 0x780FFF6F, + 0xF82F0C0A, 0x0C16D8C8, 0xC004F82F, 0x0F96700C, + 0x712CF7EF, 0x089EC100, 0x700CFF6F, 0x0BB6C000, + 0xD91AF9EF, 0x704E72AE, 0x20100A0F, 0x70801600, + 0x00408000, 0x212FE827, 0x40020480, 0xFBEF0856, + 0x46104130, 0x20532140, 0x41227014, 0x04C121CA, + 0x742C782F, 0xFEAF0BBE, 0xC5924202, 0x75224708, + 0xB5004102, 0xFC2F0D12, 0xE80D4042, 0x23CA70D6, + 0x202F2441, 0x742C04C7, 0xFEAF0B9A, 0x78E54202, + 0x258DB500, 0x714E253F, 0xF9AF0BBE, 0x140078CF, + 0x4110208D, 0x20801401, 0x01347510, 0x2111002D, + 0xF294B340, 0x208F1403, 0x0FEA4002, 0x41A1FBAF, + 0x1342273C, 0x21F4C192, 0x2078008C, 0x781B0000, + 0x38822455, 0x73046862, 0x10C12C01, 0x21447C19, + 0x255A0043, 0xC09313C1, 0x6119623A, 0x61D862DA, + 0x2444AA60, 0xA8401042, 0x78B4C08B, 0x09299020, + 0x438900E0, 0xC08FB060, 0x902078B4, 0xB0806981, + 0x178C255A, 0x3F802400, 0x013C0000, 0x78346098, + 0x04441800, 0x78B4C089, 0x09239020, 0xB0400080, + 0x78B4C08D, 0x69819020, 0x255AB080, 0x2455178C, + 0x60983C40, 0x18007834, 0x0E910444, 0xC18F13B1, + 0x910079B4, 0x0050083D, 0x7074E88F, 0x1783255A, + 0x0E7F208A, 0x3F812400, 0x013C0000, 0x01E120CA, + 0xB1006179, 0xEB8EF00E, 0xB1606861, 0x1783255A, + 0x3F812400, 0x013C0000, 0x79146179, 0x01C51900, + 0x78B4C08D, 0xE9179020, 0x32C22305, 0x16CB2304, + 0x10032378, 0xF41A7A6B, 0x00700931, 0xB0406941, + 0x1782255A, 0x3C402455, 0x78346058, 0x01C51800, + 0x7054F00C, 0x1782255A, 0x0E7F208A, 0x3C412455, + 0x01E120CA, 0xB1006159, 0xF16671A5, 0xE68F71C5, + 0xFFC5061C, 0x41C3750C, 0x000101B4, 0xF9AF0A92, + 0x41C34202, 0x000001B5, 0xF9AF0A86, 0x70AD740C, + 0x0A56DE0F, 0x78AFF9AF, 0x41C34200, 0x000101B6, + 0xF9AF0A6E, 0x268D740C, 0x71A51DFF, 0x01B741C3, + 0x0A5E0000, 0x740CF9AF, 0x20911400, 0x215FC693, + 0x245523CD, 0x66BE3880, 0x1401651D, 0x0F71208F, + 0x740C1464, 0x01B841C3, 0x0A360001, 0x4222F9AF, + 0x42B1DF0F, 0x24821201, 0x01B941C3, 0x0A220001, + 0x740CF9AF, 0x1E3F278C, 0x740CD9DD, 0xF9AF0A12, + 0x740CB911, 0x01BB41C3, 0x0A060001, 0x4222F9AF, + 0x42D1DF0F, 0x24821201, 0x01BC41C3, 0x09F20001, + 0x740CF9AF, 0x1E3F278D, 0x41C3740C, 0x000001BD, + 0xF98F09DE, 0xE50FE60F, 0xF1C97126, 0x208D1400, + 0x13640FAB, 0x42A14FB0, 0x240A7104, 0x20A87000, + 0x096D0E40, 0xC08F30AE, 0x008120F4, 0x00B40925, + 0x0783225A, 0x3F802400, 0x013C0000, 0x20146078, + 0x98800041, 0x814111FE, 0x2C44643C, 0xB0201081, + 0x20F4C08D, 0x2455008C, 0x60783C40, 0x10B40C17, + 0x20149820, 0x14FE030C, 0x6199914C, 0x00812944, + 0x2400B020, 0x00003F8C, 0xC087013C, 0x10C32435, + 0x7854792E, 0x2B44633B, 0xB0200081, 0xC6877144, + 0x091F7EB4, 0x740C336E, 0x11441600, 0x41C34202, + 0x000301C1, 0xF9AF093A, 0x140143A1, 0x72C5208F, + 0x71A575F1, 0x1400F7AF, 0x0F99208D, 0xC1871364, + 0x79B44FB0, 0x240A7104, 0x42A17000, 0x034020A8, + 0x308E0913, 0x080B9900, 0xB8830052, 0x7813F002, + 0x7224B100, 0xF0367144, 0x270479B8, 0x262F2040, + 0xF22DF007, 0x70801600, 0x017C8000, 0xC08FE809, + 0x034020F4, 0xC08DE808, 0x034020F4, 0x2706E804, + 0xF01D2057, 0xC287C191, 0x22F561B9, 0x0A190342, + 0x890001F2, 0x03310815, 0x700C7104, 0x01C241C3, + 0xF00A0001, 0x7704E804, 0xF009A900, 0x41C3700C, + 0x000101C3, 0xF72F0DA2, 0x140142A1, 0x71A5208F, + 0x93650F99, 0xC001712C, 0x262F7704, 0xC041F007, + 0x262FF205, 0x034CF5C7, 0x1600FFC2, 0x80007080, + 0x0895017C, 0x1400001E, 0x0F8D2081, 0xC8081044, + 0x903841CB, 0x160015C0, 0x80007088, 0x200512D9, + 0x4F30040B, 0x240A7104, 0x20A87000, 0x08670D80, + 0xC491106E, 0x034D2940, 0x2205642A, 0x6A740600, + 0x4A76DAC0, 0x25057E05, 0x687212C0, 0x10082596, + 0x02402305, 0x6428B0C0, 0x060E2005, 0x4A10B804, + 0x25057E05, 0x68B212C0, 0x12402505, 0x6428B0C0, + 0x060E2005, 0x4A10B804, 0x21547E05, 0x7B051800, + 0xB3C078A5, 0x2305642B, 0xBB04060C, 0x7A857A62, + 0x7124B040, 0x716E70ED, 0xEF08724E, 0x70801600, + 0x00408000, 0x00100879, 0x40027EFB, 0xFBAF0BE6, + 0xC18741C1, 0x894079D4, 0xE8058922, 0x7D4569B4, + 0x6AB4F003, 0x710C7D25, 0x0B1278F8, 0x780FFA2F, + 0x2347212F, 0x4202750C, 0x01C541C3, 0x43E10003, + 0xF96F0F8E, 0x0440240A, 0x0BCAC100, 0x4022FF2F, + 0x205FC003, 0x60D80B00, 0x70827002, 0x20300815, + 0x0B27A8B6, 0x1E002010, 0x80007342, 0xF00800F7, + 0x20100B21, 0x73421E00, 0x00F28000, 0x228D71ED, + 0x706E2FFE, 0x1E00F00A, 0x80007342, 0xF0060101, + 0x73421E00, 0x00FC8000, 0xFA2F0AA2, 0xC808730C, + 0x2005B802, 0x90070F81, 0xC002C090, 0x2480B100, + 0x14043D06, 0xC6DA341B, 0x1CFCC2FA, 0xC1A5B6C8, + 0x702CC140, 0x0D5AC044, 0xC000F9AF, 0x1443256F, + 0x8D00C043, 0x900747CB, 0x2078C2C0, 0xD90F0100, + 0xE030B802, 0x0B9EB700, 0xD80FF8AF, 0x71AED9FF, + 0x208A700E, 0xB7320FC7, 0x15441F28, 0x94041FDC, + 0xB708B706, 0x15441F04, 0x7054C200, 0x093E711C, + 0x710CFF2F, 0xFACF0ADE, 0x1097150E, 0x720C776E, + 0x800046CB, 0x46D31220, 0x12D98000, 0x34041C0A, + 0x34041C08, 0x8E00C041, 0xD840E803, 0xD825F002, + 0x2D00B89F, 0xB9022401, 0x040D210F, 0x7D0B8800, + 0x40C3F2A1, 0x12DC8000, 0x40028020, 0x0F76C200, + 0xC300FBEF, 0x7DAFC203, 0x0872700C, 0x41A1F96F, + 0xF78F083E, 0x702C700C, 0xF92F0BB2, 0x450842A1, + 0xF7EF0DEA, 0x0DF6D8C8, 0x78B0F7EF, 0x329B2440, + 0x32192440, 0x341B2300, 0x34192100, 0x70AD700F, + 0x6892C808, 0x1F802405, 0xC034901F, 0x8E23B0A0, + 0x09338E02, 0x79020024, 0x20831600, 0x28406941, + 0x240A0381, 0x20A87080, 0x0B1303C0, 0x2405002E, + 0xBA921042, 0xBA9FBA9C, 0x7104B2A0, 0x000071C3, + 0x09864000, 0xD814FD2F, 0xFE8F0F8A, 0x712CC004, + 0xF7EF08EA, 0x8E027810, 0x4110704E, 0x03942840, + 0x083F8E03, 0xD80F0464, 0x20801600, 0x044E0827, + 0x2F802405, 0x02F49004, 0x22059000, 0xE88B2012, + 0x41C3740C, 0x0003024B, 0x43224202, 0xF96F0DA2, + 0x712644A1, 0x2F942400, 0x40000000, 0x0A46F1E2, + 0xD90FF8AF, 0x3011082D, 0x20310A33, 0x15C02500, + 0x7A10702C, 0x0EEE4002, 0x4150FEEF, 0x712C4002, + 0xFEEF0EE2, 0x1B004222, 0x23083342, 0xF0062353, + 0x20110A0B, 0x33421900, 0x71A5710F, 0x98D40D25, + 0x41C34003, 0x00010250, 0xF72F0A4E, 0x0F164202, + 0xC001F90F, 0x7704710E, 0xC0417014, 0x202FF54D, + 0x41C304CA, 0x00000252, 0xF72F0A2E, 0x202FB83F, + 0x43C304C7, 0x01328000, 0x140B70E2, 0x2049308D, + 0xC0220881, 0x140A4832, 0x49103080, 0x00802009, + 0xAB02AB00, 0x6852C808, 0x30801409, 0x0F8C2205, + 0xC034901F, 0x4834B420, 0x200949B0, 0xAB010300, + 0x8E03AB03, 0x08378E62, 0x786200E4, 0x038D2B40, + 0x40C36881, 0x12D98000, 0x240A88C0, 0x20A87300, + 0x0E1303C0, 0x220510EE, 0xB8920340, 0xB89FB89C, + 0x7164B020, 0x000075C3, 0x0E4A4000, 0x700CFE8F, + 0xB708B706, 0xC0A5B702, 0x341B1404, 0x78E0C6DA, + 0x1CFCC2FA, 0xC1BBB6C8, 0x710C4018, 0x01402800, + 0x2140250A, 0x160068B2, 0x80007080, 0x260A0162, + 0x44702100, 0x47304158, 0xB203208C, 0x31801C68, + 0xE899F403, 0xE809F009, 0xBD41208C, 0xBF8220CC, + 0x00700000, 0x2050F20F, 0x204A3080, 0x208C21C0, + 0xF40D8802, 0x70801600, 0x01648000, 0x80802053, + 0x0CAEF205, 0x712CF82F, 0x26424010, 0x250F20C0, + 0x212F1553, 0x08232007, 0x706F0135, 0x40C3790D, + 0x0FA08000, 0x02022040, 0x004D20F4, 0x005222F4, + 0xBB8E736C, 0x736CF006, 0x000045CB, 0x704EFFFF, + 0x44CB710C, 0xFE030000, 0xB60A468B, 0x000041C3, + 0xB604F0B0, 0x1C5C6943, 0x276F3004, 0x1C441443, + 0xB61C3004, 0x6C0AB610, 0x40C3B60F, 0xFFB50001, + 0xB969B629, 0x2258B643, 0xC0400B02, 0x000140C3, + 0x1C4EFE04, 0x24403084, 0xB63B1282, 0xB662489A, + 0x000743C3, 0xC058F004, 0x1C42B864, 0x42C33084, + 0xF0B40001, 0x6B0BC04C, 0x6A0BC049, 0x8F00C046, + 0x01002078, 0xB61AC152, 0xB617B962, 0xE030B802, + 0xB60BC14F, 0xD966C080, 0x33041C5A, 0x31C51C50, + 0x31C51C2C, 0x36C41C2A, 0x36C41C10, 0x1C0AC243, + 0x1C6436C4, 0x1C5E36C4, 0x1C5836C4, 0xC35536C4, + 0x36C41C52, 0x36C41C4C, 0x36C41C46, 0x36C41C40, + 0x36C41C3A, 0x31851C28, 0x30851C22, 0x00E00BAE, + 0x30C51C1C, 0x4142D80F, 0x43424242, 0xFB6F0BD2, + 0x0480240A, 0x722C700C, 0x706C704C, 0x0C1A44A1, + 0x45A1FB6F, 0x14C7262F, 0x12012D41, 0x704C78AF, + 0x0922706C, 0x44C1FF2F, 0x2102217D, 0x0407212F, + 0xFE2F0E96, 0x40C240C1, 0xF8AF0B12, 0x45CB41A2, + 0x4DAC8001, 0x0B2B43B1, 0x212F3135, 0x0C5606C7, + 0x4082FF2F, 0x7280244A, 0x20A8702C, 0x080B0240, + 0x1D00004E, 0x72A515C4, 0x71677124, 0x0F9FF1ED, + 0x46EA2030, 0xB203208C, 0x4082F406, 0x00E00C82, + 0xF010702C, 0xBC01208C, 0x40C2F406, 0x01600846, + 0xF0084182, 0x410340A2, 0x08CE4223, 0x706C0160, + 0xBC01208C, 0x76F2F205, 0xFE610EBC, 0x0EBA4082, + 0x4082FE6F, 0x2A102354, 0x2382222F, 0x456A702E, + 0x21350945, 0x0447212F, 0xFF2F0BDA, 0x704C4082, + 0x02950A2D, 0x008E081D, 0x20832033, 0xE90DC11A, + 0x00520B0B, 0x79C29520, 0x9520B520, 0xB5207142, + 0x714472A5, 0x0BF7F1EE, 0xF1F68013, 0x22902040, + 0xF1E07126, 0xA0310A71, 0x208C464A, 0xF407B203, + 0x0BEE4082, 0x702C00E0, 0x208CF00F, 0xF407BC01, + 0x0FB240C2, 0x41820120, 0x40A2F007, 0x42234103, + 0x01600836, 0x704C706C, 0x900741C3, 0x1924C29C, + 0x706C0015, 0x70841E00, 0xFED49007, 0x708C8F00, + 0x01002078, 0x1904B802, 0xD80F0014, 0xB144B140, + 0x1E00B146, 0x90077084, 0x1E00F804, 0x901F7084, + 0x0A5EC004, 0x702CFB6F, 0x1404C0BB, 0xC6DA341B, + 0x1CFCC2FA, 0xC1BAB6C8, 0x41C34510, 0x000003DD, + 0xF96F097E, 0x730C740C, 0x900741DB, 0x70EEC17C, + 0xF9EF0CDA, 0x30051900, 0xFEEF095E, 0x0D5240A2, + 0x710CF9EF, 0x45CBD840, 0x4E748001, 0xD90BB89F, + 0x10E588E0, 0x0A0A8090, 0x40A1FEEF, 0x0A0240A1, + 0xD911FEEF, 0xD90BC808, 0xB802DAF7, 0x0F802005, + 0x00B89038, 0xC0409000, 0xF7EF0D0E, 0x40A140A1, + 0x0D06D911, 0xDAF8F7EF, 0xD91140A1, 0xFC6F0EE6, + 0x089E724C, 0xC096FF2F, 0x0D7EC096, 0xD90BF9EF, + 0x0D76C096, 0xD911F9EF, 0x800046CB, 0x8E001220, + 0x209F704C, 0xC3960582, 0x60B9708C, 0x00A00C1E, + 0x2705750C, 0x40DB141B, 0x4EBF8001, 0x30F10B1F, + 0x30CF2378, 0x704C8E00, 0x0582209F, 0x708CC396, + 0x06012000, 0x00A00BF6, 0x6F01D80A, 0x903B46D3, + 0xC041C0B8, 0x000042C3, 0xC808BA68, 0x718C43A2, + 0x70CC70AC, 0x68324350, 0x2105D870, 0xB1000581, + 0x0C02D8C8, 0x218AFFEF, 0x44D30004, 0x4DAC8001, + 0x32112440, 0x800047CB, 0x220A12D9, 0x24402500, + 0x0F413210, 0xD8C82135, 0x082D8F00, 0x212F05EE, + 0x09F205C7, 0x40A2FF2F, 0x7280244A, 0x4342708D, + 0x20A84202, 0x080B0280, 0x9320030E, 0x7264B220, + 0x71857244, 0x25122240, 0x25102040, 0xF1E371E6, + 0x0004218A, 0x43A24262, 0x70AC708C, 0x0B9670CC, + 0x704EFFEF, 0x2500200A, 0x21350A45, 0x8F0040A2, + 0x04AE0831, 0x0487212F, 0xFF2F099A, 0x244A40A2, + 0x706D7280, 0x442A4302, 0x030020A8, 0x02CE080F, + 0x94209340, 0x793D6159, 0x7264B320, 0x71657285, + 0x25102040, 0x25112140, 0xF1E07146, 0x00E009C2, + 0xD870702C, 0x43A2D910, 0x000042C3, 0x718C2950, + 0x70CC70AC, 0xFFEF0B2E, 0xD8704050, 0x4202D910, + 0x708C43A2, 0x0B1E70AC, 0x70CCFFEF, 0xB802C808, + 0x05812005, 0xB100C000, 0x09DE40A1, 0xD90BFE6F, + 0x09D640A1, 0xD911FE6F, 0xFEEF0F16, 0xC096C096, + 0xF9EF0BF6, 0xC096D90B, 0xF9EF0BEE, 0x8E00D911, + 0x209F704C, 0xC3960582, 0x60B9708C, 0x00A00A9E, + 0x0B1D750C, 0x704C30F1, 0x209F8E00, 0xC3960582, + 0x2000708C, 0x0A860601, 0xD80A00A0, 0x45CB70CD, + 0xBF648000, 0x0E61C001, 0x252F1025, 0xD8C80387, + 0x0004218A, 0x43A24262, 0x0A9A728C, 0x70CCFFEF, + 0x2500200A, 0x093D702E, 0x8F002115, 0x046E082B, + 0x0447212F, 0xFF2F089E, 0x244A40A2, 0x708D7280, + 0x41A14302, 0x024020A8, 0x030E0809, 0xB1409340, + 0x72247264, 0x20407185, 0xE5142510, 0xF1E57126, + 0xF1D271C5, 0x08CA40A2, 0x712C00E0, 0xF9EF0AC2, + 0x1900700C, 0xC0BA3045, 0x341B1404, 0x78E0C6DA, + 0x1CFCC2FA, 0x2482B6C8, 0xC1443F17, 0xC08D4318, + 0x0ECE702C, 0xDA14F6AF, 0x0E0A750C, 0xD918F96F, + 0x800041DB, 0x11001222, 0x0ABA3081, 0x700CFB6F, + 0x00012052, 0x30801100, 0x742C6038, 0x704C7E0F, + 0xFE2F0E22, 0x206D40C1, 0x740C01CD, 0x41C342A1, + 0x0002033B, 0xF92F0E6A, 0xED8A43C1, 0x033D41C3, + 0x0E5E0000, 0xD80AF92F, 0x000007A9, 0x1243266F, + 0xF86F0982, 0x148F16F4, 0x750CC04C, 0xF96F0DA6, + 0x1100702C, 0x0A5E3081, 0x700CFB6F, 0x00012052, + 0x30801100, 0x742C6038, 0x704C7D0F, 0xFE2F0DC6, + 0x206D40A1, 0x41C301C0, 0x0002033C, 0xC04243A1, + 0x0E0E740C, 0xC202F92F, 0xB802C808, 0x0F812005, + 0xC0909007, 0x0F802005, 0x00909004, 0xB8899000, + 0xC004B100, 0x00002079, 0xC045E008, 0x7014C00C, + 0x20CAC005, 0xC04502A2, 0xC0438E00, 0x10801639, + 0x730C7014, 0xF219C046, 0xC003C102, 0x700C790B, + 0x20CAC048, 0xC04800E2, 0x70801600, 0x017B8000, + 0x001E081B, 0xC003C102, 0xD807790B, 0x20CAC046, + 0xC0460122, 0x700CF003, 0xC004C048, 0x2FC3268A, + 0x208A7014, 0xDE250FC7, 0x200226CA, 0xBE9FC106, + 0xBFC3C008, 0x700E6038, 0xC74A702E, 0xC007C047, + 0xA000210C, 0x002D0210, 0xC10272AE, 0x2440220A, + 0x790BC003, 0xF20E700C, 0x220AC006, 0x210C2440, + 0x700CA000, 0x1418F7C6, 0xC0063012, 0x0440200E, + 0x21012A40, 0x22056852, 0x7A052052, 0x68B66834, + 0x728E7945, 0x706E7D25, 0x8E204262, 0x716E8E1B, + 0x2B007825, 0xB9022081, 0x0081210F, 0xF211790B, + 0x202F7F2F, 0x08FE0487, 0x41E1FEEF, 0xC003C102, + 0xF207790B, 0xD8FF79AF, 0xFEEF097A, 0x248C42E1, + 0x160029BF, 0x80007080, 0x08130001, 0x244A00BF, + 0x16000FC0, 0x80007084, 0x40630120, 0x42C2702C, + 0x70AC726C, 0x091E70CC, 0x70EEF8AF, 0x230A720F, + 0x8E2025C0, 0x71EE8E1B, 0x2F007905, 0xB80224C0, + 0x04C0200F, 0xF2A3782B, 0x000045D3, 0x231F28F0, + 0x11022540, 0x2D41308D, 0x251F2095, 0x671F154F, + 0x30801105, 0x03640839, 0x44D3704E, 0x1A3C8000, + 0x0A27C005, 0xC0042005, 0x2500E887, 0x101C1680, + 0x0A0F0080, 0x0A7E2000, 0x24000060, 0x248023C0, + 0x71462184, 0x77A2F1EE, 0xF1E471A5, 0xC103C202, + 0xF2397A2B, 0x308D1102, 0x036408E3, 0x10522544, + 0x30801103, 0x0354203C, 0xC00570ED, 0x10050F4F, + 0xE888C004, 0x16802500, 0x0080101C, 0x10000F3B, + 0x30061410, 0x7BF079B0, 0x704C4062, 0x0822718C, + 0x71ACF7EF, 0x42624122, 0x0802219A, 0x229FC393, + 0x61790401, 0x245F6159, 0x623A2A02, 0x2501225F, + 0x7AF4623A, 0x71E5B200, 0x1105F1D9, 0x71A53080, + 0x708EF1CC, 0x20950C77, 0x20100C09, 0xF0038E1B, + 0xE8338E00, 0x20100C0B, 0x30921104, 0x1102F003, + 0x24783092, 0xE8852000, 0x308F1105, 0x1103F003, + 0xC305308F, 0x14104062, 0x41423006, 0x718C42E1, + 0xF7AF0FAE, 0x412270AC, 0x219A4262, 0xC3930802, + 0x0401229F, 0x30061410, 0x2A0D245A, 0x70AC728C, + 0xC3056179, 0x4142623A, 0x42E1655D, 0x0F82B500, + 0x4062F7AF, 0x7186B50A, 0x208CF1C6, 0x05F334FD, + 0x7126FFEF, 0x242FC005, 0x40A22000, 0x800043DB, + 0xC04B0025, 0x30811300, 0x3080131B, 0x710C7905, + 0x04002800, 0x200FB802, 0x782B0400, 0x702EF2AB, + 0x01527136, 0x090D000D, 0x131B2010, 0xF0043080, + 0x30801300, 0xF29D7014, 0x2214704E, 0x7156244F, + 0x002D012E, 0x702CC08D, 0xF6AF0B26, 0x24004282, + 0x00003F93, 0x231605EC, 0x70CD2413, 0x24532315, + 0x24932314, 0xC003C102, 0xF236790B, 0x79EF70AD, + 0x0B7A7AAF, 0x710CF92F, 0xE988C104, 0x16812700, + 0x0081111C, 0x10400D47, 0x230A41C1, 0x219A1400, + 0xC2930802, 0x1401239F, 0x2A0C215A, 0x2503225A, + 0x7261623A, 0x61796299, 0x000121F4, 0x78B4C08D, + 0x0A1B9040, 0xB0200045, 0x3F802400, 0x054C0000, + 0x60987061, 0x7BB4631B, 0x71A5B3C0, 0x0DA3C005, + 0xF0199004, 0x410240C1, 0x0802209A, 0x219FC293, + 0x60580401, 0x215A6038, 0x61192A01, 0x2500225A, + 0x14346110, 0x090F3101, 0x1B000005, 0x1C342384, + 0xC0073004, 0x07607610, 0x71C5FFE5, 0xC003C102, + 0xF21F790B, 0xC68D70AD, 0xE888C004, 0x16802700, + 0x0080101C, 0x10000D1F, 0xE88D9600, 0x41C3700C, + 0x00040343, 0x43224202, 0x0480240A, 0xF6AF0F1A, + 0x71A545A1, 0x0DD5C005, 0x72C59024, 0x1434F00E, + 0xE88C3100, 0x41C3700C, 0x00030344, 0x43224202, + 0xF6AF0EF6, 0x0480240A, 0x71E57146, 0x7126F169, + 0x258DF158, 0x710E22BD, 0x710C704E, 0x1300C049, + 0x131B3081, 0x79053080, 0x2800710C, 0xB8020480, + 0x0480200F, 0x02F4782B, 0xC0470021, 0xD9504042, + 0xF72F0A12, 0x200A734C, 0x24003480, 0x00003F80, + 0x209F054C, 0x70AE3401, 0x30182000, 0x02CC71B6, + 0x0D0D000D, 0x131B2010, 0xF0043080, 0x30801300, + 0x02AE7014, 0x710C0021, 0x05402800, 0xF9AF0CDE, + 0x252F780F, 0x40421540, 0xFB2F0D8A, 0x471041A1, + 0xC003C102, 0xF2C0790B, 0x20002752, 0x700E708E, + 0x23512200, 0x08FBC052, 0xDB0820B5, 0x2007C012, + 0x790F0400, 0x215F700C, 0x653E0502, 0x43484330, + 0x082BC105, 0x796F0065, 0xE988C104, 0x16812600, + 0x0081111C, 0x00400811, 0x30812034, 0x71917C6F, + 0x004523CA, 0x71047244, 0xC006F1EC, 0x708DC208, + 0x00032109, 0x3F802400, 0x05EC0000, 0x04802016, + 0x05402015, 0x04C02014, 0xC005B060, 0x7000240A, + 0x050020A8, 0xE888C004, 0x16802600, 0x0080101C, + 0x10000C15, 0x32C02000, 0x79629020, 0x00820907, + 0xB020C108, 0x71857265, 0x72CE70ED, 0x244A6F72, + 0x702C7100, 0x20A870CD, 0x40420640, 0x3F822400, + 0x054C0000, 0x0401209F, 0x255A6058, 0x621A2A02, + 0x2500235F, 0x20F46058, 0x783B00C2, 0x71647124, + 0x00002A00, 0x27147E05, 0xC207140F, 0x79CF78EF, + 0xFEAF0CF2, 0xC00A7A4F, 0x0B00205F, 0x71ED78F5, + 0x70237022, 0x253F268D, 0x7106A8DE, 0x4042F185, + 0x2A02255A, 0x0401209F, 0x3F812400, 0x054C0000, + 0x621A6038, 0xE886C004, 0x05041A24, 0x05041A10, + 0xE886C00C, 0x05041A26, 0x05041A12, 0x0F1B8A30, + 0x12242030, 0xB8020080, 0x8A127905, 0x7825B804, + 0x00811226, 0xB902F008, 0x12267905, 0xB8040080, + 0x8A327825, 0x7E0569D6, 0x79CFC007, 0x0C767A0F, + 0x740CFEAF, 0x205FC00A, 0x60B80B00, 0x70237042, + 0x0382182E, 0x3F802400, 0x05EC0000, 0x04802016, + 0x05402015, 0x20300F0D, 0x880290E0, 0xF004B804, + 0xBF049001, 0xC0077F05, 0x23C7242F, 0x0BA6790F, + 0x4082FEAF, 0x2140C00A, 0x205F3890, 0x21400B00, + 0x21403991, 0x42A23B93, 0x240A4342, 0x651D0500, + 0x21007542, 0x2032334E, 0xAEF22346, 0x3A8F2140, + 0x1085161E, 0x23472132, 0x233267A9, 0xC1402340, + 0x034541C3, 0xC0410008, 0xF8EF0F66, 0x0D27740C, + 0x8E322030, 0xE81EC009, 0x1E00C003, 0x80007042, + 0xC10200FB, 0xF23D790B, 0x40C38E3E, 0x01718000, + 0xC009F029, 0xC003E81B, 0x70421E00, 0x00F18000, + 0x790BC102, 0x8E3EF22D, 0x800040C3, 0xF01B0167, + 0x1E00C003, 0x80007042, 0xC1020100, 0xF221790B, + 0x40C38E3E, 0x01768000, 0xC003F00D, 0x70421E00, + 0x00F68000, 0x790BC102, 0x8E3EF213, 0x800040C3, + 0x1801016C, 0x20320052, 0x18012341, 0x21320052, + 0xA8202341, 0xA82167A9, 0x23412332, 0x2040A822, + 0x053D3A18, 0x71A6FFEF, 0x714EC00B, 0xC04B7704, + 0x700C7014, 0xFFE204EA, 0x0A22C049, 0x730CF9AF, + 0x3F172480, 0x341B1404, 0x78E0C6DA, 0x09FEC0F1, + 0x710CF9AF, 0x030541C3, 0x0E960000, 0xD80AF8EF, + 0x030641C3, 0x42C30001, 0x25030000, 0xF8EF0E82, + 0x740CD80A, 0x030741C3, 0x714C0004, 0x738C726C, + 0xF8EF0E6E, 0x740C74AC, 0x030841C3, 0x704C0004, + 0x123444C3, 0x45C3ABCD, 0xEF12ABCD, 0xF8EF0E52, + 0x09AADB07, 0x700CF9AF, 0x00200A7E, 0x700CD807, + 0x00C420AB, 0xF0007FFF, 0x2079C2E6, 0x4708000E, + 0x256F4E18, 0xB5001A43, 0x10002752, 0xF82F0946, + 0x30021A06, 0x41C3E808, 0x000002F6, 0xF8EF0E12, + 0xF018D80A, 0xEF05D80A, 0xB912D9BD, 0x41C3F004, + 0x000002F5, 0xF8CF0DFA, 0xF90F0C96, 0xEF86E802, + 0x085678DB, 0x7404FEEF, 0x084E78DB, 0x7304FEEF, + 0x40C370F5, 0x8009FFFF, 0x006120C2, 0x30031A06, + 0xD8FDB500, 0xFD6F0B66, 0x00E120CA, 0x78E0C6C6, + 0x7FE0710C, 0x00C420AB, 0x1E00710C, 0x900C7004, + 0x7EE00088, 0x7014C2F6, 0x42C3C808, 0x01238000, + 0x901C43C3, 0x404804B0, 0x0F8122CA, 0x01248000, + 0x008B2840, 0x23056BA4, 0xDF3F10C1, 0x23058A40, + 0x91001343, 0xBF08E50C, 0x12CD2505, 0x938078E4, + 0x784595C0, 0x2404B100, 0x7EE413C0, 0x7AC57845, + 0xB540B300, 0x901C41D3, 0x100004E4, 0x21401080, + 0x16002215, 0x80007081, 0x48350124, 0x14402305, + 0x254090C0, 0x25CE2116, 0x26531021, 0x23051181, + 0x23051542, 0x25001583, 0x92209057, 0x01131300, + 0x01902153, 0x001A4230, 0x23530024, 0x25002194, + 0x000E943E, 0x25000024, 0x0022953E, 0x752C0003, + 0x0A06700C, 0xB913F6AF, 0x6832C808, 0x05832105, + 0x05422105, 0x04402105, 0x7EE44328, 0x23D22204, + 0x15C12605, 0x23502000, 0x2305B020, 0x901C1F80, + 0x270404E8, 0x758214CF, 0x2005B020, 0x7DE52480, + 0xB3A0B200, 0x78E0C6D6, 0x4628C2E4, 0x16004508, + 0x90307100, 0x1A2103BC, 0xE909301C, 0x10710E3D, + 0x724C700C, 0x30831A07, 0x258CF020, 0x004E9804, + 0x258C0029, 0x00629FC3, 0x258C002C, 0x258C9002, + 0xF23D9004, 0x9404258C, 0x258CF23D, 0xF44F9804, + 0x1A07754C, 0xF00A3143, 0x030241C3, 0x096A0001, + 0x42C1F6AF, 0x30821207, 0x41C3D80A, 0x00030303, + 0x0C4E43A1, 0x44C1F8EF, 0x258CC6C4, 0xF6D597C8, + 0x9808258C, 0x258CF223, 0xF2259848, 0x9F800D97, + 0xE9010000, 0xF223F02B, 0x9402258C, 0x714CF427, + 0x30431A07, 0x258CF1E2, 0xF21D9844, 0x9408258C, + 0xDA07F41D, 0x31C31A07, 0x734CF1D8, 0x30C31A07, + 0x744CF1D4, 0x31031A07, 0xDA08F1D0, 0x32031A07, + 0xDA09F1CC, 0x32431A07, 0x704CF1C8, 0x30031A07, + 0x764CF1C4, 0x31831A07, 0xDA0AF1C0, 0x32831A07, + 0x78E0F1BC, 0x8FC3208C, 0x0821F209, 0x41C301D1, + 0x0470901C, 0x00451900, 0x41C3F006, 0x0470901C, + 0x01051900, 0x00051900, 0x903041C3, 0xB10000C8, + 0x0020001D, 0x00051904, 0x903041C3, 0xB10000C8, + 0xB104B830, 0x00200009, 0x00051904, 0x903041C3, + 0x91000010, 0x801F08FF, 0x0B822155, 0x080F9200, + 0x1A0408B1, 0x1ACE0045, 0x9100005D, 0x801E08FF, + 0x78E07EE0, 0x70801600, 0x01078000, 0x01002044, + 0xB8227FE0, 0x0343226F, 0x0500120E, 0x000070D3, + 0x700C0C80, 0x07C520E0, 0x050112E0, 0xF60BE1FF, + 0x02032142, 0x00940B23, 0x0430092B, 0xF20FE1C0, + 0x218CF014, 0xF20B8002, 0x8010218C, 0x091DF211, + 0x00000F81, 0x8A004000, 0x8A00F007, 0x0080206D, + 0x8A00F004, 0xB8C0781D, 0x20797FE0, 0x8A000000, + 0x00C0206D, 0x78E0F1FA, 0x70801600, 0x00058000, + 0x20797FE0, 0x78E00000, 0x0F8EC0F1, 0xE809FFCF, + 0x70801600, 0x00F48000, 0x710CB8E4, 0x700CF402, + 0x7EE0C0D1, 0x216FC0F1, 0x890005C3, 0x700CB8E6, + 0x895AF208, 0x00811135, 0x73347945, 0xFFC10FCC, + 0x7EE0C0D1, 0x0F43216F, 0xB8E18900, 0x7CE0700C, + 0x810011E8, 0x7000263C, 0x0C7F0000, 0x78E07EE0, + 0x4300C0F1, 0x70801600, 0x00018000, 0x013F0825, + 0x0EA64428, 0xD808FFEF, 0xFFEF0ED2, 0x232F4060, + 0xF20880C8, 0xFFEF0EC6, 0x14001404, 0x0F3F238C, + 0x7EE0C0D1, 0x44CBC5E1, 0x28F00000, 0x030D201F, + 0x786A789B, 0x0184229F, 0x2C4160BB, 0x782A1080, + 0x605C6078, 0x800042C3, 0x22561A3E, 0x64080800, + 0x10012415, 0x60336A0A, 0x0A256152, 0x700C00E4, + 0x1F812434, 0x1B408000, 0x21CC7230, 0xF78880C6, + 0x4A314970, 0x79307810, 0x00002109, 0x78E0C4C2, + 0x1600C2E8, 0x80007101, 0x47C3000A, 0x18000000, + 0x21044010, 0x248A01C1, 0x27507001, 0x700D0307, + 0x70CC702D, 0x70CD70ED, 0x706D704C, 0x20A8708D, + 0x20150101, 0x906023C0, 0x087B9001, 0x631D00E4, + 0x6B014873, 0x7D0C73C0, 0x00462340, 0x21007034, + 0x20DA1349, 0x20D503C1, 0xF22D1001, 0x01E10915, + 0x8C07208B, 0x271A780C, 0x621A1003, 0xF0237E75, + 0x083BF20D, 0xDB08023F, 0x8003208B, 0x262FF213, + 0xDB07F005, 0x01A323CA, 0x204BF011, 0xF2078300, + 0x736CB8E3, 0x00A123CA, 0x781DF009, 0x00432044, + 0xB8E5F005, 0x23CA756C, 0x647C0121, 0x23157BEC, + 0x71E510CB, 0x00300E4B, 0x2905D8C9, 0x21781180, + 0x71F00003, 0x767D729D, 0x26CA7074, 0x20CA0081, + 0x71041381, 0x118D2805, 0xFFEF0E42, 0xE8897E1D, + 0xBD2271A5, 0x1FC0257C, 0x25CA7014, 0x18821FE1, + 0x2080239C, 0x18002084, 0x700C2342, 0x41C3C6C8, + 0x00020215, 0x08EA4201, 0x4321F8EF, 0x021641C3, + 0x08DE0000, 0xD8C9F8EF, 0xC6C8730C, 0x42C3C2E4, + 0x12208000, 0x8A404300, 0x02C1239F, 0x0582229F, + 0x2232627A, 0x80010F8D, 0x714C4E86, 0xE9047A18, + 0x12012585, 0x0A8A6A12, 0x2005F6EF, 0x252F008E, + 0x700C0387, 0xDA22762C, 0x244A43A1, 0x0BEE0480, + 0x70CCF72F, 0xD907D880, 0x706C724C, 0x70AC708C, + 0xF72F0BDA, 0x700C70CC, 0xF72F0B82, 0xC6C4712C, + 0xB80243E3, 0x0F822005, 0x00009000, 0xFE6F09E6, + 0x7B204020, 0x78E0B200, 0x4608C2E6, 0x70801600, + 0x00088000, 0x72AD7214, 0x0A264728, 0x25CAF6EF, + 0x0E461161, 0x0A02F70F, 0x0819F6CF, 0x700C003F, + 0x704CD907, 0x708C706C, 0x0B8270AC, 0x70CCF72F, + 0x752CD809, 0x704CB813, 0x0008238A, 0x45C1708C, + 0xF72F0B6A, 0xD80C70CC, 0x42A1D92B, 0x708C706C, + 0x0B5A45C1, 0x70CCF72F, 0xD92BD80C, 0x706C42A1, + 0x45C1708C, 0xF72F0B46, 0xEF0670CC, 0xD80C6D41, + 0xF005D92B, 0xD92BD80C, 0x706C42A1, 0x45C1708C, + 0xF72F0B2A, 0x708C70CC, 0x4788D92B, 0xBF9242A1, + 0x40E1726C, 0x0B1645C1, 0x70CCF72F, 0xD92BD80C, + 0x726C42A1, 0x45C1708C, 0xF72F0B02, 0x700C70CC, + 0x744CD907, 0x708C706C, 0x0AF270AC, 0x264AF72F, + 0x7DFB0280, 0x40A1D907, 0x706CDA10, 0x45C1708C, + 0xF72F0ADA, 0x2F4170CC, 0xD90710C0, 0x706C744C, + 0x70AC708C, 0xF72F0AC6, 0x700C70CC, 0x744CD907, + 0x708C706C, 0x0AB670AC, 0x264AF72F, 0x0D420BC0, + 0x700CF70F, 0x744CD907, 0x708C706C, 0x0A9E70AC, + 0x70CCF72F, 0x18002555, 0x704CD907, 0x708C706C, + 0x0A8A45C1, 0x70CCF72F, 0x78E0C6C6, 0xC1A6C3FA, + 0xC045D977, 0x0F1AB910, 0x740CF8AF, 0x800040C3, + 0x10020150, 0x42830501, 0x1002B220, 0xB2210501, + 0x05011002, 0x1002B222, 0xB2230501, 0x05011002, + 0x9020B224, 0x9021B225, 0x9022B226, 0x808010D7, + 0xE805B227, 0x30961210, 0x120FF003, 0x700E3096, + 0x800040C3, 0xC0441228, 0x01F07216, 0x702C0026, + 0x20510811, 0x70801600, 0x003F8000, 0xF2E97014, + 0x2800710C, 0x0A160400, 0x780FF96F, 0x702EC005, + 0xF29C7014, 0x202FC704, 0xC0803407, 0x04402015, + 0x040020F4, 0xF6EF086A, 0x0C8268B2, 0x78B0F72F, + 0x70AD45F1, 0x010875D2, 0x704E0026, 0x3540210A, + 0x0BF7706E, 0x11012095, 0x740C3494, 0x1F8E2532, + 0x04788000, 0x41C34222, 0x00050078, 0x240A4362, + 0x45C10400, 0xF8AF0E4A, 0x0500260A, 0x13310E1B, + 0x3083120E, 0x0407202F, 0xFB2F0F3E, 0x0487212F, + 0xDA22E803, 0x6B09F00A, 0x2538DA22, 0x23781001, + 0x20052000, 0x7AC0807E, 0x4382710C, 0x04C02800, + 0x683244C1, 0x782570CC, 0x272F762C, 0x700C2007, + 0xF72F095A, 0x05C0250A, 0x13310E79, 0x1487262F, + 0x0EF64003, 0x41C1FB2F, 0x244FE823, 0x740C21D4, + 0x41C34222, 0x00050079, 0x240A4362, 0x254A0400, + 0x0DCE0300, 0x260AF8AF, 0x0B130500, 0x704C2030, + 0x7704CA0E, 0x10000D07, 0x700CDA22, 0x4382762C, + 0x0300244A, 0x05C0250A, 0xF72F0902, 0x400370CC, + 0xFB2F0EA6, 0xE88E41C1, 0x742C700C, 0xF72F0BE2, + 0x0B11704C, 0x700C2030, 0x0BD6702C, 0x704CF72F, + 0x71667146, 0x74A6F187, 0xF17E71A5, 0x74367126, + 0xFFE506DA, 0xF045E72C, 0x704E740F, 0x72EEC080, + 0x04802015, 0x70AD70AE, 0x040020F4, 0x2005781B, + 0x00040F93, 0x0E4D1000, 0x240A2030, 0x25002580, + 0x80002F95, 0x70ED1228, 0x2B00225A, 0x1F822732, + 0x04788000, 0x007A41C3, 0x78F50002, 0x04002014, + 0x200E2532, 0x0D1A740C, 0x43C1F8AF, 0x71E578AF, + 0x71A57062, 0xB89CB802, 0x248DB89F, 0xA0C02A3F, + 0x26FF278D, 0x0D1571AE, 0x78AF103E, 0xB8027062, + 0xB89FB89C, 0x04441800, 0x30BF208D, 0xC0047146, + 0x72047106, 0xF10AC044, 0x901C40C3, 0xB02001F8, + 0x804418F0, 0x78E0C7DA, 0x716EC2F4, 0x23064010, + 0x16002013, 0x80007080, 0x70140131, 0x2740224A, + 0x2100240A, 0x46504570, 0x0E864628, 0x22CAF6AF, + 0x70AD25A1, 0x011C7552, 0x40A20026, 0x1F912532, + 0x06188000, 0x092A4122, 0x2632FAEF, 0x08BD144F, + 0x0D1B0010, 0x700C1131, 0x744CD910, 0x708C706C, + 0x0400250A, 0xF6EF0FC6, 0x700C70CC, 0x704C762C, + 0x240A43E1, 0x250A0440, 0x0FB20400, 0x70CCF6EF, + 0xD922700C, 0xF72F0A9A, 0x0D85704C, 0x0E191755, + 0x1F08734E, 0x16000000, 0x80007080, 0x085D00CA, + 0xF034001F, 0x734F0E55, 0x00000006, 0x14110D61, + 0x800040C3, 0x88201222, 0x203C8803, 0x0D1A0040, + 0x4162FB2F, 0x0F96E81A, 0xD8FAFBAF, 0x700C7910, + 0xF72F0A4E, 0x274F704C, 0x700C11C3, 0x704C762C, + 0x0440240A, 0x0400250A, 0xF6EF0F42, 0x700C70CC, + 0x0A2ED922, 0x704CF72F, 0x0F62D8FA, 0x7910FB8F, + 0x0A1E700C, 0x704CF72F, 0xF19671A5, 0x0C41EDFE, + 0x8E012010, 0x00DF080D, 0x20538E14, 0xF21880FE, + 0x0EBA700C, 0x712CF6EF, 0xF68F0D86, 0x000040C3, + 0x0FC23A98, 0xD908FC2F, 0xFE6F0CE6, 0x40C340C1, + 0x0D400003, 0xFC2F0FAE, 0xF1E0D908, 0xF1D7D8C8, + 0xD941700C, 0xF72F09CA, 0x700C704C, 0xF6EF0E7E, + 0x0E41712C, 0x8E1C2010, 0x015E0831, 0xF68F0D42, + 0x20452053, 0xD919D880, 0xDB85744C, 0x0EAE708C, + 0x70CCF6EF, 0x0E56700C, 0x712CF6EF, 0x005B40C3, + 0x0F628D80, 0x702CFC2F, 0x09EE700C, 0x4102F8EF, + 0x78E0C6D4, 0x716EC2F6, 0x23064010, 0x16002013, + 0x80007080, 0x70140131, 0x2740224A, 0x2140240A, + 0x2100250A, 0x47504670, 0x0BD24628, 0x22CAF96F, + 0x0CDE25A1, 0x0AE2F68F, 0x70ADFE4F, 0x012A7552, + 0x40C20026, 0x1F912532, 0x06188000, 0x0F824122, + 0x2632FAAF, 0x7014144F, 0x0D11F285, 0x700C2030, + 0x091ED91E, 0x714CF72F, 0x11310D55, 0x762C700C, + 0xF72F090E, 0x700C714C, 0x704CD92C, 0x708C706C, + 0x0400250A, 0xF6EF0E06, 0x700C70CC, 0x704CD92D, + 0x708C706C, 0x0400250A, 0xF6EF0DF2, 0x700C70CC, + 0x08DE762C, 0x714CF72F, 0x41E14022, 0xF72F09B2, + 0x25424202, 0x08451600, 0xF0500154, 0x41E14022, + 0xF72F099E, 0xED234202, 0x14D00D31, 0x94110DE7, + 0x800040C3, 0x88201222, 0x203C8803, 0x0B5A0040, + 0x4162FB2F, 0x700CE867, 0x0896762C, 0x714CF72F, + 0x11C1274F, 0xF1DC4022, 0x70801600, 0x00CA8000, + 0x003E0859, 0xD91E700C, 0x0C47F025, 0x8E012010, + 0x00DF080D, 0x20538E14, 0xF21B80FE, 0xFE4F09D6, + 0x0D1A700C, 0x712CF6EF, 0xF68F0BE6, 0xFE4F09EA, + 0x000040C3, 0x0E1E3A98, 0xD908FC2F, 0xFE6F0B42, + 0x40C340C1, 0x0D400003, 0xFC2F0E0A, 0x700CD908, + 0x082ED918, 0x714CF72F, 0x762C700C, 0xF72F0822, + 0x71A5714C, 0x098EF16C, 0x700CFE4F, 0xF6EF0CCE, + 0x0F5B712C, 0x8E1C2010, 0x015E084B, 0xF68F0B92, + 0xFE4F0996, 0xD925700C, 0xDB85704C, 0x250A708C, + 0x0CFA0400, 0x70CCF6EF, 0xD926700C, 0xDB85704C, + 0x70AC708C, 0xF6EF0CE6, 0x094A70CC, 0x700CFE4F, + 0xF6EF0C8A, 0x40C3712C, 0x8D80005B, 0xFC2F0D96, + 0x710C702C, 0xF8EF0822, 0x09B64102, 0xC6D6F98F, + 0x47CBC2EA, 0x02FE8000, 0x10911700, 0xF92F0CBE, + 0x40C3730C, 0x11388000, 0xE80B8800, 0x70801600, + 0x00018000, 0x02002044, 0x00002078, 0x700CF002, + 0x0E36D911, 0xB913F62F, 0x207E090B, 0x0D5AD820, + 0x09EAFF8F, 0x8FA1F94F, 0x10901700, 0xF6AF0AF2, + 0x10022589, 0xFE4F08F2, 0x70CDED1B, 0x1F802600, + 0x03808000, 0xDA0F8820, 0xF72F0826, 0x80801080, + 0x762C700C, 0xF6EF0F3A, 0x258D714C, 0x71C51CBF, + 0xFE4F08A2, 0x0BE6700C, 0x712CF6EF, 0x0896F003, + 0x080FFE4F, 0xD822207E, 0xFF8F0CFE, 0x0912F1D5, + 0x090DF98F, 0xD821207E, 0xFF8F0CEE, 0x78E0C6CA, + 0x43C3C5E1, 0x04628000, 0x93034008, 0xF042242F, + 0x7A1DF215, 0x2200706D, 0x00040F8C, 0x20A81000, + 0x201503C0, 0x716512C2, 0x924192A0, 0x7D45BA10, + 0xBA9C6C52, 0xBA9F7185, 0x6038A2A0, 0x9300B303, + 0xB3006038, 0x78E0C4C2, 0x1CFCC2FA, 0x4710B6C8, + 0xB89FD840, 0x2100240A, 0x45504378, 0x00991000, + 0x10E54630, 0x700E8098, 0x716E724E, 0x24002B00, + 0x2004722E, 0xB80206CF, 0x040E200F, 0x70AD4003, + 0xF23078EB, 0x23402B00, 0xF92F0B92, 0x40C3780F, + 0x11388000, 0xE8188800, 0x70801600, 0x00018000, + 0x00FF0825, 0x259F4002, 0x209F1582, 0x42C202C1, + 0x708C43A2, 0x0500250A, 0x651975E2, 0xFFEF0CCA, + 0xF01078CF, 0x259F4002, 0x209F1582, 0x42C202C1, + 0x240A43A2, 0x75E20500, 0x0B126519, 0x78CFFFEF, + 0x218D4023, 0x71AD243F, 0x20BF228D, 0x0B2E710E, + 0x730CF92F, 0x341B1404, 0x78E0C6DA, 0x4568C3E6, + 0x47284648, 0xB0091CF8, 0x30011C04, 0x30C21C01, + 0xF6EF0D9A, 0x2578C360, 0x41C11000, 0x6841781B, + 0xF6EF0D3E, 0x0D86C080, 0x40E1F6EF, 0x0A8E700C, + 0x712CF6EF, 0x78E0C7C6, 0x2945C2E4, 0x4608018B, + 0x0D3D70AD, 0x8E0112C5, 0x8E228E40, 0x7A05B808, + 0xB8088E03, 0xB8107825, 0x00812005, 0x8E448E05, + 0xB8087734, 0xF2077845, 0xB99CB902, 0xB100B99F, + 0x0AD6F003, 0x76C5FC0F, 0xF1E571A5, 0x78E0C6C4, + 0x7034C2E4, 0x800041C3, 0xF22712E0, 0x00C1110A, + 0x7180244A, 0x7B31C808, 0x2144B923, 0x68520401, + 0x22057965, 0x90030F8C, 0x7B2FD580, 0x0F812205, + 0xD5849003, 0x800042C3, 0xB4600548, 0x20A8B160, + 0x12100300, 0x79050401, 0x2105B902, 0x90030F81, + 0xB160C000, 0x2042F017, 0xF215803C, 0x20A86944, + 0x120604C0, 0xB8020400, 0x0F832005, 0x00009000, + 0x04C0120E, 0xB8237911, 0x04002044, 0x780F7825, + 0x720CB300, 0x900345CB, 0x46CBD478, 0xF07C9007, + 0x10C51D00, 0xFC2F0A32, 0x10C51E00, 0x900F41C3, + 0x2150E008, 0x710C04C2, 0x01451900, 0x01451A00, + 0xB200B100, 0xB600B500, 0x78E0C6C4, 0x42C3C0E6, + 0x12228000, 0x40288A81, 0x0C518AA0, 0x43001364, + 0x00022479, 0xE20970B4, 0x22CAC808, 0x20050062, + 0x221F00CE, 0x2D40034B, 0x240A130F, 0x7FC57080, + 0x20A8706C, 0x2B400440, 0x70B40200, 0x20F478C0, + 0x78E512C1, 0xB8027164, 0xB8927165, 0xB89FB89C, + 0x7591B020, 0xF7A971A5, 0x78E0C4C6, 0x4010C2E8, + 0x800046CB, 0x47CB1222, 0x4DAC8001, 0x2754E903, + 0x8EA01F0F, 0x08578E01, 0xD8C80364, 0x800040C3, + 0x880012D9, 0x036E0843, 0x0F7A79AF, 0x4002FE2F, + 0xC8084408, 0x13822D40, 0x7280244A, 0x700C6832, + 0x20A87A25, 0x0C2104C0, 0x255A100E, 0x61F91501, + 0x000321F4, 0x02812840, 0x21057945, 0x90040F81, + 0xB1600320, 0x71A57104, 0x09A2F1D6, 0xC6C8FC0F, + 0x718EC2F4, 0x2C004610, 0x16002040, 0x80007093, + 0xB8020004, 0x200F4230, 0x0AAF0051, 0x235302F0, + 0xE28A20D3, 0x700EF4B4, 0x081372AE, 0x16002010, + 0x80007080, 0x08890040, 0x272F0010, 0x40421400, + 0xFAAF0982, 0x260041E1, 0x42C323C1, 0x0E9C8000, + 0x89218960, 0x6149634D, 0x6914E804, 0xF0047D05, + 0x7D25BD04, 0x2800710C, 0x08A20400, 0x780FF92F, + 0x750C7EAF, 0x41C34242, 0x000301D3, 0x0D224302, + 0x44C1F86F, 0x0447212F, 0xFE2F0AC2, 0x235F40C1, + 0x60F82B00, 0x70C37042, 0x123C8000, 0x20300A15, + 0x0CC7A8A0, 0x1E002010, 0x80007342, 0xF008017E, + 0x20100CCB, 0x73421E00, 0x017D8000, 0x258D710E, + 0x708E2DFE, 0x700EF064, 0x081372AE, 0x16002010, + 0x80007080, 0x08890040, 0x272F0010, 0x40421400, + 0xFAAF08E2, 0x260041E1, 0x42C323C1, 0x0E9C8000, + 0x89218960, 0x6149634D, 0x6914E804, 0xF0047D05, + 0x7D25BD04, 0x2800710C, 0x08020400, 0x780FF92F, + 0x750C7EAF, 0x41C34242, 0x000301D4, 0x0C824302, + 0x44C1F86F, 0x0447212F, 0xFE2F08BA, 0x235F40C1, + 0x60F82B00, 0x70C37042, 0x12388000, 0x20300A15, + 0x0C31A8A0, 0x1E002010, 0x80007342, 0xF00800F7, + 0x20100C35, 0x73421E00, 0x00F28000, 0x258D710E, + 0x708E2DFE, 0x1E00F014, 0x80007342, 0xF0100180, + 0x73421E00, 0x01018000, 0x1E00F00A, 0x80007342, + 0xF006017F, 0x73421E00, 0x00FC8000, 0x70801600, + 0x00408000, 0x730CE803, 0x710CF002, 0xF8CF0F6E, + 0x78E0C6D4, 0xC1A8C3E6, 0x1243276F, 0x800145CB, + 0x8FC04E74, 0x1756712C, 0x20441080, 0x09B60202, + 0x40A1FBAF, 0xD91440A1, 0xF6EF0FBE, 0x178A704C, + 0x40A11082, 0x099EBAC3, 0xD914FBAF, 0xF8EF0F22, + 0x0B4EC084, 0xC080FE2F, 0x082EC080, 0xD910F92F, + 0x08358F17, 0x40C3001E, 0x12D88000, 0xE8148800, + 0x41C3BEC3, 0x12288000, 0x1B00265F, 0x6119602A, + 0x1DA28902, 0x89011002, 0x10021D57, 0xAD4C8903, + 0x10021DED, 0xD91040A1, 0xF6EF0F5E, 0x40A1DAFB, + 0x0942D910, 0xDA41FBAF, 0x702C40A1, 0xDBFFC284, + 0xFFEF0AFA, 0x40A1708C, 0x092AD910, 0x744CFBAF, + 0x702C40A1, 0x0BDEC280, 0x716CF72F, 0x78E0C7C6, + 0x78E07EE0, 0x1CFCC2FA, 0x2482B6C8, 0x46303604, + 0x0F46702C, 0x4318F7AF, 0x451071AD, 0x16C02D00, + 0xF9EF0DE2, 0x0DEA68F2, 0x4210F9EF, 0x8E82208C, + 0x238A70CD, 0xF7062F83, 0xF9CF0DD6, 0x08932054, + 0x70831600, 0x00048000, 0x750CBBC3, 0x41C34263, + 0x0002040D, 0xF86F0AEA, 0x16D0270F, 0x41C3D82E, + 0x0E010001, 0xB70F478B, 0xB709D895, 0xB890D897, + 0x41C3C155, 0x012A0007, 0x2154C040, 0xB86C0942, + 0xC043C149, 0xC808E115, 0xC2466989, 0x00422005, + 0x7224B755, 0xBA30C24F, 0xB7567905, 0xC14C6C49, + 0x00812005, 0x03032005, 0x30441C42, 0x1C44B930, + 0x6A2E3044, 0x20057905, 0x00010F80, 0xB73B00FB, + 0xB703B930, 0xB73CB830, 0xB704D90F, 0x714CC080, + 0x31C51C50, 0x33441C4E, 0xB7AAB7B0, 0x1C58B7C2, + 0x1C523384, 0x1C4C3384, 0x1C463384, 0x1C403384, + 0xB7DD3384, 0xB7D7B7DA, 0xB7D1B7D4, 0xB7CBB7CE, + 0xB7C5B7C8, 0xFDEF0B32, 0x1600C352, 0x80007083, + 0x245512D9, 0x244A3801, 0x700C7200, 0x33801C8C, + 0x33801C88, 0x33801C84, 0x33801C80, 0x040020A8, + 0x0B137A1D, 0x2605008E, 0x90381F82, 0x9240012C, + 0x7224B140, 0x000076C3, 0x71044000, 0x1643276F, + 0x20448F00, 0xF2068202, 0x70851E00, 0xC3789007, + 0x41C3700C, 0xC25C9007, 0x800046CB, 0x1E001222, + 0x901C7004, 0x1E000004, 0x90077004, 0xB100F804, + 0x1964EA99, 0xD9400205, 0x900740C3, 0xB020C2C4, + 0x8E41B0A8, 0x0A778E20, 0x7A5B0064, 0x70402614, + 0x048C8000, 0x00412217, 0x09B66942, 0x702CF5EF, + 0x1600F02D, 0x80007082, 0x72540008, 0x901C43C3, + 0x42C30000, 0xF8009007, 0x1964F406, 0xB3000004, + 0xF006B200, 0x01051964, 0xB2A0B3A0, 0x8E008E21, + 0x0024092B, 0x71247902, 0x7040240A, 0x03C020A8, + 0x06812000, 0x70022614, 0x048C8000, 0x0081111C, + 0x21787104, 0xB9080001, 0xD8AAB220, 0x70041E00, + 0xC0B89007, 0xF64F0B0A, 0x0407202F, 0xC057D907, + 0x145CD841, 0xB8133005, 0x706C744C, 0x0C6E708C, + 0x70CCF6AF, 0xD907700C, 0x706CDA08, 0x70AC708C, + 0xF6AF0C5A, 0x145C70CC, 0xD8803005, 0xD907B893, + 0x706C744C, 0x0C46708C, 0x70CCF6AF, 0x0BEE700C, + 0x712CF6AF, 0x000040C3, 0x0CFA1388, 0x752CFBEF, + 0xD9FF710C, 0xFB6F0986, 0x216F704C, 0x40D32443, + 0x048C8000, 0x20801100, 0x01012078, 0x7424B902, + 0x180AB806, 0x20892042, 0x41C30E43, 0x000103E3, + 0x740C6846, 0xF86F089A, 0x20841808, 0x6872C808, + 0x901C40C3, 0x23050504, 0xB1A00001, 0x0F812305, + 0x04FC901C, 0x834418A4, 0x0F802305, 0x04DC901C, + 0x11009000, 0x0A1B2082, 0xB8C500B1, 0x02C2204F, + 0x8F20B140, 0x00FE0925, 0x0301204F, 0x204FF009, + 0xB1400302, 0x09158F20, 0x204F00FE, 0x23050341, + 0x901C0F80, 0xB02004F4, 0x0F802305, 0xC3EC9007, + 0x71051E00, 0xC12C903B, 0x088EB0A0, 0x710CFB2F, + 0xB802C808, 0x0F812005, 0x00949004, 0x1C909120, + 0x8F203040, 0x00DE091B, 0x0F812005, 0xC0949007, + 0x30001490, 0x0080206C, 0x00C02045, 0x1600B100, + 0x80007080, 0x22440126, 0xB8E22051, 0xF9A20C48, + 0x21004063, 0x42D32491, 0x0FB08000, 0x3A402455, + 0x28012240, 0x0FD2DA72, 0x2344F5AF, 0x40C32054, + 0xF0A70000, 0x30041C66, 0x000140C3, 0xC058FF74, + 0x0004208A, 0x30041C6A, 0x100AD972, 0x1C682080, + 0xB8063344, 0x30041C64, 0xFFEF0822, 0x3A402455, + 0x204B8F00, 0xF4068E00, 0x0812C098, 0xD90CFFEF, + 0xD90FD80F, 0x24CD2400, 0xF76F0C2A, 0x27912140, + 0x204B8F00, 0xF4088E00, 0xF84F0D46, 0x0E924063, + 0x712CFF6F, 0x78AFC217, 0x0447212F, 0xFB2F0BDA, + 0x8F404118, 0x8E00224B, 0x0A67F20B, 0x700C00FF, + 0x041441C3, 0x0C420001, 0x026FF5CF, 0x41C30000, + 0x0000040F, 0xF82F0F2A, 0xD861740C, 0x900745CB, + 0xB808C29C, 0xB500712C, 0xF6AF0A22, 0xD941D808, + 0x0004208A, 0xB500B914, 0xF82F0F06, 0x1600740C, + 0x80007080, 0xB8E20001, 0x002201FA, 0x1008DD0A, + 0x09FA2100, 0x712CF6AF, 0x1EFF258C, 0x41C3F0F8, + 0x00000411, 0xF82F0EDA, 0x710C740C, 0xF6AF09DE, + 0x2455712C, 0x41423A40, 0xF5AF0ECE, 0x2455DA10, + 0x22403940, 0x0EC22401, 0xDA10F5AF, 0x8E20700C, + 0xC05EC05F, 0xC05CC05D, 0x082F8E01, 0x78220064, + 0xC8086841, 0x7080240A, 0x20A86872, 0x294003C0, + 0xC2980380, 0x7A357865, 0x0F802005, 0x00A89004, + 0x71249000, 0x700CA200, 0xF6AF0982, 0x8E01712C, + 0x2001258A, 0x082F8E20, 0x78220064, 0xC8086861, + 0x70C0240A, 0x20A86852, 0x294003C0, 0x78450380, + 0x0F832005, 0x00A89004, 0x3A402455, 0x71244820, + 0x0FE2B300, 0x700CFD4F, 0xF6AF0942, 0x8EA0712C, + 0x08D98E01, 0x2D400364, 0xD8891391, 0x2F922105, + 0x01C89004, 0x20041A00, 0xFBEF09AE, 0x20F4D808, + 0x24552340, 0x23153A53, 0x24552353, 0x26153956, + 0x41C32356, 0x00050412, 0xB80242A1, 0x04402005, + 0x3E112454, 0x0F802005, 0x01CC9004, 0x21159000, + 0x1A002351, 0x20442005, 0x43660058, 0x1600740C, + 0x260A2017, 0x11000600, 0x240A2012, 0x250A05C0, + 0x0DBE0480, 0x4470F82F, 0x3011081B, 0x20330A17, + 0x20402740, 0x00F5080B, 0x71EE714E, 0x2F84F003, + 0x081D2FBF, 0x0A193010, 0x27402072, 0x080D2040, + 0x774E00F5, 0xF00477EE, 0x2FBF2F84, 0x20310A19, + 0x30002078, 0x00002079, 0xB805791B, 0x00522142, + 0x04172042, 0x25D42400, 0x25C01E00, 0x24801900, + 0x1B0071A5, 0xF1962500, 0x2DBD258C, 0x096A4063, + 0x702CF7AF, 0x00100883, 0x8E408E21, 0x00A40941, + 0x0A832040, 0x7942C808, 0x240A7124, 0x20A87040, + 0x2A400600, 0x7C05030C, 0x10C12405, 0x2105B902, + 0x90040F8D, 0x6C320000, 0x0F8C2105, 0x00A89004, + 0xB5209420, 0x4941C198, 0xB4207144, 0xFD0F0A46, + 0x1008F01B, 0x08062100, 0x712CF6AF, 0x0C224063, + 0x702CFF6F, 0x702C40C2, 0xFD2F0DD6, 0x2540724C, + 0xC8082A95, 0x05402005, 0x704C41C2, 0x708C706C, + 0xFFAF0E5E, 0x0E6E71AC, 0x70CDFD4F, 0x900745CB, + 0x4063C29C, 0xFAAF0F2E, 0x41C3B5C0, 0x00000415, + 0xF82F0CAE, 0x700C740C, 0x0D62702C, 0x704CFB2F, + 0xB5D4B5D2, 0x08218F00, 0xC80800DE, 0x2005B802, + 0x90070F81, 0x1490C094, 0xB1003000, 0x73841E00, + 0xC3789007, 0xF60F0E5A, 0x752C700C, 0xF6AF0AC2, + 0x700C714C, 0xF66F0F76, 0x0CCE712C, 0x700CFAEF, + 0xF60F0E3E, 0xD907700C, 0x706C744C, 0x70AC708C, + 0xF66F0FAA, 0x708C70CC, 0x3005145C, 0x732C4080, + 0x4223B890, 0x01032841, 0xF66F0F92, 0xD88070CC, + 0x744CD907, 0x708C706C, 0x0F8270AC, 0x70CCF66F, + 0x0F2A700C, 0x712CF66F, 0xFD0F095A, 0xFD4F0DB6, + 0xD90FC080, 0xFDAF0D02, 0x1600704C, 0x8000708C, + 0x245512D9, 0x244A3801, 0x700C7200, 0x040020A8, + 0x0C137A1D, 0x9140108E, 0x1F832605, 0x012C9038, + 0x7224B340, 0x000076C3, 0x71044000, 0x36042480, + 0x341B1404, 0x78E0C6DA, 0x2482C3F4, 0x228A3102, + 0x10822084, 0x2033070F, 0x250A048E, 0x46702100, + 0x43304450, 0xFF6F08D6, 0xE8084110, 0x710478CF, + 0x2049B822, 0xF0050FCE, 0x10320E45, 0x2648700E, + 0x40D11000, 0x780F7104, 0x7000240A, 0x034020A8, + 0x0407202F, 0x20002115, 0x09139020, 0x900103C5, + 0x10050F0B, 0x700E7706, 0x0892F006, 0x7014FF4F, + 0x206220C0, 0xDD3FE6BF, 0xF01DF6C2, 0xD940E6C0, + 0x45C96E01, 0x004B20CA, 0x240A78C2, 0x20A87000, + 0x21150300, 0x90202340, 0x03C50911, 0x0F0D9001, + 0x71A51005, 0xF007DD3F, 0xFF4F0852, 0x25C27014, + 0x084A1062, 0xE809FF4F, 0x24802132, 0x79026D32, + 0x04022018, 0x4DD1F004, 0x14022602, 0x7E2F78CF, + 0x200C2115, 0x4F109400, 0x94017B10, 0x7F4F78E2, + 0x081A7810, 0x2009FF6F, 0x701400CD, 0x138E2709, + 0xFF6F080A, 0x106225C0, 0x40A17014, 0x138125CA, + 0x710CF213, 0x20300B0F, 0x30431C05, 0x704C712C, + 0x702CF003, 0x0E2A42A2, 0xC380F9AF, 0x3100140C, + 0x710478CA, 0x7CB0B822, 0x0C177B10, 0x24892030, + 0x0E1B1FC3, 0x0B272051, 0xD9592071, 0x0E17F016, + 0x0B232051, 0xD93E2071, 0x0B17F010, 0xD9552071, + 0x0B17F00C, 0xD93A2071, 0xD957F008, 0xD953F006, + 0xD93CF004, 0xD938F002, 0x6909B99F, 0xC2608840, + 0x0A0DC220, 0x23890325, 0xC4200FC3, 0x8900A880, + 0xC020C060, 0x00C50807, 0xA960C320, 0x78E0C7D4, + 0x1600C2EA, 0x8000708E, 0x71141222, 0xDD75D870, + 0x25CA4130, 0x16001001, 0x80007080, 0x08771223, + 0x16000384, 0x80007080, 0x086712D9, 0x79CF03AE, + 0xFDEF0BA2, 0x46004022, 0x742D70EC, 0x702C720D, + 0x03822114, 0xBA0CC808, 0x27157845, 0x702C0042, + 0x02450937, 0x00AE0E2D, 0x7B0561BB, 0x2305BB02, + 0x90380F8C, 0x265A0000, 0x7B541503, 0x0F8B2334, + 0x4DAC8001, 0x800043C3, 0x23F40F60, 0xB46002C3, + 0x71447124, 0x712CF1E6, 0x173F208D, 0x71C5752D, + 0xC6CAF1C3, 0x1CFCC2FA, 0x44D3B6C8, 0x12228000, + 0x14014018, 0x14002080, 0x200C2090, 0x011AA000, + 0x4748002D, 0x0C172140, 0x000E45D3, 0x21400000, + 0x21400816, 0x21540402, 0x21050819, 0x2705055B, + 0x26052557, 0x25052556, 0x46CB2095, 0x00009000, + 0x800041C3, 0x892012D9, 0x040E09D5, 0x2513205A, + 0x800145CB, 0x7F604DAC, 0x23402334, 0x23512840, + 0x21055020, 0x75622612, 0x26C22205, 0xB9027945, + 0xB10079C5, 0x95017F60, 0x25422205, 0x79455020, + 0x79C5B902, 0x7F60B100, 0x22059502, 0x50202582, + 0xB9027945, 0xB10079C5, 0x95037F60, 0x25D22205, + 0x21055020, 0xB9020481, 0xB10079C5, 0x95047F60, + 0x26112100, 0x21964100, 0xC8082008, 0x26C22105, + 0xB8027845, 0xB02078C5, 0x95057F60, 0x25422105, + 0x79455020, 0x79C5B902, 0x7F60B100, 0x21059506, + 0x50202582, 0xB9027945, 0xB10079C5, 0x95077F60, + 0x25C22105, 0x79455020, 0x79C5B902, 0x7F60B100, + 0x21059508, 0x50202651, 0x04412105, 0x2105B902, + 0x90380F81, 0xB1000000, 0x20801401, 0xA000200C, + 0xFFE50720, 0x14047106, 0xC6DA341B, 0x1CFCC2FA, + 0x2482B6C8, 0x45683902, 0xC0414730, 0x700C700E, + 0x31001C90, 0x30801C8C, 0xEB05C040, 0xF80F0EF2, + 0x41DBC040, 0xC0C49007, 0xFF2F0D72, 0x30451900, + 0x30021C0D, 0x702C710C, 0x0BA642A1, 0xC382F9AF, + 0xD825726F, 0x8820B89F, 0x7905881B, 0x2800710C, + 0xB8020400, 0x0400200F, 0x0252782B, 0x16000001, + 0x8000708D, 0x16001222, 0x80007080, 0x75101223, + 0x000D023A, 0x800040C3, 0x880012D9, 0x83402011, + 0x00210224, 0x097E79AF, 0x148CFDEF, 0x1C983000, + 0x20143000, 0x70CD2340, 0x0F962000, 0x04708000, + 0x13002D40, 0x30001C94, 0x30001498, 0x83802011, + 0x40C3F2EF, 0x28F00000, 0xC1017A1B, 0x200B201F, + 0x794AB822, 0x251A40C9, 0x44CB1003, 0x1B3C8000, + 0x1184209A, 0x3089140D, 0x61787161, 0x64197001, + 0x89026097, 0x10300919, 0x14149142, 0x782A3101, + 0xB8227104, 0x10112700, 0xF0044748, 0x4150671F, + 0x12012E40, 0x30001494, 0xC8087905, 0xC0017905, + 0x0412214F, 0xE80A4330, 0x09717361, 0x23001030, + 0x60980200, 0xF0379002, 0x20110F23, 0x1A00255A, + 0x201478D5, 0x20000400, 0x80000F81, 0x70C3BEC4, + 0xC0048000, 0x04441900, 0x2455B0E0, 0x09463A01, + 0x78F0F96F, 0xE807CA05, 0x3A002455, 0xFB2F0A6A, + 0x09AE41E2, 0xE808FC8F, 0x20811600, 0xFB2F0A5A, + 0x3A002455, 0x24002205, 0x2005B802, 0x90000F8F, + 0x24550048, 0xF0773A00, 0x60906419, 0x60388922, + 0x09027810, 0x2455F96F, 0x24003A01, 0x00003F81, + 0x08F2009E, 0x78F0F96F, 0xE806C000, 0x3100149E, + 0x30041CA0, 0xE80ECA05, 0x3A002455, 0xFB2F0A0A, + 0x240041E2, 0x00003F80, 0x09FE009E, 0x41E2FB2F, + 0xFC8F093E, 0x1600E80F, 0x09EE2081, 0x2455FB2F, + 0x24003A00, 0x00003F80, 0x09DE009E, 0x1600FB2F, + 0xCA052081, 0x091AE887, 0x08A1FC8F, 0x24550030, + 0x24553A00, 0x24003A00, 0x00003F81, 0x724C009E, + 0xFD0F08DA, 0x20310F37, 0x3A002455, 0x1A15255A, + 0x800044D3, 0x2515C004, 0x25142395, 0x0F022415, + 0x2400F7EF, 0x1C002554, 0x25002004, 0x80002F80, + 0x1CA0BEC4, 0x180023C4, 0x22050444, 0xBF02240F, + 0x1F922705, 0x00489000, 0xF7EF0ECA, 0x3A002455, + 0x1A00BF86, 0xBF9C2004, 0x3F802400, 0x009E0000, + 0x0EB2BF9F, 0xB700F7CF, 0x30001490, 0x2B40E809, + 0x20052080, 0x90040F80, 0x18000320, 0x71C50444, + 0x0618E689, 0xF008FFC5, 0x3F812400, 0x009E0000, + 0xF1B8714C, 0xFFEF05C3, 0x238D71A5, 0x710E337B, + 0x30051900, 0x39022480, 0x341B1404, 0x78E0C6DA, + 0x1600C3F2, 0x80007091, 0x0AD20004, 0x2482FF2F, + 0x1C053102, 0x710C3002, 0x704C712C, 0xF9AF0902, + 0x2153C380, 0x718E20D1, 0x726E700E, 0x47CB714E, + 0x12208000, 0xB89FD825, 0x881B8820, 0x2C007905, + 0xB8022400, 0x0400200F, 0xF2C1782B, 0x8F038FC2, + 0x017A7610, 0x40C3000D, 0x12D98000, 0x20118800, + 0xF2B38380, 0x13002E40, 0x30881405, 0x04012005, + 0x7825C808, 0x7280244A, 0x706D6892, 0x1F892405, + 0x00A09004, 0x0A0020A8, 0x000040C3, 0x68320A3C, + 0x201F78CC, 0x41C32042, 0x1B3C8000, 0x4061621A, + 0x0184209A, 0x1030080D, 0x60386058, 0xF0069002, + 0x6030611B, 0x60788B62, 0x12710B0F, 0x12832B40, + 0x10041900, 0x7B85F007, 0x0F832305, 0x01E89004, + 0x7165B300, 0x70801600, 0x00EE8000, 0xF4757014, + 0x10100821, 0x6159622D, 0x140C8922, 0x782A3100, + 0x20047104, 0x00000F80, 0xB822FFFC, 0xF004651D, + 0x89A46159, 0x08118F05, 0x720C03A5, 0xF88F080E, + 0xF006710C, 0xF8AF0806, 0x700C710C, 0x4002AF00, + 0xFA2F08B2, 0x451041C1, 0x08AA4002, 0x41C1FA2F, + 0x2B01215F, 0x00002078, 0x7404B802, 0x8F006119, + 0x00002114, 0x700279AF, 0xA8A860F8, 0x20002578, + 0x0CC26841, 0x4002F5EF, 0x20300D17, 0xE8118F00, + 0x20100A3B, 0x73421E00, 0x00508000, 0xE810F02A, + 0x20100A35, 0x73421E00, 0x00FA8000, 0x0A33F022, + 0x1E002010, 0x80007342, 0xF01C0035, 0x20100A2D, + 0x73421E00, 0x00F08000, 0x1E00F014, 0x80007342, + 0xF0100051, 0x73421E00, 0x00FF8000, 0x1E00F00A, + 0x80007342, 0xF0060036, 0x73421E00, 0x00F58000, + 0xF86F0F5A, 0x71C5730C, 0x704EF143, 0x2D3C238D, + 0xC7D2710E, 0x7A00244A, 0x800040C3, 0x20A8C444, + 0x180001C0, 0x20800003, 0x7EE0000E, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const u32 DMAC_TRANS_DCCM[] = { + 0x00000000, 0x21500030, 0x00044004, 0x00006000, + 0x00FF56DF, 0x00020000, 0x07000000, 0x08010000, + 0x00000000, 0x00000110, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x10000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xD0D00000, 0xDDDDD0D0, + 0x8686DDDD, 0x54548686, 0xB4B45454, 0x2E2EB4B4, + 0x00002E2E, 0x28280000, 0x28282828, 0x00002828, + 0x2E060000, 0x0C0C2E06, 0x10100C0C, 0x02021010, + 0x00000202, 0x00000000, 0x77770000, 0x00007777, + 0x00000000, 0x00000000, 0x24240000, 0x00002424, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x60600000, 0x00006060, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x0000001F, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x57000001, 0x0000004F, 0x00000000, 0x00000000, + 0x00000100, 0x00000000, 0x001E001E, 0x00FF00FF, + 0x000F6E0A, 0x0005000F, 0x00000000, 0x00000000, + 0x005C0032, 0x00E000B6, 0x0164013A, 0x01E801BE, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x01000000, 0x00000000, + 0x00000000, 0x00000000, 0x06400C80, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x050B0000, + 0x00000006, 0x00000000, 0x00000000, 0x08080808, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x010CA635, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000004, 0x00000000, 0x00040000, + 0x00000000, 0x00000000, 0x180F0E0C, 0x4746451E, + 0x004A4948, 0x01000000, 0x00000000, 0x00000000, + 0x00000000, 0x00040000, 0x00000001, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x0002F059, 0xFFB50003, + 0x00000001, 0x0001F0B5, 0xF0B30001, 0x00000001, + 0x0001F0B4, 0xF0B00000, 0x00300001, 0x0007F003, + 0xF0040000, 0x00000007, 0x0001FE03, 0xFE040000, + 0x00000001, 0x0007F011, 0xFE210000, 0x00000001, + 0x0001F0B1, 0xFFBE0182, 0x00000001, 0x0001F0BE, + 0xF0A70001, 0x00000001, 0x0001F0A2, 0x00790002, + 0x00400002, 0x00000308, 0x00000560, 0x00000000, + 0x80000DB4, 0x00000309, 0x00000561, 0x00000001, + 0x80000DC5, 0x000E0305, 0x000E0205, 0x00000003, + 0x80000DD6, 0x000E0300, 0x000E0200, 0x00000003, + 0x80000E3C, 0x000E0301, 0x000E0201, 0x00000003, + 0x80000E4F, 0x000E0302, 0x000E0202, 0x00000003, + 0x80000E62, 0x000E0303, 0x000E0203, 0x00000003, + 0x80000E75, 0x000E0304, 0x000E0204, 0x00000002, + 0x80000E88, 0x01FF01FF, 0x000E0000, 0x00000000, + 0x00000063, 0x00000064, 0x00000660, 0x00000000, + 0x80000D87, 0x00000661, 0x00000001, 0x80000DA5, + 0x000E00F0, 0x00000003, 0x80000DE7, 0x000E00F1, + 0x00000003, 0x80000DF8, 0x000E00F2, 0x00000003, + 0x80000E09, 0x000E00F3, 0x00000003, 0x80000E1A, + 0x000E00F4, 0x00000002, 0x80000E2B, 0x000E00F5, + 0x00000003, 0x80000D96, 0x02011210, 0x1C0A1403, + 0x0B112E29, 0x1916150D, 0x180F0E0C, 0x453A131E, + 0x49484746, 0x02006E4A, 0x00000100, 0x02150028, + 0x0085000A, 0x00000000, 0x02150001, 0x0085042B, + 0x0001010B, 0x00020000, 0x0640042B, 0x0190010B, + 0x00010002, 0x06400002, 0x01900855, 0x00030215, + 0x00030001, 0x0ABE0855, 0x02B00215, 0x00010004, + 0x0ABE0004, 0x02B00C80, 0x00050320, 0x00040002, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00280000, + 0x00050215, 0x00000043, 0x00010000, 0x042B0215, + 0x00850043, 0x00000001, 0x042B0001, 0x00850640, + 0x000200C8, 0x00010001, 0x08550640, 0x010B00C8, + 0x00010003, 0x08550002, 0x010B0ABE, 0x00040158, + 0x00020001, 0x0C800ABE, 0x01900158, 0x00010005, + 0x0C800002, 0x01900E95, 0x000601D3, 0x00030001, + 0x10AB0E95, 0x021501D3, 0x00010007, 0x10AB0003, + 0x021512C0, 0x00080258, 0x00030002, 0x157C12C0, + 0x02B00258, 0x00020009, 0x157C0004, 0x02B01770, + 0x000A02EE, 0x00040002, 0x19001770, 0x032002EE, + 0x0002000B, 0x19000004, 0x03201D4C, 0x000C03AA, + 0x00050003, 0x21551D4C, 0x042B03AA, 0x0003000D, + 0x21550006, 0x042B2580, 0x000E04B0, 0x00070003, + 0x02150028, 0x0085000A, 0x00040004, 0x00010001, + 0x00030001, 0x02150004, 0x0085042B, 0x0004010B, + 0x00000006, 0x00020002, 0x00050003, 0x0640042B, + 0x0190010B, 0x00080006, 0x00030001, 0x00040002, + 0x06400006, 0x01900855, 0x00080215, 0x0002000A, + 0x00030004, 0x00070004, 0x0ABE0855, 0x02B00215, + 0x000E0008, 0x00070001, 0x00040004, 0x0ABE0008, + 0x02B00C80, 0x000A0320, 0x00030010, 0x00040009, + 0x00080004, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00280000, 0x00050215, + 0x00020043, 0x00000002, 0x00010000, 0x00030002, + 0x042B0215, 0x00850043, 0x00030002, 0x00010000, + 0x00020001, 0x042B0003, 0x00850640, 0x000300C8, + 0x00010004, 0x00010002, 0x00030002, 0x08550640, + 0x010B00C8, 0x00050004, 0x00020001, 0x00020002, + 0x08550004, 0x010B0ABE, 0x00040158, 0x00010007, + 0x00020004, 0x00040002, 0x0C800ABE, 0x01900158, + 0x00080005, 0x00050002, 0x00020002, 0x0C800004, + 0x01900E95, 0x000601D3, 0x00020009, 0x00030005, + 0x00050002, 0x10AB0E95, 0x021501D3, 0x000B0006, + 0x00070002, 0x00020003, 0x10AB0005, 0x021512C0, + 0x00070258, 0x0003000C, 0x00030008, 0x00050002, + 0x157C12C0, 0x02B00258, 0x000E0008, 0x00090003, + 0x00020004, 0x157C0006, 0x02B01770, 0x000902EE, + 0x0004000F, 0x0004000A, 0x00060002, 0x19001770, + 0x032002EE, 0x00100009, 0x000B0004, 0x00020004, + 0x19000006, 0x03201D4C, 0x000B03AA, 0x00050013, + 0x0005000D, 0x00070002, 0x21551D4C, 0x042B03AA, + 0x0016000C, 0x000F0005, 0x00020006, 0x21550008, + 0x042B2580, 0x000E04B0, 0x00060018, 0x00070010, + 0x00090002, 0x02150028, 0x0085000A, 0x00060006, + 0x00000006, 0x00000000, 0x00060001, 0x02150007, + 0x0085042B, 0x0008010B, 0x00080008, 0x00000000, + 0x00020000, 0x00090007, 0x0640042B, 0x0190010B, + 0x000A000A, 0x0001000C, 0x00030001, 0x00080002, + 0x0640000A, 0x01900855, 0x000C0215, 0x000E000E, + 0x00040002, 0x00030004, 0x000B0008, 0x0ABE0855, + 0x02B00215, 0x00100010, 0x00030012, 0x00050003, + 0x000A0004, 0x0ABE000E, 0x02B00C80, 0x00120320, + 0x00140014, 0x00070005, 0x00040007, 0x000E000A, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00280000, 0x00050215, + 0x00030043, 0x00030003, 0x00000000, 0x00010000, + 0x00040003, 0x042B0215, 0x00850043, 0x00040004, + 0x00000004, 0x00000000, 0x00040001, 0x042B0005, + 0x00850640, 0x000500C8, 0x00050005, 0x00010001, + 0x00010002, 0x00050004, 0x08550640, 0x010B00C8, + 0x00070006, 0x00010007, 0x00020002, 0x00040002, + 0x08550006, 0x010B0ABE, 0x00080158, 0x00090008, + 0x00020002, 0x00020003, 0x00070005, 0x0C800ABE, + 0x01900158, 0x000A0009, 0x0003000A, 0x00040004, + 0x00050002, 0x0C800007, 0x01900E95, 0x000A01D3, + 0x000C000B, 0x00040003, 0x00030005, 0x00080005, + 0x10AB0E95, 0x021501D3, 0x000D000C, 0x0004000E, + 0x00060005, 0x00060003, 0x10AB0009, 0x021512C0, + 0x000D0258, 0x000F000E, 0x00060005, 0x00030007, + 0x00090006, 0x157C12C0, 0x02B00258, 0x0010000F, + 0x00060011, 0x00080007, 0x00060004, 0x157C000A, + 0x02B01770, 0x001002EE, 0x00130011, 0x00070006, + 0x00040009, 0x000B0007, 0x19001770, 0x032002EE, + 0x00120011, 0x00070014, 0x000A0008, 0x00070004, + 0x1900000B, 0x03201D4C, 0x001403AA, 0x00180016, + 0x00090007, 0x0005000B, 0x000E0009, 0x21551D4C, + 0x042B03AA, 0x00190017, 0x0008001A, 0x000B000A, + 0x000A0006, 0x21550010, 0x042B2580, 0x001904B0, + 0x001D001C, 0x000B0008, 0x0007000C, 0x0012000B, + 0x00000A05, 0x50000000, 0x446B6C63, 0x6F434143, + 0x43416564, 0x63500030, 0x43446B6C, 0x646F4341, + 0x53514465, 0x6C635000, 0x4143446B, 0x65646F43, + 0x00314341, 0x6B6C6350, 0x4F444344, 0x65736666, + 0x30434174, 0x6C635000, 0x4443446B, 0x7366664F, + 0x43417465, 0x63500031, 0x43446B6C, 0x66664F44, + 0x44746573, 0x50005351, 0x446B6C63, 0x6F434143, + 0x71446564, 0x00306E4C, 0x6B6C6350, 0x43414344, + 0x4465646F, 0x316E4C71, 0x6C635000, 0x4143446B, + 0x65646F43, 0x6E4C7144, 0x63500032, 0x43446B6C, + 0x646F4341, 0x4C714465, 0x5000336E, 0x446B6C63, + 0x6F434143, 0x71446564, 0x00346E4C, 0x6B6C6350, + 0x4F444344, 0x65736666, 0x4C714474, 0x5000306E, + 0x446B6C63, 0x664F4443, 0x74657366, 0x6E4C7144, + 0x63500031, 0x43446B6C, 0x66664F44, 0x44746573, + 0x326E4C71, 0x6C635000, 0x4443446B, 0x7366664F, + 0x71447465, 0x00336E4C, 0x6B6C6350, 0x4F444344, + 0x65736666, 0x4C714474, 0x0000346E, 0x04050607, + 0x00010203, 0x0C0B0A09, 0xB50F0E0D, 0x000001FF, + 0x01F0B500, 0xB3000100, 0x000001F0, 0x01F0B400, + 0xB0000100, 0x300001F0, 0x07F00300, 0x04000000, + 0x000007F0, 0x01FE0300, 0x04000000, 0x000001FE, + 0x07F01100, 0x21000000, 0x000001FE, 0x01FFBE00, + 0xBE000000, 0x010001F0, 0x01F0A700, 0xA2000000, + 0x020001F0, 0x02007900, 0x00004000, 0x0001008B, + 0xF05F0000, 0x00000001, 0x0001FFB5, 0xF0B30001, + 0x01FF0001, 0x0001F0B4, 0xF0B001FF, 0x00300001, + 0x0007F003, 0xF0040000, 0x00000007, 0x0001FE03, + 0xFE040000, 0x00000001, 0x0007F011, 0xFE210000, + 0x00000001, 0x0001F0B1, 0xF0A70002, 0x00000001, + 0x000E000F, 0x000C000D, 0x000A000B, 0x00080009, + 0x00060007, 0x00040005, 0x00020003, 0x00000001, + 0x00110010, 0x00130012, 0x00150014, 0x00170016, + 0x00190018, 0x001B001A, 0x001D001C, 0x001F001E, + 0xEF77DBB7, 0xFBDFF7BD, 0xBDDFB76F, 0xBDFFBDEF, + 0x00000200, 0x00000200, 0x00000200, 0x00000200, + 0x00000010, 0x00000010, 0x00000010, 0x00000010, + 0x0001FFB5, 0xF0B30001, 0x00000001, 0x0001F0B4, + 0xF0B90000, 0x00010001, 0x0001F0BA, 0xF0B10001, + 0x00020001, 0x0007F003, 0xF0040000, 0x00000007, + 0x0001FE03, 0xFE040000, 0x00000001, 0x0007F011, + 0xFE210000, 0x00000001, 0x0007F010, 0xFE200002, + 0x00020001, 0x0007F01B, 0xF01CFFFF, 0xFFFF0007, + 0x0001FE2A, 0xFE2BFFFF, 0xFFFF0001, 0x00020079, + 0xFFB50040, 0x00010001, 0x0001F0B3, 0xF0B40000, + 0x00000001, 0x0001F0B9, 0xF0BA0001, 0x00010001, + 0x0001F0B1, 0xF0B00002, 0x00300001, 0x0007F003, + 0xF0040000, 0x00000007, 0x0001FE03, 0xFE040000, + 0x00000001, 0x0007F011, 0xFE210000, 0x00000001, + 0x0007F010, 0xFE200002, 0x00020001, 0x0007F01B, + 0xF01CFFFF, 0xFFFF0007, 0x0001FE2A, 0xFE2BFFFF, + 0xFFFF0001, 0x00020079, 0x00000040, 0x08840884, + 0x00000020, 0x00010010, 0x00010012, 0x0001007A, + 0x00010028, 0x00060000, 0x50005000, 0x02008050, + 0x00000000, 0x00060080, 0x3C5A5555, 0x00600000, + 0x00000000, 0x00000000, 0x00000070, 0x00000075, + 0x00000026, 0x000000A0, 0x000000A1, 0x000000A4, + 0x000000A5, 0x0A030201, 0x0E0D0C0B, 0x1413120F, + 0x18171615, 0x1E1C1A19, 0x2221201F, 0x2E292825, + 0x4746453A, 0x004A4948, 0x00000000, 0x00000000, +}; + +static const u32 DMAC_TRANS_ACSM[] = { + 0x0000C028, 0x00100000, 0x00000000, 0x00000000, + 0x00000000, 0x04000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0000C858, 0x00100000, 0x0000E088, 0x00100000, + 0x0000E038, 0x00100000, 0x0000C858, 0x00100000, + 0x0000C088, 0x00100000, 0x00000000, 0x00000000, + 0x0000C028, 0x00100000, 0x00000000, 0x00000000, + 0x00000000, 0x04000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0000C858, 0x00100000, 0x0000E208, 0x00100000, + 0x0000E038, 0x00100000, 0x0000C858, 0x00100000, + 0x0000C208, 0x00100000, 0x00000000, 0x00000000, + 0x0000C040, 0x00100000, 0x00000000, 0x00100000, + 0x0000C068, 0x00100000, 0x00000000, 0x00000000, + 0x0000C2F0, 0x00100000, 0x00000000, 0x00000000, + 0x0000C370, 0x00100000, 0x00000000, 0x00000000, + 0x0000D2D8, 0x00100000, 0x0000E008, 0x00100000, + 0x00000000, 0x7B000000, 0x00000000, 0x00000000, + 0x0000C0F0, 0x00100000, 0x0000CFD8, 0x00100000, + 0x0000C008, 0x00100000, 0x00000000, 0x00000000, + 0x00000000, 0x3B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x0000D058, 0x00100000, + 0x0000C008, 0x00100000, 0x00000000, 0x00000000, + 0x00000000, 0x3B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x0000D0D8, 0x00100000, + 0x0000C088, 0x00100000, 0x00000000, 0x00000000, + 0x00000000, 0x3B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x0000D158, 0x00100000, + 0x0000C008, 0x00100000, 0x00000000, 0x00000000, + 0x00000000, 0x6B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0D00402C, 0x04000001, 0x08004050, 0x00000000, + 0x00000000, 0x04000000, 0x00000000, 0x00000000, + 0x00000000, 0x04000000, 0x08034050, 0x00000000, + 0x00000000, 0x1F000000, 0x00000000, 0x08000000, + 0x00000000, 0x04000000, 0x0000407C, 0x00000000, + 0x00000000, 0x04000000, 0x00000000, 0x00000000, + 0x00000000, 0x04000001, 0x00000000, 0x00000000, + 0x00000000, 0x04000000, 0x00000000, 0x00000000, + 0x00000000, 0x1B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0D00802C, 0x04100001, 0x08008050, 0x00100000, + 0x00000000, 0x04000000, 0x00000000, 0x00000000, + 0x00000000, 0x04000000, 0x08038050, 0x00100000, + 0x00000000, 0x1F000000, 0x00000000, 0x08000000, + 0x00000000, 0x04000000, 0x0000807C, 0x00100000, + 0x00000000, 0x04000000, 0x00000000, 0x00000000, + 0x00000000, 0x04000001, 0x00000000, 0x00000000, + 0x00000000, 0x04000000, 0x00000000, 0x00000000, + 0x00000000, 0x1B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0D00402C, 0x00000001, 0x08004050, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x08034050, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x08034050, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x08004050, 0x00000000, + 0x00000000, 0x1B000000, 0x00000000, 0x08000000, + 0x00000000, 0x00000000, 0x0000407C, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x5B000000, 0x00000000, 0x1C000000, + 0x0D00802C, 0x00100001, 0x08008050, 0x00100000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x08038050, 0x00100000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x08038050, 0x00100000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x08008050, 0x00100000, + 0x00000000, 0x1B000000, 0x00000000, 0x08000000, + 0x00000000, 0x00000000, 0x0000807C, 0x00100000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x4B000000, 0x00000000, 0x28000000, + 0x0D00402C, 0x00000001, 0x08035198, 0x00000000, + 0x00000000, 0x2B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x08035218, 0x00000000, + 0x00000000, 0x1B000000, 0x00000000, 0x08000000, + 0x00000000, 0x00000000, 0x0000407C, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x1B000000, 0x00000000, 0x00000000, + 0x0D00802C, 0x00100001, 0x08039198, 0x00100000, + 0x00000000, 0x2B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x08039218, 0x00100000, + 0x00000000, 0x1B000000, 0x00000000, 0x08000000, + 0x00000000, 0x00000000, 0x0000807C, 0x00100000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x3B000000, 0x00000000, 0x04000000, + 0x0000D2D8, 0x00100000, 0x0000E008, 0x00100000, + 0x00000000, 0x7B000000, 0x00000000, 0x00000000, + 0x0000C0F0, 0x00100000, 0x0000CFD8, 0x00100000, + 0x0000C008, 0x00100000, 0x00000000, 0x00000000, + 0x00000000, 0x3B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x0000D058, 0x00100000, + 0x0000C008, 0x00100000, 0x00000000, 0x00000000, + 0x00000000, 0x3B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x0000D0D8, 0x00100000, + 0x0000C088, 0x00100000, 0x00000000, 0x00000000, + 0x00000000, 0x3B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x0000D158, 0x00100000, + 0x0000C008, 0x00100000, 0x00000000, 0x00000000, + 0x00000000, 0x6B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0D00402C, 0x04000001, 0x08004050, 0x00000000, + 0x00000000, 0x04000000, 0x08034050, 0x00000000, + 0x00000000, 0x4F000000, 0x00000000, 0x08000000, + 0x0000407C, 0x04000000, 0x00000000, 0x00000000, + 0x00000000, 0x1F000000, 0x00000000, 0x00000000, + 0x00000000, 0x04000001, 0x00000000, 0x00000000, + 0x00000000, 0x04000000, 0x00000000, 0x00000000, + 0x00000000, 0x1B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0D00802C, 0x04100001, 0x08008050, 0x00100000, + 0x00000000, 0x04000000, 0x08038050, 0x00100000, + 0x00000000, 0x4F000000, 0x00000000, 0x08000000, + 0x0000807C, 0x04100000, 0x00000000, 0x00000000, + 0x00000000, 0x1F000000, 0x00000000, 0x00000000, + 0x00000000, 0x04000001, 0x00000000, 0x00000000, + 0x00000000, 0x04000000, 0x00000000, 0x00000000, + 0x00000000, 0x1B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0D00402C, 0x00000001, 0x08004050, 0x00000000, + 0x00000000, 0x00000000, 0x08034050, 0x00000000, + 0x00000000, 0x00000000, 0x08034050, 0x00000000, + 0x00000000, 0x00000000, 0x08004050, 0x00000000, + 0x00000000, 0x4B000000, 0x00000000, 0x08000000, + 0x0000407C, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x1B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x5B000000, 0x00000000, 0x1C000000, + 0x0D00802C, 0x00100001, 0x08008050, 0x00100000, + 0x00000000, 0x00000000, 0x08038050, 0x00100000, + 0x00000000, 0x00000000, 0x08038050, 0x00100000, + 0x00000000, 0x00000000, 0x08008050, 0x00100000, + 0x00000000, 0x4B000000, 0x00000000, 0x08000000, + 0x0000807C, 0x00100000, 0x00000000, 0x00000000, + 0x00000000, 0x1B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x2B000000, 0x00000000, 0x28000000, + 0x0D00402C, 0x00000001, 0x08035198, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x08035218, 0x00000000, + 0x00000000, 0x4B000000, 0x00000000, 0x08000000, + 0x0000407C, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x1B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0D00802C, 0x00100001, 0x08039198, 0x00100000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x08039218, 0x00100000, + 0x00000000, 0x4B000000, 0x00000000, 0x08000000, + 0x0000807C, 0x00100000, 0x00000000, 0x00000000, + 0x00000000, 0x1B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x6B000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const u32 DATA_A[] = { + 0x00000001, 0x00000019, 0x0000002E, 0x00000043, + 0x0000005B, 0x00000070, 0x00000085, 0x0000009D, + 0x000000B2, 0x000000C7, 0x000000DF, 0x000000F4, + 0x00000109, 0x00000113, 0x00000115, 0x00000119, +}; + +static const u32 DATA_B[] = { + 0x00000018, 0x0000002D, 0x00000042, 0x0000005A, + 0x0000006F, 0x00000084, 0x0000009C, 0x000000B1, + 0x000000C6, 0x000000DE, 0x000000F3, 0x00000108, + 0x00000112, 0x00000114, 0x00000118, 0x0000011A, +}; + +static const u32 ACSM_0[] = { + 0x0000C9D8, 0x00000000, 0x0000C808, 0x00000000, + 0x00000000, 0x5B000000, 0x00000000, 0x00000000, + 0x0000C958, 0x00000000, 0x0000C608, 0x00000000, + 0x00000000, 0x5B000000, 0x00000000, 0x00000000, + 0x0000C0D8, 0x00000000, 0x0000E848, 0x00000000, + 0x00000000, 0x5B000000, 0x00000000, 0x00000000, + 0x0000C158, 0x00000000, 0x0000EEC8, 0x00000000, + 0x00000000, 0x5B000000, 0x00000000, 0x00000000, + 0x0000C1D8, 0x00000000, 0x0000C348, 0x00000000, + 0x00000000, 0x5B000000, 0x00000000, 0x00000000, + 0x0000C558, 0x00000000, 0x0000EA08, 0x00000000, + 0x00000000, 0x5B000000, 0x00000000, 0x00000000, + 0x0000C5D8, 0x00000000, 0x0000DA48, 0x00000000, + 0x00000000, 0x5B000000, 0x00000000, 0x00000000, + 0x000048D8, 0x00000000, 0x00004308, 0x00000000, + 0x000088D8, 0x00000000, 0x00009708, 0x00000000, + 0x00000000, 0x5B000000, 0x00000000, 0x00000000, + 0x0000CA58, 0x00000000, 0x0000C108, 0x00000000, + 0x00000000, 0x5B000000, 0x00000000, 0x00000000, + 0x0000CB58, 0x00000000, 0x0000C008, 0x00000000, + 0x00000000, 0x5B000000, 0x00000000, 0x00000000, + 0x0000D4D8, 0x00000000, 0x0000F008, 0x00000000, + 0x00000000, 0x5B000000, 0x00000000, 0x00000000, + 0x0000DD58, 0x00000000, 0x0000C008, 0x00000000, +}; + +static const u32 ACSM_123[] = { + 0x0000C9D8, 0x00000000, 0x0000C008, 0x00000000, + 0x00000000, 0x2B000000, 0x00000000, 0x00000000, + 0x0000C958, 0x00000000, 0x0000C008, 0x00000000, + 0x00000000, 0x2B000000, 0x00000000, 0x00000000, + 0x0000C0D8, 0x00000000, 0x0000E808, 0x00000000, + 0x00000000, 0x2B000000, 0x00000000, 0x00000000, + 0x0000C158, 0x00000000, 0x0000EA88, 0x00000000, + 0x00000000, 0x2B000000, 0x00000000, 0x00000000, + 0x0000C1D8, 0x00000000, 0x0000C308, 0x00000000, + 0x00000000, 0x2B000000, 0x00000000, 0x00000000, + 0x0000C558, 0x00000000, 0x0000EA08, 0x00000000, + 0x00000000, 0x2B000000, 0x00000000, 0x00000000, + 0x0000C5D8, 0x00000000, 0x0000C008, 0x00000000, + 0x00000000, 0x2B000000, 0x00000000, 0x00000000, + 0x000048D8, 0x00000000, 0x00004008, 0x00000000, + 0x000088D8, 0x00000000, 0x00009408, 0x00000000, + 0x00000000, 0x2B000000, 0x00000000, 0x00000000, + 0x0000CA58, 0x00000000, 0x0000C108, 0x00000000, + 0x00000000, 0x2B000000, 0x00000000, 0x00000000, + 0x0000CB58, 0x00000000, 0x0000C008, 0x00000000, + 0x00000000, 0x2B000000, 0x00000000, 0x00000000, + 0x0000D4D8, 0x00000000, 0x0000F008, 0x00000000, + 0x00000000, 0x2B000000, 0x00000000, 0x00000000, + 0x0000DD58, 0x00000000, 0x0000C008, 0x00000000, +}; + +static const u32 DATA_C[] = { + 0x00000000, 0x000000FE, 0x000000A8, 0x0000F040, + 0x0000F040, 0x00000000, 0x0000FFFF, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const u32 DATA_3_1[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x0000084F, + 0x0000084F, 0x0000082B, 0x0000082B, 0x0000084F, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00001810, 0x00001810, 0x00000428, 0x0000192C, + 0x0000181C, 0x0000181C, 0x00000434, 0x00003938, + 0x00001808, 0x00001808, 0x00000420, 0x00001124, +}; + +static const u32 DATA_3_2[] = { + 0x000040A0, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x0000024E, 0x0000004E, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0000024E, 0x0000004E, 0x0000006F, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const u32 DATA_3_3[] = { + 0x00000086, 0x00000190, 0x00000A69, 0x00000058, + 0x0000001B, 0x00000000, 0x00000043, 0x00000000, + 0x00000017, 0x0000004F, 0x00000006, 0x00000006, + 0x0000000E, 0x00000068, 0x00000000, 0x00000000, +}; + +static const u32 DATA_3_4[] = { + 0x00000003, 0x00000000, 0x00000000, 0x00000000, + 0x00000009, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x0000001C, 0x0000071C, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000003, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000077, 0x00000707, 0x00000030, 0x00003300, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000099, 0x00000000, 0x00000000, 0x00000000, +}; + +static const u32 DATA_3_5[] = { + 0x00000003, 0x00000000, 0x00000000, 0x00000000, + 0x00000009, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x0000001C, 0x0000071C, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000003, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000077, 0x00007777, 0x00000030, 0x00003300, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000099, 0x00000000, 0x00000000, 0x00000000, +}; + +static const u32 DMAC_TRANS_PIE[] = { + 0x3f7ab480, 0x00016420, 0x00000400, 0x00000000, + 0x80000480, 0x00000fc0, 0x04000c00, 0x00000000, + 0x84000480, 0x00000c00, 0x04000800, 0x00000000, + 0x84000080, 0x00000c00, 0x000001e0, 0x00000000, + 0x80068200, 0x0000400f, 0x00008d40, 0x00000000, + 0xa0000480, 0x00002420, 0x04000400, 0x00000000, + 0x9c001ca0, 0x00001c04, 0xa8000880, 0x00001c06, + 0x80010080, 0x00001c04, 0x04000400, 0x00000000, + 0x80010480, 0x00001c04, 0x04000800, 0x00000000, + 0x00000040, 0x00006000, 0xa0000080, 0x00002420, + 0x00001020, 0x00000000, 0x00001020, 0x00000000, + 0x00001020, 0x00000000, 0x00003020, 0x00000000, + 0x80000080, 0x00001c04, 0xa8000880, 0x00001c06, + 0x80010880, 0x00001c04, 0x04000400, 0x00000000, + 0x80010c80, 0x00001c04, 0x04000800, 0x00000000, + 0x00001020, 0x00000000, 0x00002c20, 0x00000000, + 0x00002c20, 0x00000000, 0x00002c20, 0x00000000, + 0x80000080, 0x00001c04, 0x000001e0, 0x00000000, + 0xa8000480, 0x00001c04, 0x04000400, 0x00000000, + 0x40004200, 0x00004000, 0x00011140, 0x00000000, + 0xc80038a0, 0x00001c01, 0xcc003ca0, 0x00001c01, + 0xa40000a0, 0x00001c06, 0xa8001c80, 0x00001c06, + 0x80051080, 0x00001c04, 0x04000400, 0x00000000, + 0x80051480, 0x00001c04, 0x04000800, 0x00000000, + 0x00000840, 0x00006000, 0x80000080, 0x00001c04, + 0xcc000080, 0x00001c01, 0xa8001c80, 0x00001c06, + 0x80051880, 0x00001c04, 0x04000400, 0x00000000, + 0x80051c80, 0x00001c04, 0x04000800, 0x00000000, + 0x00000840, 0x00006000, 0x80000080, 0x00001c04, + 0xc8000080, 0x00001c01, 0xcc003ca0, 0x00001c01, + 0xa8001c80, 0x00001c06, 0x80052080, 0x00001c04, + 0x04000400, 0x00000000, 0x80052480, 0x00001c04, + 0x04000800, 0x00000000, 0x00000840, 0x00006000, + 0x80000080, 0x00001c04, 0xc80038a0, 0x00001c01, + 0x54000091, 0x00018fc0, 0x54000091, 0x00014fc0, + 0xf0000091, 0x000187c1, 0xf0000091, 0x000147c1, + 0x08000611, 0x00001800, 0x00013d71, 0x00000000, + 0x04000911, 0x0001a420, 0x04001000, 0x00000000, + 0x00000a11, 0x00001800, 0x00017551, 0x00000000, + 0x00014571, 0x00000000, 0x00000611, 0x00001800, + 0x00017571, 0x00000000, 0x24000491, 0x0001e420, + 0x000021d1, 0x00000000, 0x00001031, 0x00000000, + 0x00001031, 0x00000000, 0x00002c31, 0x00000000, + 0xa8000091, 0x00001c06, 0x80016891, 0x00001c04, + 0x04000400, 0x00000000, 0x80016c91, 0x00001c04, + 0x04000800, 0x00000000, 0x00000851, 0x00006000, + 0x80000091, 0x00001c04, 0xa8000080, 0x00001c04, + 0x04000800, 0x00000000, 0x000001e0, 0x00000000, + 0xa8000080, 0x00001c06, 0x80012880, 0x00001c04, + 0x04000400, 0x00000000, 0x80012c80, 0x00001c04, + 0x04000800, 0x00000000, 0x00000840, 0x00006000, + 0x80000080, 0x00001c04, 0x000001e0, 0x00000000, + 0x00080200, 0x0000400e, 0x0001b540, 0x00000000, + 0x00020200, 0x0000400e, 0x0001b540, 0x00000000, + 0x80068200, 0x0000400f, 0x30000cc0, 0x000007c4, + 0x000001e0, 0x00000000, 0x00100600, 0x00000010, + 0x2c0004c0, 0x000003c0, 0x8c0028a0, 0x00017bc1, + 0xa0000480, 0x00002420, 0x04000400, 0x00000000, + 0x8c0014a0, 0x000143c1, 0xa0000080, 0x00002420, + 0x78000480, 0x000003d8, 0x7c000480, 0x000007f8, + 0x08000080, 0x00000fe0, 0x08000080, 0x000007e0, + 0x00080600, 0x00000008, 0x000004c0, 0x00014fc4, + 0x000004c0, 0x000147c4, 0x00002420, 0x00000000, + 0x08000480, 0x00000fe0, 0x08000480, 0x000007e0, + 0x00000080, 0x00014fc4, 0x00000080, 0x000147c4, + 0x78000080, 0x000003d8, 0x7c000080, 0x000007f8, + 0x8c002ca0, 0x00017bc1, 0xa0000480, 0x00002420, + 0x04000400, 0x00000000, 0x8c0018a0, 0x000143c1, + 0xa0000080, 0x00002420, 0x2c000080, 0x00000000, + 0x2c000080, 0x00000040, 0x2c000080, 0x00000080, + 0x2c000080, 0x000000c0, 0x2c000080, 0x00000100, + 0x2c000080, 0x00000140, 0x00200600, 0x00000020, + 0x2c0000c0, 0x000001c0, 0x2c0000c0, 0x00000200, + 0x2c0000c0, 0x00000240, 0x2c0000c0, 0x00000280, + 0x2c0000c0, 0x000002c0, 0x2c0000c0, 0x00000300, + 0xc4000880, 0x000007c0, 0x04000400, 0x00000000, + 0x0c000480, 0x00000fc4, 0x04002000, 0x00000000, + 0x0c000480, 0x000007c4, 0x04002000, 0x00000000, + 0x0c000080, 0x00000fc4, 0x0c000080, 0x000007c4, + 0xc4000080, 0x000007c0, 0x04000400, 0x00000000, + 0xe0000480, 0x00000803, 0x04002000, 0x00000000, + 0x04000600, 0x00000400, 0x265a58c0, 0x000187c8, + 0x58000080, 0x000007c0, 0x04000400, 0x00000000, + 0xe0000080, 0x00000803, 0x04002000, 0x00000000, + 0x000001e0, 0x00000000, 0x50000080, 0x00001c01, + 0x40000480, 0x00002c0c, 0xc4000080, 0x000007c0, + 0x2c000080, 0x000007c2, 0x8c200080, 0x00000fc2, + 0x00200600, 0x00000020, 0x880c0080, 0x00000c02, + 0x880c00c0, 0x00000c42, 0x247ffc80, 0x000007c2, + 0x281ffc80, 0x000007c2, 0x04000400, 0x00000000, + 0x800c0080, 0x00000fc2, 0x04000800, 0x00000000, + 0x98000480, 0x00000fc2, 0x28000480, 0x00000fc0, + 0x04001000, 0x00000000, 0x80fffc80, 0x00000fc2, + 0x30000080, 0x000007c4, 0x00010600, 0x00000001, + 0x0002fd40, 0x00000000, 0x80068200, 0x0000400f, + 0x00030160, 0x00000000, 0x0001a1c0, 0x00000000, + 0xe0000480, 0x00000803, 0x04001c00, 0x00000000, + 0x28000080, 0x00000fc0, 0x88000480, 0x00000802, + 0x04000400, 0x00000000, 0x5c000080, 0x000007c2, + 0x02000600, 0x00000200, 0x2c0010c0, 0x00003bc1, + 0x2c001880, 0x00003bc1, 0x18001880, 0x00003bc1, + 0x1c001880, 0x00003bc1, 0x20001880, 0x00003bc1, + 0x24001880, 0x00003bc1, 0x28001880, 0x00003bc1, + 0x00020200, 0x0000400e, 0x00036d40, 0x00000000, + 0x40004600, 0x00000000, 0x00035940, 0x00000000, + 0x04000900, 0x0001a420, 0x04001000, 0x00000000, + 0x40004a00, 0x00000000, 0x0c0010e0, 0x00001800, + 0x0c0000c0, 0x00001800, 0x04000480, 0x00001800, + 0x04000800, 0x00000000, 0x08000480, 0x00001800, + 0x04000800, 0x00000000, 0x000001e0, 0x00000000, + 0x9c000cb1, 0x00001c01, 0x9c0010b1, 0x00001c03, + 0x24000091, 0x00001c01, 0x00000051, 0x00004000, + 0x00039531, 0x00000000, 0x40001a01, 0x00000000, + 0x00039561, 0x00000000, 0x24000081, 0x00001c01, + 0x00000041, 0x00004000, 0x000001e0, 0x00000000, + 0x84000900, 0x0000241c, 0xc0014200, 0x0000c001, + 0x0003ad40, 0x00000000, 0x04001000, 0x00000000, + 0x2c0008a0, 0x00000802, 0x000001e0, 0x00000000, + 0x40000480, 0x00002c0c, 0x04000400, 0x00000000, + 0x04000080, 0x00002c00, 0x04000400, 0x00000000, + 0x00020200, 0x0000400e, 0x00044540, 0x00000000, + 0x40004600, 0x00000000, 0x040004c0, 0x00001800, + 0x080004c0, 0x00001800, 0x00044540, 0x00000000, + 0x08000080, 0x00001800, 0x04000400, 0x00000000, + 0x04000080, 0x00001800, 0x00000081, 0x00001800, + 0x04000400, 0x00000000, 0x88000480, 0x00000802, + 0x04000800, 0x00000000, 0x0c000900, 0x00001800, + 0x04001000, 0x00000000, 0x00010a00, 0x00000001, + 0x00042140, 0x00000000, 0x0c000c80, 0x00001800, + 0x00000020, 0x00000000, 0x00000020, 0x00000000, + 0x0c000880, 0x00001800, 0x00000020, 0x00000000, + 0x0c000080, 0x00001800, 0x00044920, 0x00000000, + 0x0c001c80, 0x00001800, 0x00001020, 0x00000000, + 0x00001020, 0x00000000, 0x0c001880, 0x00001800, + 0x00001020, 0x00000000, 0x00001020, 0x00000000, + 0x00001020, 0x00000000, 0x0c001080, 0x00001800, + 0x00044920, 0x00000000, 0x00000080, 0x00001800, + 0x00200600, 0x00000020, 0x0004a160, 0x00000000, + 0x18000080, 0x00003bc1, 0x1c000080, 0x00003bc1, + 0x20000080, 0x00003bc1, 0x24000080, 0x00003bc1, + 0x28000080, 0x00003bc1, 0x2c000880, 0x00003801, + 0x2c001080, 0x00003841, 0x2c000880, 0x00003881, + 0x2c001080, 0x000038c1, 0x2c000880, 0x00003901, + 0x2c001080, 0x00003941, 0x2c000880, 0x00003981, + 0x2c001080, 0x000039c1, 0x02000600, 0x00000200, + 0x2c0010c0, 0x00003bc1, 0x58000080, 0x000003cf, + 0x5c000080, 0x000003cf, 0x5c000880, 0x000000cf, + 0x5c000880, 0x0000028f, 0x00052d20, 0x00000000, + 0x18000080, 0x00003801, 0x18000080, 0x00003841, + 0x18000080, 0x00003881, 0x18000080, 0x000038c1, + 0x1c000080, 0x00003801, 0x1c000080, 0x00003841, + 0x1c000080, 0x00003881, 0x1c000080, 0x000038c1, + 0x20000080, 0x00003801, 0x20000080, 0x00003841, + 0x20000080, 0x00003881, 0x20000080, 0x000038c1, + 0x24000080, 0x00003801, 0x24000080, 0x00003841, + 0x24000080, 0x00003881, 0x24000080, 0x000038c1, + 0x28000080, 0x00003841, 0x28000080, 0x000038c1, + 0x2c000880, 0x00003801, 0x2c001080, 0x00003841, + 0x2c000880, 0x00003881, 0x2c001080, 0x000038c1, + 0x02000600, 0x00000200, 0x2c0010c0, 0x00003bc1, + 0x58000080, 0x0000000f, 0x5c000080, 0x0000000f, + 0x58000080, 0x0000004f, 0x5c000080, 0x0000004f, + 0x58000080, 0x0000008f, 0x5c000080, 0x0000008f, + 0x58000080, 0x000000cf, 0x58000080, 0x0000010f, + 0x5c000080, 0x0000010f, 0x58000080, 0x0000014f, + 0x5c000080, 0x0000014f, 0x20000080, 0x00002bcc, + 0x00053d31, 0x00000000, 0x40001a00, 0x00000000, + 0x00053d60, 0x00000000, 0x040030a0, 0x00002c00, + 0x88000080, 0x00000802, 0x5c1ffc80, 0x000007c2, + 0x00800600, 0x00000080, 0xbc000900, 0x00016c0c, + 0x040000c0, 0x00002424, 0x040080e0, 0x00002424, + 0x04000000, 0x00000000, 0x98000095, 0x00002c0c, + 0x9c000095, 0x00002c0c, 0x98001cb5, 0x00002c0c, + 0x9c0020b5, 0x00002c0c, 0x98000095, 0x00002c0c, + 0x9c000095, 0x00002c0c, 0x40000095, 0x00002c0c, + 0x00000605, 0x00002000, 0x400000c5, 0x00002c0c, + 0x800004c5, 0x00002c0c, 0x800000c5, 0x00002c0c, + 0x040000e5, 0x00002c00, 0xbc0000e5, 0x00016c0c, + 0x04000000, 0x00000000, 0x9bfe00e5, 0x00002c0c, + 0x9ffe00e5, 0x00002c0c, 0x9bfe04e5, 0x00002c0c, + 0x9ffe04e5, 0x00002c0c, 0x9bfe00e5, 0x00002c0c, + 0x9ffe00e5, 0x00002c0c, 0x400004e5, 0x00002c0c, + 0x04000400, 0x00000000, 0xbc0008a5, 0x00016c0c, + 0x000001e0, 0x00000000, 0xe8030c80, 0x00001c01, + 0x04000400, 0x00000000, 0xe8000080, 0x00001c01, + 0x000001e0, 0x00000000, 0x88000080, 0x00000802, + 0x04000c00, 0x00000000, 0x0000cc80, 0x00000808, + 0x1c000480, 0x00000fc1, 0x1c000080, 0x00000fc1, + 0x1c000480, 0x000007c1, 0x1c000080, 0x000007c1, + 0x00000080, 0x00000808, 0x50000080, 0x00001c01, + 0xb8000480, 0x00000801, 0x04000400, 0x00000000, + 0x00040600, 0x00000004, 0x598000e0, 0x000007c0, + 0x28000480, 0x00000fc0, 0x04001000, 0x00000000, + 0xe0000080, 0x00000803, 0x04001400, 0x00000000, + 0x88000880, 0x00000802, 0x00000c20, 0x00000000, + 0x40004600, 0x00000000, 0x00062160, 0x00000000, + 0x1c000880, 0x00000fc1, 0x1c000080, 0x00000fc1, + 0x1c000880, 0x000007c1, 0x1c000080, 0x000007c1, + 0x04003c00, 0x00000000, 0x00040600, 0x00000004, + 0x00064140, 0x00000000, 0x0001bdc0, 0x00000000, + 0x28000080, 0x00000fc0, 0x80000080, 0x00000fc2, + 0x98000080, 0x00000fc2, 0x24000080, 0x000007c2, + 0x28000080, 0x000007c2, 0x883c0080, 0x00000fc2, + 0x80040200, 0x0000400f, 0x00067940, 0x00000000, + 0x00080200, 0x0000400e, 0x00067940, 0x00000000, + 0xe4000480, 0x00000801, 0x04000800, 0x00000000, + 0xe4000080, 0x00000801, 0x04000800, 0x00000000, + 0xe8030c81, 0x00001c01, 0x04000800, 0x00000000, + 0xe8000081, 0x00001c01, 0x04000400, 0x00000000, + 0x40001a01, 0x00000000, 0x0006a541, 0x00000000, + 0xa0000481, 0x00002420, 0x04000400, 0x00000000, + 0x40003201, 0x00000000, 0x0006c541, 0x00000000, + 0x0006a561, 0x00000000, 0x00001c21, 0x00000000, + 0xa0000081, 0x00002420, 0x04000400, 0x00000000, + 0x00020601, 0x00000002, 0xe8030cc1, 0x00001c01, + 0x04000800, 0x00000000, 0xe80000c1, 0x00001c01, + 0x04000400, 0x00000000, 0xa0000081, 0x00002420, + 0x04000400, 0x00000000, 0xe8030c91, 0x00001c01, + 0x04000800, 0x00000000, 0xe8000091, 0x00001c01, + 0x04000400, 0x00000000, 0xa8000480, 0x00001c04, + 0x04000400, 0x00000000, 0x18000081, 0x0001e420, + 0x40006611, 0x00000000, 0x0006f551, 0x00000000, + 0x000021d1, 0x00000000, 0xa0000491, 0x00002420, + 0x04000400, 0x00000000, 0x540020b1, 0x00014fc0, + 0xf00024b1, 0x000147c1, 0xa0000091, 0x00002420, + 0x000001e0, 0x00000000, 0xa8000080, 0x00001c06, + 0x80013080, 0x00001c04, 0x04000400, 0x00000000, + 0x80013480, 0x00001c04, 0x04000800, 0x00000000, + 0x04001c00, 0x00000000, 0x80000080, 0x00001c04, + 0x00000420, 0x00000000, 0xa8000080, 0x00001c06, + 0x80013880, 0x00001c04, 0x04000400, 0x00000000, + 0x80013c80, 0x00001c04, 0x04000800, 0x00000000, + 0x04001c00, 0x00000000, 0x80000080, 0x00001c04, + 0x000001e0, 0x00000000, 0x20000086, 0x0001c7c4, + 0x9e000480, 0x000007c2, 0xc4060080, 0x000007c2, + 0xd4000480, 0x000007c2, 0xe4000480, 0x000007c2, + 0x9c003080, 0x00001c04, 0x7c000080, 0x0001c7c1, + 0x88000c80, 0x000007c2, 0x64000c80, 0x00000801, + 0x90000880, 0x000007c2, 0xec0ffc80, 0x000007c2, + 0xec000080, 0x000007c2, 0xf8000080, 0x000007fe, + 0xf8000480, 0x000007c2, 0xf8000480, 0x000007d2, + 0xa8001080, 0x00001c06, 0x80014880, 0x00001c04, + 0x04000400, 0x00000000, 0x80014c80, 0x00001c04, + 0x04000800, 0x00000000, 0x00000840, 0x00006000, + 0x80000080, 0x00001c04, 0xf8000080, 0x000007c2, + 0xf8000080, 0x000007d2, 0xec0ffc80, 0x000007c2, + 0xec000080, 0x000007c2, 0xf8000480, 0x000007c6, + 0xf8000480, 0x000007d6, 0xa8001080, 0x00001c06, + 0x80015080, 0x00001c04, 0x04000400, 0x00000000, + 0x80015480, 0x00001c04, 0x04000800, 0x00000000, + 0x00000840, 0x00006000, 0x80000080, 0x00001c04, + 0xf8000080, 0x000007c6, 0xf8000080, 0x000007d6, + 0x64000880, 0x00000801, 0x00001420, 0x00000000, + 0xc4000480, 0x000007c0, 0x04001000, 0x00000000, + 0xc4000080, 0x000007c0, 0x04000600, 0x00000400, + 0x24c8c8c0, 0x000147c8, 0x80000480, 0x00000802, + 0x04000400, 0x00000000, 0x80000080, 0x00000802, + 0x90000080, 0x000007c2, 0x98000c80, 0x000007c2, + 0xa8001080, 0x00001c06, 0x80015880, 0x00001c04, + 0x04000400, 0x00000000, 0x80015c80, 0x00001c04, + 0x04000800, 0x00000000, 0x00000840, 0x00006000, + 0x80000080, 0x00001c04, 0x04000800, 0x00000000, + 0x98000080, 0x000007c2, 0x88000080, 0x000007c2, + 0x64000080, 0x00000801, 0x7c000480, 0x0001c7c1, + 0xe4000480, 0x00000801, 0x04000800, 0x00000000, + 0xe4000080, 0x00000801, 0x04000800, 0x00000000, + 0x00001820, 0x00000000, 0x90000480, 0x000007c2, + 0xa8001080, 0x00001c06, 0x80016080, 0x00001c04, + 0x04000400, 0x00000000, 0x80016480, 0x00001c04, + 0x04000800, 0x00000000, 0x00000840, 0x00006000, + 0x80000080, 0x00001c04, 0x04000800, 0x00000000, + 0x80000480, 0x00000802, 0x04000400, 0x00000000, + 0x80000080, 0x00000802, 0x90000080, 0x000007c2, + 0x04000800, 0x00000000, 0xe4000480, 0x00000801, + 0x04000800, 0x00000000, 0xe4000080, 0x00000801, + 0x04000800, 0x00000000, 0xa8000080, 0x00001c04, + 0x50000480, 0x00001c01, 0x20000486, 0x0001c7c4, + 0x000001e0, 0x00000000, 0x80008600, 0x00000000, + 0x0008d560, 0x00000000, 0x80000480, 0x00000802, + 0x04000400, 0x00000000, 0x80000080, 0x00000802, + 0x04000400, 0x00000000, 0xe4000480, 0x00000801, + 0x04000800, 0x00000000, 0xe4000080, 0x00000801, + 0xa8000080, 0x00001c04, 0xb8000080, 0x00000801, + 0x04000800, 0x00000000, 0x00001080, 0x000033c2, + 0x50000480, 0x00001c01, 0xb4000080, 0x00002400, + 0x88000481, 0x00000c00, 0x24000480, 0x00001c01, + 0x000001e0, 0x00000000, 0x40000480, 0x00002c0c, + 0x2c000080, 0x000007c2, 0x8c000080, 0x00000fc2, + 0x00200600, 0x00000020, 0x880c0080, 0x00000c02, + 0x880c00c0, 0x00000c42, 0x247ffc80, 0x000007c2, + 0x281ffc80, 0x000007c2, 0x04000400, 0x00000000, + 0x98000480, 0x00000fc2, 0x28000480, 0x00000fc0, + 0x04001000, 0x00000000, 0x80fffc80, 0x00000fc2, + 0x04000400, 0x00000000, 0xe0000480, 0x00000803, + 0x04002000, 0x00000000, 0x28000080, 0x00000fc0, + 0x50000080, 0x00001c01, 0x00000480, 0x00001800, + 0x0c000080, 0x00001800, 0x5c000080, 0x000007c2, + 0x04000080, 0x00002c00, 0x02000600, 0x00000200, + 0x2c0010c0, 0x00003bc1, 0x2c001880, 0x00003bc1, + 0x18001880, 0x00003bc1, 0x1c001880, 0x00003bc1, + 0x20001880, 0x00003bc1, 0x24001880, 0x00003bc1, + 0x28001880, 0x00003bc1, 0x20000880, 0x00002bcc, + 0x040030a0, 0x00002c00, 0x24000080, 0x00001c01, + 0xb4000480, 0x00002400, 0x00000040, 0x00004000, + 0x00000020, 0x00000000, 0x00000020, 0x00000000, + 0x88000c80, 0x00000c00, 0x80000080, 0x00000fc0, + 0x04000c00, 0x00000000, 0x88000480, 0x00000802, + 0x000001e0, 0x00000000, 0x00001880, 0x000033c2, + 0x000009c1, 0x00000000, 0x9c000d11, 0x00001c01, + 0x04001011, 0x00000000, 0x9c001111, 0x00001c03, + 0x04001011, 0x00000000, 0x9c000091, 0x00001c01, + 0x9c000091, 0x00001c03, 0x0009dd21, 0x00000000, + 0xb8000480, 0x00000801, 0x04000800, 0x00000000, + 0x80068200, 0x0000400f, 0x0009d540, 0x00000000, + 0x000091c0, 0x00000000, 0x000181c0, 0x00000000, + 0x0002a5c0, 0x00000000, 0x000371c0, 0x00000000, + 0x000399c0, 0x00000000, 0x0003b1c0, 0x00000000, + 0x0005cdc0, 0x00000000, 0x40004200, 0x00000000, + 0x6001c0e0, 0x00002425, 0x00080200, 0x0000400e, + 0x000a2140, 0x00000000, 0x000a0531, 0x00000000, + 0x00070dc0, 0x00000000, 0x80008600, 0x00000000, + 0x000a2140, 0x00000000, 0x00074dc2, 0x00000000, + 0x80068200, 0x0000400f, 0xc40004c0, 0x000007c0, + 0x04001000, 0x00000000, 0xc40000c0, 0x000007c0, + 0x40006611, 0x00000000, 0x000a6951, 0x00000000, + 0x80068211, 0x0000400f, 0x000a6951, 0x00000000, + 0x00080211, 0x0000400e, 0x000a4151, 0x00000000, + 0x80008611, 0x00000000, 0x000a4d71, 0x00000000, + 0x00001031, 0x00000000, 0x00001031, 0x00000000, + 0x00002c31, 0x00000000, 0xa8000091, 0x00001c06, + 0x80016891, 0x00001c04, 0x04000400, 0x00000000, + 0x80016c91, 0x00001c04, 0x04000800, 0x00000000, + 0x00000851, 0x00006000, 0x80000091, 0x00001c04, + 0x24000091, 0x0001e420, 0x0008adc0, 0x00000000, + 0x00000000, 0x00000000, 0x0008f5c0, 0x00000000, + 0x24000480, 0x00001c01, 0x00000400, 0x00000000, + 0x50000080, 0x00001c01, 0x9c000d00, 0x00001c01, + 0x04001000, 0x00000000, 0x9c001100, 0x00001c03, + 0x04001000, 0x00000000, 0x9c000080, 0x00001c01, + 0x9c000080, 0x00001c03, 0x00001880, 0x000033c2, + 0xb8000480, 0x00000801, 0x04000c00, 0x00000000, + 0x24000491, 0x0001e420, 0xa8000080, 0x00001c06, + 0x80012880, 0x00001c04, 0x04000400, 0x00000000, + 0x80012c80, 0x00001c04, 0x04000800, 0x00000000, + 0x00000840, 0x00006000, 0x80000080, 0x00001c04, + 0x2c000080, 0x000007c2, 0x8c200080, 0x00000fc2, + 0x00200600, 0x00000020, 0x883c0080, 0x00000c02, + 0x883c00c0, 0x00000c42, 0x98000480, 0x00000fc2, + 0x28000480, 0x00000fc0, 0x04001000, 0x00000000, + 0x80fffc80, 0x00000fc2, 0x247ffc80, 0x000007c2, + 0x281ffc80, 0x000007c2, 0x04000400, 0x00000000, + 0xe0000480, 0x00000803, 0x28000080, 0x00000fc0, + 0x00800600, 0x00000080, 0x040000c0, 0x00002424, + 0x040080e0, 0x00002424, 0x400004e2, 0x00002c0c, + 0x04000800, 0x00000000, 0x400000e2, 0x00002c0c, + 0x04000800, 0x00000000, 0x800004e0, 0x00002c0c, + 0x800000e0, 0x00002c0c, 0x00000605, 0x00002000, + 0x400004c2, 0x00002c0c, 0x04000800, 0x00000000, + 0x400000c2, 0x00002c0c, 0x04000800, 0x00000000, + 0x800004c0, 0x00002c0c, 0x800000c0, 0x00002c0c, + 0x04000c00, 0x00000000, 0x24000080, 0x00001c01, + 0x10000200, 0x00005000, 0x000b5540, 0x00000000, + 0x00000040, 0x00004000, 0x28000480, 0x00000fc0, + 0x04001000, 0x00000000, 0xe0000080, 0x00000803, + 0x04000800, 0x00000000, 0x28000080, 0x00000fc0, + 0x80000080, 0x00000fc2, 0x98000080, 0x00000fc2, + 0x24000080, 0x000007c2, 0x28000080, 0x000007c2, + 0xe4000480, 0x00000801, 0x04000800, 0x00000000, + 0xe4000080, 0x00000801, 0x04000800, 0x00000000, + 0xa8000480, 0x00001c04, 0xe8030c80, 0x00001c01, + 0x04000800, 0x00000000, 0xe8000080, 0x00001c01, + 0x04000400, 0x00000000, 0x9c000ca0, 0x00001c01, + 0x9c0010a0, 0x00001c03, 0x000a0520, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +#endif /* __DRIVERS_RAM_RENESAS_DBSC5_R8A78000_DRAM_H__ */ diff --git a/drivers/ram/renesas/dbsc5/rtvram.c b/drivers/ram/renesas/dbsc5/rtvram.c index 6c149284bc6..bf30a207142 100644 --- a/drivers/ram/renesas/dbsc5/rtvram.c +++ b/drivers/ram/renesas/dbsc5/rtvram.c @@ -13,34 +13,41 @@ #define RTVRAM_VBUF_CFG 0x6504 #define RTVRAM_VBUF_CFG_CACHE_MODE_8WAY (1 << 8) #define RTVRAM_VBUF_CFG_VBUF_SIZE_28M (6 << 0) +#define RTVRAM_VBUF_CFG_VBUF_SIZE_32M (7 << 0) #define RTVRAM_EXT_MODE 0x8500 #define RTVRAM_EXT_MODE_EXT BIT(0) #define RTVRAM_VBUF_BADDR 0xC580 -#define RTVRAM_VBUF_NUM 7 - -#define SDRAM_40BIT_ADDR_TOP 0x0400000000ULL #define RTVRAM_VBUF_AREA_SIZE SZ_4M struct renesas_dbsc5_rtvram_priv { void __iomem *regs; }; +struct renesas_dbsc5_rtvram_data { + u8 sdram_40bit_addr_top; /* Left-shift by 32 */ + u8 vbuf_num; + u8 size; + u8 size_bit; +}; + static int renesas_dbsc5_rtvram_probe(struct udevice *dev) { struct renesas_dbsc5_rtvram_priv *priv = dev_get_priv(dev); + struct renesas_dbsc5_rtvram_data *data = + (struct renesas_dbsc5_rtvram_data *)dev_get_driver_data(dev); u64 addr; int i; /* Set each 4MB from the top of SDRAM as the buffer area of RT-VRAM. */ - for (i = 0; i < RTVRAM_VBUF_NUM; i++) { - addr = (SDRAM_40BIT_ADDR_TOP + (RTVRAM_VBUF_AREA_SIZE * i)) >> 16; + for (i = 0; i < data->vbuf_num + 1; i++) { + addr = (((u64)(data->sdram_40bit_addr_top) << 32ULL) + (RTVRAM_VBUF_AREA_SIZE * i)) >> 16; writel(lower_32_bits(addr), priv->regs + (RTVRAM_VBUF_BADDR + (4 * i))); } /* Cache Mode: 8-way, VBF size: 28M */ setbits_le32(priv->regs + RTVRAM_VBUF_CFG, - RTVRAM_VBUF_CFG_CACHE_MODE_8WAY | RTVRAM_VBUF_CFG_VBUF_SIZE_28M); + RTVRAM_VBUF_CFG_CACHE_MODE_8WAY | data->size_bit); /* Change from Compatible Mode to Extended Mode */ writel(RTVRAM_EXT_MODE_EXT, priv->regs + RTVRAM_EXT_MODE); @@ -65,9 +72,11 @@ static int renesas_dbsc5_rtvram_get_info(struct udevice *dev, struct ram_info *info) { struct renesas_dbsc5_rtvram_priv *priv = dev_get_priv(dev); + struct renesas_dbsc5_rtvram_data *data = + (struct renesas_dbsc5_rtvram_data *)dev_get_driver_data(dev); info->base = (phys_addr_t)priv->regs; - info->size = 28 * SZ_1M; + info->size = data->size * SZ_1M; return 0; } @@ -76,14 +85,29 @@ static const struct ram_ops renesas_dbsc5_rtvram_ops = { .get_info = renesas_dbsc5_rtvram_get_info, }; +struct renesas_dbsc5_rtvram_data gen4_rtvram_data = { + .sdram_40bit_addr_top = 0x4, + .vbuf_num = 7, + .size = 28, + .size_bit = RTVRAM_VBUF_CFG_VBUF_SIZE_28M, +}; + +struct renesas_dbsc5_rtvram_data gen5_rtvram_data = { + .sdram_40bit_addr_top = 0x12, + .vbuf_num = 8, + .size = 32, + .size_bit = RTVRAM_VBUF_CFG_VBUF_SIZE_32M, +}; + static const struct udevice_id renesas_dbsc5_rtvram_ids[] = { - { .compatible = "renesas,r8a779g0-rtvram" }, - { .compatible = "renesas,r8a779h0-rtvram" }, + { .compatible = "renesas,r8a779g0-rtvram", .data = (ulong)&gen4_rtvram_data }, + { .compatible = "renesas,r8a779h0-rtvram", .data = (ulong)&gen4_rtvram_data }, + { .compatible = "renesas,r8a78000-rtvram", .data = (ulong)&gen5_rtvram_data }, { /* sentinel */ } }; U_BOOT_DRIVER(renesas_dbsc5_rtvram) = { - .name = "rtvram", + .name = "dbsc5_rtvram", .id = UCLASS_RAM, .of_match = renesas_dbsc5_rtvram_ids, .of_to_plat = renesas_dbsc5_rtvram_of_to_plat, diff --git a/drivers/ram/stm32mp1/Kconfig b/drivers/ram/stm32mp1/Kconfig index 1aaf064c30c..76bd17a8874 100644 --- a/drivers/ram/stm32mp1/Kconfig +++ b/drivers/ram/stm32mp1/Kconfig @@ -6,43 +6,43 @@ config STM32MP1_DDR select SPL_RAM if SPL default y help - activate STM32MP1 DDR controller driver for STM32MP1 soc - family: support for LPDDR2, LPDDR3 and DDR3 - the SDRAM parameters for controleur and phy need to be provided - in device tree (computed by DDR tuning tools) + activate STM32MP1 DDR controller driver for STM32MP1 soc + family: support for LPDDR2, LPDDR3 and DDR3 + the SDRAM parameters for controleur and phy need to be provided + in device tree (computed by DDR tuning tools) config STM32MP1_DDR_INTERACTIVE bool "STM32MP1 DDR driver : interactive support" depends on STM32MP1_DDR help - activate interactive support in STM32MP1 DDR controller driver - used for DDR tuning tools - to enter in intercative mode type 'd' during SPL DDR driver - initialisation + activate interactive support in STM32MP1 DDR controller driver + used for DDR tuning tools + to enter in intercative mode type 'd' during SPL DDR driver + initialisation config STM32MP1_DDR_INTERACTIVE_FORCE bool "STM32MP1 DDR driver : force interactive mode" depends on STM32MP1_DDR_INTERACTIVE help - force interactive mode in STM32MP1 DDR controller driver - skip the polling of character 'd' in console - useful when SPL is loaded in sysram - directly by programmer + force interactive mode in STM32MP1 DDR controller driver + skip the polling of character 'd' in console + useful when SPL is loaded in sysram + directly by programmer config STM32MP1_DDR_TESTS bool "STM32MP1 DDR driver : tests support" depends on STM32MP1_DDR_INTERACTIVE default y help - activate test support for interactive support in - STM32MP1 DDR controller driver: command test + activate test support for interactive support in + STM32MP1 DDR controller driver: command test config STM32MP1_DDR_TUNING bool "STM32MP1 DDR driver : support of tuning" depends on STM32MP1_DDR_INTERACTIVE default y help - activate tuning command in STM32MP1 DDR interactive mode - used for DDR tuning tools - - DQ Deskew algorithm - - DQS Trimming + activate tuning command in STM32MP1 DDR interactive mode + used for DDR tuning tools + - DQ Deskew algorithm + - DQS Trimming diff --git a/drivers/reboot-mode/Kconfig b/drivers/reboot-mode/Kconfig index 72b33d71223..3fdb4218a8b 100644 --- a/drivers/reboot-mode/Kconfig +++ b/drivers/reboot-mode/Kconfig @@ -11,26 +11,26 @@ config DM_REBOOT_MODE depends on DM select DEVRES help - Enable support for reboot mode control. This will allow users to - adjust the boot process based on reboot mode parameter - passed to U-Boot. + Enable support for reboot mode control. This will allow users to + adjust the boot process based on reboot mode parameter + passed to U-Boot. config DM_REBOOT_MODE_GPIO bool "Use GPIOs as reboot mode backend" depends on DM_REBOOT_MODE help - Use GPIOs to control the reboot mode. This will allow users to boot - a device in a specific mode by using a GPIO that can be controlled - outside U-Boot. + Use GPIOs to control the reboot mode. This will allow users to boot + a device in a specific mode by using a GPIO that can be controlled + outside U-Boot. config DM_REBOOT_MODE_RTC bool "Use RTC as reboot mode backend" depends on DM_RTC depends on DM_REBOOT_MODE help - Use RTC non volatile memory to control the reboot mode. This will allow users to boot - a device in a specific mode by using a register(s) that can be controlled - outside U-Boot (e.g. Kernel). + Use RTC non volatile memory to control the reboot mode. This will allow users to boot + a device in a specific mode by using a register(s) that can be controlled + outside U-Boot (e.g. Kernel). config REBOOT_MODE_NVMEM bool "Use NVMEM reboot mode" diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index f07ae903a28..7f9e35283f9 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -48,6 +48,15 @@ config REMOTEPROC_RENESAS_APMU Say 'y' here to add support for Renesas R-Car Gen4 Cortex-R52 processor via the remoteproc framework. +config REMOTEPROC_RENESAS_RSIP + bool "Support for Renesas R-Car Gen5 RSIP start of SCP/CR52/CA720 processors" + select REMOTEPROC + depends on ARCH_RENESAS && RCAR_GEN5 && DM && OF_CONTROL + help + Say 'y' here to add support for Renesas R-Car Gen5 RSIP + start of SCP, Cortex-R52 and Cortex-A720 processors via + the remoteproc framework. + config REMOTEPROC_SANDBOX bool "Support for Test processor for Sandbox" select REMOTEPROC diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 7ea8023c50b..250915d0de4 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -11,6 +11,7 @@ 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_RENESAS_RSIP) += renesas_rsip.o obj-$(CONFIG_REMOTEPROC_SANDBOX) += sandbox_testproc.o obj-$(CONFIG_REMOTEPROC_STM32_COPRO) += stm32_copro.o obj-$(CONFIG_REMOTEPROC_TI_K3_ARM64) += ti_k3_arm64_rproc.o diff --git a/drivers/remoteproc/ipu_rproc.c b/drivers/remoteproc/ipu_rproc.c index 2ca78b550a7..8f0b619daf7 100644 --- a/drivers/remoteproc/ipu_rproc.c +++ b/drivers/remoteproc/ipu_rproc.c @@ -695,9 +695,8 @@ static int ipu_probe(struct udevice *dev) priv = dev_get_priv(dev); priv->mem.bus_addr = - devfdt_get_addr_size_name(dev, - ipu_mem_names[0], - (fdt_addr_t *)&priv->mem.size); + dev_read_addr_size_name(dev, ipu_mem_names[0], + (fdt_addr_t *)&priv->mem.size); ret = reset_get_by_index(dev, 2, &reset); if (ret < 0) { @@ -718,7 +717,7 @@ static int ipu_probe(struct udevice *dev) priv->mem.cpu_addr = map_physmem(priv->mem.bus_addr, priv->mem.size, MAP_NOCACHE); - if (devfdt_get_addr(dev) == 0x58820000) + if (dev_read_addr(dev) == 0x58820000) priv->id = 0; else priv->id = 1; diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c index 9aec138637b..b0823bfd22d 100644 --- a/drivers/remoteproc/pru_rproc.c +++ b/drivers/remoteproc/pru_rproc.c @@ -421,19 +421,16 @@ static void pru_set_id(struct pru_privdata *priv, struct udevice *dev) static int pru_probe(struct udevice *dev) { struct pru_privdata *priv; - ofnode node; - - node = dev_ofnode(dev); priv = dev_get_priv(dev); priv->prusspriv = dev_get_priv(dev->parent); - priv->pru_iram = devfdt_get_addr_size_index(dev, PRU_MEM_IRAM, - &priv->pru_iramsz); - priv->pru_ctrl = devfdt_get_addr_size_index(dev, PRU_MEM_CTRL, - &priv->pru_ctrlsz); - priv->pru_debug = devfdt_get_addr_size_index(dev, PRU_MEM_DEBUG, - &priv->pru_debugsz); + priv->pru_iram = dev_read_addr_size_index(dev, PRU_MEM_IRAM, + &priv->pru_iramsz); + priv->pru_ctrl = dev_read_addr_size_index(dev, PRU_MEM_CTRL, + &priv->pru_ctrlsz); + priv->pru_debug = dev_read_addr_size_index(dev, PRU_MEM_DEBUG, + &priv->pru_debugsz); priv->iram_da = 0; priv->pdram_da = 0; diff --git a/drivers/remoteproc/renesas_rsip.c b/drivers/remoteproc/renesas_rsip.c new file mode 100644 index 00000000000..76ccaf93b1a --- /dev/null +++ b/drivers/remoteproc/renesas_rsip.c @@ -0,0 +1,358 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Copyright (C) 2026 Renesas Electronics Corp. + */ + +#include <asm/io.h> +#include <dm.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <errno.h> +#include <hang.h> +#include <linux/iopoll.h> +#include <linux/sizes.h> +#include <malloc.h> +#include <remoteproc.h> + +/* R-Car X5H contains 1 SCP core, 6 lockstep Cortex-R52 and 32 Cortex-A720AE cores. */ +#define RCAR5_SCP_CORES 1 +#define RCAR5_CR52_CORES 12 +#define RCAR5_CA720_CORES 32 + +#define SCP_BASE 0xc1340000 +#define SCP_CPUWAIT (SCP_BASE + 0x30) +#define SCP_CPUWAIT_WAIT BIT(0) +#define SCP_STCM 0xc1000000 + +struct scp_scmi_shmem { + u32 reserved0; + u32 status; + u64 reserved1; + u32 flags; + u32 length; + u32 message_header; + u8 payload[]; +}; + +struct scp_scmi_pd_power_state_set_a2p { + u32 flags; + u32 domain_id; + u32 power_state; + u32 boot_addr; +}; + +/* The addresses in range 0x08000000..0x1fffffff are incremented by 0xa0000000 */ +#define MFIS_COMMON_BASE 0xb89e1000 +#define MFIS_SCP_WACNTR (MFIS_COMMON_BASE + 0x904) + +/* The addresses in range 0x08000000..0x1fffffff are incremented by 0xa0000000 */ +#define MFIS_SCP_BASE 0xb8840000 +#define MFIS_SCP_REICR8 (MFIS_SCP_BASE + 0x28004) +#define MFIS_SCP_CODEVALUE 0xacc00000 +#define MFIS_SCP_REG_MASK GENMASK(19, 0) + +/** + * mfis_scp_unlock() - Release MFIS-SCP lock + * @lck: MFIS lock register + */ +static void mfis_scp_unlock(const u32 lck) +{ + writel(MFIS_SCP_CODEVALUE | (lck & MFIS_SCP_REG_MASK), MFIS_SCP_WACNTR); +} + +#define SCP_SCMI_SHMEM_AREA09 0xc1060800 +#define SCP_SCMI_STATUS_MASK 0x3 +#define SCP_SCMI_STATUS_FREE 0x1 + +/** + * scp_wait_fw_free() - Wait for SCP channel to be free for communication + */ +static void scp_wait_fw_free(void) +{ + struct scp_scmi_shmem *shmem = (struct scp_scmi_shmem *)SCP_SCMI_SHMEM_AREA09; + + while ((shmem->status & SCP_SCMI_STATUS_MASK) != SCP_SCMI_STATUS_FREE) + mdelay(1); +} + +/** + * scp_send_interrupt() - Raise interrupt on SCP side + */ +static void scp_send_interrupt(void) +{ + mfis_scp_unlock(MFIS_SCP_REICR8); + /* Send SCP IRQ */ + writel(1, MFIS_SCP_REICR8); +} + +/* SCMI power domain IDs */ +#define SCMI_PD_CORE_RT_CORE00 117 +#define SCMI_PD_CORE_AP_CORE00 129 + +/* + * FIXME: This is custom extension to the SCMI PD protocol: + * - Protocol 0x11 (PD) + * - Command 0x11 (POWER_STATE_SET_BOOTADDR - custom) + * This must be removed when proper upstream SCP port exists + */ +#define SCMI_PD_POWER_STATE_SET_BOOTADDR 0x4411 + +/** + * scp_cpu_core_start() - Boot CPU core by invoking SCP via SCMI + * @core: CPU core to boot + * @ep: Entry point + */ +static void scp_cpu_core_start(const u32 core, const u32 ep) +{ + struct scp_scmi_shmem *shmem = (struct scp_scmi_shmem *)SCP_SCMI_SHMEM_AREA09; + struct scp_scmi_pd_power_state_set_a2p scmi_parameter = { + .flags = 1, /* Asynchronous power transition using APMU */ + .domain_id = core, + .power_state = 0, /* Power on */ + .boot_addr = ep, + }; + u32 status; + + /* Wait for SCP to be free, then set it busy */ + scp_wait_fw_free(); + shmem->status &= ~SCP_SCMI_STATUS_FREE; + + /* Set up the message and copy it to SHMEM */ + shmem->message_header = SCMI_PD_POWER_STATE_SET_BOOTADDR; + memcpy(shmem->payload, &scmi_parameter, sizeof(scmi_parameter)); + shmem->length = sizeof(shmem->message_header) + sizeof(scmi_parameter); + + /* Send message to SCP and wait for completion */ + scp_send_interrupt(); + scp_wait_fw_free(); + + /* Read back the result */ + status = readl((uintptr_t)shmem->payload); + if (status) + printf("SCP POWER_STATE_SET failed, status=0x%x\n", status); +} + +/** + * struct renesas_rsip_rproc_privdata - remote processor private data + * @core_id: CPU core id + * @ep: Entry point + */ +struct renesas_rsip_rproc_privdata { + ulong core_id; + ulong ep; +}; + +/** + * renesas_rsip_rproc_load() - Load the remote processor + * @dev: corresponding remote processor device + * @addr: Address in memory where image is stored + * @size: Size in bytes of the image + * + * Return: 0 if all went ok, else corresponding -ve error + */ +static int renesas_rsip_rproc_load(struct udevice *dev, ulong addr, ulong size) +{ + struct renesas_rsip_rproc_privdata *priv = dev_get_priv(dev); + + priv->ep = addr; + + if (priv->core_id == 0) /* SCP */ + memcpy((void *)SCP_STCM, (void *)addr, size); + + return 0; +} + +/** + * renesas_rsip_rproc_start() - Start the remote processor + * @dev: corresponding remote processor device + * + * Return: 0 if all went ok, else corresponding -ve error + */ +static int renesas_rsip_rproc_start(struct udevice *dev) +{ + struct renesas_rsip_rproc_privdata *priv = dev_get_priv(dev); + int scmi_core; + + if (priv->core_id == 0) { + /* SCP */ + clrbits_le32(SCP_CPUWAIT, SCP_CPUWAIT_WAIT); + return 0; + } else if (priv->core_id >= RCAR5_SCP_CORES && + priv->core_id < RCAR5_SCP_CORES + RCAR5_CR52_CORES) { + /* CR52 */ + scmi_core = priv->core_id - RCAR5_SCP_CORES + + SCMI_PD_CORE_RT_CORE00; + } else if (priv->core_id >= RCAR5_SCP_CORES + RCAR5_CR52_CORES && + priv->core_id < RCAR5_SCP_CORES + RCAR5_CR52_CORES + RCAR5_CA720_CORES) { + /* CA720 */ + scmi_core = priv->core_id - RCAR5_SCP_CORES - RCAR5_CR52_CORES + + SCMI_PD_CORE_AP_CORE00; + } + + scp_cpu_core_start(scmi_core, priv->ep); + + return 0; +} + +/** + * renesas_rsip_rproc_stop() - Stop the remote processor + * @dev: corresponding remote processor device + * + * Return: 0 if all went ok, else corresponding -ve error + */ +static int renesas_rsip_rproc_stop(struct udevice *dev) +{ + struct renesas_rsip_rproc_privdata *priv = dev_get_priv(dev); + + if (priv->core_id == 0) { /* SCP */ + setbits_le32(SCP_CPUWAIT, SCP_CPUWAIT_WAIT); + return 0; + } + + return 0; +} + +/** + * renesas_rsip_rproc_reset() - Reset the remote processor + * @dev: corresponding remote processor device + * + * Return: 0 if all went ok, else corresponding -ve error + */ +static int renesas_rsip_rproc_reset(struct udevice *dev) +{ + renesas_rsip_rproc_stop(dev); + renesas_rsip_rproc_start(dev); + return 0; +} + +/** + * renesas_rsip_rproc_is_running() - Is the remote processor running + * @dev: corresponding remote processor device + * + * Return: 0 if the remote processor is running, 1 otherwise + */ +static int renesas_rsip_rproc_is_running(struct udevice *dev) +{ + /* We assume the core is stopped. */ + return 1; +} + +/** + * renesas_rsip_rproc_init() - Initialize the remote processor + * @dev: corresponding remote processor device + * + * Return: 0 if all went ok, else corresponding -ve error + */ +static int renesas_rsip_rproc_init(struct udevice *dev) +{ + return 0; +} + +/** + * renesas_rsip_rproc_device_to_virt() - Convert device address to virtual address + * @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_rsip_rproc_device_to_virt(struct udevice *dev, ulong da, + ulong size, bool *is_iomem) +{ + return (void *)da; +} + +static const struct dm_rproc_ops renesas_rsip_rproc_ops = { + .init = renesas_rsip_rproc_init, + .load = renesas_rsip_rproc_load, + .start = renesas_rsip_rproc_start, + .stop = renesas_rsip_rproc_stop, + .reset = renesas_rsip_rproc_reset, + .is_running = renesas_rsip_rproc_is_running, + .device_to_virt = renesas_rsip_rproc_device_to_virt, +}; + +/** + * renesas_rsip_rproc_of_to_plat() - Convert OF data to platform data + * @dev: corresponding remote processor device + * + * Return: 0 if all went ok, else corresponding -ve error + */ +static int renesas_rsip_rproc_of_to_plat(struct udevice *dev) +{ + struct renesas_rsip_rproc_privdata *priv = dev_get_priv(dev); + + priv->core_id = dev_get_driver_data(dev); + + return 0; +} + +U_BOOT_DRIVER(renesas_rsip_core) = { + .name = "rcar-rsip-core", + .id = UCLASS_REMOTEPROC, + .ops = &renesas_rsip_rproc_ops, + .of_to_plat = renesas_rsip_rproc_of_to_plat, + .priv_auto = sizeof(struct renesas_rsip_rproc_privdata), +}; + +/** + * renesas_rsip_rproc_bind() - Bind rproc driver to each core control + * @dev: corresponding remote processor parent device + * + * Return: 0 if all went ok, else corresponding -ve error + */ +static int renesas_rsip_rproc_bind(struct udevice *parent) +{ + ofnode pnode = dev_ofnode(parent); + struct udevice *cdev; + struct driver *cdrv; + char name[32]; + ulong i; + int ret; + + cdrv = lists_driver_lookup_name("rcar-rsip-core"); + if (!cdrv) + return -ENOENT; + + /* Singleton SCP core is core 0 */ + ret = device_bind_with_driver_data(parent, cdrv, + strdup("rcar-rsip-scp"), + 0, pnode, &cdev); + if (ret) + return ret; + + /* Cores 1..13 are Cortex-R52 */ + for (i = 0; i < RCAR5_CR52_CORES; i++) { + snprintf(name, sizeof(name), "rcar-rsip-cr.%ld", i); + ret = device_bind_with_driver_data(parent, cdrv, strdup(name), + i + RCAR5_SCP_CORES, pnode, + &cdev); + if (ret) + return ret; + } + + /* Cores 14..46 are Cortex-A720 */ + for (i = 0; i < RCAR5_CA720_CORES; i++) { + snprintf(name, sizeof(name), "rcar-rsip-ca.%ld", i); + ret = device_bind_with_driver_data(parent, cdrv, strdup(name), + i + RCAR5_SCP_CORES + RCAR5_CR52_CORES, + pnode, &cdev); + if (ret) + return ret; + } + + return 0; +} + +static const struct udevice_id renesas_rsip_rproc_ids[] = { + { .compatible = "renesas,r8a78000-rproc" }, + { } +}; + +U_BOOT_DRIVER(renesas_rsip_rproc) = { + .name = "rcar-rsip-rproc", + .of_match = renesas_rsip_rproc_ids, + .id = UCLASS_NOP, + .bind = renesas_rsip_rproc_bind, +}; diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c index 7326f5a4b30..c5810dd0994 100644 --- a/drivers/remoteproc/ti_k3_r5f_rproc.c +++ b/drivers/remoteproc/ti_k3_r5f_rproc.c @@ -861,7 +861,7 @@ static int k3_r5f_probe(struct udevice *dev) return 0; } - ret = k3_r5f_proc_request(core); + ret = ti_sci_proc_request(&core->tsp); if (ret) return ret; diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 66911199c8b..db764ed5ace 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -64,6 +64,22 @@ config RESET_BCM6345 help Support reset controller on BCM6345. +config RESET_BRCMSTB + depends on ARCH_BCM283X + bool "Generic Reset controller driver for Broadcom" + help + This enables reset controller for Broadcom devices. + If you wish to use reset resources managed by the Broadcom + Reset Controller, say Y here. Otherwise, say N. + +config RESET_BRCMSTB_RESCAL + depends on ARCH_BCM283X + bool "Generic Rescal Reset controller driver for Broadcom" + help + Support rescal reset controller on Broadcom. + If you wish to use reset resources managed by the Broadcom + Reset Controller, say Y here. Otherwise, say N. + config RESET_UNIPHIER bool "Reset controller driver for UniPhier SoCs" depends on ARCH_UNIPHIER @@ -91,6 +107,15 @@ config RESET_AST2600 Say Y if you want to control reset signals of different peripherals through System Control Unit (SCU). +config RESET_AST2700 + bool "Reset controller driver for AST2700 SoCs" + depends on DM_RESET && ASPEED_AST2700 + default y if ASPEED_AST2700 + help + Support for reset controller on AST2700 SoC. + Say Y if you want to control reset signals of different peripherals + through System Control Unit (SCU). + config RESET_ROCKCHIP bool "Reset controller driver for Rockchip SoCs" depends on DM_RESET && ARCH_ROCKCHIP && CLK @@ -100,6 +125,15 @@ config RESET_ROCKCHIP though is that some reset signals, like I2C or MISC reset multiple devices. +config SPL_RESET_ROCKCHIP + bool "SPL reset controller driver for Rockchip SoCs" + depends on SPL_DM_RESET && ARCH_ROCKCHIP && SPL_CLK + default y + help + Support for the reset controller on Rockchip SoCs in SPL. Select this + if you observe any reset-related warnings or errors when booting SPL, + such as when using UFS storage + config RESET_HSDK bool "Synopsys HSDK Reset Driver" depends on DM_RESET && TARGET_HSDK @@ -239,19 +273,11 @@ config RESET_AT91 config RESET_RZG2L_USBPHY_CTRL bool "Enable support for Renesas RZ/G2L USB 2.0 PHY control" - depends on DM_RESET - select REGULATOR_RZG2L_USBPHY + depends on DM_RESET && REGULATOR_RZG2L_USBPHY help Enable support for controlling USB 2.0 PHY resets on the Renesas RZ/G2L SoC. This is required for USB 2.0 functionality to work on this SoC. -config RESET_SPACEMIT_K1 - bool "Support for SPACEMIT's K1 Reset driver" - depends on DM_RESET - help - Support for SPACEMIT's K1 Reset system. Basic Assert/Deassert - is supported. - source "drivers/reset/stm32/Kconfig" endmenu diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 088545c6473..384f4336331 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -13,10 +13,13 @@ obj-$(CONFIG_RESET_AIROHA) += reset-airoha.o obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o obj-$(CONFIG_RESET_HSDK) += reset-hsdk.o obj-$(CONFIG_RESET_BCM6345) += reset-bcm6345.o +obj-$(CONFIG_RESET_BRCMSTB) += reset-brcmstb.o +obj-$(CONFIG_RESET_BRCMSTB_RESCAL) += reset-brcmstb-rescal.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o obj-$(CONFIG_RESET_AST2500) += reset-ast2500.o obj-$(CONFIG_RESET_AST2600) += reset-ast2600.o -obj-$(CONFIG_RESET_ROCKCHIP) += reset-rockchip.o rst-rk3506.o rst-rk3528.o rst-rk3576.o rst-rk3588.o +obj-$(CONFIG_RESET_AST2700) += reset-ast2700.o +obj-$(CONFIG_$(PHASE_)RESET_ROCKCHIP) += reset-rockchip.o rst-rk3506.o rst-rk3528.o rst-rk3576.o rst-rk3588.o obj-$(CONFIG_RESET_MESON) += reset-meson.o obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o obj-$(CONFIG_RESET_MEDIATEK) += reset-mediatek.o @@ -34,7 +37,7 @@ obj-$(CONFIG_RESET_DRA7) += reset-dra7.o obj-$(CONFIG_RESET_AT91) += reset-at91.o obj-$(CONFIG_$(PHASE_)RESET_JH7110) += reset-jh7110.o obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += reset-rzg2l-usbphy-ctrl.o -obj-$(CONFIG_RESET_SPACEMIT_K1) += reset-spacemit-k1.o +obj-$(CONFIG_CLK_SPACEMIT_K1) += spacemit/ obj-$(CONFIG_ARCH_STM32) += stm32/ obj-$(CONFIG_ARCH_STM32MP) += stm32/ diff --git a/drivers/reset/reset-ast2500.c b/drivers/reset/reset-ast2500.c index f3543fa8cc1..c85906bbeb5 100644 --- a/drivers/reset/reset-ast2500.c +++ b/drivers/reset/reset-ast2500.c @@ -77,10 +77,10 @@ static int ast2500_reset_probe(struct udevice *dev) return rc; } - priv->scu = devfdt_get_addr_ptr(scu_dev); + priv->scu = dev_read_addr_ptr(scu_dev); if (IS_ERR_OR_NULL(priv->scu)) { debug("%s: invalid SCU base pointer\n", __func__); - return PTR_ERR(priv->scu); + return -EINVAL; } return 0; @@ -91,7 +91,7 @@ static const struct udevice_id ast2500_reset_ids[] = { { } }; -struct reset_ops ast2500_reset_ops = { +static const struct reset_ops ast2500_reset_ops = { .rst_assert = ast2500_reset_assert, .rst_deassert = ast2500_reset_deassert, .rst_status = ast2500_reset_status, diff --git a/drivers/reset/reset-ast2600.c b/drivers/reset/reset-ast2600.c index ec7b9b6625d..71b6220225a 100644 --- a/drivers/reset/reset-ast2600.c +++ b/drivers/reset/reset-ast2600.c @@ -76,10 +76,10 @@ static int ast2600_reset_probe(struct udevice *dev) return rc; } - priv->scu = devfdt_get_addr_ptr(scu_dev); + priv->scu = dev_read_addr_ptr(scu_dev); if (IS_ERR_OR_NULL(priv->scu)) { debug("%s: invalid SCU base pointer\n", __func__); - return PTR_ERR(priv->scu); + return -EINVAL; } return 0; @@ -90,7 +90,7 @@ static const struct udevice_id ast2600_reset_ids[] = { { } }; -struct reset_ops ast2600_reset_ops = { +static const struct reset_ops ast2600_reset_ops = { .rst_assert = ast2600_reset_assert, .rst_deassert = ast2600_reset_deassert, .rst_status = ast2600_reset_status, diff --git a/drivers/reset/reset-ast2700.c b/drivers/reset/reset-ast2700.c new file mode 100644 index 00000000000..2dd9e36cc0a --- /dev/null +++ b/drivers/reset/reset-ast2700.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) ASPEED Technology Inc. + */ + +#include <asm/io.h> +#include <dm.h> +#include <linux/err.h> +#include <reset.h> +#include <reset-uclass.h> + +/* Offset of the modrst register block within the SCU. */ +#define AST2700_RESET_OFFSET 0x200 + +struct ast2700_reset_priv { + void __iomem *base; +}; + +static int ast2700_reset_assert(struct reset_ctl *reset_ctl) +{ + struct ast2700_reset_priv *priv = dev_get_priv(reset_ctl->dev); + + if (reset_ctl->id < 32) + writel(BIT(reset_ctl->id), priv->base); + else + writel(BIT(reset_ctl->id - 32), priv->base + 0x20); + + return 0; +} + +static int ast2700_reset_deassert(struct reset_ctl *reset_ctl) +{ + struct ast2700_reset_priv *priv = dev_get_priv(reset_ctl->dev); + + if (reset_ctl->id < 32) + writel(BIT(reset_ctl->id), priv->base + 0x04); + else + writel(BIT(reset_ctl->id - 32), priv->base + 0x24); + + return 0; +} + +static int ast2700_reset_status(struct reset_ctl *reset_ctl) +{ + struct ast2700_reset_priv *priv = dev_get_priv(reset_ctl->dev); + int status; + + if (reset_ctl->id < 32) + status = BIT(reset_ctl->id) & readl(priv->base); + else + status = BIT(reset_ctl->id - 32) & readl(priv->base + 0x20); + + return !!status; +} + +static int ast2700_reset_probe(struct udevice *dev) +{ + struct ast2700_reset_priv *priv = dev_get_priv(dev); + void __iomem *scu_base; + + scu_base = dev_read_addr_ptr(dev); + if (!scu_base) + return -EINVAL; + + priv->base = scu_base + AST2700_RESET_OFFSET; + + return 0; +} + +static const struct reset_ops ast2700_reset_ops = { + .rst_assert = ast2700_reset_assert, + .rst_deassert = ast2700_reset_deassert, + .rst_status = ast2700_reset_status, +}; + +U_BOOT_DRIVER(ast2700_reset) = { + .name = "ast2700_reset", + .id = UCLASS_RESET, + .probe = ast2700_reset_probe, + .ops = &ast2700_reset_ops, + .priv_auto = sizeof(struct ast2700_reset_priv), +}; diff --git a/drivers/reset/reset-at91.c b/drivers/reset/reset-at91.c index 165c87acdc4..ebbfae1469b 100644 --- a/drivers/reset/reset-at91.c +++ b/drivers/reset/reset-at91.c @@ -79,7 +79,7 @@ static int at91_rst_deassert(struct reset_ctl *reset_ctl) return at91_rst_update(reset, reset_ctl->id, false); } -struct reset_ops at91_reset_ops = { +static const struct reset_ops at91_reset_ops = { .of_xlate = at91_reset_of_xlate, .rst_assert = at91_rst_assert, .rst_deassert = at91_rst_deassert, diff --git a/drivers/reset/reset-bcm6345.c b/drivers/reset/reset-bcm6345.c index 6f140574216..161d00d1b0c 100644 --- a/drivers/reset/reset-bcm6345.c +++ b/drivers/reset/reset-bcm6345.c @@ -49,7 +49,7 @@ static int bcm6345_reset_request(struct reset_ctl *rst) return bcm6345_reset_assert(rst); } -struct reset_ops bcm6345_reset_reset_ops = { +static const struct reset_ops bcm6345_reset_reset_ops = { .request = bcm6345_reset_request, .rst_assert = bcm6345_reset_assert, .rst_deassert = bcm6345_reset_deassert, diff --git a/drivers/reset/reset-brcmstb-rescal.c b/drivers/reset/reset-brcmstb-rescal.c new file mode 100644 index 00000000000..fc8fcfa8b3f --- /dev/null +++ b/drivers/reset/reset-brcmstb-rescal.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Broadcom STB generic reset controller + * + * Copyright (C) 2024 EPAM Systems + * Moved from linux kernel: + * Copyright (C) 2018-2020 Broadcom + */ + +#include <asm/io.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <errno.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <log.h> +#include <malloc.h> +#include <reset-uclass.h> + +#define BRCM_RESCAL_START 0x0 +#define BRCM_RESCAL_START_BIT BIT(0) +#define BRCM_RESCAL_CTRL 0x4 +#define BRCM_RESCAL_STATUS 0x8 +#define BRCM_RESCAL_STATUS_BIT BIT(0) + +struct brcm_rescal_reset { + void __iomem *base; +}; + +/* Also doubles a deassert */ +static int brcm_rescal_reset_set(struct reset_ctl *rst) +{ + struct brcm_rescal_reset *data = dev_get_priv(rst->dev); + void __iomem *base = data->base; + u32 reg; + int ret; + + reg = readl(base + BRCM_RESCAL_START); + writel(reg | BRCM_RESCAL_START_BIT, base + BRCM_RESCAL_START); + reg = readl(base + BRCM_RESCAL_START); + if (!(reg & BRCM_RESCAL_START_BIT)) { + dev_err(rst->dev, "failed to start SATA/PCIe rescal\n"); + return -EIO; + } + + ret = readl_poll_timeout(base + BRCM_RESCAL_STATUS, reg, + (reg & BRCM_RESCAL_STATUS_BIT), 100); + if (ret) { + dev_err(rst->dev, "time out on SATA/PCIe rescal\n"); + return ret; + } + + reg = readl(base + BRCM_RESCAL_START); + writel(reg & ~BRCM_RESCAL_START_BIT, base + BRCM_RESCAL_START); + + dev_dbg(rst->dev, "SATA/PCIe rescal success\n"); + return 0; +} + +/* A dummy function - deassert/reset does all the work */ +static int brcm_rescal_reset_assert(struct reset_ctl *rst) +{ + return 0; +} + +static int brcm_rescal_reset_xlate(struct reset_ctl *reset_ctl, + struct ofnode_phandle_args *args) +{ + /* This is needed if #reset-cells == 0. */ + return 0; +} + +static const struct reset_ops brcm_rescal_reset_ops = { + .rst_deassert = brcm_rescal_reset_set, + .rst_assert = brcm_rescal_reset_assert, + .of_xlate = brcm_rescal_reset_xlate, +}; + +static int brcm_rescal_reset_probe(struct udevice *dev) +{ + struct brcm_rescal_reset *data = dev_get_priv(dev); + + data->base = dev_remap_addr(dev); + if (!data->base) + return -EINVAL; + + return 0; +} + +static const struct udevice_id brcm_rescal_reset_of_match[] = { + {.compatible = "brcm,bcm7216-pcie-sata-rescal"}, + {}, +}; + +U_BOOT_DRIVER(brcmstb_reset_rescal) = { + .name = "brcmstb-reset-rescal", + .id = UCLASS_RESET, + .of_match = brcm_rescal_reset_of_match, + .ops = &brcm_rescal_reset_ops, + .probe = brcm_rescal_reset_probe, + .priv_auto = sizeof(struct brcm_rescal_reset), +}; diff --git a/drivers/reset/reset-brcmstb.c b/drivers/reset/reset-brcmstb.c new file mode 100644 index 00000000000..7861f7c9baf --- /dev/null +++ b/drivers/reset/reset-brcmstb.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Broadcom STB generic reset controller + * + * Copyright (C) 2024 EPAM Systems + * + * Moved from linux kernel: + * Author: Florian Fainelli <[email protected]> + * Copyright (C) 2018 Broadcom + */ + +#include <asm/io.h> +#include <dm.h> +#include <errno.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <log.h> +#include <malloc.h> +#include <reset-uclass.h> + +struct brcmstb_reset { + void __iomem *base; +}; + +#define SW_INIT_SET 0x00 +#define SW_INIT_CLEAR 0x04 +#define SW_INIT_STATUS 0x08 + +#define SW_INIT_BIT(id) BIT((id) & 0x1f) +#define SW_INIT_BANK(id) ((id) >> 5) + +#define usleep_range(a, b) udelay((b)) + +/* A full bank contains extra registers that we are not utilizing but still + * qualify as a single bank. + */ +#define SW_INIT_BANK_SIZE 0x18 + +static int brcmstb_reset_assert(struct reset_ctl *rst) +{ + unsigned int off = SW_INIT_BANK(rst->id) * SW_INIT_BANK_SIZE; + struct brcmstb_reset *priv = dev_get_priv(rst->dev); + + writel_relaxed(SW_INIT_BIT(rst->id), priv->base + off + SW_INIT_SET); + return 0; +} + +static int brcmstb_reset_deassert(struct reset_ctl *rst) +{ + unsigned int off = SW_INIT_BANK(rst->id) * SW_INIT_BANK_SIZE; + struct brcmstb_reset *priv = dev_get_priv(rst->dev); + + writel_relaxed(SW_INIT_BIT(rst->id), priv->base + off + SW_INIT_CLEAR); + /* Maximum reset delay after de-asserting a line and seeing block + * operation is typically 14us for the worst case, build some slack + * here. + */ + usleep_range(100, 200); + return 0; +} + +static int brcmstb_reset_status(struct reset_ctl *rst) +{ + unsigned int off = SW_INIT_BANK(rst->id) * SW_INIT_BANK_SIZE; + struct brcmstb_reset *priv = dev_get_priv(rst->dev); + + return readl_relaxed(priv->base + off + SW_INIT_STATUS) & + SW_INIT_BIT(rst->id); +} + +struct reset_ops brcmstb_reset_reset_ops = { + .rst_assert = brcmstb_reset_assert, + .rst_deassert = brcmstb_reset_deassert, + .rst_status = brcmstb_reset_status}; + +static int brcmstb_reset_probe(struct udevice *dev) +{ + struct brcmstb_reset *priv = dev_get_priv(dev); + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + + return 0; +} + +static const struct udevice_id brcmstb_reset_ids[] = { + {.compatible = "brcm,brcmstb-reset"}, {/* sentinel */}}; + +U_BOOT_DRIVER(brcmstb_reset) = { + .name = "brcmstb-reset", + .id = UCLASS_RESET, + .of_match = brcmstb_reset_ids, + .ops = &brcmstb_reset_reset_ops, + .probe = brcmstb_reset_probe, + .priv_auto = sizeof(struct brcmstb_reset), +}; diff --git a/drivers/reset/reset-dra7.c b/drivers/reset/reset-dra7.c index 2f0ec4c042f..6b570d87d23 100644 --- a/drivers/reset/reset-dra7.c +++ b/drivers/reset/reset-dra7.c @@ -51,7 +51,7 @@ static int dra7_reset_assert(struct reset_ctl *reset_ctl) return 0; } -struct reset_ops dra7_reset_ops = { +static const struct reset_ops dra7_reset_ops = { .rst_assert = dra7_reset_assert, .rst_deassert = dra7_reset_deassert, }; diff --git a/drivers/reset/reset-mediatek.c b/drivers/reset/reset-mediatek.c index 4b3afab92ea..66bcf7c29b6 100644 --- a/drivers/reset/reset-mediatek.c +++ b/drivers/reset/reset-mediatek.c @@ -47,7 +47,7 @@ static int mediatek_reset_deassert(struct reset_ctl *reset_ctl) priv->regofs + ((id / 32) << 2), BIT(id % 32), 0); } -struct reset_ops mediatek_reset_ops = { +static const struct reset_ops mediatek_reset_ops = { .rst_assert = mediatek_reset_assert, .rst_deassert = mediatek_reset_deassert, }; diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 6337cdaaffa..8c27563ce23 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -66,7 +66,7 @@ static int meson_reset_deassert(struct reset_ctl *reset_ctl) return meson_reset_level(reset_ctl, false); } -struct reset_ops meson_reset_ops = { +static const struct reset_ops meson_reset_ops = { .request = meson_reset_request, .rst_assert = meson_reset_assert, .rst_deassert = meson_reset_deassert, diff --git a/drivers/reset/reset-npcm.c b/drivers/reset/reset-npcm.c index a3b85a42250..66b541f09e6 100644 --- a/drivers/reset/reset-npcm.c +++ b/drivers/reset/reset-npcm.c @@ -126,7 +126,7 @@ static const struct udevice_id npcm_reset_ids[] = { { } }; -struct reset_ops npcm_reset_ops = { +static const struct reset_ops npcm_reset_ops = { .request = npcm_reset_request, .rfree = npcm_reset_free, .rst_assert = npcm_reset_assert, diff --git a/drivers/reset/reset-raspberrypi.c b/drivers/reset/reset-raspberrypi.c index 1792f0813f7..73acd301e3d 100644 --- a/drivers/reset/reset-raspberrypi.c +++ b/drivers/reset/reset-raspberrypi.c @@ -28,7 +28,7 @@ static int raspberrypi_reset_assert(struct reset_ctl *reset_ctl) } } -struct reset_ops raspberrypi_reset_ops = { +static const struct reset_ops raspberrypi_reset_ops = { .request = raspberrypi_reset_request, .rst_assert = raspberrypi_reset_assert, }; diff --git a/drivers/reset/reset-spacemit-k1.c b/drivers/reset/reset-spacemit-k1.c deleted file mode 100644 index 613e002fc4f..00000000000 --- a/drivers/reset/reset-spacemit-k1.c +++ /dev/null @@ -1,548 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2022 Spacemit Inc. - * Copyright (C) 2025 Huan Zhou <[email protected]> - */ - -#include <asm/io.h> -#include <config.h> -#include <dm.h> -#include <dm/device_compat.h> -#include <dm/device-internal.h> -#include <dm/lists.h> -#include <dt-bindings/reset/spacemit-k1-reset.h> -#include <linux/bitops.h> -#include <reset-uclass.h> - -/* APBC register offset */ -#define APBC_UART1_CLK_RST 0x0 -#define APBC_UART2_CLK_RST 0x4 -#define APBC_GPIO_CLK_RST 0x8 -#define APBC_PWM0_CLK_RST 0xc -#define APBC_PWM1_CLK_RST 0x10 -#define APBC_PWM2_CLK_RST 0x14 -#define APBC_PWM3_CLK_RST 0x18 -#define APBC_TWSI8_CLK_RST 0x20 -#define APBC_UART3_CLK_RST 0x24 -#define APBC_RTC_CLK_RST 0x28 -#define APBC_TWSI0_CLK_RST 0x2c -#define APBC_TWSI1_CLK_RST 0x30 -#define APBC_TIMERS1_CLK_RST 0x34 -#define APBC_TWSI2_CLK_RST 0x38 -#define APBC_AIB_CLK_RST 0x3c -#define APBC_TWSI4_CLK_RST 0x40 -#define APBC_TIMERS2_CLK_RST 0x44 -#define APBC_ONEWIRE_CLK_RST 0x48 -#define APBC_TWSI5_CLK_RST 0x4c -#define APBC_DRO_CLK_RST 0x58 -#define APBC_IR_CLK_RST 0x5c -#define APBC_TWSI6_CLK_RST 0x60 -#define APBC_TWSI7_CLK_RST 0x68 -#define APBC_TSEN_CLK_RST 0x6c - -#define APBC_UART4_CLK_RST 0x70 -#define APBC_UART5_CLK_RST 0x74 -#define APBC_UART6_CLK_RST 0x78 -#define APBC_SSP3_CLK_RST 0x7c - -#define APBC_SSPA0_CLK_RST 0x80 -#define APBC_SSPA1_CLK_RST 0x84 - -#define APBC_IPC_AP2AUD_CLK_RST 0x90 -#define APBC_UART7_CLK_RST 0x94 -#define APBC_UART8_CLK_RST 0x98 -#define APBC_UART9_CLK_RST 0x9c - -#define APBC_CAN0_CLK_RST 0xa0 -#define APBC_PWM4_CLK_RST 0xa8 -#define APBC_PWM5_CLK_RST 0xac -#define APBC_PWM6_CLK_RST 0xb0 -#define APBC_PWM7_CLK_RST 0xb4 -#define APBC_PWM8_CLK_RST 0xb8 -#define APBC_PWM9_CLK_RST 0xbc -#define APBC_PWM10_CLK_RST 0xc0 -#define APBC_PWM11_CLK_RST 0xc4 -#define APBC_PWM12_CLK_RST 0xc8 -#define APBC_PWM13_CLK_RST 0xcc -#define APBC_PWM14_CLK_RST 0xd0 -#define APBC_PWM15_CLK_RST 0xd4 -#define APBC_PWM16_CLK_RST 0xd8 -#define APBC_PWM17_CLK_RST 0xdc -#define APBC_PWM18_CLK_RST 0xe0 -#define APBC_PWM19_CLK_RST 0xe4 -/* end of APBC register offset */ - -/* MPMU register offset */ -#define MPMU_WDTPCR 0x200 -/* end of MPMU register offset */ - -/* APMU register offset */ -#define APMU_JPG_CLK_RES_CTRL 0x20 -#define APMU_CSI_CCIC2_CLK_RES_CTRL 0x24 -#define APMU_ISP_CLK_RES_CTRL 0x38 -#define APMU_LCD_CLK_RES_CTRL1 0x44 -#define APMU_LCD_SPI_CLK_RES_CTRL 0x48 -#define APMU_LCD_CLK_RES_CTRL2 0x4c -#define APMU_CCIC_CLK_RES_CTRL 0x50 -#define APMU_SDH0_CLK_RES_CTRL 0x54 -#define APMU_SDH1_CLK_RES_CTRL 0x58 -#define APMU_USB_CLK_RES_CTRL 0x5c -#define APMU_QSPI_CLK_RES_CTRL 0x60 -#define APMU_USB_CLK_RES_CTRL 0x5c -#define APMU_DMA_CLK_RES_CTRL 0x64 -#define APMU_AES_CLK_RES_CTRL 0x68 -#define APMU_VPU_CLK_RES_CTRL 0xa4 -#define APMU_GPU_CLK_RES_CTRL 0xcc -#define APMU_SDH2_CLK_RES_CTRL 0xe0 -#define APMU_PMUA_MC_CTRL 0xe8 -#define APMU_PMU_CC2_AP 0x100 -#define APMU_PMUA_EM_CLK_RES_CTRL 0x104 - -#define APMU_AUDIO_CLK_RES_CTRL 0x14c -#define APMU_HDMI_CLK_RES_CTRL 0x1B8 - -#define APMU_PCIE_CLK_RES_CTRL_0 0x3cc -#define APMU_PCIE_CLK_RES_CTRL_1 0x3d4 -#define APMU_PCIE_CLK_RES_CTRL_2 0x3dc - -#define APMU_EMAC0_CLK_RES_CTRL 0x3e4 -#define APMU_EMAC1_CLK_RES_CTRL 0x3ec -/* end of APMU register offset */ - -/* APBC2 register offset */ -#define APBC2_UART1_CLK_RST 0x00 -#define APBC2_SSP2_CLK_RST 0x04 -#define APBC2_TWSI3_CLK_RST 0x08 -#define APBC2_RTC_CLK_RST 0x0c -#define APBC2_TIMERS0_CLK_RST 0x10 -#define APBC2_KPC_CLK_RST 0x14 -#define APBC2_GPIO_CLK_RST 0x1c -/* end of APBC2 register offset */ - -enum spacemit_reset_base_type { - RST_BASE_TYPE_MPMU = 0, - RST_BASE_TYPE_APMU = 1, - RST_BASE_TYPE_APBC = 2, - RST_BASE_TYPE_APBS = 3, - RST_BASE_TYPE_CIU = 4, - RST_BASE_TYPE_DCIU = 5, - RST_BASE_TYPE_DDRC = 6, - RST_BASE_TYPE_AUDC = 7, - RST_BASE_TYPE_APBC2 = 8, -}; - -struct spacemit_reset_signal { - u32 offset; - u32 mask; - u32 deassert_val; - u32 assert_val; - enum spacemit_reset_base_type type; -}; - -struct spacemit_reset_base { - void __iomem *mpmu_base; - void __iomem *apmu_base; - void __iomem *apbc_base; - void __iomem *apbs_base; - void __iomem *ciu_base; - void __iomem *dciu_base; - void __iomem *ddrc_base; - void __iomem *audio_ctrl_base; - void __iomem *apbc2_base; -}; - -struct spacemit_reset { - struct spacemit_reset_base io_base; - const struct spacemit_reset_signal *signals; -}; - -enum { - RESET_TWSI6_SPL = 0, - RESET_TWSI8_SPL, - RESET_SDH_AXI_SPL, - RESET_SDH0_SPL, - RESET_USB_AXI_SPL, - RESET_USBP1_AXI_SPL, - RESET_USB3_0_SPL, - RESET_QSPI_SPL, - RESET_QSPI_BUS_SPL, - RESET_AES_SPL, - RESET_SDH2_SPL, - RESET_NUMBER_SPL -}; - -static const struct spacemit_reset_signal - k1_reset_signals[RESET_NUMBER] = { - [RESET_UART1] = { APBC_UART1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_UART2] = { APBC_UART2_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_GPIO] = { APBC_GPIO_CLK_RST, BIT(2), 0, - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM0] = { APBC_PWM0_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM1] = { APBC_PWM1_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM2] = { APBC_PWM2_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM3] = { APBC_PWM3_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM4] = { APBC_PWM4_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM5] = { APBC_PWM5_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM6] = { APBC_PWM6_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM7] = { APBC_PWM7_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM8] = { APBC_PWM8_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM9] = { APBC_PWM9_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM10] = { APBC_PWM10_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM11] = { APBC_PWM11_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM12] = { APBC_PWM12_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM13] = { APBC_PWM13_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM14] = { APBC_PWM14_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM15] = { APBC_PWM15_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM16] = { APBC_PWM16_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM17] = { APBC_PWM17_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM18] = { APBC_PWM18_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_PWM19] = { APBC_PWM19_CLK_RST, - BIT(2) | BIT(0), - BIT(0), - BIT(2), - RST_BASE_TYPE_APBC }, - [RESET_SSP3] = { APBC_SSP3_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_UART3] = { APBC_UART3_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_RTC] = { APBC_RTC_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_TWSI0] = { APBC_TWSI0_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_TIMERS1] = { APBC_TIMERS1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_AIB] = { APBC_AIB_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_TIMERS2] = { APBC_TIMERS2_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_ONEWIRE] = { APBC_ONEWIRE_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_SSPA0] = { APBC_SSPA0_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_SSPA1] = { APBC_SSPA1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_DRO] = { APBC_DRO_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_IR] = { APBC_IR_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_TWSI1] = { APBC_TWSI1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_TSEN] = { APBC_TSEN_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_TWSI2] = { APBC_TWSI2_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_TWSI4] = { APBC_TWSI4_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_TWSI5] = { APBC_TWSI5_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_TWSI6] = { APBC_TWSI6_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_TWSI7] = { APBC_TWSI7_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_TWSI8] = { APBC_TWSI8_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_IPC_AP2AUD] = { APBC_IPC_AP2AUD_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_UART4] = { APBC_UART4_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_UART5] = { APBC_UART5_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_UART6] = { APBC_UART6_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_UART7] = { APBC_UART7_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_UART8] = { APBC_UART8_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_UART9] = { APBC_UART9_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - [RESET_CAN0] = { APBC_CAN0_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC }, - /* MPMU */ - [RESET_WDT] = { MPMU_WDTPCR, BIT(2), 0, BIT(2), RST_BASE_TYPE_MPMU }, - /* APMU */ - [RESET_JPG] = { APMU_JPG_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU }, - [RESET_CSI] = { APMU_CSI_CCIC2_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU }, - [RESET_CCIC2_PHY] = { APMU_CSI_CCIC2_CLK_RES_CTRL, - BIT(2), - BIT(2), - 0, - RST_BASE_TYPE_APMU }, - [RESET_CCIC3_PHY] = { APMU_CSI_CCIC2_CLK_RES_CTRL, - BIT(29), - BIT(29), - 0, - RST_BASE_TYPE_APMU }, - [RESET_ISP] = { APMU_ISP_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU }, - [RESET_ISP_AHB] = { APMU_ISP_CLK_RES_CTRL, BIT(3), BIT(3), 0, RST_BASE_TYPE_APMU }, - [RESET_ISP_CI] = { APMU_ISP_CLK_RES_CTRL, BIT(16), BIT(16), 0, RST_BASE_TYPE_APMU }, - [RESET_ISP_CPP] = { APMU_ISP_CLK_RES_CTRL, BIT(27), BIT(27), 0, RST_BASE_TYPE_APMU }, - [RESET_LCD] = { APMU_LCD_CLK_RES_CTRL1, BIT(4), BIT(4), 0, RST_BASE_TYPE_APMU }, - [RESET_DSI_ESC] = { APMU_LCD_CLK_RES_CTRL1, BIT(3), BIT(3), 0, RST_BASE_TYPE_APMU }, - [RESET_V2D] = { APMU_LCD_CLK_RES_CTRL1, BIT(27), BIT(27), 0, RST_BASE_TYPE_APMU }, - [RESET_MIPI] = { APMU_LCD_CLK_RES_CTRL1, BIT(15), BIT(15), 0, RST_BASE_TYPE_APMU }, - [RESET_LCD_SPI] = { APMU_LCD_SPI_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU }, - [RESET_LCD_SPI_BUS] = { APMU_LCD_SPI_CLK_RES_CTRL, - BIT(4), - BIT(4), - 0, - RST_BASE_TYPE_APMU }, - [RESET_LCD_SPI_HBUS] = { APMU_LCD_SPI_CLK_RES_CTRL, - BIT(2), - BIT(2), - 0, - RST_BASE_TYPE_APMU }, - [RESET_LCD_MCLK] = { APMU_LCD_CLK_RES_CTRL2, BIT(9), BIT(9), 0, RST_BASE_TYPE_APMU }, - [RESET_CCIC_4X] = { APMU_CCIC_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU }, - [RESET_CCIC1_PHY] = { APMU_CCIC_CLK_RES_CTRL, BIT(2), BIT(2), 0, RST_BASE_TYPE_APMU }, - [RESET_SDH_AXI] = { APMU_SDH0_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU }, - [RESET_SDH0] = { APMU_SDH0_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU }, - [RESET_SDH1] = { APMU_SDH1_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU }, - [RESET_USB_AXI] = { APMU_USB_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU }, - [RESET_USBP1_AXI] = { APMU_USB_CLK_RES_CTRL, BIT(4), BIT(4), 0, RST_BASE_TYPE_APMU }, - [RESET_USB3_0] = { APMU_USB_CLK_RES_CTRL, - BIT(9) | BIT(10) | BIT(11), - BIT(9) | BIT(10) | BIT(11), - 0, - RST_BASE_TYPE_APMU }, - [RESET_QSPI] = { APMU_QSPI_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU }, - [RESET_QSPI_BUS] = { APMU_QSPI_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU }, - [RESET_DMA] = { APMU_DMA_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU }, - [RESET_AES] = { APMU_AES_CLK_RES_CTRL, BIT(4), BIT(4), 0, RST_BASE_TYPE_APMU }, - [RESET_VPU] = { APMU_VPU_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU }, - [RESET_GPU] = { APMU_GPU_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU }, - [RESET_SDH2] = { APMU_SDH2_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU }, - [RESET_MC] = { APMU_PMUA_MC_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU }, - [RESET_EM_AXI] = { APMU_PMUA_EM_CLK_RES_CTRL, BIT(0), BIT(0), 0, RST_BASE_TYPE_APMU }, - [RESET_EM] = { APMU_PMUA_EM_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU }, - [RESET_AUDIO_SYS] = { APMU_AUDIO_CLK_RES_CTRL, - BIT(0) | BIT(2) | BIT(3), - BIT(0) | BIT(2) | BIT(3), - 0, - RST_BASE_TYPE_APMU }, - [RESET_HDMI] = { APMU_HDMI_CLK_RES_CTRL, BIT(9), BIT(9), 0, RST_BASE_TYPE_APMU }, - [RESET_PCIE0] = { APMU_PCIE_CLK_RES_CTRL_0, - BIT(3) | BIT(4) | BIT(5) | BIT(8), - BIT(3) | BIT(4) | BIT(5), - BIT(8), - RST_BASE_TYPE_APMU }, - [RESET_PCIE1] = { APMU_PCIE_CLK_RES_CTRL_1, - BIT(3) | BIT(4) | BIT(5) | BIT(8), - BIT(3) | BIT(4) | BIT(5), - BIT(8), - RST_BASE_TYPE_APMU }, - [RESET_PCIE2] = { APMU_PCIE_CLK_RES_CTRL_2, 0x138, 0x38, 0x100, RST_BASE_TYPE_APMU }, - [RESET_EMAC0] = { APMU_EMAC0_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU }, - [RESET_EMAC1] = { APMU_EMAC1_CLK_RES_CTRL, BIT(1), BIT(1), 0, RST_BASE_TYPE_APMU }, - [RESET_SEC_UART1] = { APBC2_UART1_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 }, - [RESET_SEC_SSP2] = { APBC2_SSP2_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 }, - [RESET_SEC_TWSI3] = { APBC2_TWSI3_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 }, - [RESET_SEC_RTC] = { APBC2_RTC_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 }, - [RESET_SEC_TIMERS0] = { APBC2_TIMERS0_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 }, - [RESET_SEC_KPC] = { APBC2_KPC_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 }, - [RESET_SEC_GPIO] = { APBC2_GPIO_CLK_RST, BIT(2), 0, BIT(2), RST_BASE_TYPE_APBC2 }, - }; - -static u32 spacemit_reset_read(struct spacemit_reset *reset, u32 id) -{ - void __iomem *base; - - switch (reset->signals[id].type) { - case RST_BASE_TYPE_APMU: - base = reset->io_base.apmu_base; - break; - case RST_BASE_TYPE_APBC: - base = reset->io_base.apbc_base; - break; - default: - base = reset->io_base.apbc_base; - break; - } - - return readl(base + reset->signals[id].offset); -} - -static void spacemit_reset_write(struct spacemit_reset *reset, u32 value, u32 id) -{ - void __iomem *base; - - switch (reset->signals[id].type) { - case RST_BASE_TYPE_APMU: - base = reset->io_base.apmu_base; - break; - case RST_BASE_TYPE_APBC: - base = reset->io_base.apbc_base; - break; - default: - base = reset->io_base.apbc_base; - break; - } - - writel(value, base + reset->signals[id].offset); -} - -static void spacemit_reset_set(struct reset_ctl *rst, u32 id, bool assert) -{ - u32 value; - struct spacemit_reset *reset = dev_get_priv(rst->dev); - - value = spacemit_reset_read(reset, id); - - if (assert) { - value &= ~reset->signals[id].mask; - value |= reset->signals[id].assert_val; - } else { - value &= ~reset->signals[id].mask; - value |= reset->signals[id].deassert_val; - } - - spacemit_reset_write(reset, value, id); -} - -static int spacemit_reset_update(struct reset_ctl *rst, bool assert) -{ - if (rst->id < RESET_UART1 || rst->id >= RESET_NUMBER) - return 0; - - /* can not write to twsi8 */ - if (rst->id == RESET_TWSI8) - return 0; - - spacemit_reset_set(rst, rst->id, assert); - return 0; -} - -static int spacemit_reset_assert(struct reset_ctl *rst) -{ - return spacemit_reset_update(rst, true); -} - -static int spacemit_reset_deassert(struct reset_ctl *rst) -{ - return spacemit_reset_update(rst, false); -} - -static int spacemit_k1_reset_probe(struct udevice *dev) -{ - struct spacemit_reset *reset = dev_get_priv(dev); - - reset->io_base.mpmu_base = (void *)dev_remap_addr_index(dev, 0); - if (!reset->io_base.mpmu_base) { - pr_err("failed to map mpmu registers\n"); - goto out; - } - - reset->io_base.apmu_base = (void *)dev_remap_addr_index(dev, 1); - if (!reset->io_base.apmu_base) { - pr_err("failed to map apmu registers\n"); - goto out; - } - - reset->io_base.apbc_base = (void *)dev_remap_addr_index(dev, 2); - if (!reset->io_base.apbc_base) { - pr_err("failed to map apbc registers\n"); - goto out; - } - - reset->io_base.apbs_base = (void *)dev_remap_addr_index(dev, 3); - if (!reset->io_base.apbs_base) { - pr_err("failed to map apbs registers\n"); - goto out; - } - - reset->io_base.ciu_base = (void *)dev_remap_addr_index(dev, 4); - if (!reset->io_base.ciu_base) { - pr_err("failed to map ciu registers\n"); - goto out; - } - - reset->io_base.dciu_base = (void *)dev_remap_addr_index(dev, 5); - if (!reset->io_base.dciu_base) { - pr_err("failed to map dragon ciu registers\n"); - goto out; - } - - reset->io_base.ddrc_base = (void *)dev_remap_addr_index(dev, 6); - if (!reset->io_base.ddrc_base) { - pr_err("failed to map ddrc registers\n"); - goto out; - } - - reset->io_base.apbc2_base = (void *)dev_remap_addr_index(dev, 7); - if (!reset->io_base.apbc2_base) { - pr_err("failed to map apbc2 registers\n"); - goto out; - } - - reset->signals = k1_reset_signals; - -out: - return 0; -} - -const struct reset_ops k1_reset_ops = { - .rst_assert = spacemit_reset_assert, - .rst_deassert = spacemit_reset_deassert, -}; - -static const struct udevice_id k1_reset_ids[] = { - { .compatible = "spacemit,k1-reset", }, - {}, -}; - -U_BOOT_DRIVER(k1_reset) = { - .name = "spacemit,k1-reset", - .id = UCLASS_RESET, - .ops = &k1_reset_ops, - .of_match = k1_reset_ids, - .probe = spacemit_k1_reset_probe, - .priv_auto = sizeof(struct spacemit_reset), -}; diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c index fd47e1f9e37..6195edd5b2f 100644 --- a/drivers/reset/reset-sunxi.c +++ b/drivers/reset/reset-sunxi.c @@ -67,7 +67,7 @@ static int sunxi_reset_deassert(struct reset_ctl *reset_ctl) return sunxi_set_reset(reset_ctl, true); } -struct reset_ops sunxi_reset_ops = { +static const struct reset_ops sunxi_reset_ops = { .request = sunxi_reset_request, .rst_assert = sunxi_reset_assert, .rst_deassert = sunxi_reset_deassert, diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c index fe4cebf54f1..c199e3e5da7 100644 --- a/drivers/reset/reset-uclass.c +++ b/drivers/reset/reset-uclass.c @@ -13,6 +13,7 @@ #include <reset-uclass.h> #include <dm/devres.h> #include <dm/lists.h> +#include <linux/delay.h> static inline struct reset_ops *reset_dev_ops(struct udevice *dev) { @@ -225,6 +226,39 @@ int reset_deassert_bulk(struct reset_ctl_bulk *bulk) return 0; } +int reset_reset(struct reset_ctl *reset_ctl, ulong delay_us) +{ + struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); + int ret; + + debug("%s(reset_ctl=%p, delay_us=%lu)\n", __func__, reset_ctl, + delay_us); + + if (ops->rst_reset) + return ops->rst_reset(reset_ctl, delay_us); + + ret = reset_assert(reset_ctl); + if (ret < 0) + return ret; + + udelay(delay_us); + + return reset_deassert(reset_ctl); +} + +int reset_reset_bulk(struct reset_ctl_bulk *bulk, ulong delay_us) +{ + int i, ret; + + for (i = 0; i < bulk->count; i++) { + ret = reset_reset(&bulk->resets[i], delay_us); + if (ret < 0) + return ret; + } + + return 0; +} + int reset_status(struct reset_ctl *reset_ctl) { struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c index d04e8eef3bb..2b58f3a75b4 100644 --- a/drivers/reset/reset-zynqmp.c +++ b/drivers/reset/reset-zynqmp.c @@ -45,6 +45,16 @@ static int zynqmp_reset_deassert(struct reset_ctl *rst) PM_RESET_ACTION_RELEASE); } +static int zynqmp_reset_reset(struct reset_ctl *rst, ulong delay_us) +{ + struct zynqmp_reset_priv *priv = dev_get_priv(rst->dev); + + dev_dbg(rst->dev, "%s(rst=%p) (id=%lu)\n", __func__, rst, rst->id); + + return zynqmp_pm_reset_assert(priv->reset_id + rst->id, + PM_RESET_ACTION_PULSE); +} + static int zynqmp_reset_request(struct reset_ctl *rst) { struct zynqmp_reset_priv *priv = dev_get_priv(rst->dev); @@ -74,6 +84,7 @@ const struct reset_ops zynqmp_reset_ops = { .request = zynqmp_reset_request, .rst_assert = zynqmp_reset_assert, .rst_deassert = zynqmp_reset_deassert, + .rst_reset = zynqmp_reset_reset, }; static const struct udevice_id zynqmp_reset_ids[] = { diff --git a/drivers/reset/sandbox-reset-test.c b/drivers/reset/sandbox-reset-test.c index dfacb764bc7..64c205596c5 100644 --- a/drivers/reset/sandbox-reset-test.c +++ b/drivers/reset/sandbox-reset-test.c @@ -96,6 +96,20 @@ int sandbox_reset_test_deassert_bulk(struct udevice *dev) return reset_deassert_bulk(sbrt->bulkp); } +int sandbox_reset_test_reset(struct udevice *dev) +{ + struct sandbox_reset_test *sbrt = dev_get_priv(dev); + + return reset_reset(sbrt->ctlp, 0); +} + +int sandbox_reset_test_reset_bulk(struct udevice *dev) +{ + struct sandbox_reset_test *sbrt = dev_get_priv(dev); + + return reset_reset_bulk(sbrt->bulkp, 0); +} + int sandbox_reset_test_free(struct udevice *dev) { struct sandbox_reset_test *sbrt = dev_get_priv(dev); diff --git a/drivers/reset/sandbox-reset.c b/drivers/reset/sandbox-reset.c index adf9eedcba6..12812f0f340 100644 --- a/drivers/reset/sandbox-reset.c +++ b/drivers/reset/sandbox-reset.c @@ -9,12 +9,14 @@ #include <reset-uclass.h> #include <asm/io.h> #include <asm/reset.h> +#include <linux/delay.h> #define SANDBOX_RESET_SIGNALS 101 struct sandbox_reset_signal { bool asserted; bool requested; + int reset_count; }; struct sandbox_reset { @@ -31,6 +33,7 @@ static int sandbox_reset_request(struct reset_ctl *reset_ctl) return -EINVAL; sbr->signals[reset_ctl->id].requested = true; + sbr->signals[reset_ctl->id].reset_count = 0; return 0; } @@ -66,6 +69,21 @@ static int sandbox_reset_deassert(struct reset_ctl *reset_ctl) return 0; } +static int sandbox_reset_reset(struct reset_ctl *reset_ctl, ulong delay_us) +{ + struct sandbox_reset *sbr = dev_get_priv(reset_ctl->dev); + + debug("%s(reset_ctl=%p, delay_us=%lu)\n", __func__, reset_ctl, + delay_us); + + sbr->signals[reset_ctl->id].asserted = true; + udelay(delay_us); + sbr->signals[reset_ctl->id].asserted = false; + sbr->signals[reset_ctl->id].reset_count++; + + return 0; +} + static int sandbox_reset_bind(struct udevice *dev) { debug("%s(dev=%p)\n", __func__, dev); @@ -85,11 +103,12 @@ static const struct udevice_id sandbox_reset_ids[] = { { } }; -struct reset_ops sandbox_reset_reset_ops = { +static const struct reset_ops sandbox_reset_reset_ops = { .request = sandbox_reset_request, .rfree = sandbox_reset_free, .rst_assert = sandbox_reset_assert, .rst_deassert = sandbox_reset_deassert, + .rst_reset = sandbox_reset_reset, }; U_BOOT_DRIVER(sandbox_reset) = { @@ -102,6 +121,33 @@ U_BOOT_DRIVER(sandbox_reset) = { .ops = &sandbox_reset_reset_ops, }; +/* + * Second sandbox reset controller for tests: same assert/deassert + * behaviour as sandbox_reset, but no rst_reset so reset_reset() uses + * the core assert / udelay / deassert fallback (reset_count never bumps). + */ +static const struct udevice_id sandbox_reset_fallback_ids[] = { + { .compatible = "sandbox,reset-ctl-fallback-only" }, + { } +}; + +static const struct reset_ops sandbox_reset_fallback_reset_ops = { + .request = sandbox_reset_request, + .rfree = sandbox_reset_free, + .rst_assert = sandbox_reset_assert, + .rst_deassert = sandbox_reset_deassert, +}; + +U_BOOT_DRIVER(sandbox_reset_fallback) = { + .name = "sandbox_reset_fallback", + .id = UCLASS_RESET, + .of_match = sandbox_reset_fallback_ids, + .bind = sandbox_reset_bind, + .probe = sandbox_reset_probe, + .priv_auto = sizeof(struct sandbox_reset), + .ops = &sandbox_reset_fallback_reset_ops, +}; + int sandbox_reset_query(struct udevice *dev, unsigned long id) { struct sandbox_reset *sbr = dev_get_priv(dev); @@ -125,3 +171,15 @@ int sandbox_reset_is_requested(struct udevice *dev, unsigned long id) return sbr->signals[id].requested; } + +int sandbox_reset_get_count(struct udevice *dev, unsigned long id) +{ + struct sandbox_reset *sbr = dev_get_priv(dev); + + debug("%s(dev=%p, id=%ld)\n", __func__, dev, id); + + if (id >= SANDBOX_RESET_SIGNALS) + return -EINVAL; + + return sbr->signals[id].reset_count; +} diff --git a/drivers/reset/spacemit/Makefile b/drivers/reset/spacemit/Makefile new file mode 100644 index 00000000000..16722c68954 --- /dev/null +++ b/drivers/reset/spacemit/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# SpacemiT reset drivers + +obj-y += reset-spacemit-k1.o diff --git a/drivers/reset/spacemit/reset-spacemit-k1.c b/drivers/reset/spacemit/reset-spacemit-k1.c new file mode 100644 index 00000000000..129e1cc96f1 --- /dev/null +++ b/drivers/reset/spacemit/reset-spacemit-k1.c @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SpacemiT K1 reset driver (syscon-bound). + * + * Copyright (C) 2022 Spacemit Inc. + * Copyright (C) 2025 Huan Zhou <[email protected]> + * Copyright (C) 2026 RISCstar Ltd. + */ + +#include <asm/io.h> +#include <dm.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dt-bindings/clock/spacemit,k1-syscon.h> +#include <linux/bitops.h> +#include <malloc.h> +#include <reset-uclass.h> +#include <soc/spacemit/k1-reset.h> +#include <soc/spacemit/k1-syscon.h> + +/* =================================================================== + * Per-syscon reset signal tables. + * + * Indexed by the kernel-side per-syscon-local IDs from + * <dt-bindings/clock/spacemit,k1-syscon.h>. Each entry is + * (offset, assert_mask, deassert_mask): bits in assert_mask are set + * when the reset line is asserted; bits in deassert_mask are set when + * deasserted; the union (assert_mask | deassert_mask) is the set of + * bits the controller will overwrite on each transition. + * + * Layout mirrors the kernel-side K1 reset driver. + * =================================================================== + */ + +struct spacemit_k1_reset_data { + u32 offset; + u32 assert_mask; + u32 deassert_mask; +}; + +#define RESET_DATA(o, a, d) { \ + .offset = (o), .assert_mask = (a), .deassert_mask = (d) \ +} + +static const struct spacemit_k1_reset_data k1_mpmu_resets[] = { + [RESET_WDT] = RESET_DATA(MPMU_WDTPCR, BIT(2), 0), +}; + +static const struct spacemit_k1_reset_data k1_apbc_resets[] = { + [RESET_UART0] = RESET_DATA(APBC_UART1_CLK_RST, BIT(2), 0), + [RESET_UART2] = RESET_DATA(APBC_UART2_CLK_RST, BIT(2), 0), + [RESET_UART3] = RESET_DATA(APBC_UART3_CLK_RST, BIT(2), 0), + [RESET_UART4] = RESET_DATA(APBC_UART4_CLK_RST, BIT(2), 0), + [RESET_UART5] = RESET_DATA(APBC_UART5_CLK_RST, BIT(2), 0), + [RESET_UART6] = RESET_DATA(APBC_UART6_CLK_RST, BIT(2), 0), + [RESET_UART7] = RESET_DATA(APBC_UART7_CLK_RST, BIT(2), 0), + [RESET_UART8] = RESET_DATA(APBC_UART8_CLK_RST, BIT(2), 0), + [RESET_UART9] = RESET_DATA(APBC_UART9_CLK_RST, BIT(2), 0), + [RESET_GPIO] = RESET_DATA(APBC_GPIO_CLK_RST, BIT(2), 0), + [RESET_PWM0] = RESET_DATA(APBC_PWM0_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM1] = RESET_DATA(APBC_PWM1_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM2] = RESET_DATA(APBC_PWM2_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM3] = RESET_DATA(APBC_PWM3_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM4] = RESET_DATA(APBC_PWM4_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM5] = RESET_DATA(APBC_PWM5_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM6] = RESET_DATA(APBC_PWM6_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM7] = RESET_DATA(APBC_PWM7_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM8] = RESET_DATA(APBC_PWM8_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM9] = RESET_DATA(APBC_PWM9_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM10] = RESET_DATA(APBC_PWM10_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM11] = RESET_DATA(APBC_PWM11_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM12] = RESET_DATA(APBC_PWM12_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM13] = RESET_DATA(APBC_PWM13_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM14] = RESET_DATA(APBC_PWM14_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM15] = RESET_DATA(APBC_PWM15_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM16] = RESET_DATA(APBC_PWM16_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM17] = RESET_DATA(APBC_PWM17_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM18] = RESET_DATA(APBC_PWM18_CLK_RST, BIT(2), BIT(0)), + [RESET_PWM19] = RESET_DATA(APBC_PWM19_CLK_RST, BIT(2), BIT(0)), + [RESET_SSP3] = RESET_DATA(APBC_SSP3_CLK_RST, BIT(2), 0), + [RESET_RTC] = RESET_DATA(APBC_RTC_CLK_RST, BIT(2), 0), + [RESET_TWSI0] = RESET_DATA(APBC_TWSI0_CLK_RST, BIT(2), 0), + [RESET_TWSI1] = RESET_DATA(APBC_TWSI1_CLK_RST, BIT(2), 0), + [RESET_TWSI2] = RESET_DATA(APBC_TWSI2_CLK_RST, BIT(2), 0), + [RESET_TWSI4] = RESET_DATA(APBC_TWSI4_CLK_RST, BIT(2), 0), + [RESET_TWSI5] = RESET_DATA(APBC_TWSI5_CLK_RST, BIT(2), 0), + [RESET_TWSI6] = RESET_DATA(APBC_TWSI6_CLK_RST, BIT(2), 0), + [RESET_TWSI7] = RESET_DATA(APBC_TWSI7_CLK_RST, BIT(2), 0), + [RESET_TWSI8] = RESET_DATA(APBC_TWSI8_CLK_RST, BIT(2), 0), + [RESET_TIMERS1] = RESET_DATA(APBC_TIMERS1_CLK_RST, BIT(2), 0), + [RESET_TIMERS2] = RESET_DATA(APBC_TIMERS2_CLK_RST, BIT(2), 0), + [RESET_AIB] = RESET_DATA(APBC_AIB_CLK_RST, BIT(2), 0), + [RESET_ONEWIRE] = RESET_DATA(APBC_ONEWIRE_CLK_RST, BIT(2), 0), + [RESET_SSPA0] = RESET_DATA(APBC_SSPA0_CLK_RST, BIT(2), 0), + [RESET_SSPA1] = RESET_DATA(APBC_SSPA1_CLK_RST, BIT(2), 0), + [RESET_DRO] = RESET_DATA(APBC_DRO_CLK_RST, BIT(2), 0), + [RESET_IR] = RESET_DATA(APBC_IR_CLK_RST, BIT(2), 0), + [RESET_TSEN] = RESET_DATA(APBC_TSEN_CLK_RST, BIT(2), 0), + [RESET_IPC_AP2AUD] = RESET_DATA(APBC_IPC_AP2AUD_CLK_RST, BIT(2), 0), + [RESET_CAN0] = RESET_DATA(APBC_CAN0_CLK_RST, BIT(2), 0), +}; + +static const struct spacemit_k1_reset_data k1_apmu_resets[] = { + [RESET_CCIC_4X] = RESET_DATA(APMU_CCIC_CLK_RES_CTRL, 0, BIT(1)), + [RESET_CCIC1_PHY] = RESET_DATA(APMU_CCIC_CLK_RES_CTRL, 0, BIT(2)), + [RESET_SDH_AXI] = RESET_DATA(APMU_SDH0_CLK_RES_CTRL, 0, BIT(0)), + [RESET_SDH0] = RESET_DATA(APMU_SDH0_CLK_RES_CTRL, 0, BIT(1)), + [RESET_SDH1] = RESET_DATA(APMU_SDH1_CLK_RES_CTRL, 0, BIT(1)), + [RESET_SDH2] = RESET_DATA(APMU_SDH2_CLK_RES_CTRL, 0, BIT(1)), + [RESET_USBP1_AXI] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(4)), + [RESET_USB_AXI] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(0)), + [RESET_USB30_AHB] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(9)), + [RESET_USB30_VCC] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(10)), + [RESET_USB30_PHY] = RESET_DATA(APMU_USB_CLK_RES_CTRL, 0, BIT(11)), + [RESET_QSPI] = RESET_DATA(APMU_QSPI_CLK_RES_CTRL, 0, BIT(1)), + [RESET_QSPI_BUS] = RESET_DATA(APMU_QSPI_CLK_RES_CTRL, 0, BIT(0)), + [RESET_DMA] = RESET_DATA(APMU_DMA_CLK_RES_CTRL, 0, BIT(0)), + [RESET_AES] = RESET_DATA(APMU_AES_CLK_RES_CTRL, 0, BIT(4)), + [RESET_VPU] = RESET_DATA(APMU_VPU_CLK_RES_CTRL, 0, BIT(0)), + [RESET_GPU] = RESET_DATA(APMU_GPU_CLK_RES_CTRL, 0, BIT(1)), + [RESET_EMMC] = RESET_DATA(APMU_PMUA_EM_CLK_RES_CTRL, 0, BIT(1)), + [RESET_EMMC_X] = RESET_DATA(APMU_PMUA_EM_CLK_RES_CTRL, 0, BIT(0)), + [RESET_AUDIO_SYS] = RESET_DATA(APMU_AUDIO_CLK_RES_CTRL, 0, BIT(0)), + [RESET_AUDIO_MCU] = RESET_DATA(APMU_AUDIO_CLK_RES_CTRL, 0, BIT(2)), + [RESET_AUDIO_APMU] = RESET_DATA(APMU_AUDIO_CLK_RES_CTRL, 0, BIT(3)), + [RESET_HDMI] = RESET_DATA(APMU_HDMI_CLK_RES_CTRL, 0, BIT(9)), + [RESET_PCIE0_DBI] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_0, 0, BIT(3)), + [RESET_PCIE0_SLAVE] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_0, 0, BIT(4)), + [RESET_PCIE0_MASTER] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_0, 0, BIT(5)), + [RESET_PCIE0_GLOBAL] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_0, BIT(8), 0), + [RESET_PCIE1_DBI] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_1, 0, BIT(3)), + [RESET_PCIE1_SLAVE] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_1, 0, BIT(4)), + [RESET_PCIE1_MASTER] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_1, 0, BIT(5)), + [RESET_PCIE1_GLOBAL] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_1, BIT(8), 0), + [RESET_PCIE2_DBI] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_2, 0, BIT(3)), + [RESET_PCIE2_SLAVE] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_2, 0, BIT(4)), + [RESET_PCIE2_MASTER] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_2, 0, BIT(5)), + [RESET_PCIE2_GLOBAL] = RESET_DATA(APMU_PCIE_CLK_RES_CTRL_2, BIT(8), 0), + [RESET_EMAC0] = RESET_DATA(APMU_EMAC0_CLK_RES_CTRL, 0, BIT(1)), + [RESET_EMAC1] = RESET_DATA(APMU_EMAC1_CLK_RES_CTRL, 0, BIT(1)), + [RESET_JPG] = RESET_DATA(APMU_JPG_CLK_RES_CTRL, 0, BIT(0)), + [RESET_CCIC2PHY] = RESET_DATA(APMU_CSI_CCIC2_CLK_RES_CTRL, 0, BIT(2)), + [RESET_CCIC3PHY] = RESET_DATA(APMU_CSI_CCIC2_CLK_RES_CTRL, 0, BIT(29)), + [RESET_CSI] = RESET_DATA(APMU_CSI_CCIC2_CLK_RES_CTRL, 0, BIT(1)), + [RESET_ISP] = RESET_DATA(APMU_ISP_CLK_RES_CTRL, 0, BIT(0)), + [RESET_ISP_CPP] = RESET_DATA(APMU_ISP_CLK_RES_CTRL, 0, BIT(27)), + [RESET_ISP_BUS] = RESET_DATA(APMU_ISP_CLK_RES_CTRL, 0, BIT(3)), + [RESET_ISP_CI] = RESET_DATA(APMU_ISP_CLK_RES_CTRL, 0, BIT(16)), + [RESET_DPU_MCLK] = RESET_DATA(APMU_LCD_CLK_RES_CTRL2, 0, BIT(9)), + [RESET_DPU_ESC] = RESET_DATA(APMU_LCD_CLK_RES_CTRL1, 0, BIT(3)), + [RESET_DPU_HCLK] = RESET_DATA(APMU_LCD_CLK_RES_CTRL1, 0, BIT(4)), + [RESET_DPU_SPIBUS] = RESET_DATA(APMU_LCD_SPI_CLK_RES_CTRL, 0, BIT(4)), + [RESET_DPU_SPI_HBUS] = RESET_DATA(APMU_LCD_SPI_CLK_RES_CTRL, 0, BIT(2)), + [RESET_V2D] = RESET_DATA(APMU_LCD_CLK_RES_CTRL1, 0, BIT(27)), + [RESET_MIPI] = RESET_DATA(APMU_LCD_CLK_RES_CTRL1, 0, BIT(15)), + [RESET_MC] = RESET_DATA(APMU_PMUA_MC_CTRL, 0, BIT(0)), +}; + +static const struct spacemit_k1_reset_data k1_apbc2_resets[] = { + [RESET_APBC2_UART1] = RESET_DATA(APBC2_UART1_CLK_RST, BIT(2), 0), + [RESET_APBC2_SSP2] = RESET_DATA(APBC2_SSP2_CLK_RST, BIT(2), 0), + [RESET_APBC2_TWSI3] = RESET_DATA(APBC2_TWSI3_CLK_RST, BIT(2), 0), + [RESET_APBC2_RTC] = RESET_DATA(APBC2_RTC_CLK_RST, BIT(2), 0), + [RESET_APBC2_TIMERS0] = RESET_DATA(APBC2_TIMERS0_CLK_RST, BIT(2), 0), + [RESET_APBC2_KPC] = RESET_DATA(APBC2_KPC_CLK_RST, BIT(2), 0), + [RESET_APBC2_GPIO] = RESET_DATA(APBC2_GPIO_CLK_RST, BIT(2), 0), +}; + +/* =================================================================== + * Driver + * =================================================================== + */ + +struct spacemit_k1_reset_priv { + void __iomem *base; + const struct spacemit_k1_reset_data *table; + size_t table_size; +}; + +static int spacemit_k1_reset_xfer(struct reset_ctl *rst, bool assert) +{ + struct spacemit_k1_reset_priv *priv = dev_get_priv(rst->dev); + const struct spacemit_k1_reset_data *e; + u32 v; + + if (rst->id >= priv->table_size) + return -EINVAL; + + e = &priv->table[rst->id]; + if (e->assert_mask == 0 && e->deassert_mask == 0) + return -EINVAL; /* not owned by this syscon */ + + v = readl(priv->base + e->offset); + v &= ~(e->assert_mask | e->deassert_mask); + v |= assert ? e->assert_mask : e->deassert_mask; + writel(v, priv->base + e->offset); + + return 0; +} + +static int spacemit_k1_reset_assert(struct reset_ctl *rst) +{ + return spacemit_k1_reset_xfer(rst, true); +} + +static int spacemit_k1_reset_deassert(struct reset_ctl *rst) +{ + return spacemit_k1_reset_xfer(rst, false); +} + +static int spacemit_k1_reset_request(struct reset_ctl *rst) +{ + struct spacemit_k1_reset_priv *priv = dev_get_priv(rst->dev); + + return rst->id < priv->table_size ? 0 : -EINVAL; +} + +static const struct reset_ops spacemit_k1_reset_ops = { + .request = spacemit_k1_reset_request, + .rst_assert = spacemit_k1_reset_assert, + .rst_deassert = spacemit_k1_reset_deassert, +}; + +static int spacemit_k1_reset_probe(struct udevice *dev) +{ + struct spacemit_k1_reset_priv *priv = dev_get_priv(dev); + + priv->base = (void __iomem *)dev_remap_addr(dev); + if (!priv->base) + return -ENODEV; + + return 0; +} + +U_BOOT_DRIVER(spacemit_k1_reset) = { + .name = "spacemit_k1_reset", + .id = UCLASS_RESET, + .ops = &spacemit_k1_reset_ops, + .probe = spacemit_k1_reset_probe, + .priv_auto = sizeof(struct spacemit_k1_reset_priv), + .flags = DM_FLAG_PRE_RELOC, +}; + +int spacemit_k1_reset_bind(struct udevice *parent, + enum spacemit_k1_reset_syscon syscon) +{ + struct spacemit_k1_reset_priv *priv; + struct udevice *rst_dev; + const struct spacemit_k1_reset_data *table; + size_t table_size; + int ret; + + switch (syscon) { + case SPACEMIT_K1_RESET_MPMU: + table = k1_mpmu_resets; + table_size = ARRAY_SIZE(k1_mpmu_resets); + break; + case SPACEMIT_K1_RESET_APMU: + table = k1_apmu_resets; + table_size = ARRAY_SIZE(k1_apmu_resets); + break; + case SPACEMIT_K1_RESET_APBC: + table = k1_apbc_resets; + table_size = ARRAY_SIZE(k1_apbc_resets); + break; + case SPACEMIT_K1_RESET_APBC2: + table = k1_apbc2_resets; + table_size = ARRAY_SIZE(k1_apbc2_resets); + break; + default: + return -EINVAL; + } + + ret = device_bind_driver_to_node(parent, "spacemit_k1_reset", "reset", + dev_ofnode(parent), &rst_dev); + if (ret) + return ret; + + priv = malloc(sizeof(*priv)); + if (!priv) { + device_unbind(rst_dev); + return -ENOMEM; + } + priv->table = table; + priv->table_size = table_size; + dev_set_priv(rst_dev, priv); + + return 0; +} diff --git a/drivers/reset/sti-reset.c b/drivers/reset/sti-reset.c index 412a0c5b452..37a37a72fd3 100644 --- a/drivers/reset/sti-reset.c +++ b/drivers/reset/sti-reset.c @@ -290,7 +290,7 @@ static int sti_reset_deassert(struct reset_ctl *reset_ctl) return sti_reset_program_hw(reset_ctl, false); } -struct reset_ops sti_reset_ops = { +static const struct reset_ops sti_reset_ops = { .rst_assert = sti_reset_assert, .rst_deassert = sti_reset_deassert, }; diff --git a/drivers/reset/stm32/stm32-reset-mp21.c b/drivers/reset/stm32/stm32-reset-mp21.c index 7d169d7582f..0e92b0f5d5d 100644 --- a/drivers/reset/stm32/stm32-reset-mp21.c +++ b/drivers/reset/stm32/stm32-reset-mp21.c @@ -5,7 +5,7 @@ */ #include <dm.h> -#include <stm32-reset-core.h> +#include "stm32-reset-core.h" #include <stm32mp21_rcc.h> #include <dt-bindings/reset/st,stm32mp21-rcc.h> diff --git a/drivers/reset/tegra-car-reset.c b/drivers/reset/tegra-car-reset.c index e3ecc8d3735..63f148cf3d9 100644 --- a/drivers/reset/tegra-car-reset.c +++ b/drivers/reset/tegra-car-reset.c @@ -42,7 +42,7 @@ static int tegra_car_reset_deassert(struct reset_ctl *reset_ctl) return 0; } -struct reset_ops tegra_car_reset_ops = { +static const struct reset_ops tegra_car_reset_ops = { .request = tegra_car_reset_request, .rst_assert = tegra_car_reset_assert, .rst_deassert = tegra_car_reset_deassert, diff --git a/drivers/reset/tegra186-reset.c b/drivers/reset/tegra186-reset.c index 89624227c29..1d8f40acaef 100644 --- a/drivers/reset/tegra186-reset.c +++ b/drivers/reset/tegra186-reset.c @@ -43,7 +43,7 @@ static int tegra186_reset_deassert(struct reset_ctl *reset_ctl) return tegra186_reset_common(reset_ctl, CMD_RESET_DEASSERT); } -struct reset_ops tegra186_reset_ops = { +static const struct reset_ops tegra186_reset_ops = { .rst_assert = tegra186_reset_assert, .rst_deassert = tegra186_reset_deassert, }; diff --git a/drivers/rng/iproc_rng200.c b/drivers/rng/iproc_rng200.c index 4c49aa9e444..aa211df28cd 100644 --- a/drivers/rng/iproc_rng200.c +++ b/drivers/rng/iproc_rng200.c @@ -155,7 +155,7 @@ static int iproc_rng200_of_to_plat(struct udevice *dev) { struct iproc_rng200_plat *pdata = dev_get_plat(dev); - pdata->base = devfdt_map_physmem(dev, sizeof(void *)); + pdata->base = dev_remap_addr(dev); if (!pdata->base) return -ENODEV; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 65d9bf533cb..6fb3019a644 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -44,8 +44,8 @@ config VPL_DM_RTC config RTC_ENABLE_32KHZ_OUTPUT bool "Enable RTC 32Khz output" help - Some real-time clocks support the output of 32kHz square waves (such as ds3231), - the config symbol choose Real Time Clock device 32Khz output feature. + Some real-time clocks support the output of 32kHz square waves (such as ds3231), + the config symbol choose Real Time Clock device 32Khz output feature. config RTC_ARMADA38X bool "Enable Armada 38x Marvell SoC RTC" @@ -163,6 +163,9 @@ config RTC_PCF85063 help If you say yes here you get support for the NXP PCF85063 RTC and compatible chips. + Support for the following chip features is currently not implemented: + - NVMEM device for RAM register + - CLKOUT generation config RTC_PCF8563 bool "Philips PCF8563" diff --git a/drivers/rtc/ds1307.c b/drivers/rtc/ds1307.c index 04921099101..4176ab3701e 100644 --- a/drivers/rtc/ds1307.c +++ b/drivers/rtc/ds1307.c @@ -68,157 +68,6 @@ enum ds_type { #define MCP7941X_BIT_ST 0x80 #define MCP7941X_BIT_VBATEN 0x08 -#ifndef CONFIG_DM_RTC - -/*---------------------------------------------------------------------*/ -#undef DEBUG_RTC - -#ifdef DEBUG_RTC -#define DEBUGR(fmt, args...) printf(fmt, ##args) -#else -#define DEBUGR(fmt, args...) -#endif -/*---------------------------------------------------------------------*/ - -#ifndef CFG_SYS_I2C_RTC_ADDR -# define CFG_SYS_I2C_RTC_ADDR 0x68 -#endif - -#if defined(CONFIG_RTC_DS1307) && (CONFIG_SYS_I2C_SPEED > 100000) -# error The DS1307 is specified only up to 100kHz! -#endif - -static uchar rtc_read (uchar reg); -static void rtc_write (uchar reg, uchar val); - -/* - * Get the current time from the RTC - */ -int rtc_get (struct rtc_time *tmp) -{ - int rel = 0; - uchar sec, min, hour, mday, wday, mon, year; - -#ifdef CONFIG_RTC_MCP79411 -read_rtc: -#endif - sec = rtc_read (RTC_SEC_REG_ADDR); - min = rtc_read (RTC_MIN_REG_ADDR); - hour = rtc_read (RTC_HR_REG_ADDR); - wday = rtc_read (RTC_DAY_REG_ADDR); - mday = rtc_read (RTC_DATE_REG_ADDR); - mon = rtc_read (RTC_MON_REG_ADDR); - year = rtc_read (RTC_YR_REG_ADDR); - - DEBUGR ("Get RTC year: %02x mon: %02x mday: %02x wday: %02x " - "hr: %02x min: %02x sec: %02x\n", - year, mon, mday, wday, hour, min, sec); - -#ifdef CONFIG_RTC_DS1307 - if (sec & RTC_SEC_BIT_CH) { - printf ("### Warning: RTC oscillator has stopped\n"); - /* clear the CH flag */ - rtc_write (RTC_SEC_REG_ADDR, - rtc_read (RTC_SEC_REG_ADDR) & ~RTC_SEC_BIT_CH); - rel = -1; - } -#endif - -#ifdef CONFIG_RTC_MCP79411 - /* make sure that the backup battery is enabled */ - if (!(wday & MCP7941X_BIT_VBATEN)) { - rtc_write(RTC_DAY_REG_ADDR, - wday | MCP7941X_BIT_VBATEN); - } - - /* clock halted? turn it on, so clock can tick. */ - if (!(sec & MCP7941X_BIT_ST)) { - rtc_write(RTC_SEC_REG_ADDR, MCP7941X_BIT_ST); - printf("Started RTC\n"); - goto read_rtc; - } -#endif - - tmp->tm_sec = bcd2bin (sec & 0x7F); - tmp->tm_min = bcd2bin (min & 0x7F); - tmp->tm_hour = bcd2bin (hour & 0x3F); - tmp->tm_mday = bcd2bin (mday & 0x3F); - tmp->tm_mon = bcd2bin (mon & 0x1F); - tmp->tm_year = bcd2bin (year) + ( bcd2bin (year) >= 70 ? 1900 : 2000); - tmp->tm_wday = bcd2bin ((wday - 1) & 0x07); - tmp->tm_yday = 0; - tmp->tm_isdst= 0; - - DEBUGR ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", - tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - - return rel; -} - -/* - * Set the RTC - */ -int rtc_set (struct rtc_time *tmp) -{ - DEBUGR ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", - tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, - tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - - if (tmp->tm_year < 1970 || tmp->tm_year > 2069) - printf("WARNING: year should be between 1970 and 2069!\n"); - - rtc_write (RTC_YR_REG_ADDR, bin2bcd (tmp->tm_year % 100)); - rtc_write (RTC_MON_REG_ADDR, bin2bcd (tmp->tm_mon)); -#ifdef CONFIG_RTC_MCP79411 - rtc_write (RTC_DAY_REG_ADDR, - bin2bcd (tmp->tm_wday + 1) | MCP7941X_BIT_VBATEN); -#else - rtc_write (RTC_DAY_REG_ADDR, bin2bcd (tmp->tm_wday + 1)); -#endif - rtc_write (RTC_DATE_REG_ADDR, bin2bcd (tmp->tm_mday)); - rtc_write (RTC_HR_REG_ADDR, bin2bcd (tmp->tm_hour)); - rtc_write (RTC_MIN_REG_ADDR, bin2bcd (tmp->tm_min)); -#ifdef CONFIG_RTC_MCP79411 - rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec) | MCP7941X_BIT_ST); -#else - rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec)); -#endif - - return 0; -} - -/* - * Reset the RTC. We setting the date back to 1970-01-01. - * We also enable the oscillator output on the SQW/OUT pin and program - * it for 32,768 Hz output. Note that according to the datasheet, turning - * on the square wave output increases the current drain on the backup - * battery to something between 480nA and 800nA. - */ -void rtc_reset (void) -{ - rtc_write (RTC_SEC_REG_ADDR, 0x00); /* clearing Clock Halt */ - rtc_write (RTC_CTL_REG_ADDR, RTC_CTL_BIT_SQWE | RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS0); -} - -/* - * Helper functions - */ - -static -uchar rtc_read (uchar reg) -{ - return (i2c_reg_read (CFG_SYS_I2C_RTC_ADDR, reg)); -} - -static void rtc_write (uchar reg, uchar val) -{ - i2c_reg_write (CFG_SYS_I2C_RTC_ADDR, reg, val); -} - -#endif /* !CONFIG_DM_RTC */ - -#ifdef CONFIG_DM_RTC static int ds1307_rtc_set(struct udevice *dev, const struct rtc_time *tm) { int ret; @@ -267,9 +116,9 @@ static int ds1307_rtc_get(struct udevice *dev, struct rtc_time *tm) if (ret < 0) return ret; - if (type == ds_1337 || type == ds_1340) { - uint reg = (type == ds_1337) ? DS1337_STAT_REG_ADDR : - DS1340_STAT_REG_ADDR; + if (type == ds_1337 || type == ds_1339 || type == ds_1340) { + uint reg = (type == ds_1340) ? DS1340_STAT_REG_ADDR : + DS1337_STAT_REG_ADDR; int status = dm_i2c_reg_read(dev, reg); if (status >= 0 && (status & RTC_STAT_BIT_OSF)) { @@ -366,4 +215,3 @@ U_BOOT_DRIVER(rtc_ds1307) = { .of_match = ds1307_rtc_ids, .ops = &ds1307_rtc_ops, }; -#endif /* CONFIG_DM_RTC */ diff --git a/drivers/rtc/goldfish_rtc.c b/drivers/rtc/goldfish_rtc.c index d2991ca6719..652eec7dd0c 100644 --- a/drivers/rtc/goldfish_rtc.c +++ b/drivers/rtc/goldfish_rtc.c @@ -40,8 +40,8 @@ static int goldfish_rtc_get(struct udevice *dev, struct rtc_time *time) u64 time_low; u64 now; - time_low = ioread32(base + GOLDFISH_TIME_LOW); - time_high = ioread32(base + GOLDFISH_TIME_HIGH); + time_low = __raw_readl(base + GOLDFISH_TIME_LOW); + time_high = __raw_readl(base + GOLDFISH_TIME_HIGH); now = (time_high << 32) | time_low; do_div(now, 1000000000U); @@ -62,8 +62,8 @@ static int goldfish_rtc_set(struct udevice *dev, const struct rtc_time *time) return -EINVAL; now = rtc_mktime(time) * 1000000000ULL; - iowrite32(now >> 32, base + GOLDFISH_TIME_HIGH); - iowrite32(now, base + GOLDFISH_TIME_LOW); + __raw_writel(now >> 32, base + GOLDFISH_TIME_HIGH); + __raw_writel(now, base + GOLDFISH_TIME_LOW); if (time->tm_isdst > 0) priv->isdst = 1; @@ -80,9 +80,13 @@ static int goldfish_rtc_of_to_plat(struct udevice *dev) struct goldfish_rtc_plat *plat = dev_get_plat(dev); fdt_addr_t addr; + plat->reg = 0; + addr = dev_read_addr(dev); - if (addr != FDT_ADDR_T_NONE) - plat->reg = addr; + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + plat->reg = addr; return 0; } diff --git a/drivers/rtc/i2c_rtc_emul.c b/drivers/rtc/i2c_rtc_emul.c index ea11c72c964..41bdf275f1e 100644 --- a/drivers/rtc/i2c_rtc_emul.c +++ b/drivers/rtc/i2c_rtc_emul.c @@ -191,7 +191,7 @@ static int sandbox_i2c_rtc_xfer(struct udevice *emul, struct i2c_msg *msg, return 0; } -struct dm_i2c_ops sandbox_i2c_rtc_emul_ops = { +static const struct dm_i2c_ops sandbox_i2c_rtc_emul_ops = { .xfer = sandbox_i2c_rtc_xfer, }; diff --git a/drivers/rtc/m41t62.c b/drivers/rtc/m41t62.c index 7bfea9e0b31..b3734baf63e 100644 --- a/drivers/rtc/m41t62.c +++ b/drivers/rtc/m41t62.c @@ -66,7 +66,7 @@ static void m41t62_update_rtc_time(struct rtc_time *tm, u8 *buf) { debug("%s: raw read data - sec=%02x, min=%02x, hr=%02x, " "mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n", - __FUNCTION__, + __func__, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); @@ -83,7 +83,7 @@ static void m41t62_update_rtc_time(struct rtc_time *tm, u8 *buf) debug("%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, + __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); } diff --git a/drivers/rtc/mcfrtc.c b/drivers/rtc/mcfrtc.c index 9708971c5c4..23ffb2b31a1 100644 --- a/drivers/rtc/mcfrtc.c +++ b/drivers/rtc/mcfrtc.c @@ -73,7 +73,7 @@ int rtc_set(struct rtc_time *tmp) days += month_days[i]; if (i == 1) - days += isleap(i); + days += isleap(tmp->tm_year); } days += tmp->tm_mday - 1; diff --git a/drivers/rtc/pcf85063.c b/drivers/rtc/pcf85063.c index 737d4547aca..421c42c0b81 100644 --- a/drivers/rtc/pcf85063.c +++ b/drivers/rtc/pcf85063.c @@ -11,11 +11,33 @@ #include <dm/device_compat.h> #define PCF85063_REG_CTRL1 0x00 /* status */ -#define PCF85063_REG_CTRL1_SR 0x58 +#define PCF85063_REG_CTRL1_CAP_SEL BIT(0) +#define PCF85063_REG_CTRL1_STOP BIT(5) +#define PCF85063_REG_CTRL1_EXT_TEST BIT(7) +#define PCF85063_REG_CTRL1_SWR 0x58 /* Software reset command */ + +#define PCF85063_REG_CTRL2 0x01 +#define PCF85063_CTRL2_AF BIT(6) +#define PCF85063_CTRL2_AIE BIT(7) + +#define PCF85063_REG_OFFSET 0x02 +#define PCF85063_OFFSET_SIGN_BIT 6 /* 2's complement sign bit */ +#define PCF85063_OFFSET_MODE BIT(7) +#define PCF85063_OFFSET_STEP0 4340 +#define PCF85063_OFFSET_STEP1 4069 + +#define PCF85063_REG_CLKO_F_MASK 0x07 /* frequency mask */ +#define PCF85063_REG_CLKO_F_32768HZ 0x00 +#define PCF85063_REG_CLKO_F_OFF 0x07 + +#define PCF85063_REG_RAM 0x03 #define PCF85063_REG_SC 0x04 /* datetime */ #define PCF85063_REG_SC_OS 0x80 +#define PCF85063_REG_ALM_S 0x0b +#define PCF85063_AEN BIT(7) + static int pcf85063_get_time(struct udevice *dev, struct rtc_time *tm) { u8 regs[7]; @@ -35,7 +57,9 @@ static int pcf85063_get_time(struct udevice *dev, struct rtc_time *tm) tm->tm_hour = bcd2bin(regs[2] & 0x3f); tm->tm_mday = bcd2bin(regs[3] & 0x3f); tm->tm_wday = regs[4] & 0x07; - tm->tm_mon = bcd2bin(regs[5] & 0x1f) - 1; + /* rtc register and rtc_time spec uses 1 - 12 */ + tm->tm_mon = bcd2bin(regs[5] & 0x1f); + /* adjust rtc_time (years since 0) to match register spec */ tm->tm_year = bcd2bin(regs[6]) + 2000; return 0; @@ -44,40 +68,102 @@ static int pcf85063_get_time(struct udevice *dev, struct rtc_time *tm) static int pcf85063_set_time(struct udevice *dev, const struct rtc_time *tm) { u8 regs[7]; + int rc; if (tm->tm_year < 2000 || tm->tm_year > 2099) { dev_err(dev, "Year must be between 2000 and 2099.\n"); return -EINVAL; } - regs[0] = bin2bcd(tm->tm_sec); + /* + * to accurately set the time, reset the divider chain and keep it in + * reset state until all time/date registers are written + */ + rc = dm_i2c_reg_clrset(dev, PCF85063_REG_CTRL1, + PCF85063_REG_CTRL1_EXT_TEST | + PCF85063_REG_CTRL1_STOP, + PCF85063_REG_CTRL1_STOP); + + if (rc) + return rc; + + /* hours, minutes and seconds */ + regs[0] = bin2bcd(tm->tm_sec) & (~PCF85063_REG_SC_OS); + regs[1] = bin2bcd(tm->tm_min); regs[2] = bin2bcd(tm->tm_hour); + + /* Day of month, 1 - 31 */ regs[3] = bin2bcd(tm->tm_mday); - regs[4] = tm->tm_wday; - regs[5] = bin2bcd(tm->tm_mon + 1); + + /* Day of week 0 - 6 */ + regs[4] = tm->tm_wday & 0x07; + + /* rtc register and rtc_time spec uses 1 - 12 */ + regs[5] = bin2bcd(tm->tm_mon); + /* adjust register to match rtc_time spec */ regs[6] = bin2bcd(tm->tm_year % 100); - return dm_i2c_write(dev, PCF85063_REG_SC, regs, sizeof(regs)); + rc = dm_i2c_write(dev, PCF85063_REG_SC, regs, sizeof(regs)); + if (rc) + return rc; + + /* + * Write the control register as a separate action since the size of + * the register space is different between the PCF85063TP and + * PCF85063A devices. The rollover point can not be used. + */ + return dm_i2c_reg_clrset(dev, PCF85063_REG_CTRL1, + PCF85063_REG_CTRL1_STOP, 0); } static int pcf85063_reset(struct udevice *dev) { - return dm_i2c_reg_write(dev, PCF85063_REG_CTRL1, PCF85063_REG_CTRL1_SR); + return dm_i2c_reg_write(dev, PCF85063_REG_CTRL1, PCF85063_REG_CTRL1_SWR); } static int pcf85063_read(struct udevice *dev, unsigned int offset, u8 *buf, unsigned int len) { + if (offset + len > dev->driver_data) + return -EINVAL; + return dm_i2c_read(dev, offset, buf, len); } static int pcf85063_write(struct udevice *dev, unsigned int offset, const u8 *buf, unsigned int len) { + if (offset + len > dev->driver_data) + return -EINVAL; + return dm_i2c_write(dev, offset, buf, len); } +static int pcf85063_load_capacitance(struct udevice *dev) +{ + u32 load = 7000; + u8 reg = 0; + + if (ofnode_read_u32(dev_ofnode(dev), "quartz-load-femtofarads", &load)) + return 0; + + switch (load) { + default: + dev_warn(dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000", + load); + fallthrough; + case 7000: + break; + case 12500: + reg = PCF85063_REG_CTRL1_CAP_SEL; + break; + } + + return dm_i2c_reg_clrset(dev, PCF85063_REG_CTRL1, + PCF85063_REG_CTRL1_CAP_SEL, reg); +} + static const struct rtc_ops pcf85063_rtc_ops = { .get = pcf85063_get_time, .set = pcf85063_set_time, @@ -88,13 +174,45 @@ static const struct rtc_ops pcf85063_rtc_ops = { static int pcf85063_probe(struct udevice *dev) { + u8 tmp; + int err; + i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS | DM_I2C_CHIP_WR_ADDRESS); + err = dm_i2c_read(dev, PCF85063_REG_SC, &tmp, sizeof(tmp)); + if (err) { + dev_err(dev, "RTC chip is not present\n"); + return err; + } + + /* + * If a Power loss is detected, SW reset the device. + * From PCF85063A datasheet: + * There is a low probability that some devices will have corruption + * of the registers after the automatic power-on reset... + */ + if (tmp & PCF85063_REG_SC_OS) { + dev_warn(dev, "POR issue detected, sending a SW reset\n"); + err = dm_i2c_reg_clrset(dev, PCF85063_REG_CTRL1, + 0xff, PCF85063_REG_CTRL1_SWR); + if (err < 0) + dev_warn(dev, "SW reset failed, trying to continue\n"); + } + + err = pcf85063_load_capacitance(dev); + if (err < 0) + dev_warn(dev, "failed to set xtal load capacitance: %d", + err); + return 0; } static const struct udevice_id pcf85063_of_id[] = { - { .compatible = "microcrystal,rv8263" }, + { .compatible = "microcrystal,rv8263", .data = 0x12 }, + { .compatible = "nxp,pcf85063", .data = 0xb }, + { .compatible = "nxp,pcf85063a", .data = 0x12 }, + { .compatible = "nxp,pcf85063tp", .data = 0xb }, + { .compatible = "nxp,pcf85073a", .data = 0x12 }, { } }; diff --git a/drivers/rtc/sandbox_rtc.c b/drivers/rtc/sandbox_rtc.c index 4404501c2f6..1ade5d50b23 100644 --- a/drivers/rtc/sandbox_rtc.c +++ b/drivers/rtc/sandbox_rtc.c @@ -73,7 +73,7 @@ static int sandbox_rtc_get_name(const struct udevice *dev, char *out_name) return acpi_copy_name(out_name, "RTCC"); } -struct acpi_ops sandbox_rtc_acpi_ops = { +static const struct acpi_ops sandbox_rtc_acpi_ops = { .get_name = sandbox_rtc_get_name, }; #endif diff --git a/drivers/scsi/sandbox_scsi.c b/drivers/scsi/sandbox_scsi.c index 544a0247083..5f0b01d86d5 100644 --- a/drivers/scsi/sandbox_scsi.c +++ b/drivers/scsi/sandbox_scsi.c @@ -128,7 +128,7 @@ static int sandbox_scsi_remove(struct udevice *dev) return 0; } -struct scsi_ops sandbox_scsi_ops = { +static const struct scsi_ops sandbox_scsi_ops = { .exec = sandbox_scsi_exec, .bus_reset = sandbox_scsi_bus_reset, }; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 116b696b08d..50e7d749921 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -82,23 +82,6 @@ static void scsi_setup_inquiry(struct scsi_cmd *pccb) pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ } -static void scsi_setup_sync_cache(struct scsi_cmd *pccb, lbaint_t start, - lbaint_t blocks) -{ - pccb->cmd[0] = SCSI_SYNC_CACHE; - pccb->cmd[1] = 0; - pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; - pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; - pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; - pccb->cmd[5] = (unsigned char)start & 0xff; - pccb->cmd[6] = 0; - pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff; - pccb->cmd[8] = (unsigned char)blocks & 0xff; - pccb->cmd[9] = 0; - pccb->cmdlen = 10; - pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ -} - static void scsi_setup_read_ext(struct scsi_cmd *pccb, lbaint_t start, lbaint_t blocks) { @@ -124,7 +107,7 @@ static void scsi_setup_write_ext(struct scsi_cmd *pccb, lbaint_t start, lbaint_t blocks) { pccb->cmd[0] = SCSI_WRITE10; - pccb->cmd[1] = 0; + pccb->cmd[1] = 0x08; /* Set FUA bit to bypass write cache */ pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; @@ -301,11 +284,6 @@ static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, buf_addr += pccb->datalen; } while (blks != 0); - /* Flush the SCSI cache so we don't lose data on board reset. */ - scsi_setup_sync_cache(pccb, 0, 0); - if (scsi_exec(bdev, pccb)) - scsi_print_error(pccb); - debug("%s: end startblk " LBAF ", blccnt " LBAF " buffer %lX\n", __func__, start, blocks, buf_addr); return blkcnt; diff --git a/drivers/scsi/scsi_bootdev.c b/drivers/scsi/scsi_bootdev.c index 28e4612f337..541b021b732 100644 --- a/drivers/scsi/scsi_bootdev.c +++ b/drivers/scsi/scsi_bootdev.c @@ -37,9 +37,6 @@ static int scsi_bootdev_hunt(struct bootdev_hunter *info, bool show) return 0; } -struct bootdev_ops scsi_bootdev_ops = { -}; - static const struct udevice_id scsi_bootdev_ids[] = { { .compatible = "u-boot,bootdev-scsi" }, { } @@ -48,7 +45,6 @@ static const struct udevice_id scsi_bootdev_ids[] = { U_BOOT_DRIVER(scsi_bootdev) = { .name = "scsi_bootdev", .id = UCLASS_BOOTDEV, - .ops = &scsi_bootdev_ops, .bind = scsi_bootdev_bind, .of_match = scsi_bootdev_ids, }; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 5f8b98f0704..e221800d5d0 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -759,11 +759,11 @@ config MVEBU_A3700_UART config MCFUART bool "Freescale ColdFire UART support" depends on M68K - help - Choose this option to add support for UART driver on the ColdFire - SoC's family. The serial communication channel provides a full-duplex - asynchronous/synchronous receiver and transmitter deriving an - operating frequency from the internal bus clock or an external clock. + help + Choose this option to add support for UART driver on the ColdFire + SoC's family. The serial communication channel provides a full-duplex + asynchronous/synchronous receiver and transmitter deriving an + operating frequency from the internal bus clock or an external clock. config MXC_UART bool "IMX serial port support" @@ -1024,12 +1024,12 @@ config OCTEON_SERIAL_BOOTCMD bool "MIPS Octeon PCI remote bootcmd input" depends on ARCH_OCTEON depends on DM_SERIAL - select SYS_IS_IN_ENV + select SYS_CONSOLE_IS_IN_ENV select CONSOLE_MUX help - This driver supports remote input over the PCIe bus from a host - to U-Boot for entering commands. It is utilized by the host - commands 'oct-remote-load' and 'oct-remote-bootcmd'. + This driver supports remote input over the PCIe bus from a host + to U-Boot for entering commands. It is utilized by the host + commands 'oct-remote-load' and 'oct-remote-bootcmd'. config OCTEON_SERIAL_PCIE_CONSOLE bool "MIPS Octeon PCIe remote console" diff --git a/drivers/serial/serial_cortina.c b/drivers/serial/serial_cortina.c index 3ae8fb46584..de8af5b0574 100644 --- a/drivers/serial/serial_cortina.c +++ b/drivers/serial/serial_cortina.c @@ -83,11 +83,13 @@ int ca_serial_setbrg(struct udevice *dev, int baudrate) static int ca_serial_getc(struct udevice *dev) { struct ca_uart_priv *priv = dev_get_priv(dev); - int ch; + unsigned int status; - ch = readl(priv->base + URX_DATA) & 0xFF; + status = readl(priv->base + UINFO); + if (status & UINFO_RX_FIFO_EMPTY) + return -EAGAIN; - return (int)ch; + return readl(priv->base + URX_DATA) & 0xFF; } static int ca_serial_putc(struct udevice *dev, const char ch) diff --git a/drivers/serial/serial_goldfish.c b/drivers/serial/serial_goldfish.c index 91dc040fcf2..732f167caae 100644 --- a/drivers/serial/serial_goldfish.c +++ b/drivers/serial/serial_goldfish.c @@ -74,8 +74,10 @@ static int goldfish_serial_of_to_plat(struct udevice *dev) fdt_addr_t addr; addr = dev_read_addr(dev); - if (addr != FDT_ADDR_T_NONE) - plat->reg = addr; + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + plat->reg = addr; return 0; } diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c index 9fdb6503085..917445e1ee2 100644 --- a/drivers/serial/serial_lpuart.c +++ b/drivers/serial/serial_lpuart.c @@ -53,11 +53,7 @@ #define FIFO_RXSIZE_MASK 0x7 #define FIFO_RXSIZE_OFF 0 #define FIFO_TXFE 0x80 -#if defined(CONFIG_ARCH_IMX8) || defined(CONFIG_ARCH_IMXRT) #define FIFO_RXFE 0x08 -#else -#define FIFO_RXFE 0x40 -#endif #define WATER_TXWATER_OFF 0 #define WATER_RXWATER_OFF 16 @@ -366,10 +362,14 @@ static int _lpuart32_serial_putc(struct lpuart_serial_plat *plat, static int _lpuart32_serial_tstc(struct lpuart_serial_plat *plat) { struct lpuart_fsl_reg32 *base = plat->reg; - u32 water; + u32 stat, water; lpuart_read32(plat->flags, &base->water, &water); + lpuart_read32(plat->flags, &base->stat, &stat); + if (stat & STAT_OR) + lpuart_write32(plat->flags, &base->stat, STAT_OR); + if ((water >> 24) == 0) return 0; @@ -523,8 +523,7 @@ static int lpuart_serial_probe(struct udevice *dev) static int lpuart_serial_of_to_plat(struct udevice *dev) { struct lpuart_serial_plat *plat = dev_get_plat(dev); - const void *blob = gd->fdt_blob; - int node = dev_of_offset(dev); + ofnode node = dev_ofnode(dev); fdt_addr_t addr; addr = dev_read_addr(dev); @@ -534,18 +533,18 @@ static int lpuart_serial_of_to_plat(struct udevice *dev) plat->reg = (void *)addr; plat->flags = dev_get_driver_data(dev); - if (fdtdec_get_bool(blob, node, "little-endian")) + if (ofnode_read_bool(node, "little-endian")) plat->flags &= ~LPUART_FLAG_REGMAP_ENDIAN_BIG; - if (!fdt_node_check_compatible(blob, node, "fsl,ls1021a-lpuart")) + if (ofnode_device_is_compatible(node, "fsl,ls1021a-lpuart")) plat->devtype = DEV_LS1021A; - else if (!fdt_node_check_compatible(blob, node, "fsl,imx7ulp-lpuart")) + else if (ofnode_device_is_compatible(node, "fsl,imx7ulp-lpuart")) plat->devtype = DEV_MX7ULP; - else if (!fdt_node_check_compatible(blob, node, "fsl,vf610-lpuart")) + else if (ofnode_device_is_compatible(node, "fsl,vf610-lpuart")) plat->devtype = DEV_VF610; - else if (!fdt_node_check_compatible(blob, node, "fsl,imx8qm-lpuart")) + else if (ofnode_device_is_compatible(node, "fsl,imx8qm-lpuart")) plat->devtype = DEV_IMX8; - else if (!fdt_node_check_compatible(blob, node, "fsl,imxrt-lpuart")) + else if (ofnode_device_is_compatible(node, "fsl,imxrt-lpuart")) plat->devtype = DEV_IMXRT; return 0; diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c index 3dca581f68f..ae4015e0fdc 100644 --- a/drivers/serial/serial_msm_geni.c +++ b/drivers/serial/serial_msm_geni.c @@ -55,6 +55,7 @@ #define SE_UART_RX_PARITY_CFG 0x2a8 #define DEF_TX_WM 2 +#define DEF_RX_WM 2 /* GENI_FORCE_DEFAULT_REG fields */ #define UART_START_READ 0x1 @@ -345,6 +346,7 @@ static void qcom_geni_serial_start_rx(struct udevice *dev) geni_se_setup_s_cmd(priv->base, UART_START_READ, 0); + writel(DEF_RX_WM, priv->base + SE_GENI_RX_WATERMARK_REG); setbits_le32(priv->base + SE_GENI_S_IRQ_EN, S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN); setbits_le32(priv->base + SE_GENI_M_IRQ_EN, M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN); } @@ -373,6 +375,7 @@ static void msm_geni_serial_setup_rx(struct udevice *dev) geni_se_setup_s_cmd(priv->base, UART_START_READ, 0); + writel(DEF_RX_WM, priv->base + SE_GENI_RX_WATERMARK_REG); setbits_le32(priv->base + SE_GENI_S_IRQ_EN, S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN); setbits_le32(priv->base + SE_GENI_M_IRQ_EN, M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN); } @@ -616,6 +619,7 @@ static inline void _debug_uart_init(void) phys_addr_t base = CONFIG_VAL(DEBUG_UART_BASE); geni_serial_init(&init_dev); + writel(DEF_RX_WM, base + SE_GENI_RX_WATERMARK_REG); geni_serial_baud(base, CLK_DIV, CONFIG_BAUDRATE); qcom_geni_serial_start_tx(base); } diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c index bc205234e24..7debff6cb3a 100644 --- a/drivers/serial/serial_sh.c +++ b/drivers/serial/serial_sh.c @@ -257,7 +257,7 @@ static int sh_serial_of_to_plat(struct udevice *dev) int ret; addr = dev_read_addr(dev); - if (!addr) + if (addr == FDT_ADDR_T_NONE) return -EINVAL; plat->base = addr; diff --git a/drivers/smem/Kconfig b/drivers/smem/Kconfig index e5d7dcc81b1..5b68ad5f10f 100644 --- a/drivers/smem/Kconfig +++ b/drivers/smem/Kconfig @@ -4,22 +4,22 @@ menuconfig SMEM if SMEM config SANDBOX_SMEM - bool "Sandbox Shared Memory Manager (SMEM)" - depends on SANDBOX && DM - help - enable SMEM support for sandbox. This is an emulation of a real SMEM - manager. - The sandbox driver allocates a shared memory from the heap and - initialzies it on start. + bool "Sandbox Shared Memory Manager (SMEM)" + depends on SANDBOX && DM + help + enable SMEM support for sandbox. This is an emulation of a real SMEM + manager. + The sandbox driver allocates a shared memory from the heap and + initialzies it on start. config MSM_SMEM - bool "Qualcomm Shared Memory Manager (SMEM)" - depends on DM - depends on ARCH_SNAPDRAGON || ARCH_IPQ40XX - select DEVRES - help - Enable support for the Qualcomm Shared Memory Manager. - The driver provides an interface to items in a heap shared among all - processors in a Qualcomm platform. + bool "Qualcomm Shared Memory Manager (SMEM)" + depends on DM + depends on ARCH_SNAPDRAGON || ARCH_IPQ40XX + select DEVRES + help + Enable support for the Qualcomm Shared Memory Manager. + The driver provides an interface to items in a heap shared among all + processors in a Qualcomm platform. endif # menu "SMEM Support" diff --git a/drivers/soc/soc_xilinx_zynqmp.c b/drivers/soc/soc_xilinx_zynqmp.c index b97cd443c60..0e13e230914 100644 --- a/drivers/soc/soc_xilinx_zynqmp.c +++ b/drivers/soc/soc_xilinx_zynqmp.c @@ -71,6 +71,11 @@ static const struct zynqmp_device zynqmp_devices[] = { .variants = ZYNQMP_VARIANT_EG_LR, }, { + .id = 0x0468A093, + .device = 1, + .variants = ZYNQMP_VARIANT_EG_LR, + }, + { .id = 0x04711093, .device = 2, .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG, @@ -209,6 +214,16 @@ static const struct zynqmp_device zynqmp_devices[] = { .variants = ZYNQMP_VARIANT_DR, }, { + .id = 0x047F9093, + .device = 58, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x047FC093, + .device = 59, + .variants = ZYNQMP_VARIANT_DR, + }, + { .id = 0x046d0093, .device = 67, .variants = ZYNQMP_VARIANT_DR, @@ -219,6 +234,36 @@ static const struct zynqmp_device zynqmp_devices[] = { .variants = ZYNQMP_VARIANT_DR_SE, }, { + .id = 0x046D1093, + .device = 65, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D2093, + .device = 55, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D3093, + .device = 57, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D4093, + .device = 42, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D5093, + .device = 63, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D6093, + .device = 64, + .variants = ZYNQMP_VARIANT_DR, + }, + { .id = 0x04712093, .device = 24, .variants = 0, @@ -313,7 +358,9 @@ static int soc_xilinx_zynqmp_detect_machine(struct udevice *dev, u32 idcode, } else if (device->variants & ZYNQMP_VARIANT_DR_SE) { strlcat(priv->machine, "dr_SE", sizeof(priv->machine)); } else if (device->variants & ZYNQMP_VARIANT_TEG) { - strlcat(priv->machine, "teg", sizeof(priv->machine)); + /* Devices with TEG variant might be TEG or TCG family */ + strlcat(priv->machine, (idcode2 & EFUSE_GPU_DIS_MASK) ? + "tcg" : "teg", sizeof(priv->machine)); } return 0; diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig index 36129cb72f6..9734bf32cb0 100644 --- a/drivers/soc/ti/Kconfig +++ b/drivers/soc/ti/Kconfig @@ -21,8 +21,8 @@ config TI_KEYSTONE_SERDES bool "Keystone SerDes driver for ethernet" depends on ARCH_KEYSTONE help - SerDes driver for Keystone SoC used for ethernet support on TI - K2 platforms. + SerDes driver for Keystone SoC used for ethernet support on TI + K2 platforms. config TI_PRUSS bool "Support for TI's K3 based Pruss driver" diff --git a/drivers/sound/da7219.c b/drivers/sound/da7219.c index 5b9b3f65263..d1d03ae91d4 100644 --- a/drivers/sound/da7219.c +++ b/drivers/sound/da7219.c @@ -170,7 +170,7 @@ static int da7219_acpi_setup_nhlt(const struct udevice *dev, } #endif -struct acpi_ops da7219_acpi_ops = { +static const struct acpi_ops da7219_acpi_ops = { #ifdef CONFIG_ACPIGEN .fill_ssdt = da7219_acpi_fill_ssdt, #ifdef CONFIG_X86 diff --git a/drivers/sound/max98357a.c b/drivers/sound/max98357a.c index da56ffdd6bb..47978d4fe27 100644 --- a/drivers/sound/max98357a.c +++ b/drivers/sound/max98357a.c @@ -136,7 +136,7 @@ static int max98357a_acpi_setup_nhlt(const struct udevice *dev, } #endif -struct acpi_ops max98357a_acpi_ops = { +static const struct acpi_ops max98357a_acpi_ops = { #ifdef CONFIG_ACPIGEN .fill_ssdt = max98357a_acpi_fill_ssdt, #ifdef CONFIG_X86 diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 4ff17617d99..007ad5e7733 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -2,10 +2,10 @@ menuconfig SPI bool "SPI Support" help The "Serial Peripheral Interface" is a low level synchronous - protocol. Chips that support SPI can have data transfer rates - up to several tens of Mbit/sec. Chips are addressed with a - controller and a chipselect. Most SPI slaves don't support - dynamic device discovery; some are even write-only or read-only. + protocol. Chips that support SPI can have data transfer rates + up to several tens of Mbit/sec. Chips are addressed with a + controller and a chipselect. Most SPI slaves don't support + dynamic device discovery; some are even write-only or read-only. SPI is widely used by microcontrollers to talk with sensors, eeprom and flash memory, codecs and various other controller @@ -200,11 +200,11 @@ config CADENCE_XSPI by using the Auto Command work mode. config CF_SPI - bool "ColdFire SPI driver" - depends on M68K - help - Enable the ColdFire SPI driver. This driver can be used on - some m68k SoCs. + bool "ColdFire SPI driver" + depends on M68K + help + Enable the ColdFire SPI driver. This driver can be used on + some m68k SoCs. config CV1800B_SPIF bool "Sophgo cv1800b SPI Flash Controller driver" @@ -352,7 +352,7 @@ config MTK_SNOR select DEVRES help Enable the Mediatek SPINOR controller driver. This driver has - better read/write performance with NOR. + better read/write performance with NOR. config MTK_SNFI_SPI bool "Mediatek SPI memory controller driver" @@ -544,11 +544,11 @@ config SPI_SIFIVE config SOFT_SPI bool "Soft SPI driver" help - Enable Soft SPI driver. This driver is to use GPIO simulate - the SPI protocol. + Enable Soft SPI driver. This driver is to use GPIO simulate + the SPI protocol. config SPI_SN_F_OSPI - tristate "Socionext F_OSPI SPI flash controller" + bool "Socionext F_OSPI SPI flash controller" select SPI_MEM help This enables support for the Socionext F_OSPI controller @@ -565,7 +565,7 @@ config SPI_SUNXI config STM32_OSPI bool "STM32MP2 OSPI driver" - depends on STM32MP25X && STM32_OMM + depends on (STM32MP23X || STM32MP25X) && STM32_OMM help Enable the STM32MP2 Octo-SPI (OSPI) driver. This driver can be used to access the SPI NOR flash chips on platforms embedding @@ -673,8 +673,8 @@ config ZYNQMP_GQSPI config SPI_STACKED_PARALLEL bool "Enable support for stacked or parallel memories" help - Enable support for stacked/or parallel memories. This functionality - may appear on Xilinx hardware. By default this is disabled. + Enable support for stacked/or parallel memories. This functionality + may appear on Xilinx hardware. By default this is disabled. endif # if DM_SPI diff --git a/drivers/spi/apple_spi.c b/drivers/spi/apple_spi.c index 5f94e9f7a74..acc87ea7bdc 100644 --- a/drivers/spi/apple_spi.c +++ b/drivers/spi/apple_spi.c @@ -228,7 +228,7 @@ static int apple_spi_set_mode(struct udevice *bus, uint mode) return 0; } -struct dm_spi_ops apple_spi_ops = { +static const struct dm_spi_ops apple_spi_ops = { .xfer = apple_spi_xfer, .set_speed = apple_spi_set_speed, .set_mode = apple_spi_set_mode, @@ -270,6 +270,7 @@ static int apple_spi_probe(struct udevice *dev) } static const struct udevice_id apple_spi_of_match[] = { + { .compatible = "apple,t8103-spi" }, { .compatible = "apple,spi" }, { /* sentinel */ } }; diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index 2a4a49c5f1c..984d4a39ded 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -31,6 +31,8 @@ #define CQSPI_DISABLE_STIG_MODE BIT(0) #define CQSPI_DMA_MODE BIT(1) +#define CQSPI_RESET_DELAY_US 10 + __weak int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv, const struct spi_mem_op *op) { @@ -256,19 +258,9 @@ static int cadence_spi_probe(struct udevice *bus) priv->resets = devm_reset_bulk_get_optional(bus); if (priv->resets) { - /* Assert all OSPI reset lines */ - ret = reset_assert_bulk(priv->resets); - if (ret) { - dev_err(bus, "Failed to assert OSPI reset: %d\n", ret); - return ret; - } - - udelay(10); - - /* Deassert all OSPI reset lines */ - ret = reset_deassert_bulk(priv->resets); + ret = reset_reset_bulk(priv->resets, CQSPI_RESET_DELAY_US); if (ret) { - dev_err(bus, "Failed to deassert OSPI reset: %d\n", ret); + dev_err(bus, "Failed to reset OSPI: %d\n", ret); return ret; } } diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c index b520c727900..0df9a4f5abd 100644 --- a/drivers/spi/designware_spi.c +++ b/drivers/spi/designware_spi.c @@ -497,6 +497,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, { struct udevice *bus = dev->parent; struct dw_spi_priv *priv = dev_get_priv(bus); + struct spi_slave *slave = dev_get_parent_priv(dev); const u8 *tx = dout; u8 *rx = din; int ret = 0; @@ -504,6 +505,17 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, u32 val; u32 cs; + /* Get bits_per_word from slave (set by device driver) */ + if (slave->bits_per_word >= 4 && slave->bits_per_word <= priv->max_xfer) { + priv->bits_per_word = slave->bits_per_word; + } else if (slave->bits_per_word == 0) { + priv->bits_per_word = 8; /* Default if not set */ + } else { + dev_warn(dev, "Invalid bits_per_word %u, using 8\n", + slave->bits_per_word); + priv->bits_per_word = 8; + } + /* spi core configured to do 8 bit transfers */ if (bitlen % 8) { dev_err(dev, "Non byte aligned SPI transfer.\n"); diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c index 117e36376b7..c5bc603b5c0 100644 --- a/drivers/spi/fsl_espi.c +++ b/drivers/spi/fsl_espi.c @@ -216,13 +216,13 @@ int espi_xfer(struct fsl_spi_slave *fsl, uint cs, unsigned int bitlen, break; case SPI_XFER_BEGIN | SPI_XFER_END: len = data_len; - buffer = (unsigned char *)malloc(len * 2); + buffer = (unsigned char *)malloc(len); if (!buffer) { debug("SF: Failed to malloc memory.\n"); return 1; } memcpy(buffer, data_out, len); - rx_offset = len; + rx_offset = 0; cmd_len = 0; break; } @@ -275,7 +275,7 @@ int espi_xfer(struct fsl_spi_slave *fsl, uint cs, unsigned int bitlen, } } if (data_in) { - memcpy(data_in, buffer + rx_offset, tran_len); + memcpy(data_in, buffer + 2 * cmd_len, tran_len); if (*buffer == 0x0b) { data_in += tran_len; data_len -= tran_len; diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c index 65ab3e306d7..5692510a558 100644 --- a/drivers/spi/fsl_qspi.c +++ b/drivers/spi/fsl_qspi.c @@ -267,6 +267,14 @@ static const struct fsl_qspi_devtype_data ls2080a_data = { .little_endian = true, }; +static const struct fsl_qspi_devtype_data spacemit_k1_data = { + .rxfifo = SZ_128, + .txfifo = SZ_256, + .ahb_buf_size = SZ_128, + .quirks = QUADSPI_QUIRK_TKT253890, + .little_endian = true, +}; + struct fsl_qspi { struct udevice *dev; void __iomem *iobase; @@ -870,6 +878,7 @@ static const struct udevice_id fsl_qspi_ids[] = { { .compatible = "fsl,ls1021a-qspi", .data = (ulong)&ls1021a_data, }, { .compatible = "fsl,ls1088a-qspi", .data = (ulong)&ls2080a_data, }, { .compatible = "fsl,ls2080a-qspi", .data = (ulong)&ls2080a_data, }, + { .compatible = "spacemit,k1-qspi", .data = (ulong)&spacemit_k1_data, }, { } }; diff --git a/drivers/spi/mtk_snor.c b/drivers/spi/mtk_snor.c index f202b2f49f5..40fc1826db6 100644 --- a/drivers/spi/mtk_snor.c +++ b/drivers/spi/mtk_snor.c @@ -1,10 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 -// -// Mediatek SPI-NOR controller driver -// -// Copyright (C) 2020 SkyLake Huang <[email protected]> -// -// Some parts are based on drivers/spi/spi-mtk-nor.c of linux version +/* + * Mediatek SPI-NOR controller driver + * + * Copyright (C) 2020 SkyLake Huang <[email protected]> + * + * Some parts are based on drivers/spi/spi-mtk-nor.c of linux version + */ #include <clk.h> #include <cpu_func.h> @@ -89,22 +90,33 @@ #define MTK_NOR_REG_DMA_END_DADR 0x724 #define MTK_NOR_PRG_MAX_SIZE 6 -// Reading DMA src/dst addresses have to be 16-byte aligned +#define MTK_NOR_PRG_CNT_MAX 56 +/* Reading DMA src/dst addresses have to be 16-byte aligned */ #define MTK_NOR_DMA_ALIGN 16 #define MTK_NOR_DMA_ALIGN_MASK (MTK_NOR_DMA_ALIGN - 1) -// and we allocate a bounce buffer if destination address isn't aligned. +/* and we allocate a bounce buffer if destination address isn't aligned. */ #define MTK_NOR_BOUNCE_BUF_SIZE PAGE_SIZE -// Buffered page program can do one 128-byte transfer +/* Buffered page program can do one 128-byte transfer */ #define MTK_NOR_PP_SIZE 128 #define CLK_TO_US(priv, clkcnt) DIV_ROUND_UP(clkcnt, (priv)->spi_freq / 1000000) #define MTK_NOR_UNLOCK_ALL 0x0 +struct mtk_snor_caps { + /* + * Some new SoCs modify the timing of fetching registers' values and IDs + * of NOR flash, they need a extra_bit which can add more clock cycles + * for fetching data. + */ + u8 extra_bit; +}; + struct mtk_snor_priv { struct device *dev; void __iomem *base; + const struct mtk_snor_caps *caps; u8 *buffer; struct clk spi_clk; struct clk ctlr_clk; @@ -168,8 +180,8 @@ static int mtk_snor_adjust_op_size(struct spi_slave *slave, return 0; if (op->addr.nbytes == 3 || op->addr.nbytes == 4) { - if (op->data.dir == SPI_MEM_DATA_IN) { //&& - // limit size to prevent timeout calculation overflow + if (op->data.dir == SPI_MEM_DATA_IN) { + /* limit size to prevent timeout calculation overflow */ if (op->data.nbytes > 0x400000) op->data.nbytes = 0x400000; if (op->addr.val & MTK_NOR_DMA_ALIGN_MASK || @@ -262,6 +274,7 @@ static int mtk_snor_read_bounce(struct mtk_snor_priv *priv, { unsigned int rdlen; int ret; + dma_addr_t bounce_dma; if (op->data.nbytes & MTK_NOR_DMA_ALIGN_MASK) rdlen = (op->data.nbytes + MTK_NOR_DMA_ALIGN) & @@ -269,11 +282,21 @@ static int mtk_snor_read_bounce(struct mtk_snor_priv *priv, else rdlen = op->data.nbytes; - ret = mtk_snor_dma_exec(priv, op->addr.val, rdlen, - (dma_addr_t)priv->buffer); + /* Map bounce buffer for DMA */ + bounce_dma = dma_map_single(priv->buffer, rdlen, DMA_FROM_DEVICE); + if (dma_mapping_error(priv->dev, bounce_dma)) { + dev_err(priv->dev, "bounce buffer dma map failed\n"); + return -EINVAL; + } - if (!ret) + ret = mtk_snor_dma_exec(priv, op->addr.val, rdlen, bounce_dma); + /* Ensure DMA writes are visible to CPU and copy the requested bytes */ + if (!ret) { + /* Synchronize cached data to CPU visible memory if needed */ memcpy(op->data.buf.in, priv->buffer, op->data.nbytes); + } + /* Unmap bounce buffer regardless of success/failure */ + dma_unmap_single(bounce_dma, rdlen, DMA_FROM_DEVICE); return ret; } @@ -361,8 +384,12 @@ static int mtk_snor_pp_buffered(struct mtk_snor_priv *priv, buf[i]; writel(val, priv->base + MTK_NOR_REG_PP_DATA); } - mtk_snor_cmd_exec(priv, MTK_NOR_CMD_WRITE, - (op->data.nbytes + 5) * BITS_PER_BYTE); + + ret = mtk_snor_cmd_exec(priv, MTK_NOR_CMD_WRITE, + (op->data.nbytes + 5) * BITS_PER_BYTE); + if (ret) + return ret; + return mtk_snor_write_buffer_disable(priv); } @@ -382,50 +409,83 @@ static int mtk_snor_pp_unbuffered(struct mtk_snor_priv *priv, static int mtk_snor_cmd_program(struct mtk_snor_priv *priv, const struct spi_mem_op *op) { - u32 tx_len = 0; - u32 trx_len = 0; + int rx_len = 0; int reg_offset = MTK_NOR_REG_PRGDATA_MAX; + int tx_len, prg_len; + int i, ret; void __iomem *reg; - u8 *txbuf; - int tx_cnt = 0; - u8 *rxbuf = op->data.buf.in; - int i = 0; + u8 val; + + tx_len = op->cmd.nbytes + op->addr.nbytes; - tx_len = 1 + op->addr.nbytes + op->dummy.nbytes; - trx_len = tx_len + op->data.nbytes; + /* count dummy bytes only if we need to write data after it */ if (op->data.dir == SPI_MEM_DATA_OUT) - tx_len += op->data.nbytes; + tx_len += op->dummy.nbytes + op->data.nbytes; + else if (op->data.dir == SPI_MEM_DATA_IN) + rx_len = op->data.nbytes; - txbuf = kmalloc_array(tx_len, sizeof(u8), GFP_KERNEL); - memset(txbuf, 0x0, tx_len * sizeof(u8)); + prg_len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes + + op->data.nbytes; - /* Join all bytes to be transferred */ - txbuf[tx_cnt] = op->cmd.opcode; - tx_cnt++; - for (i = op->addr.nbytes; i > 0; i--, tx_cnt++) - txbuf[tx_cnt] = ((u8 *)&op->addr.val)[i - 1]; - for (i = op->dummy.nbytes; i > 0; i--, tx_cnt++) - txbuf[tx_cnt] = 0x0; - if (op->data.dir == SPI_MEM_DATA_OUT) - for (i = op->data.nbytes; i > 0; i--, tx_cnt++) - txbuf[tx_cnt] = ((u8 *)op->data.buf.out)[i - 1]; + /* + * An invalid op may reach here if the caller calls exec_op without + * adjust_op_size. return -EINVAL instead of -ENOTSUPP so that + * spi-mem won't try this op again with generic spi transfers. + */ + if ((tx_len > MTK_NOR_REG_PRGDATA_MAX + 1) || + (rx_len > MTK_NOR_REG_SHIFT_MAX + 1) || + (prg_len > MTK_NOR_PRG_CNT_MAX / 8)) + return -EINVAL; - for (i = MTK_NOR_REG_PRGDATA_MAX; i >= 0; i--) - writeb(0, priv->base + MTK_NOR_REG_PRGDATA(i)); + /* fill tx data */ - for (i = 0; i < tx_len; i++, reg_offset--) - writeb(txbuf[i], priv->base + MTK_NOR_REG_PRGDATA(reg_offset)); + for (i = op->cmd.nbytes; i > 0; i--, reg_offset--) { + reg = priv->base + MTK_NOR_REG_PRGDATA(reg_offset); + val = (op->cmd.opcode >> ((i - 1) * BITS_PER_BYTE)) & 0xff; + writeb(val, reg); + } - kfree(txbuf); + for (i = op->addr.nbytes; i > 0; i--, reg_offset--) { + reg = priv->base + MTK_NOR_REG_PRGDATA(reg_offset); + val = (op->addr.val >> ((i - 1) * BITS_PER_BYTE)) & 0xff; + writeb(val, reg); + } - writel(trx_len * BITS_PER_BYTE, priv->base + MTK_NOR_REG_PRG_CNT); + if (op->data.dir == SPI_MEM_DATA_OUT) { + for (i = 0; i < op->dummy.nbytes; i++, reg_offset--) { + reg = priv->base + MTK_NOR_REG_PRGDATA(reg_offset); + writeb(0, reg); + } - mtk_snor_cmd_exec(priv, MTK_NOR_CMD_PROGRAM, trx_len * BITS_PER_BYTE); + for (i = 0; i < op->data.nbytes; i++, reg_offset--) { + reg = priv->base + MTK_NOR_REG_PRGDATA(reg_offset); + writeb(((const u8 *)(op->data.buf.out))[i], reg); + } + } - reg_offset = op->data.nbytes - 1; - for (i = 0; i < op->data.nbytes; i++, reg_offset--) { - reg = priv->base + MTK_NOR_REG_SHIFT(reg_offset); - rxbuf[i] = readb(reg); + for (; reg_offset >= 0; reg_offset--) { + reg = priv->base + MTK_NOR_REG_PRGDATA(reg_offset); + writeb(0, reg); + } + + /* trigger op */ + if (rx_len) + writel(prg_len * BITS_PER_BYTE + priv->caps->extra_bit, + priv->base + MTK_NOR_REG_PRG_CNT); + else + writel(prg_len * BITS_PER_BYTE, priv->base + MTK_NOR_REG_PRG_CNT); + + ret = mtk_snor_cmd_exec(priv, MTK_NOR_CMD_PROGRAM, prg_len * BITS_PER_BYTE); + if (ret) + return ret; + + /* fetch read data */ + reg_offset = 0; + if (op->data.dir == SPI_MEM_DATA_IN) { + for (i = op->data.nbytes - 1; i >= 0; i--, reg_offset++) { + reg = priv->base + MTK_NOR_REG_SHIFT(reg_offset); + ((u8 *)(op->data.buf.in))[i] = readb(reg); + } } return 0; @@ -467,12 +527,13 @@ static int mtk_snor_probe(struct udevice *bus) struct mtk_snor_priv *priv = dev_get_priv(bus); u8 *buffer; int ret; - u32 reg; priv->base = devfdt_get_addr_ptr(bus); if (!priv->base) return -EINVAL; + priv->caps = (const void *)dev_get_driver_data(bus); + ret = clk_get_by_name(bus, "spi", &priv->spi_clk); if (ret < 0) return ret; @@ -496,7 +557,8 @@ static int mtk_snor_probe(struct udevice *bus) priv->spi_freq = clk_get_rate(&priv->spi_clk); printf("spi frequency: %d Hz\n", priv->spi_freq); - /* With this setting, we issue one command at a time to + /* + * With this setting, we issue one command at a time to * accommodate to SPI-mem framework. */ writel(MTK_NOR_ENABLE_SF_CMD, priv->base + MTK_NOR_REG_WP); @@ -504,24 +566,13 @@ static int mtk_snor_probe(struct udevice *bus) mtk_snor_rmw(priv, MTK_NOR_REG_CFG3, MTK_NOR_DISABLE_WREN | MTK_NOR_DISABLE_SR_POLL, 0); - /* Unlock all blocks using write status command. - * SPI-MEM hasn't implemented unlock procedure on MXIC devices. - * We may remove this later. - */ - writel(2 * BITS_PER_BYTE, priv->base + MTK_NOR_REG_PRG_CNT); - writel(MTK_NOR_UNLOCK_ALL, priv->base + MTK_NOR_REG_PRGDATA(5)); - writel(MTK_NOR_IRQ_WRSR, priv->base + MTK_NOR_REG_IRQ_EN); - writel(MTK_NOR_CMD_WRSR, priv->base + MTK_NOR_REG_CMD); - ret = readl_poll_timeout(priv->base + MTK_NOR_REG_IRQ_STAT, reg, - !(reg & MTK_NOR_IRQ_WRSR), - ((3 * BITS_PER_BYTE) + 1) * 200); - return 0; } static int mtk_snor_set_speed(struct udevice *bus, uint speed) { - /* MTK's SNOR controller does not have a bus clock divider. + /* + * MTK's SNOR controller does not have a bus clock divider. * We setup maximum bus clock in dts. */ @@ -530,8 +581,7 @@ static int mtk_snor_set_speed(struct udevice *bus, uint speed) static int mtk_snor_set_mode(struct udevice *bus, uint mode) { - /* We set up mode later for each transmission. - */ + /* We set up mode later for each transmission. */ return 0; } @@ -547,8 +597,19 @@ static const struct dm_spi_ops mtk_snor_ops = { .set_mode = mtk_snor_set_mode, }; +static const struct mtk_snor_caps mtk_snor_caps_default = { + .extra_bit = 0, +}; + +static const struct mtk_snor_caps mtk_snor_caps_extra_bit = { + .extra_bit = 1, +}; + static const struct udevice_id mtk_snor_ids[] = { - { .compatible = "mediatek,mtk-snor" }, + { .compatible = "mediatek,mtk-snor", .data = (ulong)&mtk_snor_caps_default }, + { .compatible = "mediatek,mt8188-nor", .data = (ulong)&mtk_snor_caps_extra_bit }, + { .compatible = "mediatek,mt8189-nor", .data = (ulong)&mtk_snor_caps_extra_bit }, + { .compatible = "mediatek,mt8195-nor", .data = (ulong)&mtk_snor_caps_default }, {} }; diff --git a/drivers/spi/sandbox_spi.c b/drivers/spi/sandbox_spi.c index 4cc016138b1..3ee97d67f4a 100644 --- a/drivers/spi/sandbox_spi.c +++ b/drivers/spi/sandbox_spi.c @@ -61,6 +61,22 @@ uint sandbox_spi_get_mode(struct udevice *dev) return priv->mode; } +uint sandbox_spi_get_wordlen(struct udevice *dev) +{ + struct spi_slave *slave = dev_get_parent_priv(dev); + + return slave->wordlen; +} + +static int sandbox_spi_set_wordlen(struct udevice *dev, unsigned int wordlen) +{ + struct spi_slave *slave = dev_get_parent_priv(dev); + + slave->wordlen = wordlen; + + return 0; +} + static int sandbox_spi_xfer(struct udevice *slave, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { @@ -158,6 +174,7 @@ static const struct dm_spi_ops sandbox_spi_ops = { .set_mode = sandbox_spi_set_mode, .cs_info = sandbox_cs_info, .get_mmap = sandbox_spi_get_mmap, + .set_wordlen = sandbox_spi_set_wordlen, }; static const struct udevice_id sandbox_spi_ids[] = { diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index ca29cfd7c88..0186b01ad9a 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -53,18 +53,20 @@ struct aspeed_spi_regs { u32 dma_len; /* 0x8c DMA Length Register */ u32 dma_checksum; /* 0x90 Checksum Calculation Result */ u32 timings[ASPEED_SPI_MAX_CS]; /* 0x94 Read Timing Compensation */ + u32 _reserved3[83]; /* 0xA8 - 0x1F0 */ + u32 val_kept_wdt; /* 0x1F4 Value Kept WDT */ }; struct aspeed_spi_plat { u8 max_cs; - void __iomem *ahb_base; /* AHB address base for all flash devices. */ + uintptr_t ahb_base; /* AHB address base for all flash devices. */ fdt_size_t ahb_sz; /* Overall AHB window size for all flash device. */ u32 hclk_rate; /* AHB clock rate */ }; struct aspeed_spi_flash { - void __iomem *ahb_base; - u32 ahb_decoded_sz; + uintptr_t ahb_base; + size_t ahb_decoded_sz; u32 ce_ctrl_user; u32 ce_ctrl_read; u32 max_freq; @@ -84,9 +86,9 @@ struct aspeed_spi_info { u32 min_decoded_sz; u32 clk_ctrl_mask; void (*set_4byte)(struct udevice *bus, u32 cs); - u32 (*segment_start)(struct udevice *bus, u32 reg); - u32 (*segment_end)(struct udevice *bus, u32 reg); - u32 (*segment_reg)(u32 start, u32 end); + uintptr_t (*segment_start)(struct udevice *bus, u32 reg); + uintptr_t (*segment_end)(struct udevice *bus, u32 reg); + u32 (*segment_reg)(uintptr_t start, uintptr_t end); int (*adjust_decoded_sz)(struct udevice *bus); u32 (*get_clk_setting)(struct udevice *dev, uint hz); }; @@ -118,30 +120,30 @@ static u32 aspeed_spi_get_io_mode(u32 bus_width) } } -static u32 ast2400_spi_segment_start(struct udevice *bus, u32 reg) +static uintptr_t ast2400_spi_segment_start(struct udevice *bus, u32 reg) { struct aspeed_spi_plat *plat = dev_get_plat(bus); - u32 start_offset = ((reg >> 16) & 0xff) << 23; + uintptr_t start_offset = ((reg >> 16) & 0xff) << 23; if (start_offset == 0) - return (u32)plat->ahb_base; + return plat->ahb_base; - return (u32)plat->ahb_base + start_offset; + return plat->ahb_base + start_offset; } -static u32 ast2400_spi_segment_end(struct udevice *bus, u32 reg) +static uintptr_t ast2400_spi_segment_end(struct udevice *bus, u32 reg) { struct aspeed_spi_plat *plat = dev_get_plat(bus); - u32 end_offset = ((reg >> 24) & 0xff) << 23; + uintptr_t end_offset = ((reg >> 24) & 0xff) << 23; /* Meaningless end_offset, set to physical ahb base. */ if (end_offset == 0) - return (u32)plat->ahb_base; + return plat->ahb_base; - return (u32)plat->ahb_base + end_offset; + return plat->ahb_base + end_offset; } -static u32 ast2400_spi_segment_reg(u32 start, u32 end) +static u32 ast2400_spi_segment_reg(uintptr_t start, uintptr_t end) { if (start == end) return 0; @@ -206,30 +208,30 @@ static u32 ast2400_get_clk_setting(struct udevice *dev, uint max_hz) return hclk_div; } -static u32 ast2500_spi_segment_start(struct udevice *bus, u32 reg) +static uintptr_t ast2500_spi_segment_start(struct udevice *bus, u32 reg) { struct aspeed_spi_plat *plat = dev_get_plat(bus); - u32 start_offset = ((reg >> 16) & 0xff) << 23; + uintptr_t start_offset = ((reg >> 16) & 0xff) << 23; if (start_offset == 0) - return (u32)plat->ahb_base; + return plat->ahb_base; - return (u32)plat->ahb_base + start_offset; + return plat->ahb_base + start_offset; } -static u32 ast2500_spi_segment_end(struct udevice *bus, u32 reg) +static uintptr_t ast2500_spi_segment_end(struct udevice *bus, u32 reg) { struct aspeed_spi_plat *plat = dev_get_plat(bus); - u32 end_offset = ((reg >> 24) & 0xff) << 23; + uintptr_t end_offset = ((reg >> 24) & 0xff) << 23; /* Meaningless end_offset, set to physical ahb base. */ if (end_offset == 0) - return (u32)plat->ahb_base; + return plat->ahb_base; - return (u32)plat->ahb_base + end_offset; + return plat->ahb_base + end_offset; } -static u32 ast2500_spi_segment_reg(u32 start, u32 end) +static u32 ast2500_spi_segment_reg(uintptr_t start, uintptr_t end) { if (start == end) return 0; @@ -346,30 +348,30 @@ end: return hclk_div; } -static u32 ast2600_spi_segment_start(struct udevice *bus, u32 reg) +static uintptr_t ast2600_spi_segment_start(struct udevice *bus, u32 reg) { struct aspeed_spi_plat *plat = dev_get_plat(bus); - u32 start_offset = (reg << 16) & 0x0ff00000; + uintptr_t start_offset = (reg << 16) & 0x0ff00000; if (start_offset == 0) - return (u32)plat->ahb_base; + return plat->ahb_base; - return (u32)plat->ahb_base + start_offset; + return plat->ahb_base + start_offset; } -static u32 ast2600_spi_segment_end(struct udevice *bus, u32 reg) +static uintptr_t ast2600_spi_segment_end(struct udevice *bus, u32 reg) { struct aspeed_spi_plat *plat = dev_get_plat(bus); - u32 end_offset = reg & 0x0ff00000; + uintptr_t end_offset = reg & 0x0ff00000; /* Meaningless end_offset, set to physical ahb base. */ if (end_offset == 0) - return (u32)plat->ahb_base; + return plat->ahb_base; - return (u32)plat->ahb_base + end_offset + 0x100000; + return plat->ahb_base + end_offset + 0x100000; } -static u32 ast2600_spi_segment_reg(u32 start, u32 end) +static u32 ast2600_spi_segment_reg(uintptr_t start, uintptr_t end) { if (start == end) return 0; @@ -473,6 +475,70 @@ static u32 ast2600_get_clk_setting(struct udevice *dev, uint max_hz) return hclk_div; } +static uintptr_t ast2700_spi_segment_start(struct udevice *bus, u32 reg) +{ + struct aspeed_spi_plat *plat = dev_get_plat(bus); + uintptr_t start_offset = (reg & 0x0000ffff) << 16; + + if (start_offset == 0) + return plat->ahb_base; + + return plat->ahb_base + start_offset; +} + +static uintptr_t ast2700_spi_segment_end(struct udevice *bus, u32 reg) +{ + struct aspeed_spi_plat *plat = dev_get_plat(bus); + uintptr_t end_offset = reg & 0xffff0000; + + /* Meaningless end_offset, set to physical ahb base. */ + if (end_offset == 0) + return plat->ahb_base; + + return plat->ahb_base + end_offset; +} + +static u32 ast2700_spi_segment_reg(uintptr_t start, uintptr_t end) +{ + if (start == end) + return 0; + + return (((start >> 16) & 0x7fff) | ((end + 1) & 0x7fff0000)); +} + +static void ast2700_spi_chip_set_4byte(struct udevice *bus, u32 cs) +{ + struct aspeed_spi_priv *priv = dev_get_priv(bus); + u32 reg_val; + + reg_val = readl(&priv->regs->ctrl); + reg_val |= 0x11 << cs; + writel(reg_val, &priv->regs->ctrl); + + reg_val = readl(&priv->regs->val_kept_wdt); + reg_val |= (0x11 << 4) << cs; + writel(reg_val, &priv->regs->val_kept_wdt); +} + +static int ast2700_adjust_decoded_size(struct udevice *bus) +{ + struct aspeed_spi_plat *plat = dev_get_plat(bus); + struct aspeed_spi_priv *priv = dev_get_priv(bus); + struct aspeed_spi_flash *flashes = &priv->flashes[0]; + int ret; + int cs; + + /* Close unused CS. */ + for (cs = priv->num_cs; cs < plat->max_cs; cs++) + flashes[cs].ahb_decoded_sz = 0; + + ret = aspeed_spi_trim_decoded_size(bus); + if (ret != 0) + return ret; + + return 0; +} + /* * As the flash size grows up, we need to trim some decoded * size if needed for the sake of conforming the maximum @@ -512,12 +578,12 @@ static int aspeed_spi_trim_decoded_size(struct udevice *bus) return 0; } -static int aspeed_spi_read_from_ahb(void __iomem *ahb_base, void *buf, +static int aspeed_spi_read_from_ahb(uintptr_t ahb_base, void *buf, size_t len) { size_t offset = 0; - if (IS_ALIGNED((uintptr_t)ahb_base, sizeof(uintptr_t)) && + if (IS_ALIGNED(ahb_base, sizeof(uintptr_t)) && IS_ALIGNED((uintptr_t)buf, sizeof(uintptr_t))) { readsl(ahb_base, buf, len >> 2); offset = len & ~0x3; @@ -529,12 +595,12 @@ static int aspeed_spi_read_from_ahb(void __iomem *ahb_base, void *buf, return 0; } -static int aspeed_spi_write_to_ahb(void __iomem *ahb_base, const void *buf, +static int aspeed_spi_write_to_ahb(uintptr_t ahb_base, const void *buf, size_t len) { size_t offset = 0; - if (IS_ALIGNED((uintptr_t)ahb_base, sizeof(uintptr_t)) && + if (IS_ALIGNED(ahb_base, sizeof(uintptr_t)) && IS_ALIGNED((uintptr_t)buf, sizeof(uintptr_t))) { writesl(ahb_base, buf, len >> 2); offset = len & ~0x3; @@ -589,7 +655,7 @@ static int aspeed_spi_exec_op_user_mode(struct spi_slave *slave, struct aspeed_spi_priv *priv = dev_get_priv(bus); struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(slave->dev); u32 cs = slave_plat->cs[0]; - u32 ce_ctrl_reg = (u32)&priv->regs->ce_ctrl[cs]; + uintptr_t ce_ctrl_reg = (uintptr_t)&priv->regs->ce_ctrl[cs]; u32 ce_ctrl_val; struct aspeed_spi_flash *flash = &priv->flashes[cs]; u8 dummy_data[16] = {0}; @@ -602,7 +668,7 @@ static int aspeed_spi_exec_op_user_mode(struct spi_slave *slave, op->data.nbytes, op->data.buswidth); if (priv->info == &ast2400_spi_info) - ce_ctrl_reg = (u32)&priv->regs->ctrl; + ce_ctrl_reg = (uintptr_t)&priv->regs->ctrl; /* * Set controller to 4-byte address mode @@ -670,7 +736,7 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc) u32 i; u32 cs = slave_plat->cs[0]; u32 cmd_io_conf; - u32 ce_ctrl_reg; + uintptr_t ce_ctrl_reg; if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) { /* @@ -681,9 +747,9 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc) return -EOPNOTSUPP; } - ce_ctrl_reg = (u32)&priv->regs->ce_ctrl[cs]; + ce_ctrl_reg = (uintptr_t)&priv->regs->ce_ctrl[cs]; if (info == &ast2400_spi_info) - ce_ctrl_reg = (u32)&priv->regs->ctrl; + ce_ctrl_reg = (uintptr_t)&priv->regs->ctrl; if (desc->info.length > 0x1000000) priv->info->set_4byte(bus, cs); @@ -693,7 +759,7 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc) priv->flashes[cs].ahb_decoded_sz = desc->info.length; for (i = 0; i < priv->num_cs; i++) { - dev_dbg(dev, "cs: %d, sz: 0x%x\n", i, + dev_dbg(dev, "cs: %d, sz: 0x%zx\n", i, priv->flashes[cs].ahb_decoded_sz); } @@ -728,7 +794,7 @@ static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, u32 cs = slave_plat->cs[0]; int ret; - dev_dbg(dev, "read op:0x%x, addr:0x%llx, len:0x%x\n", + dev_dbg(dev, "read op:0x%x, addr:0x%llx, len:0x%zx\n", desc->info.op_tmpl.cmd.opcode, offs, len); if (priv->flashes[cs].ahb_decoded_sz < offs + len || @@ -738,7 +804,10 @@ static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc, if (ret != 0) return 0; } else { - memcpy_fromio(buf, priv->flashes[cs].ahb_base + offs, len); + memcpy_fromio(buf, + (void __iomem *)(priv->flashes[cs].ahb_base + + (uintptr_t)offs), + len); } return len; @@ -783,19 +852,19 @@ static void aspeed_spi_decoded_range_set(struct udevice *bus) struct aspeed_spi_plat *plat = dev_get_plat(bus); struct aspeed_spi_priv *priv = dev_get_priv(bus); u32 decoded_reg_val; - u32 start_addr, end_addr; + uintptr_t start_addr, end_addr; u32 cs; for (cs = 0; cs < plat->max_cs; cs++) { - start_addr = (u32)priv->flashes[cs].ahb_base; - end_addr = (u32)priv->flashes[cs].ahb_base + + start_addr = priv->flashes[cs].ahb_base; + end_addr = priv->flashes[cs].ahb_base + priv->flashes[cs].ahb_decoded_sz; decoded_reg_val = priv->info->segment_reg(start_addr, end_addr); writel(decoded_reg_val, &priv->regs->segment_addr[cs]); - dev_dbg(bus, "cs: %d, decoded_reg: 0x%x, start: 0x%x, end: 0x%x\n", + dev_dbg(bus, "cs: %d, decoded_reg: 0x%x, start: 0x%lx, end: 0x%lx\n", cs, decoded_reg_val, start_addr, end_addr); } } @@ -851,13 +920,13 @@ static int aspeed_spi_decoded_ranges_sanity(struct udevice *bus) * address base are monotonic increasing with CE#. */ for (cs = plat->max_cs - 1; cs > 0; cs--) { - if ((u32)priv->flashes[cs].ahb_base != 0 && - (u32)priv->flashes[cs].ahb_base < - (u32)priv->flashes[cs - 1].ahb_base + + if (priv->flashes[cs].ahb_base != 0 && + priv->flashes[cs].ahb_base < + priv->flashes[cs - 1].ahb_base + priv->flashes[cs - 1].ahb_decoded_sz) { - dev_err(bus, "decoded range overlay 0x%08x 0x%08x\n", - (u32)priv->flashes[cs].ahb_base, - (u32)priv->flashes[cs - 1].ahb_base); + dev_err(bus, "decoded range overlay 0x%08lx 0x%08lx\n", + priv->flashes[cs].ahb_base, + priv->flashes[cs - 1].ahb_base); return -EINVAL; } } @@ -895,14 +964,13 @@ static int aspeed_spi_read_fixed_decoded_ranges(struct udevice *bus) return ret; for (i = 0; i < count; i++) { - priv->flashes[ranges[i].cs].ahb_base = - (void __iomem *)ranges[i].ahb_base; + priv->flashes[ranges[i].cs].ahb_base = ranges[i].ahb_base; priv->flashes[ranges[i].cs].ahb_decoded_sz = ranges[i].sz; } for (i = 0; i < plat->max_cs; i++) { - dev_dbg(bus, "ahb_base: 0x%p, size: 0x%08x\n", + dev_dbg(bus, "ahb_base: 0x%lx, size: 0x%08zx\n", priv->flashes[i].ahb_base, priv->flashes[i].ahb_decoded_sz); } @@ -1063,6 +1131,32 @@ static const struct aspeed_spi_info ast2600_spi_info = { .get_clk_setting = ast2600_get_clk_setting, }; +static const struct aspeed_spi_info ast2700_fmc_info = { + .io_mode_mask = 0xf0000000, + .max_bus_width = 4, + .min_decoded_sz = 0x10000, + .clk_ctrl_mask = 0x0f000f00, + .set_4byte = ast2700_spi_chip_set_4byte, + .segment_start = ast2700_spi_segment_start, + .segment_end = ast2700_spi_segment_end, + .segment_reg = ast2700_spi_segment_reg, + .adjust_decoded_sz = ast2700_adjust_decoded_size, + .get_clk_setting = ast2600_get_clk_setting, +}; + +static const struct aspeed_spi_info ast2700_spi_info = { + .io_mode_mask = 0xf0000000, + .max_bus_width = 4, + .min_decoded_sz = 0x10000, + .clk_ctrl_mask = 0x0f000f00, + .set_4byte = ast2700_spi_chip_set_4byte, + .segment_start = ast2700_spi_segment_start, + .segment_end = ast2700_spi_segment_end, + .segment_reg = ast2700_spi_segment_reg, + .adjust_decoded_sz = ast2700_adjust_decoded_size, + .get_clk_setting = ast2600_get_clk_setting, +}; + static int aspeed_spi_claim_bus(struct udevice *dev) { struct udevice *bus = dev->parent; @@ -1129,7 +1223,8 @@ static int apseed_spi_of_to_plat(struct udevice *bus) return -EINVAL; } - plat->ahb_base = devfdt_get_addr_size_index_ptr(bus, 1, &plat->ahb_sz); + plat->ahb_base = + (uintptr_t)devfdt_get_addr_size_index_ptr(bus, 1, &plat->ahb_sz); if (!plat->ahb_base) { dev_err(bus, "wrong AHB base\n"); return -EINVAL; @@ -1147,8 +1242,8 @@ static int apseed_spi_of_to_plat(struct udevice *bus) plat->hclk_rate = clk_get_rate(&hclk); - dev_dbg(bus, "ctrl_base = 0x%x, ahb_base = 0x%p, size = 0x%llx\n", - (u32)priv->regs, plat->ahb_base, (fdt64_t)plat->ahb_sz); + dev_dbg(bus, "ctrl_base = 0x%p, ahb_base = 0x%lx, size = 0x%llx\n", + priv->regs, plat->ahb_base, (fdt64_t)plat->ahb_sz); dev_dbg(bus, "hclk = %dMHz, max_cs = %d\n", plat->hclk_rate / 1000000, plat->max_cs); @@ -1199,6 +1294,8 @@ static const struct udevice_id aspeed_spi_ids[] = { { .compatible = "aspeed,ast2500-spi", .data = (ulong)&ast2500_spi_info, }, { .compatible = "aspeed,ast2600-fmc", .data = (ulong)&ast2600_fmc_info, }, { .compatible = "aspeed,ast2600-spi", .data = (ulong)&ast2600_spi_info, }, + { .compatible = "aspeed,ast2700-fmc", .data = (ulong)&ast2700_fmc_info, }, + { .compatible = "aspeed,ast2700-spi", .data = (ulong)&ast2700_spi_info, }, { } }; diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c index 0bdc112d249..08b603f04a2 100644 --- a/drivers/spi/spi-sunxi.c +++ b/drivers/spi/spi-sunxi.c @@ -344,7 +344,7 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, struct sun4i_spi_priv *priv = dev_get_priv(bus); struct dm_spi_slave_plat *slave_plat = dev_get_parent_plat(dev); - u32 len = bitlen / 8; + u32 rst, val, len = bitlen / 8; u8 nbytes; int ret; @@ -360,8 +360,11 @@ static int sun4i_spi_xfer(struct udevice *dev, unsigned int bitlen, sun4i_spi_set_cs(bus, slave_plat->cs[0], true); /* Reset FIFOs */ - setbits_le32(SPI_REG(priv, SPI_FCR), SPI_BIT(priv, SPI_FCR_RF_RST) | - SPI_BIT(priv, SPI_FCR_TF_RST)); + rst = SPI_BIT(priv, SPI_FCR_RF_RST) | SPI_BIT(priv, SPI_FCR_TF_RST); + setbits_le32(SPI_REG(priv, SPI_FCR), rst); + ret = readl_poll_timeout(SPI_REG(priv, SPI_FCR), val, !(rst & val), 20); + if (ret) + return -EBUSY; while (len) { /* Setup the transfer now... */ diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 6b7ad47c22d..120565df149 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -88,6 +88,20 @@ void dm_spi_release_bus(struct udevice *dev) ops->release_bus(dev); } +int dm_spi_set_wordlen(struct udevice *dev, unsigned int wordlen) +{ + struct udevice *bus = dev->parent; + struct dm_spi_ops *ops = spi_get_ops(bus); + + if (bus->uclass->uc_drv->id != UCLASS_SPI) + return -EOPNOTSUPP; + + if (!ops->set_wordlen) + return -ENOSYS; + + return ops->set_wordlen(dev, wordlen); +} + int dm_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { @@ -141,6 +155,11 @@ int spi_set_speed(struct spi_slave *slave, uint hz) return ret; } +int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen) +{ + return dm_spi_set_wordlen(slave->dev, wordlen); +} + int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { @@ -245,6 +264,7 @@ static int spi_child_post_bind(struct udevice *dev) } plat->mode = mode; + plat->wordlen = SPI_DEFAULT_WORDLEN; return 0; } @@ -277,7 +297,7 @@ static int spi_child_pre_probe(struct udevice *dev) slave->max_hz = plat->max_hz; slave->mode = plat->mode; - slave->wordlen = SPI_DEFAULT_WORDLEN; + slave->wordlen = plat->wordlen; return 0; } diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c index a1f31cf653c..c93a749cd5b 100644 --- a/drivers/spi/stm32_spi.c +++ b/drivers/spi/stm32_spi.c @@ -192,6 +192,11 @@ static void stm32_spi_read_rxfifo(struct udevice *bus) log_debug("%d bytes left\n", priv->rx_len); } +static bool stm32_spi_is_enabled(void __iomem *base) +{ + return !!(readl(base + STM32_SPI_CR1) & SPI_CR1_SPE); +} + static int stm32_spi_enable(void __iomem *base) { log_debug("\n"); @@ -245,9 +250,7 @@ static void stm32_spi_stopxfer(struct udevice *dev) dev_dbg(dev, "\n"); - cr1 = readl(base + STM32_SPI_CR1); - - if (!(cr1 & SPI_CR1_SPE)) + if (!stm32_spi_is_enabled(base)) return; /* Wait on EOT or suspend the flow */ @@ -381,6 +384,44 @@ static int stm32_spi_set_speed(struct udevice *bus, uint hz) return 0; } +static int _stm32_spi_set_wordlen(struct udevice *bus, unsigned int wordlen) +{ + struct stm32_spi_priv *priv = dev_get_priv(bus); + struct stm32_spi_plat *plat = dev_get_plat(bus); + void __iomem *base = plat->base; + bool spi_enabled; + + if ((wordlen - 1) < SPI_CFG1_DSIZE_MIN || + (wordlen - 1) > SPI_CFG1_DSIZE) { + dev_err(bus, "Cannot set wordlen to %u [%d - %ld]\n", + wordlen, SPI_CFG1_DSIZE_MIN + 1, + SPI_CFG1_DSIZE + 1); + return -EINVAL; + } + + spi_enabled = stm32_spi_is_enabled(plat->base); + if (spi_enabled) + stm32_spi_disable(plat->base); + + dev_dbg(bus, "bits_per_word=%d\n", wordlen); + + priv->cur_bpw = wordlen; + clrsetbits_le32(base + STM32_SPI_CFG1, SPI_CFG1_DSIZE, + priv->cur_bpw - 1); + + if (spi_enabled) + stm32_spi_enable(plat->base); + + return 0; +} + +static int stm32_spi_set_wordlen(struct udevice *slave, unsigned int wordlen) +{ + struct udevice *bus = dev_get_parent(slave); + + return _stm32_spi_set_wordlen(bus, wordlen); +} + static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { @@ -394,18 +435,28 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, u32 xferlen; u32 mode; int xfer_status = 0; + int nb_words; xferlen = bitlen / 8; - if (xferlen <= SPI_CR2_TSIZE) - writel(xferlen, base + STM32_SPI_CR2); + if (priv->cur_bpw <= 8) + nb_words = xferlen; + else if (priv->cur_bpw <= 16) + nb_words = DIV_ROUND_UP(xferlen * 8, 16); + else + nb_words = DIV_ROUND_UP(xferlen * 8, 32); + + if (nb_words <= SPI_CR2_TSIZE) + writel(nb_words, base + STM32_SPI_CR2); else return -EMSGSIZE; priv->tx_buf = dout; priv->rx_buf = din; - priv->tx_len = priv->tx_buf ? bitlen / 8 : 0; - priv->rx_len = priv->rx_buf ? bitlen / 8 : 0; + priv->tx_len = priv->tx_buf ? xferlen : 0; + priv->rx_len = priv->rx_buf ? xferlen : 0; + dev_dbg(bus, "bitlen: %d, xferlen: %d, nb_words: %d\n", + bitlen, xferlen, nb_words); mode = SPI_FULL_DUPLEX; if (!priv->tx_buf) @@ -567,9 +618,7 @@ static int stm32_spi_probe(struct udevice *dev) priv->fifo_size = stm32_spi_get_fifo_size(dev); priv->cur_mode = SPI_FULL_DUPLEX; priv->cur_xferlen = 0; - priv->cur_bpw = SPI_DEFAULT_WORDLEN; - clrsetbits_le32(base + STM32_SPI_CFG1, SPI_CFG1_DSIZE, - priv->cur_bpw - 1); + _stm32_spi_set_wordlen(dev, SPI_DEFAULT_WORDLEN); for (i = 0; i < ARRAY_SIZE(plat->cs_gpios); i++) { if (!dm_gpio_is_valid(&plat->cs_gpios[i])) @@ -630,10 +679,12 @@ static const struct dm_spi_ops stm32_spi_ops = { .release_bus = stm32_spi_release_bus, .set_mode = stm32_spi_set_mode, .set_speed = stm32_spi_set_speed, + .set_wordlen = stm32_spi_set_wordlen, .xfer = stm32_spi_xfer, }; static const struct udevice_id stm32_spi_ids[] = { + { .compatible = "st,stm32mp25-spi", }, { .compatible = "st,stm32h7-spi", }, { } }; diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig index ab4878ebae4..e28fd9af1d0 100644 --- a/drivers/spmi/Kconfig +++ b/drivers/spmi/Kconfig @@ -3,7 +3,7 @@ menu "SPMI support" config SPMI bool "Enable SPMI bus support" depends on DM - ---help--- + help Select this to enable to support SPMI bus. SPMI (System Power Management Interface) bus is used to connect PMIC devices on various SoCs. @@ -11,13 +11,13 @@ config SPMI config SPMI_MSM bool "Support Qualcomm SPMI bus" depends on SPMI - ---help--- + help Support SPMI bus implementation found on Qualcomm Snapdragon SoCs. config SPMI_SANDBOX bool "Support for Sandbox SPMI bus" depends on SPMI - ---help--- + help Demo SPMI bus implementation. Emulates part of PM8916 as single - slave (0) on bus. It has 4 GPIO peripherals, pid 0xC0-0xC3. + slave (0) on bus. It has 4 GPIO peripherals, pid 0xC0-0xC3. endmenu diff --git a/drivers/sysinfo/Kconfig b/drivers/sysinfo/Kconfig index df83df69ffb..6922dac9170 100644 --- a/drivers/sysinfo/Kconfig +++ b/drivers/sysinfo/Kconfig @@ -59,4 +59,12 @@ config SYSINFO_GPIO This ternary number is then mapped to a board revision name using device tree properties. +config SYSINFO_TQ_EEPROM + bool "Enable TQ-Systems EEPROM sysinfo driver" + depends on I2C_EEPROM + depends on SPL_I2C_EEPROM || !SPL_SYSINFO + help + Support querying EEPROM of TQ-Systems SOMs to determine board + information. + endif diff --git a/drivers/sysinfo/Makefile b/drivers/sysinfo/Makefile index 26ca3150999..d21fb3c2270 100644 --- a/drivers/sysinfo/Makefile +++ b/drivers/sysinfo/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_SYSINFO_IOT2050) += iot2050.o obj-$(CONFIG_SYSINFO_RCAR3) += rcar3.o obj-$(CONFIG_SYSINFO_SANDBOX) += sandbox.o obj-$(CONFIG_SYSINFO_SMBIOS) += smbios.o +obj-$(CONFIG_SYSINFO_TQ_EEPROM) += tq_eeprom.o diff --git a/drivers/sysinfo/sysinfo-uclass.c b/drivers/sysinfo/sysinfo-uclass.c index f04998ef8bb..d18a168614e 100644 --- a/drivers/sysinfo/sysinfo-uclass.c +++ b/drivers/sysinfo/sysinfo-uclass.c @@ -42,6 +42,16 @@ int sysinfo_detect(struct udevice *dev) return ret; } +int sysinfo_get_and_detect(struct udevice **devp) +{ + int ret = sysinfo_get(devp); + + if (!ret) + ret = sysinfo_detect(*devp); + + return ret; +} + int sysinfo_get_fit_loadable(struct udevice *dev, int index, const char *type, const char **strp) { @@ -152,5 +162,5 @@ UCLASS_DRIVER(sysinfo) = { .id = UCLASS_SYSINFO, .name = "sysinfo", .post_bind = dm_scan_fdt_dev, - .per_device_auto = sizeof(bool), + .per_device_auto = sizeof(struct sysinfo_priv), }; diff --git a/drivers/sysinfo/tq_eeprom.c b/drivers/sysinfo/tq_eeprom.c new file mode 100644 index 00000000000..63be07b664e --- /dev/null +++ b/drivers/sysinfo/tq_eeprom.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2014-2026 TQ-Systems GmbH <[email protected]>, + * D-82229 Seefeld, Germany. + * Author: Nora Schiffer + */ + +#include <dm.h> +#include <log.h> +#include <net.h> +#include <dm/device_compat.h> +#include <linux/build_bug.h> +#include <linux/ctype.h> +#include <nvmem.h> +#include <sysinfo/tq_eeprom.h> + +#define TQ_EE_RSV1_BYTES 10 +#define TQ_EE_SERIAL_BYTES 8 +#define TQ_EE_RSV2_BYTES 8 +#define TQ_EE_BDID_BYTES 0x40 + +struct tq_eeprom_data { + u8 mac[ETH_ALEN]; /* 0x20 ... 0x25 */ + u8 rsv1[TQ_EE_RSV1_BYTES]; + u8 serial[TQ_EE_SERIAL_BYTES]; /* 0x30 ... 0x37 */ + u8 rsv2[TQ_EE_RSV2_BYTES]; + u8 id[TQ_EE_BDID_BYTES]; /* 0x40 ... 0x7f */ +}; + +static_assert(sizeof(struct tq_eeprom_data) == 0x60, + "struct tq_eeprom_data has incorrect size"); + +/** + * struct sysinfo_tq_eeprom_priv - sysinfo private data + */ +struct sysinfo_tq_eeprom_priv { + struct nvmem_cell device_info_cell; + + /* Reserve extra space for \0 in id and serial */ + char id[TQ_EE_BDID_BYTES + 1]; + char serial[TQ_EE_SERIAL_BYTES + 1]; + u8 mac[ETH_ALEN]; +}; + +static void tq_eeprom_parse_id(struct udevice *dev, const struct tq_eeprom_data *data) +{ + struct sysinfo_tq_eeprom_priv *priv = dev_get_priv(dev); + int i; + + for (i = 0; i < sizeof(data->id); i++) { + if (!(isprint(data->id[i]) && isascii(data->id[i]))) + break; + } + + if (i == 0) + dev_warn(dev, "no valid model name in EEPROM\n"); + + snprintf(priv->id, sizeof(priv->id), "%.*s", i, data->id); +} + +static int tq_eeprom_serial_len(const struct tq_eeprom_data *data, bool allow_upper) +{ + int i; + + for (i = 0; i < sizeof(data->serial); i++) { + if (!(isdigit(data->serial[i]) || (allow_upper && isupper(data->serial[i])))) + break; + } + + return i; +} + +static void tq_eeprom_parse_serial(struct udevice *dev, const struct tq_eeprom_data *data) +{ + struct sysinfo_tq_eeprom_priv *priv = dev_get_priv(dev); + bool use_new_format; + int len; + + use_new_format = data->serial[0] == 'T' && data->serial[1] == 'Q'; + + len = tq_eeprom_serial_len(data, use_new_format); + + /* For now, only serial numbers with the exact size of the field are accepted */ + if (len != sizeof(data->serial)) { + dev_warn(dev, "no valid serial number in EEPROM\n"); + len = 0; + } + + snprintf(priv->serial, sizeof(priv->serial), "%.*s", len, data->serial); +} + +static int tq_eeprom_dump(const struct sysinfo_tq_eeprom_priv *priv) +{ + printf("TQ EEPROM:\n"); + printf(" ID: %s\n", priv->id[0] ? priv->id : "<invalid>"); + printf(" SN: %s\n", priv->serial[0] ? priv->serial : "<invalid>"); + printf(" MAC: "); + if (is_valid_ethaddr(priv->mac)) + printf("%pM\n", priv->mac); + else + printf("<invalid>\n"); + + return 0; +} + +static int sysinfo_tq_eeprom_detect(struct udevice *dev) +{ + struct sysinfo_tq_eeprom_priv *priv = dev_get_priv(dev); + struct tq_eeprom_data data; + int ret; + + ret = nvmem_cell_read(&priv->device_info_cell, (u8 *)&data, sizeof(data)); + if (ret < 0) { + dev_err(dev, "EEPROM read failed: %d\n", ret); + return ret; + } + + tq_eeprom_parse_id(dev, &data); + tq_eeprom_parse_serial(dev, &data); + memcpy(priv->mac, data.mac, ETH_ALEN); + + if (!IS_ENABLED(CONFIG_SPL_BUILD)) + tq_eeprom_dump(priv); + + return 0; +} + +static int sysinfo_tq_eeprom_get_str(struct udevice *dev, int id, size_t size, char *val) +{ + struct sysinfo_tq_eeprom_priv *priv = dev_get_priv(dev); + + switch (id) { + case SYSID_TQ_MODEL: + if (!priv->id[0]) + return -ENODATA; + + strlcpy(val, priv->id, size); + return 0; + + case SYSID_TQ_SERIAL: + if (!priv->serial[0]) + return -ENODATA; + + strlcpy(val, priv->serial, size); + return 0; + + default: + return -EINVAL; + } +} + +static int sysinfo_tq_eeprom_get_data(struct udevice *dev, int id, void **data, size_t *size) +{ + struct sysinfo_tq_eeprom_priv *priv = dev_get_priv(dev); + + switch (id) { + case SYSID_TQ_MAC_ADDR: + if (!is_valid_ethaddr(priv->mac)) + return -ENODATA; + + *data = priv->mac; + *size = sizeof(priv->mac); + + return 0; + + default: + return -EINVAL; + } +} + +static const struct sysinfo_ops sysinfo_tq_eeprom_ops = { + .detect = sysinfo_tq_eeprom_detect, + .get_str = sysinfo_tq_eeprom_get_str, + .get_data = sysinfo_tq_eeprom_get_data, +}; + +static int sysinfo_tq_eeprom_probe(struct udevice *dev) +{ + struct sysinfo_tq_eeprom_priv *priv = dev_get_priv(dev); + int ret; + + ret = nvmem_cell_get_by_name(dev, "device_info", &priv->device_info_cell); + if (ret) { + dev_err(dev, "device_info not found: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct udevice_id sysinfo_tq_eeprom_ids[] = { + { .compatible = "tq,eeprom-sysinfo" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(sysinfo_tq_eeprom) = { + .name = "sysinfo_tq_eeprom", + .id = UCLASS_SYSINFO, + .of_match = sysinfo_tq_eeprom_ids, + .ops = &sysinfo_tq_eeprom_ops, + .priv_auto = sizeof(struct sysinfo_tq_eeprom_priv), + .probe = sysinfo_tq_eeprom_probe, +}; diff --git a/drivers/sysreset/sysreset_qemu_virt_ctrl.c b/drivers/sysreset/sysreset_qemu_virt_ctrl.c index e7cacc9b6e9..ce15e776f8f 100644 --- a/drivers/sysreset/sysreset_qemu_virt_ctrl.c +++ b/drivers/sysreset/sysreset_qemu_virt_ctrl.c @@ -8,6 +8,7 @@ #include <dm.h> #include <qemu_virt_ctrl.h> #include <sysreset.h> +#include <mapmem.h> #include <asm/io.h> #include <linux/err.h> @@ -24,6 +25,7 @@ static int qemu_virt_ctrl_request(struct udevice *dev, enum sysreset_t type) { struct qemu_virt_ctrl_plat *plat = dev_get_plat(dev); + void __iomem *reg = map_sysmem(plat->reg + VIRT_CTRL_REG_CMD, 0x4); u32 val; switch (type) { @@ -38,7 +40,7 @@ static int qemu_virt_ctrl_request(struct udevice *dev, enum sysreset_t type) return -EPROTONOSUPPORT; } - writel(val, plat->reg + VIRT_CTRL_REG_CMD); + __raw_writel(val, reg); return -EINPROGRESS; } diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index 5fc0505c788..4d67c948ec1 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -795,6 +795,11 @@ static optee_invoke_fn *get_invoke_func(struct udevice *dev) return ERR_PTR(-EINVAL); } +bool is_optee_smc_api(void) +{ + return is_optee_api(optee_smccc_smc); +} + static int optee_of_to_plat(struct udevice *dev) { struct optee_pdata *pdata = dev_get_plat(dev); diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 91c39aa4dee..3b7e807a024 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -13,9 +13,9 @@ config IMX_THERMAL depends on MX6 || MX7 help Support for Temperature Monitor (TEMPMON) found on Freescale i.MX SoCs. - It supports one critical trip point and one passive trip point. The - cpufreq is used as the cooling device to throttle CPUs when the - passive trip is crossed. + It supports one critical trip point and one passive trip point. The + cpufreq is used as the cooling device to throttle CPUs when the + passive trip is crossed. config IMX_SCU_THERMAL bool "Temperature sensor driver for NXP i.MX8" @@ -27,11 +27,12 @@ config IMX_SCU_THERMAL trip is crossed config IMX_TMU - bool "Thermal Management Unit driver for NXP i.MX8M and iMX93" - depends on ARCH_IMX8M || IMX93 - help - Support for Temperature sensors on NXP i.MX8M and iMX93. - It supports one critical trip point and one passive trip point. + bool "Thermal Management Unit driver for NXP i.MX8M / i.MX93 and QorIQ" + depends on ARCH_IMX8M || IMX93 || FSL_LAYERSCAPE + help + Support for the NXP Thermal Management Unit (TMU) sensors on + i.MX8M, i.MX93 and on QorIQ/Layerscape SoCs (LX2160A, + LS1028A, LS1088A, ...). The boot is hold to the cool device to throttle CPUs when the passive trip is crossed @@ -44,15 +45,30 @@ config RCAR_GEN3_THERMAL driver into the U-Boot thermal framework. config TI_DRA7_THERMAL - bool "Temperature sensor driver for TI dra7xx SOCs" - help - Enable thermal support for for the Texas Instruments DRA752 SoC family. - The driver supports reading CPU temperature. + bool "Temperature sensor driver for TI dra7xx SOCs" + help + Enable thermal support for the Texas Instruments DRA752 SoC family. + The driver supports reading CPU temperature. config TI_LM74_THERMAL - bool "Temperature sensor driver for TI LM74 chip" - help - Enable thermal support for the Texas Instruments LM74 chip. - The driver supports reading CPU temperature. + bool "Temperature sensor driver for TI LM74 chip" + help + Enable thermal support for the Texas Instruments LM74 chip. + The driver supports reading CPU temperature. + +config DM_THERMAL_JC42 + bool "JEDEC JC-42.4/TSE2004av SPD temperature sensor" + depends on DM_I2C + help + Enable support for the JEDEC JC-42.4 temperature sensor found + on the SPD bus of DDR3 and DDR4 DIMMs (TSE2004av and compatible). + +config PMBUS_THERMAL + bool "Generic PMBus temperature" + depends on DM_REGULATOR_PMBUS_HELPER + help + Expose the die-temperature reading of any PMBus voltage + regulator bound by a pmbus_helper based chip driver + as a UCLASS_THERMAL device. endif # if DM_THERMAL diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index b6f06c00ed9..475026a5ab2 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -11,3 +11,5 @@ 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 +obj-$(CONFIG_DM_THERMAL_JC42) += jc42.o +obj-$(CONFIG_PMBUS_THERMAL) += pmbus_thermal.o diff --git a/drivers/thermal/imx_tmu.c b/drivers/thermal/imx_tmu.c index 1bde4d07f52..da0825ecd34 100644 --- a/drivers/thermal/imx_tmu.c +++ b/drivers/thermal/imx_tmu.c @@ -6,14 +6,17 @@ #include <config.h> #include <asm/io.h> -#include <asm/arch/clock.h> #include <asm/arch/sys_proto.h> +#if IS_ENABLED(CONFIG_ARCH_IMX8M) || IS_ENABLED(CONFIG_IMX93) +#include <asm/arch/clock.h> +#endif #include <dm.h> #include <dm/device_compat.h> #include <dm/device-internal.h> #include <dm/device.h> #include <errno.h> #include <fuse.h> +#include <linux/bitops.h> #include <linux/delay.h> #include <malloc.h> #include <thermal.h> @@ -22,10 +25,12 @@ #define FLAGS_VER2 0x1 #define FLAGS_VER3 0x2 #define FLAGS_VER4 0x4 +#define FLAGS_QORIQ 0x8 #define TMR_DISABLE 0x0 #define TMR_ME 0x80000000 #define TMR_ALPF 0x0c000000 +#define QORIQ_TMR_ALPF (0x3 << 24) /* QorIQ ALPF lives at bits[25:24] */ #define TMTMIR_DEFAULT 0x00000002 #define TIER_DISABLE 0x0 @@ -33,7 +38,19 @@ #define TER_ADC_PD 0x40000000 #define TER_ALPF 0x3 +/* default CPU delay time to cool down if over temperature */ #define IMX_TMU_POLLING_DELAY_MS 5000 + +/* TRITSR - QorIQ Immediate Temperature Site Register. + * + * Per LX2160A Reference Manual, Rev. 1 (10/2021) section 28.3.1.24 + * the calibrated reading lives in TEMP[8:0] and is reported in + * degrees Kelvin (integer). The QorIQ regs_v1 variant has no + * fractional 0.5 degC bit, unlike the i.MX regs_v2 / VER4 layouts. + */ +#define TRITSR_V BIT(31) /* reading valid */ +#define TRITSR_TEMP_MASK GENMASK(8, 0) /* degrees Kelvin */ +#define TRITSR_KELVIN_OFFSET 273 /* TEMP[8:0] - 273 = degC */ /* * i.MX TMU Registers */ @@ -148,11 +165,37 @@ struct imx_tmu_regs_v3 { u32 trim; }; +/* + * fsl,qoriq-tmu (LX2160A, LS1028A, LS1088A, ...). Same TMU IP family as + * the i.MX "regs_v1" layout but: site-enable is a discrete TMSR at 0x08 + * (TMTMIR moves to 0x0C), and the temperature range registers are + * variable-length at 0xF10 (a SoC may use fewer than 16). Calibration is + * taken from the DT (fsl,tmu-range / fsl,tmu-calibration) exactly like + * the i.MX regs_v1 path, so qoriq reuses imx_tmu_calibration()'s scheme. + */ +struct qoriq_tmu_regs { + u32 tmr; /* 0x000 mode */ + u32 tsr; /* 0x004 status */ + u32 tmsr; /* 0x008 monitor-site enable (bit N = site N) */ + u32 tmtmir; /* 0x00C measurement interval */ + u8 res0[0x10]; + u32 tier; /* 0x020 interrupt enable */ + u32 tidr; /* 0x024 interrupt detect */ + u8 res1[0x58]; + u32 ttcfgr; /* 0x080 temperature config (cal walk) */ + u32 tscfgr; /* 0x084 sensor config (cal walk) */ + u8 res2[0x78]; + struct imx_tmu_site_regs site[SITES_MAX]; /* 0x100 */ + u8 res3[0xd10]; + u32 ttrcr[16]; /* 0xF10 temperature range control */ +}; + union tmu_regs { struct imx_tmu_regs regs_v1; struct imx_tmu_regs_v2 regs_v2; struct imx_tmu_regs_v3 regs_v3; struct imx_tmu_regs_v4 regs_v4; + struct qoriq_tmu_regs regs_qoriq; }; struct imx_tmu_plat { @@ -189,6 +232,9 @@ static int read_temperature(struct udevice *dev, int *temp) } else if (drv_data & FLAGS_VER4) { val = readl(&pdata->regs->regs_v4.tritsr0); valid = val & 0x80000000; + } else if (drv_data & FLAGS_QORIQ) { + val = readl(&pdata->regs->regs_qoriq.site[pdata->id].tritsr); + valid = val & TRITSR_V; } else { val = readl(&pdata->regs->regs_v1.site[pdata->id].tritsr); valid = val & 0x80000000; @@ -213,6 +259,19 @@ static int read_temperature(struct udevice *dev, int *temp) /* Convert Kelvin to Celsius */ *temp -= 273000; + } else if (drv_data & FLAGS_QORIQ) { + /* + * LX2160A Reference Manual, Rev. 1 (10/2021) + * section 28.3.1.24: TEMP[8:0] is the calibrated + * reading in degrees Kelvin (integer, no 0.5 degC + * bit on the regs_v1 variant). The calibration + * point examples in the same RM section 28.1.3 + * use the same Kelvin/Celsius offset: + * TTR0CR=0x800000E6 -> 230K (-43 degC) + * TTR1CR=0x8001017D -> 381K (108 degC) + */ + *temp = ((val & TRITSR_TEMP_MASK) - + TRITSR_KELVIN_OFFSET) * 1000; } else { *temp = (val & 0xff) * 1000; } @@ -265,6 +324,35 @@ static int imx_tmu_calibration(struct udevice *dev) if (drv_data & (FLAGS_VER2 | FLAGS_VER3)) return 0; + if (drv_data & FLAGS_QORIQ) { + const fdt32_t *ranges; + int n; + + ranges = dev_read_prop(dev, "fsl,tmu-range", &len); + if (!ranges || len % 4 || + len / 4 > (int)ARRAY_SIZE(pdata->regs->regs_qoriq.ttrcr)) { + dev_err(dev, "TMU: missing/invalid fsl,tmu-range\n"); + return -ENODEV; + } + n = len / 4; + for (i = 0; i < n; i++) + writel(fdt32_to_cpu(ranges[i]), + &pdata->regs->regs_qoriq.ttrcr[i]); + + calibration = dev_read_prop(dev, "fsl,tmu-calibration", &len); + if (!calibration || len % 8) { + dev_err(dev, "TMU: invalid calibration data.\n"); + return -ENODEV; + } + for (i = 0; i < len; i += 8, calibration += 2) { + writel(fdt32_to_cpu(*calibration), + &pdata->regs->regs_qoriq.ttcfgr); + writel(fdt32_to_cpu(*(calibration + 1)), + &pdata->regs->regs_qoriq.tscfgr); + } + return 0; + } + if (drv_data & FLAGS_VER4) { calibration = dev_read_prop(dev, "fsl,tmu-calibration", &len); if (!calibration || len % 8 || len > 128) { @@ -402,6 +490,18 @@ static inline void imx_tmu_mx8mq_init(struct udevice *dev) { } static void imx_tmu_arch_init(struct udevice *dev) { + /* + * QorIQ takes its calibration from the DT (fsl,tmu-calibration), + * not from OCOTP fuses, so it has no per-SoC arch init. The #if + * below is still required: the i.MX SoC-ID helpers and fuse API + * (<asm/arch/sys_proto.h>) do not exist in a Layerscape build, so + * the references must be removed at compile time, not merely + * skipped at runtime. + */ + if (dev_get_driver_data(dev) & FLAGS_QORIQ) + return; + +#if IS_ENABLED(CONFIG_ARCH_IMX8M) || IS_ENABLED(CONFIG_IMX93) if (is_imx8mm() || is_imx8mn()) imx_tmu_mx8mm_mx8mn_init(dev); else if (is_imx8mp()) @@ -412,6 +512,7 @@ static void imx_tmu_arch_init(struct udevice *dev) imx_tmu_mx8mq_init(dev); else dev_err(dev, "Unsupported SoC, TMU calibration not loaded!\n"); +#endif } static void imx_tmu_init(struct udevice *dev) @@ -443,6 +544,15 @@ static void imx_tmu_init(struct udevice *dev) /* Set update_interval */ writel(TMTMIR_DEFAULT, &pdata->regs->regs_v4.tmtmir); + } else if (drv_data & FLAGS_QORIQ) { + /* Disable monitoring */ + writel(TMR_DISABLE, &pdata->regs->regs_qoriq.tmr); + + /* Disable interrupt, using polling instead */ + writel(TIER_DISABLE, &pdata->regs->regs_qoriq.tier); + + /* Set update_interval */ + writel(TMTMIR_DEFAULT, &pdata->regs->regs_qoriq.tmtmir); } else { /* Disable monitoring */ writel(TMR_DISABLE, &pdata->regs->regs_v1.tmr); @@ -511,6 +621,18 @@ static int imx_tmu_enable_msite(struct udevice *dev) /* Enable ME */ reg |= TMR_ME; writel(reg, &pdata->regs->regs_v4.tmr); + } else if (drv_data & FLAGS_QORIQ) { + /* Clear ME, enable every site at once via the discrete TMSR */ + reg = readl(&pdata->regs->regs_qoriq.tmr); + reg &= ~TMR_ME; + writel(reg, &pdata->regs->regs_qoriq.tmr); + + writel(GENMASK(SITES_MAX - 1, 0), + &pdata->regs->regs_qoriq.tmsr); + + reg |= QORIQ_TMR_ALPF; + reg |= TMR_ME; + writel(reg, &pdata->regs->regs_qoriq.tmr); } else { /* Clear the ME before setting MSITE and ALPF*/ reg = readl(&pdata->regs->regs_v1.tmr); @@ -650,6 +772,7 @@ static const struct udevice_id imx_tmu_ids[] = { { .compatible = "fsl,imx8mm-tmu", .data = FLAGS_VER2, }, { .compatible = "fsl,imx8mp-tmu", .data = FLAGS_VER3, }, { .compatible = "fsl,imx93-tmu", .data = FLAGS_VER4, }, + { .compatible = "fsl,qoriq-tmu", .data = FLAGS_QORIQ, }, { } }; diff --git a/drivers/thermal/jc42.c b/drivers/thermal/jc42.c new file mode 100644 index 00000000000..6945260e8b0 --- /dev/null +++ b/drivers/thermal/jc42.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2026 Free Mobile - Vincent Jardin + * + * JEDEC JC-42.4 / TSE2004av Temperature Sensor driver. + * + * Generic I2C temperature sensor of the Serial Presence Detect (SPD) + * bus of DDR3 and DDR4 SO-DIMMs / UDIMMs / RDIMMs per the JEDEC + * JC-42.4 standard. The TSE2004av variant adds an integrated SPD + * EEPROM, but the thermal register interface is the same and is + * what this driver exposes. + * + * Register layout (subset): + * 0x05 Ambient temperature, 16-bit big-endian: + * bit 15 : T_CRIT alarm flag (read-only) + * bit 14 : T_HIGH alarm flag (read-only) + * bit 13 : T_LOW alarm flag (read-only) + * bit 12 : sign (two's-complement within bits[12:0]) + * bits[11:0]: magnitude * 16 (LSB = 0.0625 degC = 62.5 mC) + * 0x06 Manufacturer ID (16-bit BE, JEP-106 vendor code) + * 0x07 Device ID + Revision (upper byte = ID, lower = revision) + * ... + */ + +#include <dm.h> +#include <i2c.h> +#include <thermal.h> +#include <linux/bitops.h> + +#define JC42_REG_TEMP 0x05 + +#define JC42_TEMP_SIGN BIT(12) +#define JC42_TEMP_MAGNITUDE GENMASK(11, 0) + +static int jc42_get_temp(struct udevice *dev, int *temp) +{ + u8 buf[2]; + int ret; + int mag; + + ret = dm_i2c_read(dev, JC42_REG_TEMP, buf, sizeof(buf)); + if (ret) + return ret; + + mag = ((buf[0] << 8) | buf[1]) & (JC42_TEMP_SIGN | JC42_TEMP_MAGNITUDE); + if (mag & JC42_TEMP_SIGN) + mag -= (JC42_TEMP_SIGN << 1); + + /* + * mag is in units of 1/16 degC. Multiply first to keep one + * extra bit of precision before the divide. Worst-case range + * for a 13-bit signed value is +/-4096, so the product fits + * comfortably in an int (~4.1M mC). + */ + *temp = mag * 1000 / 16; + + return 0; +} + +static const struct dm_thermal_ops jc42_ops = { + .get_temp = jc42_get_temp, +}; + +/* + * Optional DT label property override: it replace the default DM + * device name (the ofnode name, eg "temp@18") so + * temperature list or temperature get commands + * show a human-meaningful identifier such as "ddr-top" or + * "ddr-bottom". + * It mirrors the Linux hwmon binding which uses label for the + * per-sensor display name. + */ +static int jc42_bind(struct udevice *dev) +{ + const char *label = dev_read_string(dev, "label"); + + if (label && *label) + return device_set_name(dev, label); + return 0; +} + +static const struct udevice_id jc42_match[] = { + { .compatible = "jedec,jc-42.4-temp" }, + { } +}; + +U_BOOT_DRIVER(jc42_thermal) = { + .name = "jc42_thermal", + .id = UCLASS_THERMAL, + .of_match = jc42_match, + .bind = jc42_bind, + .ops = &jc42_ops, +}; diff --git a/drivers/thermal/pmbus_thermal.c b/drivers/thermal/pmbus_thermal.c new file mode 100644 index 00000000000..c251cea8ddf --- /dev/null +++ b/drivers/thermal/pmbus_thermal.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2026 Free Mobile - Vincent Jardin + * + * Generic UCLASS_THERMAL companion for PMBus voltage regulators. + * + * Works with any chip bound by a pmbus_helper based regulator driver + * (drivers/power/regulator/<chip>.c calling + * pmbus_regulator_probe_common()). It auto-spawns one + * of these thermal devices per regulator. + * + * The reading is the chip's READ_TEMPERATURE_1 (PMBus 0x8D), decoded + * through the parent's pmbus_driver_info. + */ + +#include <dm.h> +#include <pmbus.h> +#include <thermal.h> + +static int pmbus_thermal_get_temp(struct udevice *dev, int *temp) +{ + return pmbus_regulator_read_temp(dev_get_parent(dev), temp); +} + +static const struct dm_thermal_ops pmbus_thermal_ops = { + .get_temp = pmbus_thermal_get_temp, +}; + +U_BOOT_DRIVER(pmbus_thermal) = { + .name = "pmbus_thermal", + .id = UCLASS_THERMAL, + .ops = &pmbus_thermal_ops, +}; diff --git a/drivers/thermal/ti-bandgap.c b/drivers/thermal/ti-bandgap.c index dc869f108e4..643971e12cd 100644 --- a/drivers/thermal/ti-bandgap.c +++ b/drivers/thermal/ti-bandgap.c @@ -176,7 +176,7 @@ static int ti_bandgap_probe(struct udevice *dev) { struct ti_bandgap *bgp = dev_get_priv(dev); - bgp->base = devfdt_get_addr_index(dev, 1); + bgp->base = dev_read_addr_index(dev, 1); return 0; } diff --git a/drivers/timer/goldfish_timer.c b/drivers/timer/goldfish_timer.c index 70673bbd93c..59ce43fcb46 100644 --- a/drivers/timer/goldfish_timer.c +++ b/drivers/timer/goldfish_timer.c @@ -31,8 +31,8 @@ static u64 goldfish_timer_get_count(struct udevice *dev) * We must read LOW before HIGH to latch the high 32-bit value * and ensure a consistent 64-bit timestamp. */ - low = readl(priv->base + TIMER_TIME_LOW); - high = readl(priv->base + TIMER_TIME_HIGH); + low = __raw_readl(priv->base + TIMER_TIME_LOW); + high = __raw_readl(priv->base + TIMER_TIME_HIGH); time = ((u64)high << 32) | low; @@ -45,8 +45,10 @@ static int goldfish_timer_of_to_plat(struct udevice *dev) fdt_addr_t addr; addr = dev_read_addr(dev); - if (addr != FDT_ADDR_T_NONE) - plat->reg = addr; + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + plat->reg = addr; return 0; } diff --git a/drivers/timer/orion-timer.c b/drivers/timer/orion-timer.c index 821b681a232..4d1c6b5cef2 100644 --- a/drivers/timer/orion-timer.c +++ b/drivers/timer/orion-timer.c @@ -2,6 +2,7 @@ #include <asm/io.h> #include <config.h> #include <div64.h> +#include <dm.h> #include <dm/device.h> #include <dm/fdtaddr.h> #include <timer.h> @@ -113,7 +114,7 @@ static int orion_timer_probe(struct udevice *dev) enum input_clock_type type = dev_get_driver_data(dev); struct orion_timer_priv *priv = dev_get_priv(dev); - priv->base = devfdt_remap_addr_index(dev, 0); + priv->base = dev_remap_addr_index(dev, 0); if (!priv->base) { debug("unable to map registers\n"); return -ENOMEM; diff --git a/drivers/timer/sp804_timer.c b/drivers/timer/sp804_timer.c index 05532e3330c..d1a5fc8c5bf 100644 --- a/drivers/timer/sp804_timer.c +++ b/drivers/timer/sp804_timer.c @@ -44,7 +44,7 @@ static int sp804_clk_of_to_plat(struct udevice *dev) struct sp804_timer_plat *plat = dev_get_plat(dev); plat->base = dev_read_addr(dev); - if (!plat->base) + if (plat->base == FDT_ADDR_T_NONE) return -ENOENT; return 0; diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c index 14a94f8d4a8..46805eaa013 100644 --- a/drivers/tpm/cr50_i2c.c +++ b/drivers/tpm/cr50_i2c.c @@ -889,7 +889,7 @@ static int cr50_i2c_probe(struct udevice *dev) return 0; } -struct acpi_ops cr50_acpi_ops = { +static const struct acpi_ops cr50_acpi_ops = { .fill_ssdt = cr50_acpi_fill_ssdt, }; diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig index 49472933de3..c1b84bd7559 100644 --- a/drivers/ufs/Kconfig +++ b/drivers/ufs/Kconfig @@ -19,12 +19,12 @@ config UFS_AMD_VERSAL2 config UFS_CADENCE bool "Cadence platform driver for UFS" depends on UFS - help + help This selects the platform driver for the Cadence UFS host controller present on present TI's J721e devices. config UFS_MEDIATEK - tristate "MediaTek UFS Host Controller Driver" + bool "MediaTek UFS Host Controller Driver" depends on UFS && ARCH_MEDIATEK select PHY_MTK_UFS help @@ -51,7 +51,7 @@ config UFS_PCI config UFS_QCOM bool "Qualcomm Host Controller driver for UFS" depends on UFS && ARCH_SNAPDRAGON - help + help This selects the platform driver for the UFS host controller present on Qualcomm Snapdragon SoCs. diff --git a/drivers/ufs/ufs-amd-versal2.c b/drivers/ufs/ufs-amd-versal2.c index 6c949b2ca76..3369d32d924 100644 --- a/drivers/ufs/ufs-amd-versal2.c +++ b/drivers/ufs/ufs-amd-versal2.c @@ -563,4 +563,5 @@ U_BOOT_DRIVER(ufs_versal2_pltfm) = { .id = UCLASS_UFS, .of_match = ufs_versal2_ids, .probe = ufs_versal2_probe, + .priv_auto = sizeof(struct ufs_versal2_priv), }; diff --git a/drivers/ufs/ufs-mediatek.c b/drivers/ufs/ufs-mediatek.c index e860d765eea..268627d5863 100644 --- a/drivers/ufs/ufs-mediatek.c +++ b/drivers/ufs/ufs-mediatek.c @@ -182,19 +182,15 @@ 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); + 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) { + if (err == -ENOENT) + return 0; /* no PHY, nothing to do */ + dev_err(hba->dev, "Failed to get PHY: %d.\n", err); + return err; } - if (err) - host->mphy = NULL; - return err; } @@ -321,19 +317,35 @@ static int ufs_mtk_init(struct ufs_hba *hba) ufs_mtk_init_reset(hba); - // TODO: Clocking + err = clk_get_bulk(hba->dev, &priv->clks); + if (err) { + dev_err(hba->dev, "failed to initialize clocks, err:%d\n", err); + return err; + } + + err = clk_enable_bulk(&priv->clks); + if (err) { + dev_err(hba->dev, "failed to enable clocks, err:%d\n", err); + goto err_clk_enable; + } - err = generic_phy_power_on(priv->mphy); + err = generic_phy_power_on(&priv->mphy); if (err) { dev_err(hba->dev, "%s: phy init failed, err = %d\n", __func__, err); - return err; + goto err_phy_power_on; } ufs_mtk_setup_ref_clk(hba, true); ufs_mtk_get_hw_ip_version(hba); return 0; + +err_phy_power_on: + clk_disable_bulk(&priv->clks); +err_clk_enable: + clk_release_bulk(&priv->clks); + return err; } static int ufs_mtk_device_reset(struct ufs_hba *hba) @@ -383,7 +395,9 @@ static int ufs_mtk_probe(struct udevice *dev) static const struct udevice_id ufs_mtk_ids[] = { { .compatible = "mediatek,mt6878-ufshci" }, - {}, + { .compatible = "mediatek,mt8183-ufshci" }, + { .compatible = "mediatek,mt8195-ufshci" }, + { } }; U_BOOT_DRIVER(mediatek_ufshci) = { diff --git a/drivers/ufs/ufs-mediatek.h b/drivers/ufs/ufs-mediatek.h index 11a83d34c5b..0ffd0483eff 100644 --- a/drivers/ufs/ufs-mediatek.h +++ b/drivers/ufs/ufs-mediatek.h @@ -154,7 +154,7 @@ struct ufs_mtk_mcq_intr_info { }; struct ufs_mtk_host { - struct phy *mphy; + struct phy mphy; struct reset_ctl *unipro_reset; struct reset_ctl *crypto_reset; struct reset_ctl *hci_reset; diff --git a/drivers/ufs/ufs-qcom.c b/drivers/ufs/ufs-qcom.c index dc40ee62daf..f5f5a6eb110 100644 --- a/drivers/ufs/ufs-qcom.c +++ b/drivers/ufs/ufs-qcom.c @@ -30,6 +30,7 @@ #define UFS_CPU_MAX_BANDWIDTH 819200 static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_hba *hba, bool enable); +static u32 ufs_qcom_get_core_clk_unipro_max_freq(struct ufs_hba *hba); static int ufs_qcom_enable_clks(struct ufs_qcom_priv *priv) { @@ -47,17 +48,6 @@ static int ufs_qcom_enable_clks(struct ufs_qcom_priv *priv) return 0; } -static int ufs_qcom_init_clks(struct ufs_qcom_priv *priv) -{ - int err; - struct udevice *dev = priv->hba->dev; - - err = clk_get_bulk(dev, &priv->clks); - if (err) - return err; - - return 0; -} static int ufs_qcom_check_hibern8(struct ufs_hba *hba) { @@ -557,10 +547,45 @@ static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_hba *hba, bool enable) static int ufs_qcom_init(struct ufs_hba *hba) { struct ufs_qcom_priv *priv = dev_get_priv(hba->dev); + struct udevice *dev = hba->dev; + struct clk clk; + u32 max_freq; + long rate; int err; priv->hba = hba; + /* Get maximum frequency for core_clk_unipro from device tree */ + max_freq = ufs_qcom_get_core_clk_unipro_max_freq(hba); + + /* Get and configure core_clk_unipro */ + err = clk_get_by_name(dev, "core_clk_unipro", &clk); + if (err) { + dev_err(dev, "Failed to get core_clk_unipro: %d\n", err); + return err; + } + + rate = clk_set_rate(&clk, max_freq); + if (rate < 0) { + dev_err(dev, "Failed to set core_clk_unipro rate to %u Hz: %ld\n", + max_freq, rate); + } + + /* Get all clocks */ + err = clk_get_bulk(dev, &priv->clks); + if (err) { + dev_err(dev, "clk_get_bulk failed: %d\n", err); + return err; + } + + /* Enable clocks */ + err = ufs_qcom_enable_clks(priv); + if (err) { + dev_err(dev, "failed to enable clocks: %d\n", err); + clk_release_bulk(&priv->clks); + return err; + } + /* setup clocks */ ufs_qcom_setup_clocks(hba, true, PRE_CHANGE); @@ -579,14 +604,7 @@ static int ufs_qcom_init(struct ufs_hba *hba) priv->hw_ver.minor, priv->hw_ver.step); - err = ufs_qcom_init_clks(priv); - if (err) { - dev_err(hba->dev, "failed to initialize clocks, err:%d\n", err); - return err; - } - ufs_qcom_advertise_quirks(hba); - ufs_qcom_setup_clocks(hba, true, POST_CHANGE); return 0; } diff --git a/drivers/ufs/ufs-renesas-rcar-gen5.c b/drivers/ufs/ufs-renesas-rcar-gen5.c index a21ae3f390e..a9473cd60b1 100644 --- a/drivers/ufs/ufs-renesas-rcar-gen5.c +++ b/drivers/ufs/ufs-renesas-rcar-gen5.c @@ -92,14 +92,14 @@ static int ufs_renesas_pre_init(struct ufs_hba *hba) 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, 0x80090000, 0x00000000, 0x0000000c); + ufs_dme_command(hba, 0x00000002, 0x800a0000, 0x00000000, 0x00000080); + ufs_dme_command(hba, 0x00000002, 0x80090001, 0x00000000, 0x0000000c); + ufs_dme_command(hba, 0x00000002, 0x800a0001, 0x00000000, 0x00000080); + ufs_dme_command(hba, 0x00000002, 0x800a0004, 0x00000000, 0x00000003); + ufs_dme_command(hba, 0x00000002, 0x800b0004, 0x00000000, 0x000000ea); + ufs_dme_command(hba, 0x00000002, 0x800a0005, 0x00000000, 0x00000003); + ufs_dme_command(hba, 0x00000002, 0x800b0005, 0x00000000, 0x000000ea); ufs_dme_command(hba, 0x00000002, 0xd0850000, 0x00000000, 0x00000001); writew(0x0001, priv->phy_base + 0x20000); diff --git a/drivers/ufs/ufs-rockchip.c b/drivers/ufs/ufs-rockchip.c index a13236c7f76..dc4b9b5c86d 100644 --- a/drivers/ufs/ufs-rockchip.c +++ b/drivers/ufs/ufs-rockchip.c @@ -19,13 +19,22 @@ #include "unipro.h" #include "ufs-rockchip.h" +static void ufs_rockchip_controller_reset(struct ufs_rockchip_host *host) +{ + reset_assert_bulk(&host->rsts); + udelay(1); + reset_deassert_bulk(&host->rsts); +} + static int ufs_rockchip_hce_enable_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { int err = 0; - if (status != POST_CHANGE) + if (status != POST_CHANGE) { + ufs_rockchip_controller_reset(dev_get_priv(hba->dev)); return 0; + } ufshcd_dme_reset(hba); ufshcd_dme_enable(hba); @@ -150,6 +159,8 @@ static int ufs_rockchip_common_init(struct ufs_hba *hba) return err; } + ufs_rockchip_controller_reset(host); + err = gpio_request_by_name(dev, "reset-gpios", 0, &host->device_reset, GPIOD_IS_OUT | GPIOD_ACTIVE_LOW); if (err) { diff --git a/drivers/ufs/ufs-uclass.c b/drivers/ufs/ufs-uclass.c index 81fd431f951..6a51f337e47 100644 --- a/drivers/ufs/ufs-uclass.c +++ b/drivers/ufs/ufs-uclass.c @@ -1751,7 +1751,15 @@ static int ufshcd_read_string_desc(struct ufs_hba *hba, int desc_index, goto out; } - buff_ascii = kmalloc(ascii_len, GFP_KERNEL); + /* + * utf-8 is encoded using up to 4-Bytes per character, + * however, we only allocate such a buffer because the + * utf16_to_utf8() converts the entire $ascii_len worth + * of input characters into up to 4-Byte long utf-8 + * characters. The rest of the function uses only up to + * $ascii_len bytes of that utf-8 string. + */ + buff_ascii = kmalloc(ascii_len * 4, GFP_KERNEL); if (!buff_ascii) { err = -ENOMEM; goto out; diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 93c5ee69b25..05ac388ecf2 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -1,7 +1,7 @@ menuconfig USB bool "USB support" select BLK - ---help--- + help Universal Serial Bus (USB) is a specification for a serial bus subsystem which offers higher speeds and more features than the traditional PC serial port. The bus supplies power to peripherals @@ -94,7 +94,7 @@ comment "USB peripherals" config USB_STORAGE bool "USB Mass Storage support" - ---help--- + help Say Y here if you want to connect USB mass storage devices to your board's USB port. @@ -103,7 +103,7 @@ config USB_KEYBOARD depends on DM_USB select DM_KEYBOARD select SYS_STDIO_DEREGISTER - ---help--- + help Say Y here if you want to use a USB keyboard for U-Boot command line input. @@ -111,7 +111,7 @@ config USB_ONBOARD_HUB bool "Onboard USB hub support" depends on DM_USB select DEVRES - ---help--- + help Say Y here if you want to support discrete onboard USB hubs that don't require an additional control bus for initialization, but need some non-trivial form of initialization, such as enabling a @@ -163,17 +163,17 @@ choice prompt "USB keyboard polling" default SYS_USB_EVENT_POLL_VIA_INT_QUEUE if ARCH_SUNXI default SYS_USB_EVENT_POLL - ---help--- + help Enable a polling mechanism for USB keyboard. config SYS_USB_EVENT_POLL - bool "Interrupt polling" + bool "Interrupt polling" config SYS_USB_EVENT_POLL_VIA_INT_QUEUE - bool "Poll via interrupt queue" + bool "Poll via interrupt queue" config SYS_USB_EVENT_POLL_VIA_CONTROL_EP - bool "Poll via control EP" + bool "Poll via control EP" endchoice diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig index 7964f3f41d5..ad0ef8ac2ba 100644 --- a/drivers/usb/cdns3/Kconfig +++ b/drivers/usb/cdns3/Kconfig @@ -1,5 +1,5 @@ config USB_CDNS3 - tristate "Cadence USB3 Dual-Role Controller" + bool "Cadence USB3 Dual-Role Controller" depends on USB_XHCI_HCD || USB_GADGET select DEVRES help @@ -51,14 +51,14 @@ config SPL_USB_CDNS3_HOST standard XHCI driver. config USB_CDNS3_STARFIVE - tristate "Cadence USB3 support on Starfive platforms" + bool "Cadence USB3 support on Starfive platforms" default y if STARFIVE_JH7110 help Say 'Y' here if you are building for Starfive platforms that contain Cadence USB3 controller core. E.g.: JH7110. config USB_CDNS3_TI - tristate "Cadence USB3 support on TI platforms" + bool "Cadence USB3 support on TI platforms" default USB_CDNS3 help Say 'Y' here if you are building for Texas Instruments diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 65c4d1a4e6f..be198041f08 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -106,6 +106,8 @@ done: if (DWC3_VER_IS_WITHIN(DWC31, ANY, 180A)) mdelay(50); + mdelay(100); + return 0; } @@ -206,7 +208,6 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc, struct dwc3_event_buffer *evt) { dma_free_coherent(evt->buf); - free(evt); } /** diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c index 99519602eb2..8cb5796b6ad 100644 --- a/drivers/usb/dwc3/dwc3-am62.c +++ b/drivers/usb/dwc3/dwc3-am62.c @@ -105,7 +105,7 @@ static void dwc3_ti_am62_glue_configure(struct udevice *dev, int index, writel(reg, usbss + USBSS_MODE_CONTROL); } -struct dwc3_glue_ops ti_am62_ops = { +static const struct dwc3_glue_ops ti_am62_ops = { .glue_configure = dwc3_ti_am62_glue_configure, }; diff --git a/drivers/usb/dwc3/dwc3-generic-sti.c b/drivers/usb/dwc3/dwc3-generic-sti.c index b34f5ceceac..ce195b2553b 100644 --- a/drivers/usb/dwc3/dwc3-generic-sti.c +++ b/drivers/usb/dwc3/dwc3-generic-sti.c @@ -114,7 +114,7 @@ static void dwc3_stih407_glue_configure(struct udevice *dev, int index, setbits_le32(glue_base + CLKRST_CTRL, SW_PIPEW_RESET_N); }; -struct dwc3_glue_ops stih407_ops = { +static const struct dwc3_glue_ops stih407_ops = { .glue_configure = dwc3_stih407_glue_configure, }; diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 22b9ef0b24e..2356b3bc0aa 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -330,7 +330,7 @@ void dwc3_imx8mp_glue_configure(struct udevice *dev, int index, unmap_physmem(base, MAP_NOCACHE); } -struct dwc3_glue_ops imx8mp_ops = { +static const struct dwc3_glue_ops imx8mp_ops = { .glue_configure = dwc3_imx8mp_glue_configure, }; @@ -414,7 +414,7 @@ enum dwc3_omap_utmi_mode { unmap_physmem(base, MAP_NOCACHE); } -struct dwc3_glue_ops ti_ops = { +static const struct dwc3_glue_ops ti_ops = { .glue_configure = dwc3_ti_glue_configure, }; @@ -506,16 +506,16 @@ static int dwc3_flat_dt_get_ctrl_dev(struct udevice *dev, ofnode *node) return 0; } -struct dwc3_glue_ops qcom_ops = { +static const struct dwc3_glue_ops qcom_ops = { .glue_configure = dwc3_qcom_glue_configure, }; -struct dwc3_glue_ops qcom_flat_dt_ops = { +static const struct dwc3_glue_ops qcom_flat_dt_ops = { .glue_configure = dwc3_qcom_glue_configure, .glue_get_ctrl_dev = dwc3_flat_dt_get_ctrl_dev, }; -struct dwc3_glue_ops rk_ops = { +static const struct dwc3_glue_ops rk_ops = { .glue_get_ctrl_dev = dwc3_flat_dt_get_ctrl_dev, }; diff --git a/drivers/usb/emul/Kconfig b/drivers/usb/emul/Kconfig index 279f6c6d740..6305f2496c3 100644 --- a/drivers/usb/emul/Kconfig +++ b/drivers/usb/emul/Kconfig @@ -2,6 +2,7 @@ config USB_EMUL bool "Support for USB device emulation" depends on SANDBOX select DM_USB + select SCSI select USB_HOST help Since sandbox does not have access to a real USB bus, it is possible diff --git a/drivers/usb/eth/Kconfig b/drivers/usb/eth/Kconfig index 2f6bfa8e71b..b9b77f46743 100644 --- a/drivers/usb/eth/Kconfig +++ b/drivers/usb/eth/Kconfig @@ -1,6 +1,6 @@ menuconfig USB_HOST_ETHER bool "USB to Ethernet Controller Drivers" - ---help--- + help Say Y here if you would like to enable support for USB Ethernet adapters. @@ -9,14 +9,14 @@ if USB_HOST_ETHER config USB_ETHER_ASIX bool "ASIX AX8817X (USB 2.0) support" depends on USB_HOST_ETHER - ---help--- + help Say Y here if you would like to support ASIX AX8817X based USB 2.0 Ethernet Devices. config USB_ETHER_ASIX88179 bool "ASIX AX88179 (USB 3.0) support" depends on USB_HOST_ETHER - ---help--- + help Say Y here if you would like to support ASIX AX88179 based USB 3.0 Ethernet Devices. @@ -24,7 +24,7 @@ config USB_ETHER_LAN75XX bool "Microchip LAN75XX support" depends on USB_HOST_ETHER depends on PHYLIB - ---help--- + help Say Y here if you would like to support Microchip LAN75XX Hi-Speed USB 2.0 to 10/100/1000 Gigabit Ethernet controller. Supports 10Base-T/ 100Base-TX/1000Base-T. @@ -34,7 +34,7 @@ config USB_ETHER_LAN78XX bool "Microchip LAN78XX support" depends on USB_HOST_ETHER depends on PHYLIB - ---help--- + help Say Y here if you would like to support Microchip LAN78XX USB 3.1 Gen 1 to 10/100/1000 Gigabit Ethernet controller. Supports 10Base-T/ 100Base-TX/1000Base-T. @@ -43,14 +43,14 @@ config USB_ETHER_LAN78XX config USB_ETHER_MCS7830 bool "MOSCHIP MCS7830 (7730/7830/7832) suppport" depends on USB_HOST_ETHER - ---help--- + help Say Y here if you would like to support MOSCHIP MCS7830 based (7730/7830/7832) USB 2.0 Ethernet Devices. config USB_ETHER_RTL8152 bool "Realtek RTL8152B/RTL8153 support" depends on USB_HOST_ETHER - ---help--- + help Say Y here if you would like to support Realtek RTL8152B/RTL8153 base USB Ethernet Devices. This driver also supports compatible devices from Samsung, Lenovo, TP-LINK and Nvidia. @@ -58,7 +58,7 @@ config USB_ETHER_RTL8152 config USB_ETHER_SMSC95XX bool "SMSC LAN95x support" depends on USB_HOST_ETHER - ---help--- + help Say Y here if you would like to support SMSC LAN95xx based USB 2.0 Ethernet Devices. diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index baa2eb61ea3..e42d5a43696 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -19,10 +19,10 @@ menuconfig USB_GADGET select DM_USB imply CMD_BIND help - USB is a master/slave protocol, organized with one master - host (such as a PC) controlling up to 127 peripheral devices. - The USB hardware is asymmetric, which makes it easier to set up: - you can't connect a "to-the-host" connector to a peripheral. + USB is a master/slave protocol, organized with one master + host (such as a PC) controlling up to 127 peripheral devices. + The USB hardware is asymmetric, which makes it easier to set up: + you can't connect a "to-the-host" connector to a peripheral. U-Boot can run in the host, or in the peripheral. In both cases you need a low level bus controller driver, and some software @@ -119,6 +119,7 @@ config USB_GADGET_DWC2_OTG config USB_RENESAS_USBHS bool "Renesas R-Car USB2.0 HS controller (gadget mode)" + depends on DM_USB_GADGET select USB_GADGET_DUALSPEED help The Renesas R-Car USB 2.0 high-speed gadget controller @@ -163,10 +164,10 @@ config USB_GADGET_VBUS_DRAW range 2 500 default 2 help - Some devices need to draw power from USB when they are - configured, perhaps to operate circuitry or to recharge - batteries. This is in addition to any local power supply, - such as an AC adapter or batteries. + Some devices need to draw power from USB when they are + configured, perhaps to operate circuitry or to recharge + batteries. This is in addition to any local power supply, + such as an AC adapter or batteries. Enter the maximum power your device draws through USB, in milliAmperes. The permitted range of values is 2 - 500 mA; @@ -232,7 +233,7 @@ endif # USB_GADGET_DOWNLOAD config USB_ETHER bool "USB Ethernet Gadget" - depends on NET || NET_LWIP + depends on NET default y if ARCH_SUNXI && USB_MUSB_GADGET help Creates an Ethernet network device through a USB peripheral @@ -349,9 +350,9 @@ config SPL_DFU_RAM bool "RAM device" depends on SPL_DFU && SPL_RAM_SUPPORT help - select RAM/DDR memory device for loading binary images - (u-boot/kernel) to the selected device partition using - DFU and execute the u-boot/kernel from RAM. + select RAM/DDR memory device for loading binary images + (u-boot/kernel) to the selected device partition using + DFU and execute the u-boot/kernel from RAM. endchoice diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index f7a92ded6da..0caf8b8b7b4 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -289,10 +289,6 @@ static int usba_ep_disable(struct usb_ep *_ep) if (!ep->desc) { spin_unlock_irqrestore(&udc->lock, flags); - /* REVISIT because this driver disables endpoints in - * reset_all_endpoints() before calling disconnect(), - * most gadget drivers would trigger this non-error ... - */ if (udc->gadget.speed != USB_SPEED_UNKNOWN) DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name); @@ -571,20 +567,6 @@ static void reset_all_endpoints(struct usba_udc *udc) list_del_init(&req->queue); request_complete(ep, req, -ECONNRESET); } - - /* NOTE: normally, the next call to the gadget driver is in - * charge of disabling endpoints... usually disconnect(). - * The exception would be entering a high speed test mode. - * - * FIXME remove this code ... and retest thoroughly. - */ - list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) { - spin_unlock(&udc->lock); - usba_ep_disable(&ep->ep); - spin_lock(&udc->lock); - } - } } static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex) @@ -1219,7 +1201,7 @@ static struct usba_ep *usba_udc_pdata(struct usba_platform_data *pdata, struct usba_ep *eps; int i; - eps = malloc(sizeof(struct usba_ep) * pdata->num_ep); + eps = calloc(pdata->num_ep, sizeof(struct usba_ep)); if (!eps) { log_err("failed to alloc eps\n"); return NULL; diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index 8f7256069f5..b6c11d97a62 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -548,13 +548,11 @@ static int acm_add(struct usb_configuration *c) status = udc_device_get_by_index(0, &f_acm->udc); if (status) - return status; + goto err; status = usb_add_function(c, &f_acm->usb_function); - if (status) { - free(f_acm); - return status; - } + if (status) + goto err; buf_init(&f_acm->rx_buf, 2048); buf_init(&f_acm->tx_buf, 2048); @@ -562,6 +560,10 @@ static int acm_add(struct usb_configuration *c) if (!default_acm_function) default_acm_function = f_acm; + return 0; + +err: + free(f_acm); return status; } diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 71dc58da3f0..87ed25e8bb3 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -2275,6 +2275,17 @@ static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) static void fsg_disable(struct usb_function *f) { struct fsg_dev *fsg = fsg_from_func(f); + + /* Disable the endpoints */ + if (fsg->bulk_in_enabled) { + usb_ep_disable(fsg->bulk_in); + fsg->bulk_in_enabled = 0; + } + if (fsg->bulk_out_enabled) { + usb_ep_disable(fsg->bulk_out); + fsg->bulk_out_enabled = 0; + } + fsg->common->new_fsg = NULL; raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); } diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c index f72e27028b7..cd2c282247a 100644 --- a/drivers/usb/gadget/f_sdp.c +++ b/drivers/usb/gadget/f_sdp.c @@ -75,6 +75,7 @@ struct hid_report { #define SDP_HID_PACKET_SIZE_EP1 1024 #define SDP_EXIT 1 +#define SDP_FAIL 2 struct sdp_command { u16 cmd; @@ -840,11 +841,14 @@ static int sdp_handle_in_ep(struct spl_image_info *spl_image, #ifdef CONFIG_SPL_LOAD_FIT if (image_get_magic(header) == FDT_MAGIC) { struct spl_load_info load; + int ret; debug("Found FIT\n"); spl_load_init(&load, sdp_load_read, header, 1); - spl_load_simple_fit(spl_image, &load, 0, - header); + ret = spl_load_simple_fit(spl_image, &load, 0, + header); + if (ret) + return SDP_FAIL; return SDP_EXIT; } @@ -852,9 +856,13 @@ static int sdp_handle_in_ep(struct spl_image_info *spl_image, if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER) && valid_container_hdr((void *)header)) { struct spl_load_info load; + int ret; spl_load_init(&load, sdp_load_read, header, 1); - spl_load_imx_container(spl_image, &load, 0); + ret = spl_load_imx_container(spl_image, &load, 0); + if (ret) + return SDP_FAIL; + return SDP_EXIT; } @@ -924,6 +932,8 @@ int spl_sdp_handle(struct udevice *udc, struct spl_image_info *spl_image, if (flag == SDP_EXIT) return 0; + else if (flag == SDP_FAIL) + return -EIO; schedule(); dm_usb_gadget_handle_interrupts(udc); diff --git a/drivers/usb/gadget/rcar/common.c b/drivers/usb/gadget/rcar/common.c index 2ba022a3f2c..10548f7a20c 100644 --- a/drivers/usb/gadget/rcar/common.c +++ b/drivers/usb/gadget/rcar/common.c @@ -15,6 +15,7 @@ #include <linux/err.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> +#include <reset.h> #include <usb.h> #include "common.h" @@ -91,6 +92,12 @@ void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable) u16 mask = DCFM | DRPD | DPRPU | HSE | USBE; u16 val = HSE | USBE; + /* CNEN bit is required for function operation */ + if (usbhs_get_dparam(priv, has_cnen)) { + mask |= CNEN; + val |= CNEN; + } + /* * if enable * @@ -290,6 +297,9 @@ struct usbhs_priv_otg_data { void __iomem *base; void __iomem *phybase; + struct clk_bulk clk_bulk; + struct reset_ctl_bulk reset_bulk; + struct platform_device usbhs_dev; struct usbhs_priv usbhs_priv; @@ -355,15 +365,25 @@ static int usbhs_udc_otg_gadget_handle_interrupts(struct udevice *dev) return 0; } -static int usbhs_probe(struct usbhs_priv *priv) +static int usbhs_probe(struct udevice *dev) { + struct usbhs_priv_otg_data *otg_priv = dev_get_priv(dev); + struct usbhs_priv *priv = &otg_priv->usbhs_priv; + struct renesas_usbhs_driver_param *plat_param; int ret; + plat_param = (struct renesas_usbhs_driver_param *)dev_get_driver_data(dev); + priv->dparam.type = USBHS_TYPE_RCAR_GEN3; priv->dparam.pio_dma_border = 64; priv->dparam.pipe_configs = usbhsc_new_pipe; priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe); + if (plat_param) { + priv->dparam.has_cnen = plat_param->has_cnen; + priv->dparam.cfifo_byte_addr = plat_param->cfifo_byte_addr; + } + /* call pipe and module init */ ret = usbhs_pipe_probe(priv); if (ret < 0) @@ -396,34 +416,41 @@ static int usbhs_udc_otg_probe(struct udevice *dev) { struct usbhs_priv_otg_data *priv = dev_get_priv(dev); struct usb_gadget *gadget; - struct clk_bulk clk_bulk; int ret = -EINVAL; priv->base = dev_read_addr_ptr(dev); if (!priv->base) return -EINVAL; - ret = clk_get_bulk(dev, &clk_bulk); + ret = clk_get_bulk(dev, &priv->clk_bulk); if (ret) return ret; - ret = clk_enable_bulk(&clk_bulk); + ret = clk_enable_bulk(&priv->clk_bulk); if (ret) - return ret; + goto err_clk_enable; + + ret = reset_get_bulk(dev, &priv->reset_bulk); + if (ret) + goto err_clk; + + ret = reset_deassert_bulk(&priv->reset_bulk); + if (ret) + goto err_reset_deassert; clrsetbits_le32(priv->base + UGCTRL2, UGCTRL2_USB0SEL_MASK, UGCTRL2_USB0SEL_EHCI); clrsetbits_le16(priv->base + LPSTS, LPSTS_SUSPM, LPSTS_SUSPM); ret = generic_setup_phy(dev, &priv->phy, 0, PHY_MODE_USB_OTG, 1); if (ret) - goto err_clk; + goto err_reset; priv->phybase = dev_read_addr_ptr(priv->phy.dev); priv->usbhs_priv.pdev = &priv->usbhs_dev; priv->usbhs_priv.base = priv->base; priv->usbhs_dev.dev.driver_data = &priv->usbhs_priv; - ret = usbhs_probe(&priv->usbhs_priv); + ret = usbhs_probe(dev); if (ret < 0) goto err_phy; @@ -439,27 +466,49 @@ static int usbhs_udc_otg_probe(struct udevice *dev) err_phy: generic_shutdown_phy(&priv->phy); +err_reset: + reset_assert_bulk(&priv->reset_bulk); +err_reset_deassert: + reset_release_bulk(&priv->reset_bulk); err_clk: - clk_disable_bulk(&clk_bulk); + clk_disable_bulk(&priv->clk_bulk); +err_clk_enable: + clk_release_bulk(&priv->clk_bulk); + return ret; } static int usbhs_udc_otg_remove(struct udevice *dev) { struct usbhs_priv_otg_data *priv = dev_get_priv(dev); + struct usb_gadget *gadget; usbhs_rcar3_power_ctrl(&priv->usbhs_priv, false); + gadget = usbhsg_get_gadget(&priv->usbhs_priv); + usb_del_gadget_udc(gadget); usbhs_mod_remove(&priv->usbhs_priv); usbhs_fifo_remove(&priv->usbhs_priv); usbhs_pipe_remove(&priv->usbhs_priv); generic_shutdown_phy(&priv->phy); + reset_assert_bulk(&priv->reset_bulk); + reset_release_bulk(&priv->reset_bulk); + + clk_disable_bulk(&priv->clk_bulk); + clk_release_bulk(&priv->clk_bulk); + return dm_scan_fdt_dev(dev); } +static struct renesas_usbhs_driver_param rzg2l_param = { + .has_cnen = 1, + .cfifo_byte_addr = 1, +}; + static const struct udevice_id usbhs_udc_otg_ids[] = { { .compatible = "renesas,rcar-gen3-usbhs" }, + { .compatible = "renesas,rzg2l-usbhs", .data = (unsigned long)&rzg2l_param }, {}, }; diff --git a/drivers/usb/gadget/rcar/renesas_usb.h b/drivers/usb/gadget/rcar/renesas_usb.h index 8155e3dcaf6..140a70251cf 100644 --- a/drivers/usb/gadget/rcar/renesas_usb.h +++ b/drivers/usb/gadget/rcar/renesas_usb.h @@ -111,6 +111,7 @@ struct renesas_usbhs_driver_param { u32 has_otg:1; /* for controlling PWEN/EXTLP */ u32 has_sudmac:1; /* for SUDMAC */ u32 has_usb_dmac:1; /* for USB-DMAC */ + u32 has_cnen:1; u32 cfifo_byte_addr:1; /* CFIFO is byte addressable */ #define USBHS_USB_DMAC_XFER_SIZE 32 /* hardcode the xfer size */ u32 multi_clks:1; diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index d75883e2865..6bbed9cb513 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -24,7 +24,7 @@ config USB_XHCI_HCD bool "xHCI HCD (USB 3.0) support" depends on DM && OF_CONTROL select USB_HOST - ---help--- + help The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0 "SuperSpeed" host controller hardware. @@ -149,7 +149,7 @@ config USB_EHCI_HCD select USB_HOST select EHCI_DESC_BIG_ENDIAN if SYS_BIG_ENDIAN select EHCI_MMIO_BIG_ENDIAN if SYS_BIG_ENDIAN - ---help--- + help The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0 "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware. If your USB host controller supports USB 2.0, you will likely want to @@ -174,14 +174,14 @@ config USB_EHCI_ATMEL bool "Support for Atmel on-chip EHCI USB controller" depends on ARCH_AT91 default y - ---help--- + help Enables support for the on-chip EHCI controller on Atmel chips. config USB_EHCI_EXYNOS bool "Support for Samsung Exynos EHCI USB controller" depends on ARCH_EXYNOS default y - ---help--- + help Enables support for the on-chip EHCI controller on Samsung Exynos SoCs. @@ -191,7 +191,7 @@ config USB_EHCI_MARVELL default y select USB_EHCI_IS_TDI if !ARM64 select USB_EHCI_IS_TDI if ALLEYCAT_5 - ---help--- + help Enables support for the on-chip EHCI controller on MVEBU SoCs. config USB_EHCI_MX5 @@ -205,7 +205,7 @@ config USB_EHCI_MX6 depends on ARCH_MX6 || ARCH_MX7ULP || ARCH_IMXRT select EHCI_HCD_INIT_AFTER_RESET default y - ---help--- + help Enables support for the on-chip EHCI controller on i.MX6 SoCs. config USB_EHCI_MX7 @@ -215,7 +215,7 @@ config USB_EHCI_MX7 select PHY if IMX8M || IMX9 select NOP_PHY if IMX8M || IMX9 default y - ---help--- + help Enables support for the on-chip EHCI controller on i.MX7/i.MX8M/i.MX9 SoCs. config USB_EHCI_MXS @@ -230,7 +230,7 @@ config USB_EHCI_MXS config USB_EHCI_NPCM bool "Support for Nuvoton NPCM on-chip EHCI USB controller" depends on ARCH_NPCM - ---help--- + help Enables support for the on-chip EHCI controller on Nuvoton NPCM chips. @@ -240,7 +240,7 @@ config USB_EHCI_OMAP select PHY imply NOP_PHY default y - ---help--- + help Enables support for the on-chip EHCI controller on OMAP3 and later SoCs. @@ -255,7 +255,7 @@ if USB_EHCI_MX6 || USB_EHCI_MX7 config MXC_USB_OTG_HACTIVE bool "USB Power pin high active" - ---help--- + help Set the USB Power pin polarity to be high active (PWR_POL) endif @@ -265,7 +265,7 @@ config USB_EHCI_MSM depends on DM_USB select USB_ULPI select MSM8916_USB_PHY - ---help--- + help Enables support for the on-chip EHCI controller on Qualcomm Snapdragon SoCs. @@ -280,7 +280,7 @@ config USB_EHCI_TEGRA bool "Support for NVIDIA Tegra on-chip EHCI USB controller" depends on ARCH_TEGRA select USB_EHCI_IS_TDI - ---help--- + help Enable support for Tegra on-chip EHCI USB controller. If you enable ULPI and your PHY needs a different reference clock than the standard 24 MHz then you have to define CFG_ULPI_REF_CLK to the appropriate @@ -291,14 +291,14 @@ config USB_EHCI_ZYNQ depends on ARCH_ZYNQ default y select USB_EHCI_IS_TDI - ---help--- + help Enable support for Zynq on-chip EHCI USB controller config USB_EHCI_GENERIC bool "Support for generic EHCI USB controller" depends on DM_USB default ARCH_SUNXI - ---help--- + help Enables support for generic EHCI controller. config EHCI_HCD_INIT_AFTER_RESET @@ -310,7 +310,7 @@ config USB_EHCI_FSL 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) - ---help--- + help Enables support for the on-chip EHCI controller on FSL chips. config SYS_FSL_USB_INTERNAL_UTMI_PHY @@ -340,7 +340,7 @@ config USB_OHCI_HCD depends on DM && OF_CONTROL select USB_HOST select USB_OHCI_NEW - ---help--- + help The Open Host Controller Interface (OHCI) is a standard for accessing USB 1.1 host controller hardware. It does more in hardware than Intel's UHCI specification. If your USB host controller follows the OHCI spec, @@ -361,7 +361,7 @@ config USB_OHCI_PCI config USB_OHCI_GENERIC bool "Support for generic OHCI USB controller" default ARCH_SUNXI - ---help--- + help Enables support for generic OHCI controller. config USB_OHCI_DA8XX @@ -374,7 +374,7 @@ config USB_OHCI_DA8XX config USB_OHCI_NPCM bool "Support for Nuvoton NPCM on-chip OHCI USB controller" depends on ARCH_NPCM - ---help--- + help Enables support for the on-chip OHCI controller on Nuvoton NPCM chips. @@ -391,7 +391,7 @@ config SYS_OHCI_SWAP_REG_ACCESS config USB_UHCI_HCD bool "UHCI HCD (most Intel and VIA) support" select USB_HOST - ---help--- + help The Universal Host Controller Interface is a standard by Intel for accessing the USB hardware in the PC (which is also called the USB host controller). If your USB host controller conforms to this @@ -410,7 +410,7 @@ config USB_DWC2 bool "DesignWare USB2 Core support" depends on DM && OF_CONTROL select USB_HOST - ---help--- + help The DesignWare USB 2.0 controller is compliant with the USB-Implementers Forum (USB-IF) USB 2.0 specifications. Hi-Speed (480 Mbps), Full-Speed (12 Mbps), and Low-Speed (1.5 Mbps) @@ -421,7 +421,7 @@ if USB_DWC2 config USB_DWC2_BUFFER_SIZE int "Data buffer size in kB" default 64 - ---help--- + help By default 64 kB buffer is used but if amount of RAM avaialble on the target is not enough to accommodate allocation of buffer of that size it is possible to shrink it. Smaller sizes should be fine @@ -433,7 +433,7 @@ config USB_R8A66597_HCD bool "Renesas R8A66597 USB Core support" depends on DM && OF_CONTROL select USB_HOST - ---help--- + help This enables support for the on-chip Renesas R8A66597 USB 2.0 controller, present in various RZ and SH SoCs. diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index ef4ce62a680..9cac53f07c7 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -5,7 +5,7 @@ ifdef CONFIG_$(PHASE_)DM_USB obj-y += usb-uclass.o -obj-$(CONFIG_SANDBOX) += usb-sandbox.o +obj-$(CONFIG_USB_EMUL) += usb-sandbox.o endif ifdef CONFIG_$(PHASE_)USB_STORAGE diff --git a/drivers/usb/host/ehci-marvell.c b/drivers/usb/host/ehci-marvell.c index 794a4168913..38ee17f063d 100644 --- a/drivers/usb/host/ehci-marvell.c +++ b/drivers/usb/host/ehci-marvell.c @@ -222,8 +222,8 @@ static void usb_brg_adrdec_setup(int index) break; } - size = gd->bd->bi_dram[i].size; - base = gd->bd->bi_dram[i].start; + size = gd->dram[i].size; + base = gd->dram[i].start; if ((size) && (attrib)) writel(MVCPU_WIN_CTRL_DATA(size, USB_TARGET_DRAM, attrib, MVCPU_WIN_ENABLE), diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 1d6711ccec4..3fcf9d53d59 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1750,7 +1750,7 @@ static int hc_reset(ohci_t *ohci) int timeout = 30; int smm_timeout = 50; /* 0,5 sec */ - dbg("%s\n", __FUNCTION__); + dbg("%s\n", __func__); #ifdef CONFIG_PCI_EHCI_DEVNO /* diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c index 7247245a702..1c74d6fd39a 100644 --- a/drivers/usb/host/usb-uclass.c +++ b/drivers/usb/host/usb-uclass.c @@ -134,7 +134,7 @@ int usb_alloc_device(struct usb_device *udev) struct udevice *bus = udev->controller_dev; struct dm_usb_ops *ops = usb_get_ops(bus); - /* This is only requird by some controllers - current XHCI */ + /* This is only required by some controllers - currently XHCI */ if (!ops->alloc_device) return 0; diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c index 12dc61aee9d..c294a56b3c9 100644 --- a/drivers/usb/host/xhci-mvebu.c +++ b/drivers/usb/host/xhci-mvebu.c @@ -82,6 +82,7 @@ static int xhci_usb_of_to_plat(struct udevice *dev) static const struct udevice_id xhci_usb_ids[] = { { .compatible = "marvell,armada3700-xhci" }, + { .compatible = "marvell,armada-375-xhci" }, { .compatible = "marvell,armada-380-xhci" }, { .compatible = "marvell,armada-8k-xhci" }, { } diff --git a/drivers/usb/musb-new/Kconfig b/drivers/usb/musb-new/Kconfig index f8daaddc657..208e47d8ff5 100644 --- a/drivers/usb/musb-new/Kconfig +++ b/drivers/usb/musb-new/Kconfig @@ -23,11 +23,11 @@ config USB_MUSB_GADGET if USB_MUSB_HOST || USB_MUSB_GADGET config USB_MUSB_SC5XX - bool "Analog Devices MUSB support" - depends on (SC57X || SC58X) + bool "Analog Devices MUSB support" + depends on (SC57X || SC58X) help - Say y here to enable support for the USB controller on - ADI SC57X/SC58X processors. + Say y here to enable support for the USB controller on + ADI SC57X/SC58X processors. config USB_MUSB_DA8XX bool "Enable DA8xx MUSB Controller" @@ -48,7 +48,7 @@ config USB_MUSB_TI silicon IP. config USB_MUSB_OMAP2PLUS - tristate "OMAP2430 and onwards" + bool "OMAP2430 and onwards" depends on ARCH_OMAP2PLUS config USB_MUSB_AM35X @@ -81,9 +81,9 @@ config USB_MUSB_SUNXI depends on PHY_SUN4I_USB select USB_MUSB_PIO_ONLY default y - ---help--- - Say y here to enable support for the sunxi OTG / DRC USB controller - used on almost all sunxi boards. + help + Say y here to enable support for the sunxi OTG / DRC USB controller + used on almost all sunxi boards. config USB_MUSB_UX500 bool "Enable ST-Ericsson Ux500 USB controller" diff --git a/drivers/usb/musb-new/omap2430.c b/drivers/usb/musb-new/omap2430.c index 7fd6639013a..c8c6bf0c84f 100644 --- a/drivers/usb/musb-new/omap2430.c +++ b/drivers/usb/musb-new/omap2430.c @@ -100,7 +100,7 @@ static int omap2430_musb_enable(struct musb *musb) #ifdef CONFIG_TWL4030_USB if (twl4030_usb_ulpi_init()) { serial_printf("ERROR: %s Could not initialize PHY\n", - __PRETTY_FUNCTION__); + __func__); } #endif return 0; diff --git a/drivers/usb/tcpm/Kconfig b/drivers/usb/tcpm/Kconfig index 9be4b496e82..b1ea7253720 100644 --- a/drivers/usb/tcpm/Kconfig +++ b/drivers/usb/tcpm/Kconfig @@ -1,14 +1,14 @@ # SPDX-License-Identifier: GPL-2.0 config TYPEC_TCPM - tristate "USB Type-C Port Controller Manager" + bool "USB Type-C Port Controller Manager" depends on DM help The Type-C Port Controller Manager provides a USB PD and USB Type-C state machine for use with Type-C Port Controllers. config TYPEC_FUSB302 - tristate "Fairchild FUSB302 Type-C chip driver" + bool "Fairchild FUSB302 Type-C chip driver" depends on DM && DM_I2C && TYPEC_TCPM help The Fairchild FUSB302 Type-C chip driver that works with diff --git a/drivers/usb/tcpm/tcpm.c b/drivers/usb/tcpm/tcpm.c index 3061b466d7c..d6c0be82333 100644 --- a/drivers/usb/tcpm/tcpm.c +++ b/drivers/usb/tcpm/tcpm.c @@ -207,7 +207,7 @@ static int tcpm_pd_transmit(struct udevice *dev, */ timeout_us *= 5; ret = read_poll_timeout(tcpm_transmit_helper, tx_complete, - !tx_complete, false, timeout_us, dev); + tx_complete, false, timeout_us, dev); if (ret < 0) { dev_err(dev, "TCPM: PD transmit data failed: %d\n", ret); return ret; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 08c9b020788..15000e21840 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -29,6 +29,13 @@ config VIDEO_FONT_4X6 Provides character bitmap data in header file. When selecting multiple fonts, you may want to enable CMD_SELECT_FONT too. +config VIDEO_FONT_6X8 + bool "6 x 8 font size" + help + Font for video console driver, 6 x 8 pixels. + Provides character bitmap data in header file. + When selecting multiple fonts, you may want to enable CMD_SELECT_FONT too. + config VIDEO_FONT_8X16 bool "8 x 16 font size" default y @@ -247,10 +254,10 @@ config SYS_WHITE_ON_BLACK bool "Display console as white on a black background" default y if ARCH_AT91 || ARCH_EXYNOS || ARCH_ROCKCHIP || ARCH_TEGRA || X86 || ARCH_SUNXI help - Normally the display is black on a white background, Enable this - option to invert this, i.e. white on a black background. This can be - better in low-light situations or to reduce eye strain in some - cases. + Normally the display is black on a white background, Enable this + option to invert this, i.e. white on a black background. This can be + better in low-light situations or to reduce eye strain in some + cases. config NO_FB_CLEAR bool "Skip framebuffer clear" @@ -508,10 +515,10 @@ config FRAMEBUFFER_VESA_MODE config VIDEO_LCD_ANX9804 bool "ANX9804 bridge chip" - ---help--- - Support for the ANX9804 bridge chip, which can take pixel data coming - from a parallel LCD interface and translate it on the fy into a DP - interface for driving eDP TFT displays. It uses I2C for configuration. + help + Support for the ANX9804 bridge chip, which can take pixel data coming + from a parallel LCD interface and translate it on the fy into a DP + interface for driving eDP TFT displays. It uses I2C for configuration. config ATMEL_LCD bool "Atmel LCD panel support" @@ -534,7 +541,7 @@ config VIDEO_BCM2835 that U-Boot can access it with full colour depth. config VIDEO_LCD_ENDEAVORU - tristate "Endeavoru 720x1280 DSI video mode panel" + bool "Endeavoru 720x1280 DSI video mode panel" depends on PANEL && BACKLIGHT select VIDEO_MIPI_DSI help @@ -549,11 +556,19 @@ config VIDEO_LCD_HIMAX_HX8394 depends on PANEL && BACKLIGHT select VIDEO_MIPI_DSI help - Say Y here if you want to enable support for Himax HX8394 - dsi 4dl panel. + Say Y here if you want to enable support for Himax HX8394 + dsi 4dl panel. + +config VIDEO_LCD_ILITEK_ILI9806E + bool "Ilitek ILI9806E-based panels" + depends on PANEL && BACKLIGHT + help + Say Y here if you want to enable support for panels base on + the Ilitek ILI9806E controller. Currently only the DBI panel + is implemented. config VIDEO_LCD_MOT - tristate "Atrix 4G and Droid X2 540x960 DSI video mode panel" + bool "Atrix 4G and Droid X2 540x960 DSI video mode panel" depends on PANEL && BACKLIGHT select VIDEO_MIPI_DSI help @@ -566,15 +581,15 @@ config VIDEO_LCD_NOVATEK_NT35510 bool "Novatek NT35510 DSI LCD panel support" select VIDEO_MIPI_DSI help - Say Y here if you want to enable support for Novatek nt35510 - dsi panel. + Say Y here if you want to enable support for Novatek nt35510 + dsi panel. config VIDEO_LCD_ORISETECH_OTM8009A bool "OTM8009A DSI LCD panel support" select VIDEO_MIPI_DSI help - Say Y here if you want to enable support for Orise Technology - otm8009a 480x800 dsi 2dl panel. + Say Y here if you want to enable support for Orise Technology + otm8009a 480x800 dsi 2dl panel. config VIDEO_LCD_LG_LD070WX3 bool "LD070WX3 DSI LCD panel support" @@ -594,13 +609,14 @@ config VIDEO_LCD_LG_LH400WV3 config VIDEO_LCD_RAYDIUM_RM68200 bool "RM68200 DSI LCD panel support" + depends on BACKLIGHT select VIDEO_MIPI_DSI help - Say Y here if you want to enable support for Raydium RM68200 - 720x1280 DSI video mode panel. + Say Y here if you want to enable support for Raydium RM68200 + 720x1280 DSI video mode panel. config VIDEO_LCD_RENESAS_R61307 - tristate "Renesas R61307 DSI video mode panel" + bool "Renesas R61307 DSI video mode panel" depends on PANEL && BACKLIGHT select VIDEO_MIPI_DSI help @@ -609,7 +625,7 @@ config VIDEO_LCD_RENESAS_R61307 resolution and uses 24 bit RGB per pixel. config VIDEO_LCD_RENESAS_R69328 - tristate "Renesas R69328 720x1280 DSI video mode panel" + bool "Renesas R69328 720x1280 DSI video mode panel" depends on PANEL && BACKLIGHT select VIDEO_MIPI_DSI help @@ -618,7 +634,7 @@ config VIDEO_LCD_RENESAS_R69328 resolution and uses 24 bit RGB per pixel. config VIDEO_LCD_SAMSUNG_LTL106HL02 - tristate "Samsung LTL106HL02 1920x1080 DSI video mode panel" + bool "Samsung LTL106HL02 1920x1080 DSI video mode panel" depends on PANEL && BACKLIGHT select VIDEO_MIPI_DSI help @@ -627,7 +643,7 @@ config VIDEO_LCD_SAMSUNG_LTL106HL02 resolution (1920x1080). config VIDEO_LCD_SHARP_LQ079L1SX01 - tristate "Sharp LQ079L1SX01 1536x2048 DSI video mode panel" + bool "Sharp LQ079L1SX01 1536x2048 DSI video mode panel" depends on PANEL && BACKLIGHT select VIDEO_MIPI_DSI help @@ -636,7 +652,7 @@ config VIDEO_LCD_SHARP_LQ079L1SX01 resolution (1536x2048). config VIDEO_LCD_SHARP_LQ101R1SX01 - tristate "Sharp LQ101R1SX01 2560x1600 DSI video mode panel" + bool "Sharp LQ101R1SX01 2560x1600 DSI video mode panel" depends on PANEL && BACKLIGHT select VIDEO_MIPI_DSI help @@ -646,41 +662,41 @@ config VIDEO_LCD_SHARP_LQ101R1SX01 config VIDEO_LCD_SSD2828 bool "SSD2828 bridge chip" - ---help--- - Support for the SSD2828 bridge chip, which can take pixel data coming - from a parallel LCD interface and translate it on the fly into MIPI DSI - interface for driving a MIPI compatible LCD panel. It uses SPI for - configuration. + help + Support for the SSD2828 bridge chip, which can take pixel data coming + from a parallel LCD interface and translate it on the fly into MIPI DSI + interface for driving a MIPI compatible LCD panel. It uses SPI for + configuration. config VIDEO_LCD_SSD2828_TX_CLK int "SSD2828 TX_CLK frequency (in MHz)" depends on VIDEO_LCD_SSD2828 default 0 - ---help--- - The frequency of the crystal, which is clocking SSD2828. It may be - anything in the 8MHz-30MHz range and the exact value should be - retrieved from the board schematics. Or in the case of Allwinner - hardware, it can be usually found as 'lcd_xtal_freq' variable in - FEX files. It can be also set to 0 for selecting PCLK from the - parallel LCD interface instead of TX_CLK as the PLL clock source. + help + The frequency of the crystal, which is clocking SSD2828. It may be + anything in the 8MHz-30MHz range and the exact value should be + retrieved from the board schematics. Or in the case of Allwinner + hardware, it can be usually found as 'lcd_xtal_freq' variable in + FEX files. It can be also set to 0 for selecting PCLK from the + parallel LCD interface instead of TX_CLK as the PLL clock source. config VIDEO_LCD_SSD2828_RESET string "RESET pin of SSD2828" depends on VIDEO_LCD_SSD2828 default "" - ---help--- - The reset pin of SSD2828 chip. This takes a string in the format - understood by 'sunxi_name_to_gpio' function, e.g. PH1 for pin 1 of port H. + help + The reset pin of SSD2828 chip. This takes a string in the format + understood by 'sunxi_name_to_gpio' function, e.g. PH1 for pin 1 of port H. config VIDEO_LCD_TDO_TL070WSH30 bool "TDO TL070WSH30 DSI LCD panel support" select VIDEO_MIPI_DSI help - Say Y here if you want to enable support for TDO TL070WSH30 - 1024x600 DSI video mode panel. + Say Y here if you want to enable support for TDO TL070WSH30 + 1024x600 DSI video mode panel. config VIDEO_LCD_HITACHI_TX10D07VM0BAA - tristate "Hitachi TX10D07VM0BAA 480x800 MIPI DSI video mode panel" + bool "Hitachi TX10D07VM0BAA 480x800 MIPI DSI video mode panel" depends on PANEL && BACKLIGHT select VIDEO_MIPI_DSI help @@ -689,13 +705,13 @@ config VIDEO_LCD_HITACHI_TX10D07VM0BAA config VIDEO_LCD_HITACHI_TX18D42VM bool "Hitachi tx18d42vm LVDS LCD panel support" - ---help--- - Support for Hitachi tx18d42vm LVDS LCD panels, these panels have a - lcd controller which needs to be initialized over SPI, once that is - done they work like a regular LVDS panel. + help + Support for Hitachi tx18d42vm LVDS LCD panels, these panels have a + lcd controller which needs to be initialized over SPI, once that is + done they work like a regular LVDS panel. config VIDEO_LCD_SONY_L4F00430T01 - tristate "Sony L4F00430T01 480x800 LCD panel support" + bool "Sony L4F00430T01 480x800 LCD panel support" depends on PANEL help Say Y here if you want to enable support for Sony L4F00430T01 @@ -704,7 +720,7 @@ config VIDEO_LCD_SONY_L4F00430T01 data comes from RGB. config VIDEO_LCD_SAMSUNG_S6E63M0 - tristate "Samsung S6E63M0 controller based panel support" + bool "Samsung S6E63M0 controller based panel support" depends on PANEL && BACKLIGHT help Say Y here if you want to enable support for Samsung S6E63M0 @@ -715,44 +731,44 @@ config VIDEO_LCD_SPI_CS string "SPI CS pin for LCD related config job" depends on VIDEO_LCD_SSD2828 || VIDEO_LCD_HITACHI_TX18D42VM default "" - ---help--- - This is one of the SPI communication pins, involved in setting up a - working LCD configuration. The exact role of SPI may differ for - different hardware setups. The option takes a string in the format - understood by 'sunxi_name_to_gpio' function, e.g. PH1 for pin 1 of port H. + help + This is one of the SPI communication pins, involved in setting up a + working LCD configuration. The exact role of SPI may differ for + different hardware setups. The option takes a string in the format + understood by 'sunxi_name_to_gpio' function, e.g. PH1 for pin 1 of port H. config VIDEO_LCD_SPI_SCLK string "SPI SCLK pin for LCD related config job" depends on VIDEO_LCD_SSD2828 || VIDEO_LCD_HITACHI_TX18D42VM default "" - ---help--- - This is one of the SPI communication pins, involved in setting up a - working LCD configuration. The exact role of SPI may differ for - different hardware setups. The option takes a string in the format - understood by 'sunxi_name_to_gpio' function, e.g. PH1 for pin 1 of port H. + help + This is one of the SPI communication pins, involved in setting up a + working LCD configuration. The exact role of SPI may differ for + different hardware setups. The option takes a string in the format + understood by 'sunxi_name_to_gpio' function, e.g. PH1 for pin 1 of port H. config VIDEO_LCD_SPI_MOSI string "SPI MOSI pin for LCD related config job" depends on VIDEO_LCD_SSD2828 || VIDEO_LCD_HITACHI_TX18D42VM default "" - ---help--- - This is one of the SPI communication pins, involved in setting up a - working LCD configuration. The exact role of SPI may differ for - different hardware setups. The option takes a string in the format - understood by 'sunxi_name_to_gpio' function, e.g. PH1 for pin 1 of port H. + help + This is one of the SPI communication pins, involved in setting up a + working LCD configuration. The exact role of SPI may differ for + different hardware setups. The option takes a string in the format + understood by 'sunxi_name_to_gpio' function, e.g. PH1 for pin 1 of port H. config VIDEO_LCD_SPI_MISO string "SPI MISO pin for LCD related config job (optional)" depends on VIDEO_LCD_SSD2828 default "" - ---help--- - This is one of the SPI communication pins, involved in setting up a - working LCD configuration. The exact role of SPI may differ for - different hardware setups. If wired up, this pin may provide additional - useful functionality. Such as bi-directional communication with the - hardware and LCD panel id retrieval (if the panel can report it). The - option takes a string in the format understood by 'sunxi_name_to_gpio' - function, e.g. PH1 for pin 1 of port H. + help + This is one of the SPI communication pins, involved in setting up a + working LCD configuration. The exact role of SPI may differ for + different hardware setups. If wired up, this pin may provide additional + useful functionality. Such as bi-directional communication with the + hardware and LCD panel id retrieval (if the panel can report it). The + option takes a string in the format understood by 'sunxi_name_to_gpio' + function, e.g. PH1 for pin 1 of port H. source "drivers/video/meson/Kconfig" @@ -760,9 +776,9 @@ config VIDEO_MVEBU bool "Armada XP LCD controller" depends on ARCH_MVEBU imply VIDEO_DAMAGE - ---help--- - Support for the LCD controller integrated in the Marvell - Armada XP SoC. + help + Support for the LCD controller integrated in the Marvell + Armada XP SoC. config VIDEO_OMAP3 bool "Enable OMAP3+ DSS Support" @@ -773,23 +789,23 @@ config VIDEO_OMAP3 config I2C_EDID bool "Enable EDID library" help - This enables library for accessing EDID data from an LCD panel. + This enables library for accessing EDID data from an LCD panel. config I2C_EDID_STANDARD bool "Enable standard timings EDID library expansion" depends on I2C_EDID help - This enables standard timings expansion for EDID data from an LCD panel. + This enables standard timings expansion for EDID data from an LCD panel. config DISPLAY bool "Enable Display support" depends on DM select I2C_EDID help - This supports drivers that provide a display, such as eDP (Embedded - DisplayPort) and HDMI (High Definition Multimedia Interface). - The devices provide a simple interface to start up the display, - read display information and enable it. + This supports drivers that provide a display, such as eDP (Embedded + DisplayPort) and HDMI (High Definition Multimedia Interface). + The devices provide a simple interface to start up the display, + read display information and enable it. config NXP_TDA19988 bool "Enable NXP TDA19988 support" @@ -803,7 +819,7 @@ config ATMEL_HLCD depends on ARCH_AT91 imply VIDEO_DAMAGE help - HLCDC supports video output to an attached LCD panel. + HLCDC supports video output to an attached LCD panel. config BACKLIGHT_AAT2870 bool "Backlight Driver for AAT2870" @@ -857,7 +873,7 @@ source "drivers/video/exynos/Kconfig" config LOGICORE_DP_TX bool "Enable Logicore DP TX driver" - depends on DISPLAY + depends on DISPLAY && AXI help Enable the driver for the transmitter part of the Xilinx LogiCORE DisplayPort, a IP core for Xilinx FPGAs that implements a DisplayPort @@ -922,9 +938,9 @@ config VIDEO_NX bool "Enable video support on Nexell SoC" depends on ARCH_S5P6818 || ARCH_S5P4418 help - Nexell SoC supports many video output options including eDP and - HDMI. This option enables this support which can be used on devices - which have an eDP display connected. + Nexell SoC supports many video output options including eDP and + HDMI. This option enables this support which can be used on devices + which have an eDP display connected. config VIDEO_SEPS525 bool "Enable video support for Seps525" @@ -1010,9 +1026,9 @@ config OSD bool "Enable OSD support" depends on DM help - This supports drivers that provide a OSD (on-screen display), which - is a (usually text-oriented) graphics buffer to show information on - a display. + This supports drivers that provide a OSD (on-screen display), which + is a (usually text-oriented) graphics buffer to show information on + a display. config SANDBOX_OSD bool "Enable sandbox OSD" @@ -1205,10 +1221,10 @@ config SPL_SPLASH_SCREEN config SPL_SYS_WHITE_ON_BLACK bool "Display console as white on a black background at SPL" help - Normally the display is black on a white background, Enable this - option to invert this, i.e. white on a black background at spl stage. - This can be better in low-light situations or to reduce eye strain in - some cases. + Normally the display is black on a white background, Enable this + option to invert this, i.e. white on a black background at spl stage. + This can be better in low-light situations or to reduce eye strain in + some cases. config SPL_VIDEO_PCI_DEFAULT_FB_SIZE hex "Default framebuffer size to use if no drivers request it at SPL" @@ -1271,10 +1287,10 @@ config SPL_SIMPLE_PANEL config SPL_SYS_WHITE_ON_BLACK bool "Display console as white on a black background at SPL" help - Normally the display is black on a white background, Enable this - option to invert this, i.e. white on a black background at spl stage. - This can be better in low-light situations or to reduce eye strain in - some cases. + Normally the display is black on a white background, Enable this + option to invert this, i.e. white on a black background at spl stage. + This can be better in low-light situations or to reduce eye strain in + some cases. config SPL_VIDEO_REMOVE bool "Remove video driver after SPL stage" @@ -1400,13 +1416,13 @@ config SPL_VIDEO_BPP32 will be empty. config SPL_HIDE_LOGO_VERSION - bool "Hide the version information on the splash screen at SPL" - help - Normally the U-Boot version string is shown on the display when the - splash screen is enabled. This information is not otherwise visible - since video starts up after U-Boot has displayed the initial banner. + bool "Hide the version information on the splash screen at SPL" + help + Normally the U-Boot version string is shown on the display when the + splash screen is enabled. This information is not otherwise visible + since video starts up after U-Boot has displayed the initial banner. - Enable this option to hide this information. + Enable this option to hide this information. endif endmenu diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 984768ea156..082b8967982 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -24,7 +24,7 @@ obj-$(CONFIG_$(PHASE_)PANEL) += panel-uclass.o obj-$(CONFIG_PANEL_HX8238D) += hx8238d.o obj-$(CONFIG_$(PHASE_)SIMPLE_PANEL) += simple_panel.o -obj-$(CONFIG_VIDEO_LOGO) += u_boot_logo.o +obj-$(CONFIG_VIDEO_LOGO) += u_boot_logo.bmp.o obj-$(CONFIG_$(PHASE_)BMP) += bmp.o endif @@ -61,6 +61,7 @@ obj-$(CONFIG_VIDEO_LCD_ENDEAVORU) += endeavoru-panel.o obj-$(CONFIG_VIDEO_LCD_HIMAX_HX8394) += himax-hx8394.o obj-$(CONFIG_VIDEO_LCD_HITACHI_TX10D07VM0BAA) += hitachi-tx10d07vm0baa.o obj-$(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM) += hitachi_tx18d42vm_lcd.o +obj-$(CONFIG_VIDEO_LCD_ILITEK_ILI9806E) += ilitek-ili9806e.o obj-$(CONFIG_VIDEO_LCD_LG_LD070WX3) += lg-ld070wx3.o obj-$(CONFIG_VIDEO_LCD_LG_LH400WV3) += lg-lh400wv3-sd04.o obj-$(CONFIG_VIDEO_LCD_MOT) += mot-panel.o diff --git a/drivers/video/bcm2835.c b/drivers/video/bcm2835.c index 0c81e606622..0e0cc1979eb 100644 --- a/drivers/video/bcm2835.c +++ b/drivers/video/bcm2835.c @@ -66,6 +66,7 @@ static int bcm2835_video_probe(struct udevice *dev) static const struct udevice_id bcm2835_video_ids[] = { { .compatible = "brcm,bcm2835-hdmi" }, { .compatible = "brcm,bcm2711-hdmi0" }, + { .compatible = "brcm,bcm2712-hdmi0" }, { .compatible = "brcm,bcm2708-fb" }, #if !IS_ENABLED(CONFIG_VIDEO_DT_SIMPLEFB) { .compatible = "simple-framebuffer" }, diff --git a/drivers/video/bridge/Kconfig b/drivers/video/bridge/Kconfig index 5322a002928..81261c61005 100644 --- a/drivers/video/bridge/Kconfig +++ b/drivers/video/bridge/Kconfig @@ -41,8 +41,8 @@ config VIDEO_BRIDGE_ANALOGIX_ANX6345 depends on VIDEO_BRIDGE select DM_I2C help - The Analogix ANX6345 is RGB-to-DP converter. It enables an eDP LCD - panel to be connected to an parallel LCD interface. + The Analogix ANX6345 is RGB-to-DP converter. It enables an eDP LCD + panel to be connected to an parallel LCD interface. config VIDEO_BRIDGE_SOLOMON_SSD2825 bool "Solomon SSD2825 bridge driver" diff --git a/drivers/video/bridge/anx6345.c b/drivers/video/bridge/anx6345.c index 8cee4c958bd..a5d2781aa48 100644 --- a/drivers/video/bridge/anx6345.c +++ b/drivers/video/bridge/anx6345.c @@ -403,7 +403,7 @@ static int anx6345_probe(struct udevice *dev) return anx6345_enable(dev); } -struct video_bridge_ops anx6345_ops = { +static const struct video_bridge_ops anx6345_ops = { .attach = anx6345_attach, .set_backlight = anx6345_set_backlight, .read_edid = anx6345_read_edid, diff --git a/drivers/video/bridge/ps862x.c b/drivers/video/bridge/ps862x.c index efd03752281..a08227f8355 100644 --- a/drivers/video/bridge/ps862x.c +++ b/drivers/video/bridge/ps862x.c @@ -116,7 +116,7 @@ static int ps8622_probe(struct udevice *dev) return 0; } -struct video_bridge_ops ps8622_ops = { +static const struct video_bridge_ops ps8622_ops = { .attach = ps8622_attach, .set_backlight = ps8622_set_backlight, }; diff --git a/drivers/video/bridge/ptn3460.c b/drivers/video/bridge/ptn3460.c index 5851e1ef15e..ce576c0b282 100644 --- a/drivers/video/bridge/ptn3460.c +++ b/drivers/video/bridge/ptn3460.c @@ -15,7 +15,7 @@ static int ptn3460_attach(struct udevice *dev) return video_bridge_set_active(dev, true); } -struct video_bridge_ops ptn3460_ops = { +static const struct video_bridge_ops ptn3460_ops = { .attach = ptn3460_attach, }; diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 07db613ac53..6dc0a6eaf9d 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -133,7 +133,7 @@ static int console_set_cursor_visible(struct udevice *dev, bool visible, return 0; } -struct vidconsole_ops console_ops = { +static const struct vidconsole_ops console_ops = { .putc_xy = console_putc_xy, .move_rows = console_move_rows, .set_row = console_set_row, diff --git a/drivers/video/console_rotate.c b/drivers/video/console_rotate.c index 886b25dcfaf..e478e0ef3bc 100644 --- a/drivers/video/console_rotate.c +++ b/drivers/video/console_rotate.c @@ -284,7 +284,7 @@ static int console_putc_xy_3(struct udevice *dev, uint x_frac, uint y, int cp) return VID_TO_POS(fontdata->width); } -struct vidconsole_ops console_ops_1 = { +static const struct vidconsole_ops console_ops_1 = { .putc_xy = console_putc_xy_1, .move_rows = console_move_rows_1, .set_row = console_set_row_1, @@ -293,7 +293,7 @@ struct vidconsole_ops console_ops_1 = { .select_font = console_simple_select_font, }; -struct vidconsole_ops console_ops_2 = { +static const struct vidconsole_ops console_ops_2 = { .putc_xy = console_putc_xy_2, .move_rows = console_move_rows_2, .set_row = console_set_row_2, @@ -302,7 +302,7 @@ struct vidconsole_ops console_ops_2 = { .select_font = console_simple_select_font, }; -struct vidconsole_ops console_ops_3 = { +static const struct vidconsole_ops console_ops_3 = { .putc_xy = console_putc_xy_3, .move_rows = console_move_rows_3, .set_row = console_set_row_3, diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index eaf169e8386..b9b6f394fbc 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -1069,7 +1069,7 @@ static int console_truetype_probe(struct udevice *dev) return 0; } -struct vidconsole_ops console_truetype_ops = { +static const struct vidconsole_ops console_truetype_ops = { .putc_xy = console_truetype_putc_xy, .move_rows = console_truetype_move_rows, .set_row = console_truetype_set_row, diff --git a/drivers/video/dw_mipi_dsi.c b/drivers/video/dw_mipi_dsi.c index c74fe678d12..ec5d4c81812 100644 --- a/drivers/video/dw_mipi_dsi.c +++ b/drivers/video/dw_mipi_dsi.c @@ -837,7 +837,7 @@ static int dw_mipi_dsi_enable(struct udevice *dev) return 0; } -struct dsi_host_ops dw_mipi_dsi_ops = { +static const struct dsi_host_ops dw_mipi_dsi_ops = { .init = dw_mipi_dsi_init, .enable = dw_mipi_dsi_enable, }; diff --git a/drivers/video/fonts/Makefile b/drivers/video/fonts/Makefile index 1111f92a2c6..4d32fa43994 100644 --- a/drivers/video/fonts/Makefile +++ b/drivers/video/fonts/Makefile @@ -3,8 +3,8 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, [email protected]. -obj-$(CONFIG_CONSOLE_TRUETYPE_NIMBUS) += nimbus_sans_l_regular.o -obj-$(CONFIG_CONSOLE_TRUETYPE_ANKACODER) += ankacoder_c75_r.o -obj-$(CONFIG_CONSOLE_TRUETYPE_RUFSCRIPT) += rufscript010.o -obj-$(CONFIG_CONSOLE_TRUETYPE_CANTORAONE) += cantoraone_regular.o -obj-$(CONFIG_CONSOLE_TRUETYPE_DEJAVU) += dejavu_mono.o +obj-$(CONFIG_CONSOLE_TRUETYPE_NIMBUS) += nimbus_sans_l_regular.ttf.o +obj-$(CONFIG_CONSOLE_TRUETYPE_ANKACODER) += ankacoder_c75_r.ttf.o +obj-$(CONFIG_CONSOLE_TRUETYPE_RUFSCRIPT) += rufscript010.ttf.o +obj-$(CONFIG_CONSOLE_TRUETYPE_CANTORAONE) += cantoraone_regular.ttf.o +obj-$(CONFIG_CONSOLE_TRUETYPE_DEJAVU) += dejavu_mono.ttf.o diff --git a/drivers/video/ilitek-ili9806e.c b/drivers/video/ilitek-ili9806e.c new file mode 100644 index 00000000000..9ba580639c9 --- /dev/null +++ b/drivers/video/ilitek-ili9806e.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2026 Amarula Solutions, Dario Binacchi <[email protected]> + */ + +#include <backlight.h> +#include <dm.h> +#include <mipi_display.h> +#include <panel.h> +#include <spi.h> +#include <asm/gpio.h> +#include <dm/device_compat.h> +#include <linux/delay.h> +#include <power/regulator.h> + +struct ilitek_ili9806e_priv { + struct udevice *vdd; + struct udevice *backlight; + struct gpio_desc reset_gpio; + const struct ilitek_ili9806e_desc *desc; +}; + +struct ilitek_ili9806e_desc { + const struct display_timing timing; + void (*init_sequence)(struct udevice *dev); +}; + +static int ilitek_ili9806e_dcs_write(struct udevice *dev, u8 cmd, const u8 *seq, int len) +{ + u16 data[16]; + int i, ret; + + if ((len + 1) > ARRAY_SIZE(data)) { + dev_err(dev, "Command length (%d) exceeds buffer size (%lu)\n", + len + 1, ARRAY_SIZE(data)); + return -EMSGSIZE; + } + + data[0] = cmd; + if (len) { + for (i = 0; i < len; i++) + data[i + 1] = seq[i] | 0x0100; + } + + ret = dm_spi_xfer(dev, (len + 1) * 8 * sizeof(u16), data, NULL, + SPI_XFER_ONCE); + return 0; +} + +#define ilitek_ili9806e_dcs_write_seq(dev, cmd, seq...) \ +({ \ + static const u8 b[] = { seq }; \ + ilitek_ili9806e_dcs_write(dev, cmd, b, ARRAY_SIZE(b)); \ +}) + +static int ilitek_ili9806e_enable_backlight(struct udevice *dev) +{ + struct ilitek_ili9806e_priv *priv = dev_get_priv(dev); + const struct ilitek_ili9806e_desc *desc = priv->desc; + + desc->init_sequence(dev); + + return panel_set_backlight(dev, BACKLIGHT_DEFAULT); +} + +static int ilitek_ili9806e_set_backlight(struct udevice *dev, int percent) +{ + struct ilitek_ili9806e_priv *priv = dev_get_priv(dev); + int ret; + + ret = backlight_enable(priv->backlight); + if (ret) { + dev_err(dev, "Cannot enable backlight\n"); + return ret; + } + + ret = backlight_set_brightness(priv->backlight, percent); + if (ret) + dev_err(dev, "Cannot set backlight brightness\n"); + + return ret; +} + +static int ilitek_ili9806e_get_display_timing(struct udevice *dev, + struct display_timing *timing) +{ + struct ilitek_ili9806e_priv *priv = dev_get_priv(dev); + + memcpy(timing, &priv->desc->timing, sizeof(*timing)); + + return 0; +} + +static int ilitek_ili9806e_of_to_plat(struct udevice *dev) +{ + struct ilitek_ili9806e_priv *priv = dev_get_priv(dev); + int ret; + + if (CONFIG_IS_ENABLED(DM_REGULATOR)) { + ret = device_get_supply_regulator(dev, "vdd-supply", &priv->vdd); + if (ret) { + dev_err(dev, "Cannot get vdd supply\n"); + return ret; + } + } + + ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev, + "backlight", &priv->backlight); + if (ret) { + dev_err(dev, "Cannot get backlight\n"); + return ret; + } + + ret = gpio_request_by_name(dev, "reset-gpios", 0, + &priv->reset_gpio, GPIOD_IS_OUT); + if (ret) { + dev_err(dev, "Cannot get reset GPIO\n"); + return ret; + } + + return 0; +} + +static int ilitek_ili9806e_hw_init(struct udevice *dev) +{ + struct ilitek_ili9806e_priv *priv = dev_get_priv(dev); + int ret; + + ret = dm_gpio_set_value(&priv->reset_gpio, 1); + if (ret) { + dev_err(dev, "Cannot enter reset\n"); + return ret; + } + + ret = regulator_set_enable_if_allowed(priv->vdd, 1); + if (ret) { + dev_err(dev, "Cannot enable vdd-supply\n"); + return ret; + } + + mdelay(20); + + ret = dm_gpio_set_value(&priv->reset_gpio, 0); + if (ret) { + dev_err(dev, "Cannot exit reset\n"); + return ret; + } + + mdelay(20); + + return 0; +} + +static int ilitek_ili9806e_probe(struct udevice *dev) +{ + struct ilitek_ili9806e_priv *priv = dev_get_priv(dev); + struct spi_slave *slave = dev_get_parent_priv(dev); + int ret; + + ret = spi_set_wordlen(slave, 9); + if (ret) { + dev_err(dev, "Cannot set SPI.bits_per_word\n"); + return ret; + } + + ret = spi_claim_bus(slave); + if (ret) { + dev_err(dev, "Cannot get SPI bus\n"); + return ret; + } + + priv->desc = (struct ilitek_ili9806e_desc *)dev_get_driver_data(dev); + + return ilitek_ili9806e_hw_init(dev); +} + +static const struct panel_ops ilitek_ili9806e_ops = { + .enable_backlight = ilitek_ili9806e_enable_backlight, + .set_backlight = ilitek_ili9806e_set_backlight, + .get_display_timing = ilitek_ili9806e_get_display_timing, +}; + +static void rk050hr345_ct106a_init(struct udevice *dev) +{ + /* Switch to page 1 */ + ilitek_ili9806e_dcs_write_seq(dev, 0xff, 0xff, 0x98, 0x06, 0x04, 0x01); + /* Interface Settings */ + ilitek_ili9806e_dcs_write_seq(dev, 0x08, 0x10); + ilitek_ili9806e_dcs_write_seq(dev, 0x21, 0x01); + /* Panel Settings */ + ilitek_ili9806e_dcs_write_seq(dev, 0x30, 0x01); + ilitek_ili9806e_dcs_write_seq(dev, 0x31, 0x00); + /* Power Control */ + ilitek_ili9806e_dcs_write_seq(dev, 0x40, 0x15); + ilitek_ili9806e_dcs_write_seq(dev, 0x41, 0x44); + ilitek_ili9806e_dcs_write_seq(dev, 0x42, 0x03); + ilitek_ili9806e_dcs_write_seq(dev, 0x43, 0x09); + ilitek_ili9806e_dcs_write_seq(dev, 0x44, 0x09); + ilitek_ili9806e_dcs_write_seq(dev, 0x50, 0x78); + ilitek_ili9806e_dcs_write_seq(dev, 0x51, 0x78); + ilitek_ili9806e_dcs_write_seq(dev, 0x52, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x53, 0x3a); + ilitek_ili9806e_dcs_write_seq(dev, 0x57, 0x50); + /* Timing Control */ + ilitek_ili9806e_dcs_write_seq(dev, 0x60, 0x07); + ilitek_ili9806e_dcs_write_seq(dev, 0x61, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x62, 0x08); + ilitek_ili9806e_dcs_write_seq(dev, 0x63, 0x00); + /* Gamma Settings */ + ilitek_ili9806e_dcs_write_seq(dev, 0xa0, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0xa1, 0x03); + ilitek_ili9806e_dcs_write_seq(dev, 0xa2, 0x0b); + ilitek_ili9806e_dcs_write_seq(dev, 0xa3, 0x0f); + ilitek_ili9806e_dcs_write_seq(dev, 0xa4, 0x0b); + ilitek_ili9806e_dcs_write_seq(dev, 0xa5, 0x1b); + ilitek_ili9806e_dcs_write_seq(dev, 0xa6, 0x0a); + ilitek_ili9806e_dcs_write_seq(dev, 0xa7, 0x0a); + ilitek_ili9806e_dcs_write_seq(dev, 0xa8, 0x02); + ilitek_ili9806e_dcs_write_seq(dev, 0xa9, 0x07); + ilitek_ili9806e_dcs_write_seq(dev, 0xaa, 0x05); + ilitek_ili9806e_dcs_write_seq(dev, 0xab, 0x03); + ilitek_ili9806e_dcs_write_seq(dev, 0xac, 0x0e); + ilitek_ili9806e_dcs_write_seq(dev, 0xad, 0x32); + ilitek_ili9806e_dcs_write_seq(dev, 0xae, 0x2d); + ilitek_ili9806e_dcs_write_seq(dev, 0xaf, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0xc0, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0xc1, 0x03); + ilitek_ili9806e_dcs_write_seq(dev, 0xc2, 0x0e); + ilitek_ili9806e_dcs_write_seq(dev, 0xc3, 0x10); + ilitek_ili9806e_dcs_write_seq(dev, 0xc4, 0x09); + ilitek_ili9806e_dcs_write_seq(dev, 0xc5, 0x17); + ilitek_ili9806e_dcs_write_seq(dev, 0xc6, 0x09); + ilitek_ili9806e_dcs_write_seq(dev, 0xc7, 0x07); + ilitek_ili9806e_dcs_write_seq(dev, 0xc8, 0x04); + ilitek_ili9806e_dcs_write_seq(dev, 0xc9, 0x09); + ilitek_ili9806e_dcs_write_seq(dev, 0xca, 0x06); + ilitek_ili9806e_dcs_write_seq(dev, 0xcb, 0x06); + ilitek_ili9806e_dcs_write_seq(dev, 0xcc, 0x0c); + ilitek_ili9806e_dcs_write_seq(dev, 0xcd, 0x25); + ilitek_ili9806e_dcs_write_seq(dev, 0xce, 0x20); + ilitek_ili9806e_dcs_write_seq(dev, 0xcf, 0x00); + + /* Switch to page 6 */ + ilitek_ili9806e_dcs_write_seq(dev, 0xff, 0xff, 0x98, 0x06, 0x04, 0x06); + /* GIP settings */ + ilitek_ili9806e_dcs_write_seq(dev, 0x00, 0x21); + ilitek_ili9806e_dcs_write_seq(dev, 0x01, 0x09); + ilitek_ili9806e_dcs_write_seq(dev, 0x02, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x03, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x04, 0x01); + ilitek_ili9806e_dcs_write_seq(dev, 0x05, 0x01); + ilitek_ili9806e_dcs_write_seq(dev, 0x06, 0x80); + ilitek_ili9806e_dcs_write_seq(dev, 0x07, 0x05); + ilitek_ili9806e_dcs_write_seq(dev, 0x08, 0x02); + ilitek_ili9806e_dcs_write_seq(dev, 0x09, 0x80); + ilitek_ili9806e_dcs_write_seq(dev, 0x0a, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x0b, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x0c, 0x0a); + ilitek_ili9806e_dcs_write_seq(dev, 0x0d, 0x0a); + ilitek_ili9806e_dcs_write_seq(dev, 0x0e, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x0f, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x10, 0xe0); + ilitek_ili9806e_dcs_write_seq(dev, 0x11, 0xe4); + ilitek_ili9806e_dcs_write_seq(dev, 0x12, 0x04); + ilitek_ili9806e_dcs_write_seq(dev, 0x13, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x14, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x15, 0xc0); + ilitek_ili9806e_dcs_write_seq(dev, 0x16, 0x08); + ilitek_ili9806e_dcs_write_seq(dev, 0x17, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x18, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x19, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x1a, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x1b, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x1c, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x1d, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x20, 0x01); + ilitek_ili9806e_dcs_write_seq(dev, 0x21, 0x23); + ilitek_ili9806e_dcs_write_seq(dev, 0x22, 0x45); + ilitek_ili9806e_dcs_write_seq(dev, 0x23, 0x67); + ilitek_ili9806e_dcs_write_seq(dev, 0x24, 0x01); + ilitek_ili9806e_dcs_write_seq(dev, 0x25, 0x23); + ilitek_ili9806e_dcs_write_seq(dev, 0x26, 0x45); + ilitek_ili9806e_dcs_write_seq(dev, 0x27, 0x67); + ilitek_ili9806e_dcs_write_seq(dev, 0x30, 0x01); + ilitek_ili9806e_dcs_write_seq(dev, 0x31, 0x11); + ilitek_ili9806e_dcs_write_seq(dev, 0x32, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, 0x33, 0xee); + ilitek_ili9806e_dcs_write_seq(dev, 0x34, 0xff); + ilitek_ili9806e_dcs_write_seq(dev, 0x35, 0xbb); + ilitek_ili9806e_dcs_write_seq(dev, 0x36, 0xca); + ilitek_ili9806e_dcs_write_seq(dev, 0x37, 0xdd); + ilitek_ili9806e_dcs_write_seq(dev, 0x38, 0xac); + ilitek_ili9806e_dcs_write_seq(dev, 0x39, 0x76); + ilitek_ili9806e_dcs_write_seq(dev, 0x3a, 0x67); + ilitek_ili9806e_dcs_write_seq(dev, 0x3b, 0x22); + ilitek_ili9806e_dcs_write_seq(dev, 0x3c, 0x22); + ilitek_ili9806e_dcs_write_seq(dev, 0x3d, 0x22); + ilitek_ili9806e_dcs_write_seq(dev, 0x3e, 0x22); + ilitek_ili9806e_dcs_write_seq(dev, 0x3f, 0x22); + ilitek_ili9806e_dcs_write_seq(dev, 0x40, 0x22); + ilitek_ili9806e_dcs_write_seq(dev, 0x52, 0x10); + ilitek_ili9806e_dcs_write_seq(dev, 0x53, 0x10); + + /* Switch to page 7 */ + ilitek_ili9806e_dcs_write_seq(dev, 0xff, 0xff, 0x98, 0x06, 0x04, 0x07); + ilitek_ili9806e_dcs_write_seq(dev, 0x17, 0x22); + ilitek_ili9806e_dcs_write_seq(dev, 0x02, 0x77); + ilitek_ili9806e_dcs_write_seq(dev, 0xe1, 0x79); + ilitek_ili9806e_dcs_write_seq(dev, 0xb3, 0x10); + + /* Switch to page 0 */ + ilitek_ili9806e_dcs_write_seq(dev, 0xff, 0xff, 0x98, 0x06, 0x04, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, MIPI_DCS_SET_ADDRESS_MODE, 0x00); + ilitek_ili9806e_dcs_write_seq(dev, MIPI_DCS_EXIT_SLEEP_MODE); + + mdelay(120); + + ilitek_ili9806e_dcs_write_seq(dev, MIPI_DCS_SET_DISPLAY_ON); + + mdelay(120); +} + +static const struct ilitek_ili9806e_desc rk050hr345_ct106a_desc = { + .timing = { + .pixelclock.typ = 27000000, + .hactive.typ = 480, + .hfront_porch.typ = 10, + .hback_porch.typ = 10, + .hsync_len.typ = 10, + .vactive.typ = 854, + .vfront_porch.typ = 10, + .vback_porch.typ = 10, + .vsync_len.typ = 10, + .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW, + }, + .init_sequence = rk050hr345_ct106a_init, +}; + +static const struct udevice_id ilitek_ili9806e_ids[] = { + { + .compatible = "rocktech,rk050hr345-ct106a", + .data = (ulong)&rk050hr345_ct106a_desc, + }, + { } +}; + +U_BOOT_DRIVER(ilitek_ili9806e) = { + .name = "ilitek_ili9806e", + .id = UCLASS_PANEL, + .of_match = ilitek_ili9806e_ids, + .ops = &ilitek_ili9806e_ops, + .of_to_plat = ilitek_ili9806e_of_to_plat, + .probe = ilitek_ili9806e_probe, + .priv_auto = sizeof(struct ilitek_ili9806e_priv), + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/video/imx/Kconfig b/drivers/video/imx/Kconfig index c25f209629e..0c386595559 100644 --- a/drivers/video/imx/Kconfig +++ b/drivers/video/imx/Kconfig @@ -20,7 +20,7 @@ config IPU_CLK_LEGACY depends on VIDEO_IPUV3 && !CLK default y help - Use legacy clock management instead of Common Clock Framework. + Use legacy clock management instead of Common Clock Framework. config IMX_LDB bool "Freescale i.MX8MP LDB bridge" diff --git a/drivers/video/imx/ipu.h b/drivers/video/imx/ipu.h index ae40e20bc28..aecb6adffce 100644 --- a/drivers/video/imx/ipu.h +++ b/drivers/video/imx/ipu.h @@ -136,7 +136,6 @@ struct ipu_ctx { struct clk *ipu_clk; struct clk *ldb_clk; - unsigned char ipu_clk_enabled; struct clk *di_clk[2]; struct clk *pixel_clk[2]; diff --git a/drivers/video/imx/ipu_common.c b/drivers/video/imx/ipu_common.c index 8630374a055..d3b52605731 100644 --- a/drivers/video/imx/ipu_common.c +++ b/drivers/video/imx/ipu_common.c @@ -299,9 +299,9 @@ struct ipu_ctx *ipu_probe(struct udevice *dev) #if CONFIG_IS_ENABLED(IPU_CLK_LEGACY) clk_set_parent(ctx->pixel_clk[0], ctx->ipu_clk); clk_set_parent(ctx->pixel_clk[1], ctx->ipu_clk); +#endif clk_enable(ctx->ipu_clk); -#endif for (int i = 0; i <= 1; i++) { ret = ipu_di_clk_init(ctx, i); @@ -384,10 +384,8 @@ int32_t ipu_init_channel(struct ipu_ctx *ctx, ipu_channel_t channel, debug("init channel = %d\n", IPU_CHAN_ID(channel)); - if (ctx->ipu_clk_enabled == 0) { - ctx->ipu_clk_enabled = 1; + if (!ipu_clk_enabled(ctx)) clk_enable(ipu_clk); - } if (*channel_init_mask & (1L << IPU_CHAN_ID(channel))) { printf("Warning: channel already initialized %d\n", @@ -543,7 +541,6 @@ void ipu_uninit_channel(struct ipu_ctx *ctx, ipu_channel_t channel) if (ipu_conf == 0) { clk_disable(ctx->ipu_clk); - ctx->ipu_clk_enabled = 0; } } @@ -1045,5 +1042,9 @@ ipu_color_space_t format_to_colorspace(u32 fmt) bool ipu_clk_enabled(struct ipu_ctx *ctx) { - return ctx->ipu_clk_enabled; +#if CONFIG_IS_ENABLED(IPU_CLK_LEGACY) + return clk_get_usecount(ctx->ipu_clk); +#else + return ctx->ipu_clk->enable_count; +#endif } diff --git a/drivers/video/imx/ldb.c b/drivers/video/imx/ldb.c index e918341c0a3..32a327647f8 100644 --- a/drivers/video/imx/ldb.c +++ b/drivers/video/imx/ldb.c @@ -230,7 +230,7 @@ dis_clk: return ret; } -struct video_bridge_ops imx_ldb_ops = { +static const struct video_bridge_ops imx_ldb_ops = { .attach = imx_ldb_attach, .set_backlight = imx_ldb_set_backlight, }; diff --git a/drivers/video/meson/meson_vpu.c b/drivers/video/meson/meson_vpu.c index ca627728743..a686faf9f58 100644 --- a/drivers/video/meson/meson_vpu.c +++ b/drivers/video/meson/meson_vpu.c @@ -81,8 +81,8 @@ cvbs: meson_fb.fb_size = ALIGN(meson_fb.xsize * meson_fb.ysize * ((1 << VPU_MAX_LOG2_BPP) / 8) + MESON_VPU_OVERSCAN, EFI_PAGE_SIZE); - meson_fb.base = gd->bd->bi_dram[0].start + - gd->bd->bi_dram[0].size - meson_fb.fb_size; + meson_fb.base = gd->dram[0].start + + gd->dram[0].size - meson_fb.fb_size; /* Override the framebuffer address */ uc_plat->base = meson_fb.base; @@ -175,8 +175,8 @@ static void meson_vpu_setup_simplefb(void *fdt) * at the end of the RAM and we strip this portion from the kernel * allowed region */ - mem_start = gd->bd->bi_dram[0].start; - mem_size = gd->bd->bi_dram[0].size - meson_fb.fb_size; + mem_start = gd->dram[0].start; + mem_size = gd->dram[0].size - meson_fb.fb_size; ret = fdt_fixup_memory_banks(fdt, &mem_start, &mem_size, 1); if (ret) { eprintf("Cannot setup simplefb: Error reserving memory\n"); diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig index 96af6d28ef0..41d249cb90c 100644 --- a/drivers/video/rockchip/Kconfig +++ b/drivers/video/rockchip/Kconfig @@ -21,7 +21,7 @@ menuconfig VIDEO_ROCKCHIP Rockchip RK3288 and RK3399. config VIDEO_ROCKCHIP_MAX_XRES - int "Maximum horizontal resolution (for memory allocation purposes)" + int "Maximum horizontal resolution (for memory allocation purposes)" depends on VIDEO_ROCKCHIP default 3840 if DISPLAY_ROCKCHIP_HDMI default 1920 @@ -31,7 +31,7 @@ config VIDEO_ROCKCHIP_MAX_XRES framebuffer during device-model binding/probing. config VIDEO_ROCKCHIP_MAX_YRES - int "Maximum vertical resolution (for memory allocation purposes)" + int "Maximum vertical resolution (for memory allocation purposes)" depends on VIDEO_ROCKCHIP default 2160 if DISPLAY_ROCKCHIP_HDMI default 1080 diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c index 8d0772d4e51..631ae00b1e1 100644 --- a/drivers/video/simplefb.c +++ b/drivers/video/simplefb.c @@ -9,6 +9,8 @@ #include <log.h> #include <video.h> #include <asm/global_data.h> +#include <asm/system.h> +#include <linux/sizes.h> static int simple_video_probe(struct udevice *dev) { @@ -20,8 +22,14 @@ static int simple_video_probe(struct udevice *dev) fdt_addr_t base; fdt_size_t size; u32 width, height, stride, rot; + struct ofnode_phandle_args args; + + ret = dev_read_phandle_with_args(dev, "memory-region", NULL, 0, 0, &args); + if (ret) + base = dev_read_addr_size(dev, &size); + else + base = ofnode_get_addr_size(args.node, "reg", &size); - base = dev_read_addr_size(dev, &size); if (base == FDT_ADDR_T_NONE) { debug("%s: Failed to decode memory region\n", __func__); return -EINVAL; @@ -37,6 +45,13 @@ static int simple_video_probe(struct udevice *dev) plat->base = base; plat->size = size; +#ifdef CONFIG_ARM64 + /* The framebuffer buffer might not be mapped on some devices */ + if (plat->base % SZ_4K) + log_warning("Framebuffer base %lx is not 4k aligned!\n", plat->base); + mmu_map_region((phys_addr_t)plat->base, (phys_addr_t)ALIGN(plat->size, SZ_4K), false); +#endif + video_set_flush_dcache(dev, true); debug("%s: Query resolution...\n", __func__); diff --git a/drivers/video/stm32/stm32_dsi.c b/drivers/video/stm32/stm32_dsi.c index 65a91f5cff7..29c57a4ff89 100644 --- a/drivers/video/stm32/stm32_dsi.c +++ b/drivers/video/stm32/stm32_dsi.c @@ -493,8 +493,11 @@ static int stm32_dsi_probe(struct udevice *dev) priv->hw_version != HWVER_131) { dev_err(dev, "DSI version 0x%x not supported\n", priv->hw_version); dev_dbg(dev, "remove and unbind all DSI child\n"); - device_chld_remove(dev, NULL, DM_REMOVE_NORMAL); - device_chld_unbind(dev, NULL); + ret = device_chld_remove(dev, NULL, DM_REMOVE_NORMAL); + if (!ret) + ret = device_chld_unbind(dev, NULL); + if (ret) + dev_err(dev, "Unbinding from %s failed %d\n", dev->name, ret); ret = -ENODEV; goto err_clk; } @@ -508,7 +511,7 @@ err_reg: return ret; } -struct video_bridge_ops stm32_dsi_ops = { +static const struct video_bridge_ops stm32_dsi_ops = { .attach = stm32_dsi_attach, .set_backlight = stm32_dsi_set_backlight, }; diff --git a/drivers/video/sunxi/sunxi_de2.c b/drivers/video/sunxi/sunxi_de2.c index 154641b9a69..ab36ee1595b 100644 --- a/drivers/video/sunxi/sunxi_de2.c +++ b/drivers/video/sunxi/sunxi_de2.c @@ -368,7 +368,7 @@ int sunxi_simplefb_setup(void *blob) return 0; /* Keep older kernels working */ } - start = gd->bd->bi_dram[0].start; + start = gd->dram[0].start; size = de2_plat->base - start; ret = fdt_fixup_memory_banks(blob, &start, &size, 1); if (ret) { diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c index 4a6a89ef9d2..fa492c661db 100644 --- a/drivers/video/sunxi/sunxi_display.c +++ b/drivers/video/sunxi/sunxi_display.c @@ -1336,7 +1336,7 @@ int sunxi_simplefb_setup(void *blob) * and e.g. Linux refuses to iomap RAM on ARM, see: * linux/arch/arm/mm/ioremap.c around line 301. */ - start = gd->bd->bi_dram[0].start; + start = gd->dram[0].start; size = sunxi_display->fb_addr - start; ret = fdt_fixup_memory_banks(blob, &start, &size, 1); if (ret) { diff --git a/drivers/video/tda19988.c b/drivers/video/tda19988.c index ebc8521c6ed..a4cc3a49232 100644 --- a/drivers/video/tda19988.c +++ b/drivers/video/tda19988.c @@ -522,7 +522,7 @@ static int tda19988_enable(struct udevice *dev, int panel_bpp, return 0; } -struct dm_display_ops tda19988_ops = { +static const struct dm_display_ops tda19988_ops = { .read_edid = tda19988_read_edid, .enable = tda19988_enable, }; diff --git a/drivers/video/tegra/Kconfig b/drivers/video/tegra/Kconfig index 8bc29f2838b..125504024fc 100644 --- a/drivers/video/tegra/Kconfig +++ b/drivers/video/tegra/Kconfig @@ -9,13 +9,13 @@ config VIDEO_TEGRA depends on OF_CONTROL && ARCH_TEGRA select HOST1X_TEGRA help - Enable support for Display Controller found in Tegra SoC. The - Display Controller Complex integrates two independent display - controllers. Each display controller is capable of interfacing - to an external display device, which can be a parallel interface - or SPI LCD, DVI, an HDMI HDTV, RGB monitor or a MIPI DSI LCD. - Direct interface is supported directly to most LCD displays with - TFT or TFT-like interface. + Enable support for Display Controller found in Tegra SoC. The + Display Controller Complex integrates two independent display + controllers. Each display controller is capable of interfacing + to an external display device, which can be a parallel interface + or SPI LCD, DVI, an HDMI HDTV, RGB monitor or a MIPI DSI LCD. + Direct interface is supported directly to most LCD displays with + TFT or TFT-like interface. config VIDEO_DSI_TEGRA bool "Enable DSI controller support on Tegra devices" @@ -23,9 +23,9 @@ config VIDEO_DSI_TEGRA select VIDEO_TEGRA select VIDEO_MIPI_DSI help - Enable support for the Display Serial Interface (DSI) found in - Tegra SoC. It is a MIPI standard serial bitstream, intended to - provide a low pin count interface to a display panel. + Enable support for the Display Serial Interface (DSI) found in + Tegra SoC. It is a MIPI standard serial bitstream, intended to + provide a low pin count interface to a display panel. config VIDEO_HDMI_TEGRA bool "Enable HDMI support on Tegra devices" @@ -33,31 +33,31 @@ config VIDEO_HDMI_TEGRA select I2C_EDID select VIDEO_TEGRA help - Enable support for the High-Definition Multimedia Interface (HDMI) - found in Tegra SoC. + Enable support for the High-Definition Multimedia Interface (HDMI) + found in Tegra SoC. config TEGRA_BACKLIGHT_PWM bool "Enable Tegra DC PWM backlight support" depends on BACKLIGHT && VIDEO_TEGRA help - Enable support for the Display Controller dependent PWM backlight - found in the Tegra SoC and usually used with DSI panels. + Enable support for the Display Controller dependent PWM backlight + found in the Tegra SoC and usually used with DSI panels. config TEGRA_8BIT_CPU_BRIDGE bool "Enable 8 bit panel communication protocol for Tegra 20/30" depends on VIDEO_BRIDGE && DM_GPIO && VIDEO_TEGRA select VIDEO_MIPI_DSI help - Tegra 20 and Tegra 30 feature 8 bit CPU driver panel control - protocol. This option allows use it as a MIPI DSI bridge to - set up and control compatible panel. + Tegra 20 and Tegra 30 feature 8 bit CPU driver panel control + protocol. This option allows use it as a MIPI DSI bridge to + set up and control compatible panel. config VIDEO_TEGRA124 bool "Enable video support on Tegra124" depends on ARCH_TEGRA imply VIDEO_DAMAGE help - Tegra124 supports many video output options including eDP and - HDMI. At present only eDP is supported by U-Boot. This option - enables this support which can be used on devices which - have an eDP display connected. + Tegra124 supports many video output options including eDP and + HDMI. At present only eDP is supported by U-Boot. This option + enables this support which can be used on devices which + have an eDP display connected. diff --git a/drivers/video/tegra/dsi.c b/drivers/video/tegra/dsi.c index bc308869f4e..f53fabf6fd6 100644 --- a/drivers/video/tegra/dsi.c +++ b/drivers/video/tegra/dsi.c @@ -337,7 +337,7 @@ static ssize_t tegra_dsi_host_transfer(struct mipi_dsi_host *host, return count; } -struct mipi_dsi_host_ops tegra_dsi_bridge_host_ops = { +static const struct mipi_dsi_host_ops tegra_dsi_bridge_host_ops = { .transfer = tegra_dsi_host_transfer, }; diff --git a/drivers/video/ti/Kconfig b/drivers/video/ti/Kconfig index 0483f760ea1..a3cbefef0de 100644 --- a/drivers/video/ti/Kconfig +++ b/drivers/video/ti/Kconfig @@ -6,4 +6,4 @@ config AM335X_LCD bool "Enable AM335x video support" depends on ARCH_OMAP2PLUS help - Supports video output to an attached LCD panel. + Supports video output to an attached LCD panel. diff --git a/drivers/video/tidss/Kconfig b/drivers/video/tidss/Kconfig index 3291b3ceb8d..c9849110059 100644 --- a/drivers/video/tidss/Kconfig +++ b/drivers/video/tidss/Kconfig @@ -10,7 +10,7 @@ menuconfig VIDEO_TIDSS bool "Enable TIDSS video support" - depends on VIDEO + depends on VIDEO && PANEL imply VIDEO_DAMAGE help TIDSS supports video output options LVDS and @@ -19,7 +19,7 @@ menuconfig VIDEO_TIDSS config SPL_VIDEO_TIDSS bool "Enable TIDSS video support in SPL Stage" - depends on SPL_VIDEO + depends on SPL_VIDEO && SPL_PANEL help This options enables tidss driver in SPL stage. If you need to use tidss at SPL stage use this config. diff --git a/drivers/video/zynqmp/Kconfig b/drivers/video/zynqmp/Kconfig index b35cd1fb342..2c737710639 100644 --- a/drivers/video/zynqmp/Kconfig +++ b/drivers/video/zynqmp/Kconfig @@ -3,6 +3,6 @@ config VIDEO_ZYNQMP_DPSUB bool "Enable video support for ZynqMP Display Port" depends on ZYNQMP_POWER_DOMAIN help - Enable support for Xilinx ZynqMP Display Port. Currently this file - is used as placeholder for driver. The main reason is to record - compatible string and calling power domain driver. + Enable support for Xilinx ZynqMP Display Port. Currently this file + is used as placeholder for driver. The main reason is to record + compatible string and calling power domain driver. diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c index c36e9e9b3a7..a871a1439d4 100644 --- a/drivers/virtio/virtio-uclass.c +++ b/drivers/virtio/virtio-uclass.c @@ -400,9 +400,6 @@ UCLASS_DRIVER(virtio) = { .per_device_auto = sizeof(struct virtio_dev_priv), }; -struct bootdev_ops virtio_bootdev_ops = { -}; - static const struct udevice_id virtio_bootdev_ids[] = { { .compatible = "u-boot,bootdev-virtio" }, { } @@ -411,7 +408,6 @@ static const struct udevice_id virtio_bootdev_ids[] = { U_BOOT_DRIVER(virtio_bootdev) = { .name = "virtio_bootdev", .id = UCLASS_BOOTDEV, - .ops = &virtio_bootdev_ops, .bind = virtio_bootdev_bind, .of_match = virtio_bootdev_ids, }; diff --git a/drivers/virtio/virtio_blk.c b/drivers/virtio/virtio_blk.c index 3dd0cf36268..404d9140cb2 100644 --- a/drivers/virtio/virtio_blk.c +++ b/drivers/virtio/virtio_blk.c @@ -13,7 +13,9 @@ #include <virtio.h> #include <virtio_ring.h> #include <linux/log2.h> +#include <linux/err.h> #include "virtio_blk.h" +#include <malloc.h> /** * struct virtio_blk_priv - private data for virtio block device @@ -23,10 +25,16 @@ struct virtio_blk_priv { struct virtqueue *vq; /** @blksz_shift - log2 of block size divided by 512 */ u32 blksz_shift; + /** @size_max - maximum segment size */ + u32 size_max; + /** @seg_max - maximum segment count */ + u32 seg_max; }; static const u32 feature[] = { VIRTIO_BLK_F_BLK_SIZE, + VIRTIO_BLK_F_SIZE_MAX, + VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_WRITE_ZEROES }; @@ -67,50 +75,77 @@ static void virtio_blk_init_data_sg(void *buffer, lbaint_t blkcnt, struct virtio sg->length = blkcnt * 512; } -static ulong virtio_blk_do_req(struct udevice *dev, u64 sector, - lbaint_t blkcnt, void *buffer, u32 type) +/* + * Create, execute and wait for one single virtio request. On success the + * transferred block count is returned and in the error case -EIO. + */ +static ulong virtio_blk_do_single_req(struct udevice *dev, u64 sector, + lbaint_t blkcnt, char *buffer, u32 type) { struct virtio_blk_priv *priv = dev_get_priv(dev); + /* + * The virtio device may have constrains on the maximum segment size. + * Calculate how many segments we need. + */ + u32 seg_cnt = (blkcnt * 512) / priv->size_max + 1; + lbaint_t seg_sec_cnt = priv->size_max / 512; struct virtio_blk_outhdr out_hdr; struct virtio_blk_discard_write_zeroes wz_hdr; unsigned int num_out = 0, num_in = 0; - struct virtio_sg hdr_sg, wz_sg, data_sg, status_sg; - struct virtio_sg *sgs[3]; - u8 status; + struct virtio_sg **sgs; + u8 status = VIRTIO_BLK_S_IOERR; int ret; + u32 i; - sector <<= priv->blksz_shift; - blkcnt <<= priv->blksz_shift; - virtio_blk_init_header_sg(dev, sector, type, &out_hdr, &hdr_sg); - sgs[num_out++] = &hdr_sg; + /* + * +2 is header and status descriptor; seg_cnt is the number of data segments + * required. Needs to be dynamically allocated. + */ + sgs = calloc(seg_cnt + 2, sizeof(struct virtio_sg *)); + if (!sgs) + return -ENOMEM; + + for (i = 0; i < seg_cnt + 2; ++i) { + sgs[i] = malloc(sizeof(struct virtio_sg)); + if (!sgs[i]) + goto err_free; + } + + virtio_blk_init_header_sg(dev, sector, type, &out_hdr, sgs[num_out++]); switch (type) { case VIRTIO_BLK_T_IN: - case VIRTIO_BLK_T_OUT: - virtio_blk_init_data_sg(buffer, blkcnt, &data_sg); - if (type & VIRTIO_BLK_T_OUT) - sgs[num_out++] = &data_sg; - else - sgs[num_out + num_in++] = &data_sg; - break; + case VIRTIO_BLK_T_OUT: { + i = 0; + while (i < blkcnt) { + u32 blk_per_seg = min(blkcnt - i, seg_sec_cnt); + if (type & VIRTIO_BLK_T_OUT) + virtio_blk_init_data_sg(buffer + i * 512, blk_per_seg, + sgs[num_out++]); + else + virtio_blk_init_data_sg(buffer + i * 512, blk_per_seg, + sgs[num_out + num_in++]); + i += blk_per_seg; + } + break; + } case VIRTIO_BLK_T_WRITE_ZEROES: - virtio_blk_init_write_zeroes_sg(dev, sector, blkcnt, &wz_hdr, &wz_sg); - sgs[num_out++] = &wz_sg; + virtio_blk_init_write_zeroes_sg(dev, sector, blkcnt, &wz_hdr, + sgs[num_out++]); break; default: - return -EINVAL; + goto err_free; } - virtio_blk_init_status_sg(&status, &status_sg); - sgs[num_out + num_in++] = &status_sg; + virtio_blk_init_status_sg(&status, sgs[num_out + num_in++]); log_debug("dev=%s, active=%d, priv=%p, priv->vq=%p\n", dev->name, device_active(dev), priv, priv->vq); ret = virtqueue_add(priv->vq, sgs, num_out, num_in); if (ret) - return ret; + goto err_free; virtqueue_kick(priv->vq); @@ -119,7 +154,40 @@ static ulong virtio_blk_do_req(struct udevice *dev, u64 sector, ; log_debug("done\n"); - return status == VIRTIO_BLK_S_OK ? blkcnt >> priv->blksz_shift : -EIO; +err_free: + for (i = 0; i < seg_cnt + 2; ++i) + free(sgs[i]); + free(sgs); + + return status == VIRTIO_BLK_S_OK ? blkcnt : -EIO; +} + +static ulong virtio_blk_do_req(struct udevice *dev, u64 sector, + lbaint_t blkcnt, char *buffer, u32 type) +{ + struct virtio_blk_priv *priv = dev_get_priv(dev); + lbaint_t seg_sec_cnt = priv->size_max / 512; + u32 i = 0; + ulong ret; + + sector <<= priv->blksz_shift; + blkcnt <<= priv->blksz_shift; + + /* + * The virtio device may have constrains on the maximum segment count. So + * send multiple virtio requests one after each other, if so. + */ + while (i < blkcnt) { + u32 blk_per_sg = min(blkcnt - i, seg_sec_cnt * priv->seg_max); + + ret = virtio_blk_do_single_req(dev, sector + i, blk_per_sg, + buffer + i * 512, type); + if (IS_ERR_VALUE(ret)) + return ret; + i += blk_per_sg; + } + + return blkcnt >> priv->blksz_shift; } static ulong virtio_blk_read(struct udevice *dev, lbaint_t start, @@ -164,14 +232,11 @@ static int virtio_blk_bind(struct udevice *dev) return devnum; desc->devnum = devnum; desc->part_type = PART_TYPE_UNKNOWN; - /* - * virtio mmio transport supplies string identification for us, - * while pci trnasport uses a 2-byte subvendor value. - */ - if (uc_priv->vendor >> 16) - sprintf(desc->vendor, "%s", (char *)&uc_priv->vendor); + + if (uc_priv->vendor == VIRTIO_VENDOR_QEMU) + strcpy(desc->vendor, "QEMU"); else - sprintf(desc->vendor, "%04x", uc_priv->vendor); + sprintf(desc->vendor, "%08x", uc_priv->vendor); desc->bdev = dev; /* Indicate what driver features we support */ @@ -207,6 +272,15 @@ static int virtio_blk_probe(struct udevice *dev) priv->blksz_shift = desc->log2blksz - 9; desc->lba >>= priv->blksz_shift; + if (virtio_has_feature(dev, VIRTIO_BLK_F_SIZE_MAX)) + virtio_cread(dev, struct virtio_blk_config, size_max, &priv->size_max); + else + priv->size_max = -1U; + if (virtio_has_feature(dev, VIRTIO_BLK_F_SEG_MAX)) + virtio_cread(dev, struct virtio_blk_config, seg_max, &priv->seg_max); + else + priv->seg_max = -1U; + return 0; } diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 1cd737aca24..975f98cd9e5 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -12,6 +12,7 @@ #include <virtio_types.h> #include <virtio.h> #include <virtio_ring.h> +#include <virtio_mmio.h> #include <linux/bug.h> #include <linux/compat.h> #include <linux/err.h> @@ -335,26 +336,33 @@ static int virtio_mmio_notify(struct udevice *udev, struct virtqueue *vq) static int virtio_mmio_of_to_plat(struct udevice *udev) { - struct virtio_mmio_priv *priv = dev_get_priv(udev); + struct virtio_mmio_plat *plat = dev_get_plat(udev); + fdt_addr_t addr; + + addr = dev_read_addr(udev); - priv->base = (void __iomem *)(ulong)dev_read_addr(udev); - if (priv->base == (void __iomem *)FDT_ADDR_T_NONE) + if (addr == FDT_ADDR_T_NONE) return -EINVAL; + plat->base = addr; + return 0; } static int virtio_mmio_probe(struct udevice *udev) { + struct virtio_mmio_plat *plat = dev_get_plat(udev); struct virtio_mmio_priv *priv = dev_get_priv(udev); struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev); u32 magic; + priv->base = (void __iomem *)(uintptr_t)plat->base; + /* Check magic value */ magic = readl(priv->base + VIRTIO_MMIO_MAGIC_VALUE); if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) { debug("(%s): wrong magic value 0x%08x!\n", udev->name, magic); - return 0; + return -ENODEV; } /* Check device version */ @@ -362,7 +370,7 @@ static int virtio_mmio_probe(struct udevice *udev) if (priv->version < 1 || priv->version > 2) { debug("(%s): version %d not supported!\n", udev->name, priv->version); - return 0; + return -ENXIO; } /* Check device ID */ @@ -372,7 +380,7 @@ static int virtio_mmio_probe(struct udevice *udev) * virtio-mmio device with an ID 0 is a (dummy) placeholder * with no function. End probing now with no error reported. */ - return 0; + return -ENOENT; } uc_priv->vendor = readl(priv->base + VIRTIO_MMIO_VENDOR_ID); @@ -405,11 +413,12 @@ static const struct udevice_id virtio_mmio_ids[] = { }; U_BOOT_DRIVER(virtio_mmio) = { - .name = "virtio-mmio", - .id = UCLASS_VIRTIO, - .of_match = virtio_mmio_ids, - .ops = &virtio_mmio_ops, - .probe = virtio_mmio_probe, + .name = "virtio-mmio", + .id = UCLASS_VIRTIO, + .of_match = virtio_mmio_ids, + .ops = &virtio_mmio_ops, + .probe = virtio_mmio_probe, .of_to_plat = virtio_mmio_of_to_plat, - .priv_auto = sizeof(struct virtio_mmio_priv), + .priv_auto = sizeof(struct virtio_mmio_priv), + .plat_auto = sizeof(struct virtio_mmio_plat), }; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 416d29d256a..b91727e1265 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -217,6 +217,7 @@ config SPL_WDT_GPIO config WDT_MAX6370 bool "MAX6370 watchdog timer support" depends on WDT + select GPIO select DM_GPIO help Select this to enable max6370 watchdog timer. @@ -356,6 +357,13 @@ config WDT_RENESAS help Enables Renesas SoC R8A779F0 watchdog timer support. +config WDT_RENESAS_WWDT + bool "Renesas window watchdog timer support" + depends on WDT + select SYSCON + help + Enables Renesas window watchdog timer support. + config WDT_SANDBOX bool "Enable Watchdog Timer support for Sandbox" depends on SANDBOX && WDT @@ -376,10 +384,10 @@ config WDT_SBSA bool "SBSA watchdog timer support" depends on WDT help - Select this to enable SBSA watchdog timer. - This driver can operate ARM SBSA Generic Watchdog as a single stage. - In the single stage mode, when the timeout is reached, your system - will be reset by WS1. The first signal (WS0) is ignored. + Select this to enable SBSA watchdog timer. + This driver can operate ARM SBSA Generic Watchdog as a single stage. + In the single stage mode, when the timeout is reached, your system + will be reset by WS1. The first signal (WS0) is ignored. config WDT_SIEMENS_PMIC bool "Enable PMIC Watchdog Timer support for Siemens platforms" diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 02e2674f8af..84faefdb4c2 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_WDT_NPCM) += npcm_wdt.o obj-$(CONFIG_WDT_OCTEONTX) += octeontx_wdt.o obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o obj-$(CONFIG_WDT_RENESAS) += renesas_wdt.o +obj-$(CONFIG_WDT_RENESAS_WWDT) += renesas_wwdt.o obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o obj-$(CONFIG_WDT_SIEMENS_PMIC) += siemens_pmic_wdt.o diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c index c7307f41cb7..9e998994216 100644 --- a/drivers/watchdog/apple_wdt.c +++ b/drivers/watchdog/apple_wdt.c @@ -78,6 +78,7 @@ static const struct wdt_ops apple_wdt_ops = { }; static const struct udevice_id apple_wdt_ids[] = { + { .compatible = "apple,t8103-wdt" }, { .compatible = "apple,wdt" }, { /* sentinel */ } }; diff --git a/drivers/watchdog/designware_wdt.c b/drivers/watchdog/designware_wdt.c index bd9d7105366..91228de5e8e 100644 --- a/drivers/watchdog/designware_wdt.c +++ b/drivers/watchdog/designware_wdt.c @@ -122,7 +122,7 @@ static int designware_wdt_probe(struct udevice *dev) return ret; ret = clk_enable(&clk); - if (ret) + if (ret && ret != -ENOSYS) return ret; priv->clk_khz = clk_get_rate(&clk) / 1000; diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 7fcb866f574..068f99c5fc6 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -81,7 +81,7 @@ static int mpc8xxx_wdt_of_to_plat(struct udevice *dev) { struct mpc8xxx_wdt_priv *priv = dev_get_priv(dev); - priv->base = (void __iomem *)devfdt_remap_addr(dev); + priv->base = (void __iomem *)dev_remap_addr(dev); if (!priv->base) return -EINVAL; diff --git a/drivers/watchdog/octeontx_wdt.c b/drivers/watchdog/octeontx_wdt.c index c79d9539c13..7299a9f9739 100644 --- a/drivers/watchdog/octeontx_wdt.c +++ b/drivers/watchdog/octeontx_wdt.c @@ -159,7 +159,8 @@ static const struct octeontx_wdt_data octeon_data = { }; static const struct udevice_id octeontx_wdt_ids[] = { - { .compatible = "arm,sbsa-gwdt", .data = (ulong)&octeontx_data }, + { .compatible = "marvell,cn10624-wdt", .data = (ulong)&octeontx_data }, + { .compatible = "marvell,cn9670-wdt", .data = (ulong)&octeontx_data }, { .compatible = "cavium,octeon-7890-ciu3", .data = (ulong)&octeon_data }, {} }; diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index a2000b968c9..5a6cad135aa 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -40,8 +40,14 @@ struct orion_wdt_priv { #define TIMER_A370_STATUS 0x04 #define WDT_AXP_FIXED_ENABLE_BIT BIT(10) +#define TIMER1_FIXED_ENABLE_BIT BIT(12) #define WDT_A370_EXPIRED BIT(31) +struct orion_watchdog_data { + int (*plat_start)(struct udevice *dev, u64 timeout, ulong flags); + int (*plat_stop)(struct udevice *dev); +}; + static int orion_wdt_reset(struct udevice *dev) { struct orion_wdt_priv *priv = dev_get_priv(dev); @@ -53,7 +59,59 @@ static int orion_wdt_reset(struct udevice *dev) return 0; } -static int orion_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +static int armadaxp_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct orion_wdt_priv *priv = dev_get_priv(dev); + u32 reg; + + priv->timeout = DIV_ROUND_UP(timeout_ms, 1000); + + /* Fix the wdt and timer1 clock freqency to 25MHz */ + reg = readl(priv->reg + TIMER_CTRL); + reg |= (WDT_AXP_FIXED_ENABLE_BIT | TIMER1_FIXED_ENABLE_BIT); + writel(reg, priv->reg + TIMER_CTRL); + + /* Set watchdog duration */ + writel(priv->clk_rate * priv->timeout, + priv->reg + priv->wdt_counter_offset); + + /* Clear the watchdog expiration bit */ + reg = readl(priv->reg + TIMER_A370_STATUS); + reg &= ~WDT_A370_EXPIRED; + writel(reg, priv->reg + TIMER_A370_STATUS); + + /* Enable watchdog timer */ + reg = readl(priv->reg + TIMER_CTRL); + reg |= WDT_ENABLE_BIT; + writel(reg, priv->reg + TIMER_CTRL); + + /* Enable reset on watchdog */ + reg = readl(priv->rstout); + reg |= RSTOUT_ENABLE_BIT; + writel(reg, priv->rstout); + + return 0; +} + +static int armadaxp_wdt_stop(struct udevice *dev) +{ + struct orion_wdt_priv *priv = dev_get_priv(dev); + u32 reg; + + /* Disable reset on watchdog */ + reg = readl(priv->rstout); + reg &= ~RSTOUT_ENABLE_BIT; + writel(reg, priv->rstout); + + /* Disable watchdog timer */ + reg = readl(priv->reg + TIMER_CTRL); + reg &= ~WDT_ENABLE_BIT; + writel(reg, priv->reg + TIMER_CTRL); + + return 0; +} + +static int armada380_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) { struct orion_wdt_priv *priv = dev_get_priv(dev); u32 reg; @@ -91,7 +149,7 @@ static int orion_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) return 0; } -static int orion_wdt_stop(struct udevice *dev) +static int armada380_wdt_stop(struct udevice *dev) { struct orion_wdt_priv *priv = dev_get_priv(dev); u32 reg; @@ -113,13 +171,29 @@ static int orion_wdt_stop(struct udevice *dev) return 0; } +static int orion_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct orion_watchdog_data *data = + (struct orion_watchdog_data *)dev_get_driver_data(dev); + + return data->plat_start(dev, timeout_ms, flags); +} + +static int orion_wdt_stop(struct udevice *dev) +{ + struct orion_watchdog_data *data = + (struct orion_watchdog_data *)dev_get_driver_data(dev); + + return data->plat_stop(dev); +} + static inline bool save_reg_from_ofdata(struct udevice *dev, int index, void __iomem **reg, int *offset) { fdt_addr_t addr; fdt_size_t off; - addr = devfdt_get_addr_size_index(dev, index, &off); + addr = dev_read_addr_size_index(dev, index, &off); if (addr == FDT_ADDR_T_NONE) return false; @@ -141,8 +215,10 @@ static int orion_wdt_of_to_plat(struct udevice *dev) if (!save_reg_from_ofdata(dev, 1, &priv->rstout, NULL)) goto err; - if (!save_reg_from_ofdata(dev, 2, &priv->rstout_mask, NULL)) - goto err; + if (device_is_compatible(dev, "marvell,armada-380-wdt")) { + if (!save_reg_from_ofdata(dev, 2, &priv->rstout_mask, NULL)) + goto err; + } return 0; err: @@ -173,9 +249,20 @@ static const struct wdt_ops orion_wdt_ops = { .stop = orion_wdt_stop, }; +static struct orion_watchdog_data armada380_data = { + .plat_start = armada380_wdt_start, + .plat_stop = armada380_wdt_stop, +}; + +static struct orion_watchdog_data armadaxp_data = { + .plat_start = armadaxp_wdt_start, + .plat_stop = armadaxp_wdt_stop, +}; + static const struct udevice_id orion_wdt_ids[] = { - { .compatible = "marvell,armada-380-wdt" }, - {} + { .compatible = "marvell,armada-380-wdt", .data = (ulong)&armada380_data}, + { .compatible = "marvell,armada-xp-wdt", .data = (ulong)&armadaxp_data}, + { } }; U_BOOT_DRIVER(orion_wdt) = { diff --git a/drivers/watchdog/renesas_wwdt.c b/drivers/watchdog/renesas_wwdt.c new file mode 100644 index 00000000000..60f2ac466bf --- /dev/null +++ b/drivers/watchdog/renesas_wwdt.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2026 Marek Vasut <[email protected]> + */ + +#include <asm/io.h> +#include <clk.h> +#include <dm/device_compat.h> +#include <dm.h> +#include <linux/bitfield.h> +#include <linux/iopoll.h> +#include <regmap.h> +#include <syscon.h> +#include <wdt.h> + +#define RSIP_CTL_CFG4 0xc0 +#define RSIP_CTL_CFG4_OPWDEN BIT(3) +#define RSIP_CTL_CFG4_OPWDVAC BIT(5) + +#define WDTA0_ACT_CODE 0xac +#define WDTA0WDTE 0x0 +#define WDTA0EVAC 0x4 +#define WDTA0REF 0x8 +#define WDTA0MD 0xc +#define WDTA0MD_OVF_MASK GENMASK(6, 4) +#define WDTA0MD_OVF(n) field_prep(WDTA0MD_OVF_MASK, (n)) +#define WDTA0MD_NWIE BIT(3) +#define WDTA0MD_NERM BIT(2) +#define WDTA0MD_NVS_MASK GENMASK(1, 0) +#define WDTA0MD_NVS_75P FIELD_PREP(WDTA0MD_NVS_MASK, 3) + +struct wwdt_priv { + void __iomem *base; + struct regmap *ctl; + unsigned int timeout; +}; + +/** + * wwdt_reset() - Reset or ping Window WDT + * @dev: Watchdog device + */ +static int wwdt_reset(struct udevice *dev) +{ + struct wwdt_priv *priv = dev_get_priv(dev); + const u32 cfg = readl(priv->ctl->ranges[0].start + RSIP_CTL_CFG4); + u32 rv; + + /* WDT disabled, do nothing. */ + if (!(cfg & RSIP_CTL_CFG4_OPWDEN)) + return 0; + + /* WDT with variable activation code */ + if (cfg & RSIP_CTL_CFG4_OPWDVAC) { + rv = readb(priv->base + WDTA0REF); + rv = WDTA0_ACT_CODE - rv; + writeb(rv, priv->base + WDTA0EVAC); + } else { + writeb(WDTA0_ACT_CODE, priv->base + WDTA0WDTE); + } + + return 0; +} + +/** + * wwdt_start() - Start Window WDT + * @dev: Watchdog device + * @timeout: Watchdog timeout (not used) + * @flags: Flags (not used) + */ +static int wwdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct wwdt_priv *priv = dev_get_priv(dev); + + clrsetbits_8(priv->base + WDTA0MD, + WDTA0MD_OVF_MASK | WDTA0MD_NWIE | + WDTA0MD_NERM | WDTA0MD_NVS_MASK, + WDTA0MD_OVF(priv->timeout) | WDTA0MD_NWIE | + WDTA0MD_NVS_75P); + + wwdt_reset(dev); + + return 0; +} + +/** + * wwdt_probe() - Initialize Window WDT hardware + * @dev: Watchdog device + */ +static int wwdt_probe(struct udevice *dev) +{ + struct wwdt_priv *priv = dev_get_priv(dev); + struct udevice *syscon; + unsigned long rate; + struct clk *clk; + int ret; + + priv->base = dev_remap_addr(dev); + if (!priv->base) + return -EINVAL; + + ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "syscon", &syscon); + if (ret) { + dev_err(dev, "Failed to get syscon\n"); + return ret; + } + + priv->ctl = syscon_get_regmap(syscon); + if (!priv->ctl) { + dev_err(dev, "Failed to get regmap\n"); + return -ENODEV; + } + + clk = devm_clk_get(dev, "cnt"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(dev, "Failed to get counter clock: %d\n", ret); + return ret; + } + + ret = clk_enable(clk); + if (ret) + return ret; + + rate = clk_get_rate(clk); + if (!rate) { + clk_disable(clk); + return -ENOENT; + } + + /* + * Interval time is in "2^9..2^16 / clk_wdt" range. WDTA0OVFx is + * in 0..7 range. The code below does the WDTA0OVFx calculation + * from "interval_time = (1 << N) / clk_wdt" by caculating the N. + * The N rounded down is MSbit of (interval_time * clk_wdt). The + * result is then clamped to fit into the N in 9..16 range, and + * decremented by 9 to fit into WDTA0OVFx in 0..7 range . + */ + priv->timeout = clamp(fls(CONFIG_WATCHDOG_TIMEOUT_MSECS * rate) - 1, 9, 16) - 9; + + return 0; +} + +static const struct wdt_ops wwdt_ops = { + .start = wwdt_start, + .reset = wwdt_reset, +}; + +static const struct udevice_id wwdt_ids[] = { + { .compatible = "renesas,rcar-gen5-wwdt" }, + {} +}; + +U_BOOT_DRIVER(wwdt_renesas) = { + .name = "wwdt_renesas", + .id = UCLASS_WDT, + .of_match = wwdt_ids, + .ops = &wwdt_ops, + .probe = wwdt_probe, + .priv_auto = sizeof(struct wwdt_priv), +}; diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c index 7b387266b99..866f555789c 100644 --- a/drivers/watchdog/rti_wdt.c +++ b/drivers/watchdog/rti_wdt.c @@ -39,7 +39,7 @@ #define WDT_PRELOAD_MAX 0xfff struct rti_wdt_priv { - phys_addr_t regs; + void __iomem *regs; unsigned int clk_hz; }; @@ -177,7 +177,7 @@ static int rti_wdt_probe(struct udevice *dev) struct clk clk; int ret; - priv->regs = devfdt_get_addr(dev); + priv->regs = dev_read_addr_ptr(dev); if (!priv->regs) return -EINVAL; diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c index 807884c5bc7..3a924cb2b9a 100644 --- a/drivers/watchdog/sbsa_gwdt.c +++ b/drivers/watchdog/sbsa_gwdt.c @@ -50,6 +50,7 @@ static int sbsa_gwdt_start(struct udevice *dev, u64 timeout, ulong flags) { struct sbsa_gwdt_priv *priv = dev_get_priv(dev); u32 clk; + u64 tout_wdog; /* * it work in the single stage mode in u-boot, @@ -58,8 +59,13 @@ static int sbsa_gwdt_start(struct udevice *dev, u64 timeout, ulong flags) * to half value of timeout. */ clk = get_tbclk(); - writel(clk / (2 * 1000) * timeout, - priv->reg_control + SBSA_GWDT_WOR); + + /* if requested timeout overflows, clamp it to u32_max */ + tout_wdog = ((u64)clk * timeout) / (2 * 1000); + if (tout_wdog > U32_MAX) + tout_wdog = U32_MAX; + + writel(tout_wdog, priv->reg_control + SBSA_GWDT_WOR); /* writing WCS will cause an explicit watchdog refresh */ writel(SBSA_GWDT_WCS_EN, priv->reg_control + SBSA_GWDT_WCS); diff --git a/drivers/watchdog/starfive_wdt.c b/drivers/watchdog/starfive_wdt.c index ee9ec4cdc3a..d2c16150f4c 100644 --- a/drivers/watchdog/starfive_wdt.c +++ b/drivers/watchdog/starfive_wdt.c @@ -290,9 +290,9 @@ static int starfive_wdt_of_to_plat(struct udevice *dev) { struct starfive_wdt_priv *wdt = dev_get_priv(dev); - wdt->base = (void *)dev_read_addr(dev); + wdt->base = dev_read_addr_ptr(dev); if (!wdt->base) - return -ENODEV; + return -EINVAL; wdt->apb_clk = devm_clk_get(dev, "apb"); if (IS_ERR(wdt->apb_clk)) diff --git a/drivers/watchdog/ulp_wdog.c b/drivers/watchdog/ulp_wdog.c index 83f19dc0e86..e3a89031c44 100644 --- a/drivers/watchdog/ulp_wdog.c +++ b/drivers/watchdog/ulp_wdog.c @@ -7,6 +7,7 @@ #include <asm/io.h> #include <asm/arch/imx-regs.h> #include <dm.h> +#include <linux/delay.h> #include <wdt.h> /* @@ -51,11 +52,9 @@ struct ulp_wdt_priv { #define CLK_RATE_1KHZ 1000 #define CLK_RATE_32KHZ 125 -void hw_watchdog_set_timeout(u16 val) +void hw_watchdog_set_timeout(struct wdog_regs *wdog, u16 val) { /* setting timeout value */ - struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR; - writel(val, &wdog->toval); } @@ -89,7 +88,7 @@ void ulp_watchdog_init(struct wdog_regs *wdog, u16 timeout) while (!(readl(&wdog->cs) & WDGCS_ULK)) ; - hw_watchdog_set_timeout(timeout); + hw_watchdog_set_timeout(wdog, timeout); writel(0, &wdog->win); /* setting 1-kHz clock source, enable counter running, and clear interrupt */ @@ -107,57 +106,20 @@ void ulp_watchdog_init(struct wdog_regs *wdog, u16 timeout) ulp_watchdog_reset(wdog); } -void hw_watchdog_reset(void) -{ - struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR; - - ulp_watchdog_reset(wdog); -} - -void hw_watchdog_init(void) -{ - struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR; - - ulp_watchdog_init(wdog, CONFIG_WATCHDOG_TIMEOUT_MSECS); -} - -#if !CONFIG_IS_ENABLED(SYSRESET) +#if !CONFIG_IS_ENABLED(SYSRESET) && CONFIG_IS_ENABLED(WDT) void reset_cpu(void) { - struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR; - u32 cmd32 = 0; - - if (readl(&wdog->cs) & WDGCS_CMD32EN) { - writel(UNLOCK_WORD, &wdog->cnt); - cmd32 = WDGCS_CMD32EN; - } else { - dmb(); - __raw_writel(UNLOCK_WORD0, &wdog->cnt); - __raw_writel(UNLOCK_WORD1, &wdog->cnt); - dmb(); - } + struct udevice *wdt; - /* Wait WDOG Unlock */ - while (!(readl(&wdog->cs) & WDGCS_ULK)) - ; + for (uclass_first_device(UCLASS_WDT, &wdt); + wdt; + uclass_next_device(&wdt)) { + if (!dev_read_enabled(wdt)) + continue; - hw_watchdog_set_timeout(5); /* 5ms timeout for general; 40ms timeout for imx93 */ - writel(0, &wdog->win); - - /* enable counter running */ - if (IS_ENABLED(CONFIG_ARCH_IMX9)) - writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8) | WDOG_CS_PRES | - WDGCS_INT), &wdog->cs); - else - writel((cmd32 | WDGCS_WDGE | (WDG_LPO_CLK << 8)), &wdog->cs); - - /* Wait WDOG reconfiguration */ - while (!(readl(&wdog->cs) & WDGCS_RCS)) - ; - - hw_watchdog_reset(); - - while (1); + wdt_expire_now(wdt, 0); + break; + } } #endif @@ -184,6 +146,20 @@ static int ulp_wdt_reset(struct udevice *dev) return 0; } +static int ulp_wdt_expire_now(struct udevice *dev, ulong flags) +{ + int ret; + + /* 5ms timeout for all others; 40ms timeout for "fsl,imx93-wdt" */ + ret = ulp_wdt_start(dev, 5, flags); + if (ret) + return ret; + + mdelay(50); + + return 0; +} + static int ulp_wdt_probe(struct udevice *dev) { struct ulp_wdt_priv *priv = dev_get_priv(dev); @@ -202,6 +178,7 @@ static int ulp_wdt_probe(struct udevice *dev) static const struct wdt_ops ulp_wdt_ops = { .start = ulp_wdt_start, .reset = ulp_wdt_reset, + .expire_now = ulp_wdt_expire_now, }; static const struct udevice_id ulp_wdt_ids[] = { |
