diff options
Diffstat (limited to 'drivers')
47 files changed, 963 insertions, 161 deletions
diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig index f19908113e..bf11fad6ee 100644 --- a/drivers/clk/sunxi/Kconfig +++ b/drivers/clk/sunxi/Kconfig @@ -10,6 +10,13 @@ config CLK_SUNXI if CLK_SUNXI +config CLK_SUNIV_F1C100S + bool "Clock driver for Allwinner F1C100s" + default MACH_SUNIV + help + This enables common clock driver support for platforms based + on Allwinner F1C100s SoC. + config CLK_SUN4I_A10 bool "Clock driver for Allwinner A10/A20" default MACH_SUN4I || MACH_SUN7I diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 48a48a2f00..895da02ebe 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_CLK_SUNXI) += clk_sunxi.o obj-$(CONFIG_CLK_SUNXI) += clk_sun6i_rtc.o +obj-$(CONFIG_CLK_SUNIV_F1C100S) += clk_f1c100s.o obj-$(CONFIG_CLK_SUN4I_A10) += clk_a10.o obj-$(CONFIG_CLK_SUN5I_A10S) += clk_a10s.o obj-$(CONFIG_CLK_SUN6I_A31) += clk_a31.o diff --git a/drivers/clk/sunxi/clk_a10.c b/drivers/clk/sunxi/clk_a10.c index 90b929d3d3..db92848aaf 100644 --- a/drivers/clk/sunxi/clk_a10.c +++ b/drivers/clk/sunxi/clk_a10.c @@ -31,6 +31,8 @@ static struct ccu_clk_gate a10_gates[] = { [CLK_AHB_GMAC] = GATE(0x064, BIT(17)), + [CLK_APB0_PIO] = GATE(0x068, BIT(5)), + [CLK_APB1_I2C0] = GATE(0x06c, BIT(0)), [CLK_APB1_I2C1] = GATE(0x06c, BIT(1)), [CLK_APB1_I2C2] = GATE(0x06c, BIT(2)), diff --git a/drivers/clk/sunxi/clk_a10s.c b/drivers/clk/sunxi/clk_a10s.c index addf4f4d5c..0c6564ef3b 100644 --- a/drivers/clk/sunxi/clk_a10s.c +++ b/drivers/clk/sunxi/clk_a10s.c @@ -25,6 +25,8 @@ static struct ccu_clk_gate a10s_gates[] = { [CLK_AHB_SPI1] = GATE(0x060, BIT(21)), [CLK_AHB_SPI2] = GATE(0x060, BIT(22)), + [CLK_APB0_PIO] = GATE(0x068, BIT(5)), + [CLK_APB1_I2C0] = GATE(0x06c, BIT(0)), [CLK_APB1_I2C1] = GATE(0x06c, BIT(1)), [CLK_APB1_I2C2] = GATE(0x06c, BIT(2)), diff --git a/drivers/clk/sunxi/clk_a23.c b/drivers/clk/sunxi/clk_a23.c index c45d2c3529..0280fb51e2 100644 --- a/drivers/clk/sunxi/clk_a23.c +++ b/drivers/clk/sunxi/clk_a23.c @@ -23,6 +23,8 @@ static struct ccu_clk_gate a23_gates[] = { [CLK_BUS_EHCI] = GATE(0x060, BIT(26)), [CLK_BUS_OHCI] = GATE(0x060, BIT(29)), + [CLK_BUS_PIO] = GATE(0x068, BIT(5)), + [CLK_BUS_I2C0] = GATE(0x06c, BIT(0)), [CLK_BUS_I2C1] = GATE(0x06c, BIT(1)), [CLK_BUS_I2C2] = GATE(0x06c, BIT(2)), diff --git a/drivers/clk/sunxi/clk_a31.c b/drivers/clk/sunxi/clk_a31.c index 251fc3b705..26d25f3240 100644 --- a/drivers/clk/sunxi/clk_a31.c +++ b/drivers/clk/sunxi/clk_a31.c @@ -30,6 +30,8 @@ static struct ccu_clk_gate a31_gates[] = { [CLK_AHB1_OHCI1] = GATE(0x060, BIT(30)), [CLK_AHB1_OHCI2] = GATE(0x060, BIT(31)), + [CLK_APB1_PIO] = GATE(0x068, BIT(5)), + [CLK_APB2_I2C0] = GATE(0x06c, BIT(0)), [CLK_APB2_I2C1] = GATE(0x06c, BIT(1)), [CLK_APB2_I2C2] = GATE(0x06c, BIT(2)), diff --git a/drivers/clk/sunxi/clk_a64.c b/drivers/clk/sunxi/clk_a64.c index 1004a79503..cbb9168edb 100644 --- a/drivers/clk/sunxi/clk_a64.c +++ b/drivers/clk/sunxi/clk_a64.c @@ -14,6 +14,8 @@ #include <linux/bitops.h> static const struct ccu_clk_gate a64_gates[] = { + [CLK_PLL_PERIPH0] = GATE(0x028, BIT(31)), + [CLK_BUS_MMC0] = GATE(0x060, BIT(8)), [CLK_BUS_MMC1] = GATE(0x060, BIT(9)), [CLK_BUS_MMC2] = GATE(0x060, BIT(10)), @@ -26,6 +28,8 @@ static const struct ccu_clk_gate a64_gates[] = { [CLK_BUS_OHCI0] = GATE(0x060, BIT(28)), [CLK_BUS_OHCI1] = GATE(0x060, BIT(29)), + [CLK_BUS_PIO] = GATE(0x068, BIT(5)), + [CLK_BUS_I2C0] = GATE(0x06c, BIT(0)), [CLK_BUS_I2C1] = GATE(0x06c, BIT(1)), [CLK_BUS_I2C2] = GATE(0x06c, BIT(2)), diff --git a/drivers/clk/sunxi/clk_a80.c b/drivers/clk/sunxi/clk_a80.c index 8a0834d83a..1ee1f99a8f 100644 --- a/drivers/clk/sunxi/clk_a80.c +++ b/drivers/clk/sunxi/clk_a80.c @@ -25,6 +25,8 @@ static const struct ccu_clk_gate a80_gates[] = { [CLK_BUS_SPI2] = GATE(0x580, BIT(22)), [CLK_BUS_SPI3] = GATE(0x580, BIT(23)), + [CLK_BUS_PIO] = GATE(0x590, BIT(5)), + [CLK_BUS_I2C0] = GATE(0x594, BIT(0)), [CLK_BUS_I2C1] = GATE(0x594, BIT(1)), [CLK_BUS_I2C2] = GATE(0x594, BIT(2)), diff --git a/drivers/clk/sunxi/clk_a83t.c b/drivers/clk/sunxi/clk_a83t.c index 8c6043f51e..4b57434cfa 100644 --- a/drivers/clk/sunxi/clk_a83t.c +++ b/drivers/clk/sunxi/clk_a83t.c @@ -25,6 +25,8 @@ static struct ccu_clk_gate a83t_gates[] = { [CLK_BUS_EHCI1] = GATE(0x060, BIT(27)), [CLK_BUS_OHCI0] = GATE(0x060, BIT(29)), + [CLK_BUS_PIO] = GATE(0x068, BIT(5)), + [CLK_BUS_I2C0] = GATE(0x06c, BIT(0)), [CLK_BUS_I2C1] = GATE(0x06c, BIT(1)), [CLK_BUS_I2C2] = GATE(0x06c, BIT(2)), diff --git a/drivers/clk/sunxi/clk_f1c100s.c b/drivers/clk/sunxi/clk_f1c100s.c new file mode 100644 index 0000000000..72cf8a6e5c --- /dev/null +++ b/drivers/clk/sunxi/clk_f1c100s.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: (GPL-2.0+) +/* + * Copyright (C) 2019 George Hilliard <thirtythreeforty@gmail.com>. + */ + +#include <common.h> +#include <clk-uclass.h> +#include <dm.h> +#include <errno.h> +#include <clk/sunxi.h> +#include <dt-bindings/clock/suniv-ccu-f1c100s.h> +#include <dt-bindings/reset/suniv-ccu-f1c100s.h> + +static struct ccu_clk_gate f1c100s_gates[] = { + [CLK_BUS_MMC0] = GATE(0x060, BIT(8)), + [CLK_BUS_MMC1] = GATE(0x060, BIT(9)), + [CLK_BUS_SPI0] = GATE(0x060, BIT(20)), + [CLK_BUS_SPI1] = GATE(0x060, BIT(21)), + [CLK_BUS_OTG] = GATE(0x060, BIT(24)), + + [CLK_BUS_I2C0] = GATE(0x068, BIT(16)), + [CLK_BUS_I2C1] = GATE(0x068, BIT(17)), + [CLK_BUS_I2C2] = GATE(0x068, BIT(18)), + [CLK_BUS_PIO] = GATE(0x068, BIT(19)), + + [CLK_BUS_UART0] = GATE(0x06c, BIT(20)), + [CLK_BUS_UART1] = GATE(0x06c, BIT(21)), + [CLK_BUS_UART2] = GATE(0x06c, BIT(22)), + + [CLK_USB_PHY0] = GATE(0x0cc, BIT(1)), +}; + +static struct ccu_reset f1c100s_resets[] = { + [RST_USB_PHY0] = RESET(0x0cc, BIT(0)), + + [RST_BUS_MMC0] = RESET(0x2c0, BIT(8)), + [RST_BUS_MMC1] = RESET(0x2c0, BIT(9)), + [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)), + [RST_BUS_SPI1] = RESET(0x2c0, BIT(21)), + [RST_BUS_OTG] = RESET(0x2c0, BIT(24)), + + [RST_BUS_I2C0] = RESET(0x2d0, BIT(16)), + [RST_BUS_I2C1] = RESET(0x2d0, BIT(17)), + [RST_BUS_I2C2] = RESET(0x2d0, BIT(18)), + [RST_BUS_UART0] = RESET(0x2d0, BIT(20)), + [RST_BUS_UART1] = RESET(0x2d0, BIT(21)), + [RST_BUS_UART2] = RESET(0x2d0, BIT(22)), +}; + +static const struct ccu_desc f1c100s_ccu_desc = { + .gates = f1c100s_gates, + .resets = f1c100s_resets, +}; + +static int f1c100s_clk_bind(struct udevice *dev) +{ + return sunxi_reset_bind(dev, ARRAY_SIZE(f1c100s_resets)); +} + +static const struct udevice_id f1c100s_clk_ids[] = { + { .compatible = "allwinner,suniv-f1c100s-ccu", + .data = (ulong)&f1c100s_ccu_desc }, + { } +}; + +U_BOOT_DRIVER(clk_suniv_f1c100s) = { + .name = "suniv_f1c100s_ccu", + .id = UCLASS_CLK, + .of_match = f1c100s_clk_ids, + .priv_auto = sizeof(struct ccu_priv), + .ops = &sunxi_clk_ops, + .probe = sunxi_clk_probe, + .bind = f1c100s_clk_bind, +}; diff --git a/drivers/clk/sunxi/clk_h3.c b/drivers/clk/sunxi/clk_h3.c index 59afba53ee..08a830bd18 100644 --- a/drivers/clk/sunxi/clk_h3.c +++ b/drivers/clk/sunxi/clk_h3.c @@ -14,6 +14,8 @@ #include <linux/bitops.h> static struct ccu_clk_gate h3_gates[] = { + [CLK_PLL_PERIPH0] = GATE(0x028, BIT(31)), + [CLK_BUS_MMC0] = GATE(0x060, BIT(8)), [CLK_BUS_MMC1] = GATE(0x060, BIT(9)), [CLK_BUS_MMC2] = GATE(0x060, BIT(10)), @@ -30,6 +32,8 @@ static struct ccu_clk_gate h3_gates[] = { [CLK_BUS_OHCI2] = GATE(0x060, BIT(30)), [CLK_BUS_OHCI3] = GATE(0x060, BIT(31)), + [CLK_BUS_PIO] = GATE(0x068, BIT(5)), + [CLK_BUS_I2C0] = GATE(0x06c, BIT(0)), [CLK_BUS_I2C1] = GATE(0x06c, BIT(1)), [CLK_BUS_I2C2] = GATE(0x06c, BIT(2)), diff --git a/drivers/clk/sunxi/clk_h6.c b/drivers/clk/sunxi/clk_h6.c index 4a53788352..b320234293 100644 --- a/drivers/clk/sunxi/clk_h6.c +++ b/drivers/clk/sunxi/clk_h6.c @@ -14,6 +14,10 @@ #include <linux/bitops.h> static struct ccu_clk_gate h6_gates[] = { + [CLK_PLL_PERIPH0] = GATE(0x020, BIT(31)), + + [CLK_APB1] = GATE_DUMMY, + [CLK_BUS_MMC0] = GATE(0x84c, BIT(0)), [CLK_BUS_MMC1] = GATE(0x84c, BIT(1)), [CLK_BUS_MMC2] = GATE(0x84c, BIT(2)), diff --git a/drivers/clk/sunxi/clk_h616.c b/drivers/clk/sunxi/clk_h616.c index af97d3bb9f..80099727de 100644 --- a/drivers/clk/sunxi/clk_h616.c +++ b/drivers/clk/sunxi/clk_h616.c @@ -13,6 +13,10 @@ #include <linux/bitops.h> static struct ccu_clk_gate h616_gates[] = { + [CLK_PLL_PERIPH0] = GATE(0x020, BIT(31) | BIT(27)), + + [CLK_APB1] = GATE_DUMMY, + [CLK_BUS_MMC0] = GATE(0x84c, BIT(0)), [CLK_BUS_MMC1] = GATE(0x84c, BIT(1)), [CLK_BUS_MMC2] = GATE(0x84c, BIT(2)), diff --git a/drivers/clk/sunxi/clk_h6_r.c b/drivers/clk/sunxi/clk_h6_r.c index b9e527e16a..c592886a25 100644 --- a/drivers/clk/sunxi/clk_h6_r.c +++ b/drivers/clk/sunxi/clk_h6_r.c @@ -11,6 +11,8 @@ #include <linux/bitops.h> static struct ccu_clk_gate h6_r_gates[] = { + [CLK_R_APB1] = GATE_DUMMY, + [CLK_R_APB1_TIMER] = GATE(0x11c, BIT(0)), [CLK_R_APB1_TWD] = GATE(0x12c, BIT(0)), [CLK_R_APB1_PWM] = GATE(0x13c, BIT(0)), @@ -50,8 +52,8 @@ static const struct udevice_id h6_r_clk_ids[] = { { } }; -U_BOOT_DRIVER(clk_sun6i_h6_r) = { - .name = "sun6i_h6_r_ccu", +U_BOOT_DRIVER(clk_sun50i_h6_r) = { + .name = "sun50i_h6_r_ccu", .id = UCLASS_CLK, .of_match = h6_r_clk_ids, .priv_auto = sizeof(struct ccu_priv), diff --git a/drivers/clk/sunxi/clk_r40.c b/drivers/clk/sunxi/clk_r40.c index 4d5b69a976..45633a2a52 100644 --- a/drivers/clk/sunxi/clk_r40.c +++ b/drivers/clk/sunxi/clk_r40.c @@ -32,6 +32,8 @@ static struct ccu_clk_gate r40_gates[] = { [CLK_BUS_GMAC] = GATE(0x064, BIT(17)), + [CLK_BUS_PIO] = GATE(0x068, BIT(5)), + [CLK_BUS_I2C0] = GATE(0x06c, BIT(0)), [CLK_BUS_I2C1] = GATE(0x06c, BIT(1)), [CLK_BUS_I2C2] = GATE(0x06c, BIT(2)), diff --git a/drivers/clk/sunxi/clk_sunxi.c b/drivers/clk/sunxi/clk_sunxi.c index 9673b58a49..9a21367a5d 100644 --- a/drivers/clk/sunxi/clk_sunxi.c +++ b/drivers/clk/sunxi/clk_sunxi.c @@ -27,6 +27,9 @@ static int sunxi_set_gate(struct clk *clk, bool on) const struct ccu_clk_gate *gate = priv_to_gate(priv, clk->id); u32 reg; + if ((gate->flags & CCU_CLK_F_DUMMY_GATE)) + return 0; + if (!(gate->flags & CCU_CLK_F_IS_VALID)) { printf("%s: (CLK#%ld) unhandled\n", __func__, clk->id); return 0; diff --git a/drivers/clk/sunxi/clk_v3s.c b/drivers/clk/sunxi/clk_v3s.c index cce5c658ca..67d215cbba 100644 --- a/drivers/clk/sunxi/clk_v3s.c +++ b/drivers/clk/sunxi/clk_v3s.c @@ -20,6 +20,8 @@ static struct ccu_clk_gate v3s_gates[] = { [CLK_BUS_SPI0] = GATE(0x060, BIT(20)), [CLK_BUS_OTG] = GATE(0x060, BIT(24)), + [CLK_BUS_PIO] = GATE(0x068, BIT(5)), + [CLK_BUS_I2C0] = GATE(0x06c, BIT(0)), [CLK_BUS_I2C1] = GATE(0x06c, BIT(1)), [CLK_BUS_UART0] = GATE(0x06c, BIT(16)), diff --git a/drivers/crypto/fsl/fsl_hash.c b/drivers/crypto/fsl/fsl_hash.c index a52c4ac957..9e6829b7ad 100644 --- a/drivers/crypto/fsl/fsl_hash.c +++ b/drivers/crypto/fsl/fsl_hash.c @@ -149,12 +149,20 @@ static int caam_hash_finish(void *hash_ctx, void *dest_buf, driver_hash[caam_algo].digestsize, 1); + flush_dcache_range((ulong)ctx->sg_tbl, (ulong)(ctx->sg_tbl) + len); + flush_dcache_range((ulong)ctx->sha_desc, + (ulong)(ctx->sha_desc) + (sizeof(uint32_t) * MAX_CAAM_DESCSIZE)); + flush_dcache_range((ulong)ctx->hash, + (ulong)(ctx->hash) + driver_hash[caam_algo].digestsize); + ret = run_descriptor_jr(ctx->sha_desc); if (ret) { debug("Error %x\n", ret); return ret; } else { + invalidate_dcache_range((ulong)ctx->hash, + (ulong)(ctx->hash) + driver_hash[caam_algo].digestsize); memcpy(dest_buf, ctx->hash, sizeof(ctx->hash)); } free(ctx); diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c index 1d951cf0a6..acd29924f7 100644 --- a/drivers/crypto/fsl/jr.c +++ b/drivers/crypto/fsl/jr.c @@ -623,7 +623,7 @@ static void kick_trng(int ent_delay, ccsr_sec_t *sec) static int rng_init(uint8_t sec_idx, ccsr_sec_t *sec) { - int ret, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; + int ret, gen_sk, ent_delay = RTSDCTL_ENT_DLY; struct rng4tst __iomem *rng = (struct rng4tst __iomem *)&sec->rng; u32 inst_handles; @@ -652,6 +652,15 @@ static int rng_init(uint8_t sec_idx, ccsr_sec_t *sec) * the RNG. */ ret = instantiate_rng(sec_idx, sec, gen_sk); + /* + * entropy delay is calculated via self-test method. + * self-test are run across different volatge, temp. + * if worst case value for ent_dly is identified, + * loop can be skipped for that platform. + */ + if (IS_ENABLED(CONFIG_MX6SX)) + break; + } while ((ret == -1) && (ent_delay < RTSDCTL_ENT_DLY_MAX)); if (ret) { printf("SEC%u: Failed to instantiate RNG\n", sec_idx); @@ -758,8 +767,14 @@ init: return -1; } #if CONFIG_IS_ENABLED(OF_CONTROL) - if (ofnode_valid(scu_node)) + if (ofnode_valid(scu_node)) { + if (IS_ENABLED(CONFIG_DM_RNG)) { + ret = device_bind_driver(NULL, "caam-rng", "caam-rng", NULL); + if (ret) + printf("Couldn't bind rng driver (%d)\n", ret); + } return ret; + } #endif #ifdef CONFIG_FSL_CORENET diff --git a/drivers/ddr/imx/imx8m/ddrphy_utils.c b/drivers/ddr/imx/imx8m/ddrphy_utils.c index a54449e5f1..975d553674 100644 --- a/drivers/ddr/imx/imx8m/ddrphy_utils.c +++ b/drivers/ddr/imx/imx8m/ddrphy_utils.c @@ -198,9 +198,14 @@ unsigned int lpddr4_mr_read(unsigned int mr_rank, unsigned int mr_addr) tmp = reg32_read(DRC_PERF_MON_MRR0_DAT(0)); } while ((tmp & 0x8) == 0); tmp = reg32_read(DRC_PERF_MON_MRR1_DAT(0)); - tmp = tmp & 0xff; reg32_write(DRC_PERF_MON_MRR0_DAT(0), 0x4); - + while (tmp) { //try to find a significant byte in the word + if (tmp & 0xff) { + tmp &= 0xff; + break; + } + tmp >>= 8; + } return tmp; } diff --git a/drivers/gpio/imx_rgpio2p.c b/drivers/gpio/imx_rgpio2p.c index 0e2874ca95..175e460aff 100644 --- a/drivers/gpio/imx_rgpio2p.c +++ b/drivers/gpio/imx_rgpio2p.c @@ -39,6 +39,14 @@ static int imx_rgpio2p_is_output(struct gpio_regs *regs, int offset) return val & (1 << offset) ? 1 : 0; } +static int imx_rgpio2p_bank_get_direction(struct gpio_regs *regs, int offset) +{ + if ((readl(®s->gpio_pddr) >> offset) & 0x01) + return IMX_RGPIO2P_DIRECTION_OUT; + + return IMX_RGPIO2P_DIRECTION_IN; +} + static void imx_rgpio2p_bank_direction(struct gpio_regs *regs, int offset, enum imx_rgpio2p_direction direction) { @@ -67,7 +75,11 @@ static void imx_rgpio2p_bank_set_value(struct gpio_regs *regs, int offset, static int imx_rgpio2p_bank_get_value(struct gpio_regs *regs, int offset) { - return (readl(®s->gpio_pdir) >> offset) & 0x01; + if (imx_rgpio2p_bank_get_direction(regs, offset) == + IMX_RGPIO2P_DIRECTION_IN) + return (readl(®s->gpio_pdir) >> offset) & 0x01; + + return (readl(®s->gpio_pdor) >> offset) & 0x01; } static int imx_rgpio2p_direction_input(struct udevice *dev, unsigned offset) diff --git a/drivers/misc/imx8ulp/s400_api.c b/drivers/misc/imx8ulp/s400_api.c index 3ffdeb2ad2..87f5880ccb 100644 --- a/drivers/misc/imx8ulp/s400_api.c +++ b/drivers/misc/imx8ulp/s400_api.c @@ -272,6 +272,47 @@ int ahab_release_caam(u32 core_did, u32 *response) return ret; } +int ahab_get_fw_version(u32 *fw_version, u32 *sha1, u32 *response) +{ + struct udevice *dev = gd->arch.s400_dev; + int size = sizeof(struct imx8ulp_s400_msg); + struct imx8ulp_s400_msg msg; + int ret; + + if (!dev) { + printf("s400 dev is not initialized\n"); + return -ENODEV; + } + + if (!fw_version) { + printf("Invalid parameters for f/w version read\n"); + return -EINVAL; + } + + if (!sha1) { + printf("Invalid parameters for commit sha1\n"); + return -EINVAL; + } + + msg.version = AHAB_VERSION; + msg.tag = AHAB_CMD_TAG; + msg.size = 1; + msg.command = AHAB_GET_FW_VERSION_CID; + + 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]; + + *fw_version = msg.data[1]; + *sha1 = msg.data[2]; + + return ret; +} + int ahab_dump_buffer(u32 *buffer, u32 buffer_length) { struct udevice *dev = gd->arch.s400_dev; diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index f04cc44e19..5e2921ce41 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -727,7 +727,7 @@ config ZYNQ_HISPD_BROKEN config MMC_SUNXI bool "Allwinner sunxi SD/MMC Host Controller support" - depends on ARCH_SUNXI && !UART0_PORT_F + depends on ARCH_SUNXI default y help This selects support for the SD/MMC Host Controller on diff --git a/drivers/mmc/fsl_esdhc_spl.c b/drivers/mmc/fsl_esdhc_spl.c index ea8f4cd669..760f13d240 100644 --- a/drivers/mmc/fsl_esdhc_spl.c +++ b/drivers/mmc/fsl_esdhc_spl.c @@ -106,7 +106,7 @@ again: blk_off = (sector * 512) % mmc->read_bl_len; blk_cnt = DIV_ROUND_UP(512, mmc->read_bl_len); err = mmc->block_dev.block_read(&mmc->block_dev, blk_start, blk_cnt, tmp_buf); - if (err != 1) { + if (err != blk_cnt) { puts("spl: mmc read failed!!\n"); hang(); } diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c index ee5d7fde9c..7893e9d7e3 100644 --- a/drivers/mtd/nand/raw/mxs_nand.c +++ b/drivers/mtd/nand/raw/mxs_nand.c @@ -1246,22 +1246,6 @@ int mxs_nand_setup_ecc(struct mtd_info *mtd) /* Enable BCH complete interrupt */ writel(BCH_CTRL_COMPLETE_IRQ_EN, &bch_regs->hw_bch_ctrl_set); - /* Hook some operations at the MTD level. */ - if (mtd->_read_oob != mxs_nand_hook_read_oob) { - nand_info->hooked_read_oob = mtd->_read_oob; - mtd->_read_oob = mxs_nand_hook_read_oob; - } - - if (mtd->_write_oob != mxs_nand_hook_write_oob) { - nand_info->hooked_write_oob = mtd->_write_oob; - mtd->_write_oob = mxs_nand_hook_write_oob; - } - - if (mtd->_block_markbad != mxs_nand_hook_block_markbad) { - nand_info->hooked_block_markbad = mtd->_block_markbad; - mtd->_block_markbad = mxs_nand_hook_block_markbad; - } - return 0; } @@ -1380,6 +1364,9 @@ int mxs_nand_init_spl(struct nand_chip *nand) else nand_info->max_ecc_strength_supported = 40; + if (IS_ENABLED(CONFIG_NAND_MXS_USE_MINIMUM_ECC)) + nand_info->use_minimum_ecc = true; + err = mxs_nand_alloc_buffers(nand_info); if (err) return err; @@ -1467,6 +1454,22 @@ int mxs_nand_init_ctrl(struct mxs_nand_info *nand_info) if (err) goto err_free_buffers; + /* Hook some operations at the MTD level. */ + if (mtd->_read_oob != mxs_nand_hook_read_oob) { + nand_info->hooked_read_oob = mtd->_read_oob; + mtd->_read_oob = mxs_nand_hook_read_oob; + } + + if (mtd->_write_oob != mxs_nand_hook_write_oob) { + nand_info->hooked_write_oob = mtd->_write_oob; + mtd->_write_oob = mxs_nand_hook_write_oob; + } + + if (mtd->_block_markbad != mxs_nand_hook_block_markbad) { + nand_info->hooked_block_markbad = mtd->_block_markbad; + mtd->_block_markbad = mxs_nand_hook_block_markbad; + } + err = nand_register(0, mtd); if (err) goto err_free_buffers; diff --git a/drivers/mtd/nand/raw/mxs_nand_spl.c b/drivers/mtd/nand/raw/mxs_nand_spl.c index 59a67ee414..2bfb181007 100644 --- a/drivers/mtd/nand/raw/mxs_nand_spl.c +++ b/drivers/mtd/nand/raw/mxs_nand_spl.c @@ -218,14 +218,14 @@ void nand_init(void) mxs_nand_setup_ecc(mtd); } -int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf) +int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) { - struct nand_chip *chip; - unsigned int page; + unsigned int sz; + unsigned int block, lastblock; + unsigned int page, page_offset; unsigned int nand_page_per_block; - unsigned int sz = 0; + struct nand_chip *chip; u8 *page_buf = NULL; - u32 page_off; chip = mtd_to_nand(mtd); if (!chip->numchips) @@ -235,47 +235,42 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf) if (!page_buf) return -ENOMEM; - page = offs >> chip->page_shift; - page_off = offs & (mtd->writesize - 1); + /* offs has to be aligned to a page address! */ + block = offs / mtd->erasesize; + lastblock = (offs + size - 1) / mtd->erasesize; + page = (offs % mtd->erasesize) / mtd->writesize; + page_offset = offs % mtd->writesize; nand_page_per_block = mtd->erasesize / mtd->writesize; - debug("%s offset:0x%08x len:%d page:%x\n", __func__, offs, size, page); - - while (size) { - if (mxs_read_page_ecc(mtd, page_buf, page) < 0) - return -1; - - if (size > (mtd->writesize - page_off)) - sz = (mtd->writesize - page_off); - else - sz = size; - - memcpy(buf, page_buf + page_off, sz); - - offs += mtd->writesize; - page++; - buf += (mtd->writesize - page_off); - page_off = 0; - size -= sz; - - /* - * Check if we have crossed a block boundary, and if so - * check for bad block. - */ - if (!(page % nand_page_per_block)) { - /* - * Yes, new block. See if this block is good. If not, - * loop until we find a good block. - */ - while (is_badblock(mtd, offs, 1)) { - page = page + nand_page_per_block; - /* Check i we've reached the end of flash. */ - if (page >= mtd->size >> chip->page_shift) { + while (block <= lastblock && size > 0) { + if (!is_badblock(mtd, mtd->erasesize * block, 1)) { + /* Skip bad blocks */ + while (page < nand_page_per_block) { + int curr_page = nand_page_per_block * block + page; + + if (mxs_read_page_ecc(mtd, page_buf, curr_page) < 0) { free(page_buf); - return -ENOMEM; + return -EIO; } + + if (size > (mtd->writesize - page_offset)) + sz = (mtd->writesize - page_offset); + else + sz = size; + + memcpy(dst, page_buf + page_offset, sz); + dst += sz; + size -= sz; + page_offset = 0; + page++; } + + page = 0; + } else { + lastblock++; } + + block++; } free(page_buf); @@ -294,6 +289,19 @@ void nand_deselect(void) u32 nand_spl_adjust_offset(u32 sector, u32 offs) { - /* Handle the offset adjust in nand_spl_load_image,*/ + unsigned int block, lastblock; + + block = sector / mtd->erasesize; + lastblock = (sector + offs) / mtd->erasesize; + + while (block <= lastblock) { + if (is_badblock(mtd, block * mtd->erasesize, 1)) { + offs += mtd->erasesize; + lastblock++; + } + + block++; + } + return offs; } diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c index 63d16291ff..e6e650ef8c 100644 --- a/drivers/mtd/spi/sf-uclass.c +++ b/drivers/mtd/spi/sf-uclass.c @@ -46,25 +46,12 @@ int spl_flash_get_sw_write_prot(struct udevice *dev) * TODO(sjg@chromium.org): This is an old-style function. We should remove * it when all SPI flash drivers use dm */ -struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, +struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs, unsigned int max_hz, unsigned int spi_mode) { - struct udevice *dev; - - if (spi_flash_probe_bus_cs(bus, cs, max_hz, spi_mode, &dev)) - return NULL; - - return dev_get_uclass_priv(dev); -} - -int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs, - unsigned int max_hz, unsigned int spi_mode, - struct udevice **devp) -{ struct spi_slave *slave; struct udevice *bus; char *str; - int ret; #if defined(CONFIG_SPL_BUILD) && CONFIG_IS_ENABLED(USE_TINY_PRINTF) str = "spi_flash"; @@ -74,8 +61,22 @@ int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs, snprintf(name, sizeof(name), "spi_flash@%d:%d", busnum, cs); str = strdup(name); #endif - ret = spi_get_bus_and_cs(busnum, cs, max_hz, spi_mode, - "jedec_spi_nor", str, &bus, &slave); + + if (_spi_get_bus_and_cs(busnum, cs, max_hz, spi_mode, + "jedec_spi_nor", str, &bus, &slave)) + return NULL; + + return dev_get_uclass_priv(slave->dev); +} + +int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs, + struct udevice **devp) +{ + struct spi_slave *slave; + struct udevice *bus; + int ret; + + ret = spi_get_bus_and_cs(busnum, cs, &bus, &slave); if (ret) return ret; diff --git a/drivers/net/fm/fm.c b/drivers/net/fm/fm.c index f825612640..d0b492b5a1 100644 --- a/drivers/net/fm/fm.c +++ b/drivers/net/fm/fm.c @@ -388,7 +388,7 @@ int fm_init_common(int index, struct ccsr_fman *reg) /* speed and mode will be read from DT */ ret = spi_flash_probe_bus_cs(CONFIG_SF_DEFAULT_BUS, - CONFIG_SF_DEFAULT_CS, 0, 0, &new); + CONFIG_SF_DEFAULT_CS, &new); ucode_flash = dev_get_uclass_priv(new); #else @@ -475,7 +475,7 @@ int fm_init_common(int index, struct ccsr_fman *reg) /* speed and mode will be read from DT */ ret = spi_flash_probe_bus_cs(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS, - 0, 0, &new); + &new); ucode_flash = dev_get_uclass_priv(new); #else diff --git a/drivers/net/pfe_eth/pfe_firmware.c b/drivers/net/pfe_eth/pfe_firmware.c index 6669048181..82a4aa89a4 100644 --- a/drivers/net/pfe_eth/pfe_firmware.c +++ b/drivers/net/pfe_eth/pfe_firmware.c @@ -172,31 +172,20 @@ static int pfe_fit_check(void) int pfe_spi_flash_init(void) { struct spi_flash *pfe_flash; - struct udevice *new; int ret = 0; void *addr = malloc(CONFIG_SYS_LS_PFE_FW_LENGTH); if (!addr) return -ENOMEM; - ret = spi_flash_probe_bus_cs(CONFIG_SYS_FSL_PFE_SPI_BUS, - CONFIG_SYS_FSL_PFE_SPI_CS, - CONFIG_SYS_FSL_PFE_SPI_MAX_HZ, - CONFIG_SYS_FSL_PFE_SPI_MODE, - &new); - if (ret) { - printf("SF: failed to probe spi\n"); - free(addr); - device_remove(new, DM_REMOVE_NORMAL); - return ret; - } - + pfe_flash = spi_flash_probe(CONFIG_SYS_FSL_PFE_SPI_BUS, + CONFIG_SYS_FSL_PFE_SPI_CS, + CONFIG_SYS_FSL_PFE_SPI_MAX_HZ, + CONFIG_SYS_FSL_PFE_SPI_MODE); - pfe_flash = dev_get_uclass_priv(new); if (!pfe_flash) { printf("SF: probe for pfe failed\n"); free(addr); - device_remove(new, DM_REMOVE_NORMAL); return -ENODEV; } diff --git a/drivers/net/sni_netsec.c b/drivers/net/sni_netsec.c index 24caacf847..9780f2092b 100644 --- a/drivers/net/sni_netsec.c +++ b/drivers/net/sni_netsec.c @@ -621,12 +621,10 @@ static int netsec_stop_gmac(struct netsec_priv *priv) static void netsec_spi_read(char *buf, loff_t len, loff_t offset) { - struct udevice *new; struct spi_flash *flash; - spi_flash_probe_bus_cs(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS, - CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE, &new); - flash = dev_get_uclass_priv(new); + flash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS, + CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE); spi_flash_read(flash, offset, len, buf); } diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c index 4462ed20e2..38ce2b5e0a 100644 --- a/drivers/pinctrl/pinctrl-uclass.c +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -402,6 +402,13 @@ static int __maybe_unused pinctrl_post_bind(struct udevice *dev) { const struct pinctrl_ops *ops = pinctrl_get_ops(dev); + /* + * Make sure that the pinctrl driver gets probed after binding + * as some pinctrl drivers also register the GPIO driver during + * probe, and if they are not probed GPIO-s are not registered. + */ + dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND); + if (!ops) { dev_dbg(dev, "ops is not set. Do not bind.\n"); return -EINVAL; diff --git a/drivers/power/pmic/pca9450.c b/drivers/power/pmic/pca9450.c index 2394b196c5..116ac49a8d 100644 --- a/drivers/power/pmic/pca9450.c +++ b/drivers/power/pmic/pca9450.c @@ -19,8 +19,10 @@ DECLARE_GLOBAL_DATA_PTR; static const struct pmic_child_info pmic_children_info[] = { /* buck */ { .prefix = "b", .driver = PCA9450_REGULATOR_DRIVER}, + { .prefix = "B", .driver = PCA9450_REGULATOR_DRIVER}, /* ldo */ { .prefix = "l", .driver = PCA9450_REGULATOR_DRIVER}, + { .prefix = "L", .driver = PCA9450_REGULATOR_DRIVER}, { }, }; @@ -81,9 +83,9 @@ static struct dm_pmic_ops pca9450_ops = { }; static const struct udevice_id pca9450_ids[] = { - { .compatible = "nxp,pca9450a", .data = 0x25, }, - { .compatible = "nxp,pca9450b", .data = 0x25, }, - { .compatible = "nxp,pca9450c", .data = 0x25, }, + { .compatible = "nxp,pca9450a", .data = NXP_CHIP_TYPE_PCA9450A, }, + { .compatible = "nxp,pca9450b", .data = NXP_CHIP_TYPE_PCA9450BC, }, + { .compatible = "nxp,pca9450c", .data = NXP_CHIP_TYPE_PCA9450BC, }, { } }; diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig index 9145408b3c..d6cea8ec66 100644 --- a/drivers/power/regulator/Kconfig +++ b/drivers/power/regulator/Kconfig @@ -60,6 +60,21 @@ config SPL_DM_REGULATOR_BD71837 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. + +config SPL_DM_REGULATOR_PCA9450 + bool "Enable Driver Model for NXP PCA9450 regulators in SPL" + depends on DM_REGULATOR_PCA9450 + help + 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" depends on DM_REGULATOR && DM_PMIC_DA9063 diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile index b9883df928..bc736068bc 100644 --- a/drivers/power/regulator/Makefile +++ b/drivers/power/regulator/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_$(SPL_)DM_REGULATOR_DA9063) += da9063.o obj-$(CONFIG_DM_REGULATOR_MAX77686) += max77686.o obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_BD71837) += bd71837.o +obj-$(CONFIG_$(SPL_)DM_REGULATOR_PCA9450) += pca9450.o obj-$(CONFIG_$(SPL_)REGULATOR_PWM) += pwm_regulator.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_FAN53555) += fan53555.o obj-$(CONFIG_$(SPL_)DM_REGULATOR_COMMON) += regulator_common.o diff --git a/drivers/power/regulator/pca9450.c b/drivers/power/regulator/pca9450.c new file mode 100644 index 0000000000..23badaa332 --- /dev/null +++ b/drivers/power/regulator/pca9450.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * NXP PCA9450 regulator driver + * Copyright (C) 2022 Marek Vasut <marex@denx.de> + * + * Largely based on: + * ROHM BD71837 regulator driver + */ + +#include <common.h> +#include <dm.h> +#include <log.h> +#include <linux/bitops.h> +#include <power/pca9450.h> +#include <power/pmic.h> +#include <power/regulator.h> + +#define HW_STATE_CONTROL 0 +#define DEBUG + +/** + * struct pca9450_vrange - describe linear range of voltages + * + * @min_volt: smallest voltage in range + * @step: how much voltage changes at each selector step + * @min_sel: smallest selector in the range + * @max_sel: maximum selector in the range + */ +struct pca9450_vrange { + unsigned int min_volt; + unsigned int step; + u8 min_sel; + u8 max_sel; +}; + +/** + * struct pca9450_plat - describe regulator control registers + * + * @name: name of the regulator. Used for matching the dt-entry + * @enable_reg: register address used to enable/disable regulator + * @enablemask: register mask used to enable/disable regulator + * @volt_reg: register address used to configure regulator voltage + * @volt_mask: register mask used to configure regulator voltage + * @ranges: pointer to ranges of regulator voltages and matching register + * values + * @numranges: number of voltage ranges pointed by ranges + * @dvs: whether the voltage can be changed when regulator is enabled + */ +struct pca9450_plat { + const char *name; + u8 enable_reg; + u8 enablemask; + u8 volt_reg; + u8 volt_mask; + struct pca9450_vrange *ranges; + unsigned int numranges; + bool dvs; +}; + +#define PCA_RANGE(_min, _vstep, _sel_low, _sel_hi) \ +{ \ + .min_volt = (_min), .step = (_vstep), \ + .min_sel = (_sel_low), .max_sel = (_sel_hi), \ +} + +#define PCA_DATA(_name, enreg, enmask, vreg, vmask, _range, _dvs) \ +{ \ + .name = (_name), .enable_reg = (enreg), .enablemask = (enmask), \ + .volt_reg = (vreg), .volt_mask = (vmask), .ranges = (_range), \ + .numranges = ARRAY_SIZE(_range), .dvs = (_dvs), \ +} + +static struct pca9450_vrange pca9450_buck123_vranges[] = { + PCA_RANGE(600000, 12500, 0, 0x7f), +}; + +static struct pca9450_vrange pca9450_buck456_vranges[] = { + PCA_RANGE(600000, 25000, 0, 0x70), + PCA_RANGE(3400000, 0, 0x71, 0x7f), +}; + +static struct pca9450_vrange pca9450_ldo1_vranges[] = { + PCA_RANGE(1600000, 100000, 0x0, 0x3), + PCA_RANGE(3000000, 100000, 0x4, 0x7), +}; + +static struct pca9450_vrange pca9450_ldo2_vranges[] = { + PCA_RANGE(800000, 50000, 0x0, 0x7), +}; + +static struct pca9450_vrange pca9450_ldo34_vranges[] = { + PCA_RANGE(800000, 100000, 0x0, 0x19), + PCA_RANGE(3300000, 0, 0x1a, 0x1f), +}; + +static struct pca9450_vrange pca9450_ldo5_vranges[] = { + PCA_RANGE(1800000, 100000, 0x0, 0xf), +}; + +/* + * We use enable mask 'HW_STATE_CONTROL' to indicate that this regulator + * must not be enabled or disabled by SW. The typical use-case for PCA9450 + * is powering NXP i.MX8. In this use-case we (for now) only allow control + * for BUCK4, BUCK5, BUCK6 which are not boot critical. + */ +static struct pca9450_plat pca9450_reg_data[] = { + /* Bucks 1-3 which support dynamic voltage scaling */ + PCA_DATA("BUCK1", PCA9450_BUCK1CTRL, HW_STATE_CONTROL, + PCA9450_BUCK1OUT_DVS0, PCA9450_DVS_BUCK_RUN_MASK, + pca9450_buck123_vranges, true), + PCA_DATA("BUCK2", PCA9450_BUCK2CTRL, HW_STATE_CONTROL, + PCA9450_BUCK2OUT_DVS0, PCA9450_DVS_BUCK_RUN_MASK, + pca9450_buck123_vranges, true), + PCA_DATA("BUCK3", PCA9450_BUCK3CTRL, HW_STATE_CONTROL, + PCA9450_BUCK3OUT_DVS0, PCA9450_DVS_BUCK_RUN_MASK, + pca9450_buck123_vranges, true), + /* Bucks 4-6 which do not support dynamic voltage scaling */ + PCA_DATA("BUCK4", PCA9450_BUCK4CTRL, HW_STATE_CONTROL, + PCA9450_BUCK4OUT, PCA9450_DVS_BUCK_RUN_MASK, + pca9450_buck456_vranges, false), + PCA_DATA("BUCK5", PCA9450_BUCK5CTRL, HW_STATE_CONTROL, + PCA9450_BUCK5OUT, PCA9450_DVS_BUCK_RUN_MASK, + pca9450_buck456_vranges, false), + PCA_DATA("BUCK6", PCA9450_BUCK6CTRL, HW_STATE_CONTROL, + PCA9450_BUCK6OUT, PCA9450_DVS_BUCK_RUN_MASK, + pca9450_buck456_vranges, false), + /* LDOs */ + PCA_DATA("LDO1", PCA9450_LDO1CTRL, HW_STATE_CONTROL, + PCA9450_LDO1CTRL, PCA9450_LDO12_MASK, + pca9450_ldo1_vranges, false), + PCA_DATA("LDO2", PCA9450_LDO2CTRL, HW_STATE_CONTROL, + PCA9450_LDO2CTRL, PCA9450_LDO12_MASK, + pca9450_ldo2_vranges, false), + PCA_DATA("LDO3", PCA9450_LDO3CTRL, HW_STATE_CONTROL, + PCA9450_LDO3CTRL, PCA9450_LDO34_MASK, + pca9450_ldo34_vranges, false), + PCA_DATA("LDO4", PCA9450_LDO4CTRL, HW_STATE_CONTROL, + PCA9450_LDO4CTRL, PCA9450_LDO34_MASK, + pca9450_ldo34_vranges, false), + PCA_DATA("LDO5", PCA9450_LDO5CTRL_H, HW_STATE_CONTROL, + PCA9450_LDO5CTRL_H, PCA9450_LDO5_MASK, + pca9450_ldo5_vranges, false), +}; + +static int vrange_find_value(struct pca9450_vrange *r, unsigned int sel, + unsigned int *val) +{ + if (!val || sel < r->min_sel || sel > r->max_sel) + return -EINVAL; + + *val = r->min_volt + r->step * (sel - r->min_sel); + return 0; +} + +static int vrange_find_selector(struct pca9450_vrange *r, int val, + unsigned int *sel) +{ + int ret = -EINVAL; + int num_vals = r->max_sel - r->min_sel + 1; + + if (val >= r->min_volt && + val <= r->min_volt + r->step * (num_vals - 1)) { + if (r->step) { + *sel = r->min_sel + ((val - r->min_volt) / r->step); + ret = 0; + } else { + *sel = r->min_sel; + ret = 0; + } + } + return ret; +} + +static int pca9450_get_enable(struct udevice *dev) +{ + struct pca9450_plat *plat = dev_get_plat(dev); + int val; + + /* + * boot critical regulators on pca9450 must not be controlled by sw + * due to the 'feature' which leaves power rails down if pca9450 is + * reseted to snvs state. hence we can't get the state here. + * + * if we are alive it means we probably are on run state and + * if the regulator can't be controlled we can assume it is + * enabled. + */ + if (plat->enablemask == HW_STATE_CONTROL) + return 1; + + val = pmic_reg_read(dev->parent, plat->enable_reg); + if (val < 0) + return val; + + return (val & plat->enablemask); +} + +static int pca9450_set_enable(struct udevice *dev, bool enable) +{ + int val = 0; + struct pca9450_plat *plat = dev_get_plat(dev); + + /* + * boot critical regulators on pca9450 must not be controlled by sw + * due to the 'feature' which leaves power rails down if pca9450 is + * reseted to snvs state. Hence we can't set the state here. + */ + if (plat->enablemask == HW_STATE_CONTROL) + return enable ? 0 : -EINVAL; + + if (enable) + val = plat->enablemask; + + return pmic_clrsetbits(dev->parent, plat->enable_reg, plat->enablemask, + val); +} + +static int pca9450_get_value(struct udevice *dev) +{ + struct pca9450_plat *plat = dev_get_plat(dev); + unsigned int reg, tmp; + int i, ret; + + ret = pmic_reg_read(dev->parent, plat->volt_reg); + if (ret < 0) + return ret; + + reg = ret; + reg &= plat->volt_mask; + + for (i = 0; i < plat->numranges; i++) { + struct pca9450_vrange *r = &plat->ranges[i]; + + if (!vrange_find_value(r, reg, &tmp)) + return tmp; + } + + pr_err("Unknown voltage value read from pmic\n"); + + return -EINVAL; +} + +static int pca9450_set_value(struct udevice *dev, int uvolt) +{ + struct pca9450_plat *plat = dev_get_plat(dev); + unsigned int sel; + int i, found = 0; + + /* + * An under/overshooting may occur if voltage is changed for other + * regulators but buck 1,2,3 or 4 when regulator is enabled. Prevent + * change to protect the HW + */ + if (!plat->dvs) + if (pca9450_get_enable(dev)) { + /* If the value is already set, skip the warning. */ + if (pca9450_get_value(dev) == uvolt) + return 0; + pr_err("Only DVS bucks can be changed when enabled\n"); + return -EINVAL; + } + + for (i = 0; i < plat->numranges; i++) { + struct pca9450_vrange *r = &plat->ranges[i]; + + found = !vrange_find_selector(r, uvolt, &sel); + if (found) { + unsigned int tmp; + + /* + * We require exactly the requested value to be + * supported - this can be changed later if needed + */ + found = !vrange_find_value(r, sel, &tmp); + if (found && tmp == uvolt) + break; + found = 0; + } + } + + if (!found) + return -EINVAL; + + return pmic_clrsetbits(dev->parent, plat->volt_reg, + plat->volt_mask, sel); +} + +static int pca9450_regulator_probe(struct udevice *dev) +{ + struct pca9450_plat *plat = dev_get_plat(dev); + int i, type; + + type = dev_get_driver_data(dev_get_parent(dev)); + + if (type != NXP_CHIP_TYPE_PCA9450A && type != NXP_CHIP_TYPE_PCA9450BC) { + debug("Unknown PMIC type\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(pca9450_reg_data); i++) { + if (strcmp(dev->name, pca9450_reg_data[i].name)) + continue; + + /* PCA9450B/PCA9450C uses BUCK1 and BUCK3 in dual-phase */ + if (type == NXP_CHIP_TYPE_PCA9450BC && + !strcmp(pca9450_reg_data[i].name, "BUCK3")) { + continue; + } + + *plat = pca9450_reg_data[i]; + + return 0; + } + + pr_err("Unknown regulator '%s'\n", dev->name); + + return -ENOENT; +} + +static const struct dm_regulator_ops pca9450_regulator_ops = { + .get_value = pca9450_get_value, + .set_value = pca9450_set_value, + .get_enable = pca9450_get_enable, + .set_enable = pca9450_set_enable, +}; + +U_BOOT_DRIVER(pca9450_regulator) = { + .name = PCA9450_REGULATOR_DRIVER, + .id = UCLASS_REGULATOR, + .ops = &pca9450_regulator_ops, + .probe = pca9450_regulator_probe, + .plat_auto = sizeof(struct pca9450_plat), +}; diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 26fa498bbb..45c284a408 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -84,36 +84,10 @@ config VPL_SERIAL_PRESENT This option enables the full UART in TPL, so if is it disabled, the full UART driver will be omitted, thus saving space. -# Logic to allow us to use the imply keyword to set what the default port -# should be. The default is otherwise 1. -config CONS_INDEX_0 - bool - -config CONS_INDEX_2 - bool - -config CONS_INDEX_3 - bool - -config CONS_INDEX_4 - bool - -config CONS_INDEX_5 - bool - -config CONS_INDEX_6 - bool - config CONS_INDEX int "UART used for console" depends on SPECIFY_CONSOLE_INDEX range 0 6 - default 0 if CONS_INDEX_0 - default 2 if CONS_INDEX_2 - default 3 if CONS_INDEX_3 - default 4 if CONS_INDEX_4 - default 5 if CONS_INDEX_5 - default 6 if CONS_INDEX_6 default 1 help Set this to match the UART number of the serial console. @@ -508,6 +482,20 @@ config DEBUG_UART_BASE A default should be provided by your board, but if not you will need to use the correct value here. +config SPL_DEBUG_UART_BASE + hex "Base address of UART for SPL" + depends on SPL && DEBUG_UART + default DEBUG_UART_BASE + help + This is the base address of your UART for memory-mapped UARTs for SPL. + +config TPL_DEBUG_UART_BASE + hex "Base address of UART for TPL" + depends on TPL && DEBUG_UART + default DEBUG_UART_BASE + help + This is the base address of your UART for memory-mapped UARTs for TPL. + config DEBUG_UART_CLOCK int "UART input clock" depends on DEBUG_UART diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index a4220fd0ae..78bfe6281c 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -325,7 +325,7 @@ int ns16550_tstc(struct ns16550 *com_port) static inline void _debug_uart_init(void) { - struct ns16550 *com_port = (struct ns16550 *)CONFIG_DEBUG_UART_BASE; + struct ns16550 *com_port = (struct ns16550 *)CONFIG_VAL(DEBUG_UART_BASE); int baud_divisor; /* @@ -360,7 +360,7 @@ static inline int NS16550_read_baud_divisor(struct ns16550 *com_port) static inline void _debug_uart_putc(int ch) { - struct ns16550 *com_port = (struct ns16550 *)CONFIG_DEBUG_UART_BASE; + struct ns16550 *com_port = (struct ns16550 *)CONFIG_VAL(DEBUG_UART_BASE); while (!(serial_din(&com_port->lsr) & UART_LSR_THRE)) { #ifdef CONFIG_DEBUG_UART_NS16550_CHECK_ENABLED diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index f8ec312d71..f2791c4b88 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -340,9 +340,65 @@ int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp, return ret; } -int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, - const char *drv_name, const char *dev_name, - struct udevice **busp, struct spi_slave **devp) +int spi_get_bus_and_cs(int busnum, int cs, struct udevice **busp, + struct spi_slave **devp) +{ + struct udevice *bus, *dev; + struct dm_spi_bus *bus_data; + struct spi_slave *slave; + int ret; + +#if CONFIG_IS_ENABLED(OF_PLATDATA) + ret = uclass_first_device_err(UCLASS_SPI, &bus); +#else + ret = uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus); +#endif + if (ret) { + log_err("Invalid bus %d (err=%d)\n", busnum, ret); + return ret; + } + ret = spi_find_chip_select(bus, cs, &dev); + if (ret) { + dev_err(bus, "Invalid chip select %d:%d (err=%d)\n", busnum, cs, ret); + return ret; + } + + if (!device_active(dev)) { + struct spi_slave *slave; + + ret = device_probe(dev); + if (ret) + goto err; + slave = dev_get_parent_priv(dev); + slave->dev = dev; + } + + slave = dev_get_parent_priv(dev); + bus_data = dev_get_uclass_priv(bus); + + /* + * In case the operation speed is not yet established by + * dm_spi_claim_bus() ensure the bus is configured properly. + */ + if (!bus_data->speed) { + ret = spi_claim_bus(slave); + if (ret) + goto err; + } + *busp = bus; + *devp = slave; + + return 0; + +err: + log_debug("%s: Error path, device '%s'\n", __func__, dev->name); + + return ret; +} + +int _spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, + const char *drv_name, const char *dev_name, + struct udevice **busp, struct spi_slave **devp) { struct udevice *bus, *dev; struct dm_spi_slave_plat *plat; @@ -453,8 +509,8 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs, struct udevice *dev; int ret; - ret = spi_get_bus_and_cs(busnum, cs, speed, mode, NULL, 0, &dev, - &slave); + ret = _spi_get_bus_and_cs(busnum, cs, speed, mode, NULL, 0, &dev, + &slave); if (ret) return NULL; diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index 8f4aabc3d1..ceba413727 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -150,20 +150,19 @@ static int _stm32_qspi_wait_cmd(struct stm32_qspi_priv *priv, u32 sr; int ret = 0; - if (op->data.nbytes) { - ret = readl_poll_timeout(&priv->regs->sr, sr, - sr & STM32_QSPI_SR_TCF, - STM32_QSPI_CMD_TIMEOUT_US); - if (ret) { - log_err("cmd timeout (stat:%#x)\n", sr); - } else if (readl(&priv->regs->sr) & STM32_QSPI_SR_TEF) { - log_err("transfer error (stat:%#x)\n", sr); - ret = -EIO; - } - /* clear flags */ - writel(STM32_QSPI_FCR_CTCF | STM32_QSPI_FCR_CTEF, &priv->regs->fcr); + ret = readl_poll_timeout(&priv->regs->sr, sr, + sr & STM32_QSPI_SR_TCF, + STM32_QSPI_CMD_TIMEOUT_US); + if (ret) { + log_err("cmd timeout (stat:%#x)\n", sr); + } else if (readl(&priv->regs->sr) & STM32_QSPI_SR_TEF) { + log_err("transfer error (stat:%#x)\n", sr); + ret = -EIO; } + /* clear flags */ + writel(STM32_QSPI_FCR_CTCF | STM32_QSPI_FCR_CTEF, &priv->regs->fcr); + if (!ret) ret = _stm32_qspi_wait_for_not_busy(priv); @@ -256,10 +255,6 @@ static int stm32_qspi_exec_op(struct spi_slave *slave, op->dummy.buswidth, op->data.buswidth, op->addr.val, op->data.nbytes); - ret = _stm32_qspi_wait_for_not_busy(priv); - if (ret) - return ret; - addr_max = op->addr.val + op->data.nbytes + 1; if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes) { diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig index eceff27d5f..d59102d9a6 100644 --- a/drivers/tpm/Kconfig +++ b/drivers/tpm/Kconfig @@ -185,6 +185,15 @@ config TPM2_TIS_SPI to the device using the standard TPM Interface Specification (TIS) protocol. +config TPM2_TIS_I2C + bool "Enable support for TPMv2.x I2C chips" + depends on TPM_V2 && DM_I2C + help + This driver supports TPMv2.x devices connected on the I2C bus. + The usual TPM operations and the 'tpm' command can be used to talk + to the device using the standard TPM Interface Specification (TIS) + protocol. + config TPM2_FTPM_TEE bool "TEE based fTPM Interface" depends on TEE && OPTEE && TPM_V2 diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile index 51725230c7..9540fd7fe7 100644 --- a/drivers/tpm/Makefile +++ b/drivers/tpm/Makefile @@ -13,5 +13,6 @@ obj-$(CONFIG_TPM_ST33ZP24_SPI) += tpm_tis_st33zp24_spi.o obj-$(CONFIG_$(SPL_TPL_)TPM2_CR50_I2C) += cr50_i2c.o obj-$(CONFIG_TPM2_TIS_SANDBOX) += tpm2_tis_sandbox.o sandbox_common.o obj-$(CONFIG_TPM2_TIS_SPI) += tpm2_tis_core.o tpm2_tis_spi.o +obj-$(CONFIG_TPM2_TIS_I2C) += tpm2_tis_core.o tpm2_tis_i2c.o obj-$(CONFIG_TPM2_FTPM_TEE) += tpm2_ftpm_tee.o obj-$(CONFIG_TPM2_MMIO) += tpm2_tis_core.o tpm2_tis_mmio.o diff --git a/drivers/tpm/tpm2_tis_core.c b/drivers/tpm/tpm2_tis_core.c index 51392c4584..985a816219 100644 --- a/drivers/tpm/tpm2_tis_core.c +++ b/drivers/tpm/tpm2_tis_core.c @@ -433,15 +433,16 @@ int tpm_tis_init(struct udevice *dev) log_err("Driver bug. No bus ops defined\n"); return -1; } - ret = tpm_tis_request_locality(dev, 0); - if (ret) - return ret; chip->timeout_a = TIS_SHORT_TIMEOUT_MS; chip->timeout_b = TIS_LONG_TIMEOUT_MS; chip->timeout_c = TIS_SHORT_TIMEOUT_MS; chip->timeout_d = TIS_SHORT_TIMEOUT_MS; + ret = tpm_tis_request_locality(dev, 0); + if (ret) + return ret; + /* Disable interrupts */ phy_ops->read32(dev, TPM_INT_ENABLE(chip->locality), &tmp); tmp |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT | diff --git a/drivers/tpm/tpm2_tis_i2c.c b/drivers/tpm/tpm2_tis_i2c.c new file mode 100644 index 0000000000..99d1cf218d --- /dev/null +++ b/drivers/tpm/tpm2_tis_i2c.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2022 IBM Corp. + */ + +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <i2c.h> +#include <log.h> +#include <tpm-v2.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/compiler.h> +#include <linux/types.h> +#include <linux/unaligned/be_byteshift.h> +#include <asm-generic/gpio.h> + +#include "tpm_tis.h" +#include "tpm_internal.h" + +struct tpm_tis_chip_data { + unsigned int pcr_count; + unsigned int pcr_select_min; +}; + +static uint tpm_tis_i2c_address_to_register(u32 addr) +{ + addr &= 0xFFF; + + /* + * Adapt register addresses that have changed compared to older TIS + * version. + */ + switch (addr) { + case TPM_ACCESS(0): + return 0x04; + case TPM_DID_VID(0): + return 0x48; + case TPM_RID(0): + return 0x4C; + default: + return addr; + } +} + +static int tpm_tis_i2c_read(struct udevice *dev, u32 addr, u16 len, u8 *in) +{ + int rc; + int count = 0; + uint reg = tpm_tis_i2c_address_to_register(addr); + + do { + rc = dm_i2c_read(dev, reg, in, len); + udelay(SLEEP_DURATION_US); + } while (rc && count++ < MAX_COUNT); + + return rc; +} + +static int tpm_tis_i2c_write(struct udevice *dev, u32 addr, u16 len, + const u8 *out) +{ + int rc; + int count = 0; + uint reg = tpm_tis_i2c_address_to_register(addr); + + do { + rc = dm_i2c_write(dev, reg, out, len); + udelay(SLEEP_DURATION_US); + } while (rc && count++ < MAX_COUNT); + + return rc; +} + +static int tpm_tis_i2c_read32(struct udevice *dev, u32 addr, u32 *result) +{ + __le32 result_le; + int rc; + + rc = tpm_tis_i2c_read(dev, addr, sizeof(u32), (u8 *)&result_le); + if (!rc) + *result = le32_to_cpu(result_le); + + return rc; +} + +static int tpm_tis_i2c_write32(struct udevice *dev, u32 addr, u32 value) +{ + __le32 value_le = cpu_to_le32(value); + + return tpm_tis_i2c_write(dev, addr, sizeof(value), (u8 *)&value_le); +} + +static struct tpm_tis_phy_ops phy_ops = { + .read_bytes = tpm_tis_i2c_read, + .write_bytes = tpm_tis_i2c_write, + .read32 = tpm_tis_i2c_read32, + .write32 = tpm_tis_i2c_write32, +}; + +static int tpm_tis_i2c_probe(struct udevice *udev) +{ + struct tpm_tis_chip_data *drv_data = (void *)dev_get_driver_data(udev); + struct tpm_chip_priv *priv = dev_get_uclass_priv(udev); + int rc; + u8 loc = 0; + + tpm_tis_ops_register(udev, &phy_ops); + + /* + * Force locality 0. The core driver doesn't actually write the + * locality register and instead just reads/writes various access + * bits of the selected locality. + */ + rc = dm_i2c_write(udev, 0, &loc, 1); + if (rc) + return rc; + + rc = tpm_tis_init(udev); + if (rc) + return rc; + + priv->pcr_count = drv_data->pcr_count; + priv->pcr_select_min = drv_data->pcr_select_min; + priv->version = TPM_V2; + + return 0; +} + +static int tpm_tis_i2c_remove(struct udevice *udev) +{ + return tpm_tis_cleanup(udev); +} + +static const struct tpm_ops tpm_tis_i2c_ops = { + .open = tpm_tis_open, + .close = tpm_tis_close, + .get_desc = tpm_tis_get_desc, + .send = tpm_tis_send, + .recv = tpm_tis_recv, + .cleanup = tpm_tis_cleanup, +}; + +static const struct tpm_tis_chip_data tpm_tis_std_chip_data = { + .pcr_count = 24, + .pcr_select_min = 3, +}; + +static const struct udevice_id tpm_tis_i2c_ids[] = { + { + .compatible = "nuvoton,npct75x", + .data = (ulong)&tpm_tis_std_chip_data, + }, + { + .compatible = "tcg,tpm-tis-i2c", + .data = (ulong)&tpm_tis_std_chip_data, + }, + { } +}; + +U_BOOT_DRIVER(tpm_tis_i2c) = { + .name = "tpm_tis_i2c", + .id = UCLASS_TPM, + .of_match = tpm_tis_i2c_ids, + .ops = &tpm_tis_i2c_ops, + .probe = tpm_tis_i2c_probe, + .remove = tpm_tis_i2c_remove, + .priv_auto = sizeof(struct tpm_chip), +}; diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index ee0c064f1f..cff86a51ae 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -40,6 +40,22 @@ enum usb_dr_mode usb_get_dr_mode(ofnode node) return USB_DR_MODE_UNKNOWN; } +enum usb_dr_mode usb_get_role_switch_default_mode(ofnode node) +{ + const char *dr_mode; + int i; + + dr_mode = ofnode_read_string(node, "role-switch-default-mode"); + if (!dr_mode) + return USB_DR_MODE_UNKNOWN; + + for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++) + if (!strcmp(dr_mode, usb_dr_modes[i])) + return i; + + return USB_DR_MODE_UNKNOWN; +} + static const char *const speed_names[] = { [USB_SPEED_UNKNOWN] = "UNKNOWN", [USB_SPEED_LOW] = "low-speed", diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c index 6e1a1d066b..c5310e465c 100644 --- a/drivers/usb/dwc3/dwc3-generic.c +++ b/drivers/usb/dwc3/dwc3-generic.c @@ -468,9 +468,11 @@ static int dwc3_glue_probe(struct udevice *dev) ret = generic_phy_init(&phy); if (ret) return ret; - } else if (ret != -ENOENT) { + } else if (ret != -ENOENT && ret != -ENODATA) { debug("could not get phy (err %d)\n", ret); return ret; + } else { + phy.dev = NULL; } glue->regs = dev_read_addr(dev); diff --git a/drivers/usb/gadget/max3420_udc.c b/drivers/usb/gadget/max3420_udc.c index a16095f892..fa655c98dc 100644 --- a/drivers/usb/gadget/max3420_udc.c +++ b/drivers/usb/gadget/max3420_udc.c @@ -830,8 +830,8 @@ static int max3420_udc_probe(struct udevice *dev) cs = slave_pdata->cs; speed = slave_pdata->max_hz; mode = slave_pdata->mode; - spi_get_bus_and_cs(busnum, cs, speed, mode, "spi_generic_drv", - NULL, &spid, &udc->slave); + _spi_get_bus_and_cs(busnum, cs, speed, mode, false, "spi_generic_drv", + NULL, &spid, &udc->slave); udc->dev = dev; udc->gadget.ep0 = &udc->ep[0].ep_usb; diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c index bec0d98081..1dbd65dfaa 100644 --- a/drivers/usb/host/xhci-dwc3.c +++ b/drivers/usb/host/xhci-dwc3.c @@ -209,6 +209,12 @@ static int xhci_dwc3_probe(struct udevice *dev) writel(reg, &dwc3_reg->g_usb2phycfg[0]); dr_mode = usb_get_dr_mode(dev_ofnode(dev)); + if (dr_mode == USB_DR_MODE_OTG && + dev_read_bool(dev, "usb-role-switch")) { + dr_mode = usb_get_role_switch_default_mode(dev_ofnode(dev)); + if (dr_mode == USB_DR_MODE_UNKNOWN) + dr_mode = USB_DR_MODE_OTG; + } if (dr_mode == USB_DR_MODE_UNKNOWN) /* by default set dual role mode to HOST */ dr_mode = USB_DR_MODE_HOST; |