Revision | 87069c79e830b2ab909537946a1e1db0e5fe7d8c (tree) |
---|---|
Time | 2022-07-27 20:00:54 |
Author | Tom Rini <trini@kons...> |
Commiter | Tom Rini |
@@ -1048,6 +1048,7 @@ static int do_mmc_boot_wp(struct cmd_tbl *cmdtp, int flag, | ||
1048 | 1048 | { |
1049 | 1049 | int err; |
1050 | 1050 | struct mmc *mmc; |
1051 | + int part; | |
1051 | 1052 | |
1052 | 1053 | mmc = init_mmc_device(curr_device, false); |
1053 | 1054 | if (!mmc) |
@@ -1056,7 +1057,14 @@ static int do_mmc_boot_wp(struct cmd_tbl *cmdtp, int flag, | ||
1056 | 1057 | printf("It is not an eMMC device\n"); |
1057 | 1058 | return CMD_RET_FAILURE; |
1058 | 1059 | } |
1059 | - err = mmc_boot_wp(mmc); | |
1060 | + | |
1061 | + if (argc == 2) { | |
1062 | + part = dectoul(argv[1], NULL); | |
1063 | + err = mmc_boot_wp_single_partition(mmc, part); | |
1064 | + } else { | |
1065 | + err = mmc_boot_wp(mmc); | |
1066 | + } | |
1067 | + | |
1060 | 1068 | if (err) |
1061 | 1069 | return CMD_RET_FAILURE; |
1062 | 1070 | printf("boot areas protected\n"); |
@@ -1066,7 +1074,7 @@ static int do_mmc_boot_wp(struct cmd_tbl *cmdtp, int flag, | ||
1066 | 1074 | static struct cmd_tbl cmd_mmc[] = { |
1067 | 1075 | U_BOOT_CMD_MKENT(info, 1, 0, do_mmcinfo, "", ""), |
1068 | 1076 | U_BOOT_CMD_MKENT(read, 4, 1, do_mmc_read, "", ""), |
1069 | - U_BOOT_CMD_MKENT(wp, 1, 0, do_mmc_boot_wp, "", ""), | |
1077 | + U_BOOT_CMD_MKENT(wp, 2, 0, do_mmc_boot_wp, "", ""), | |
1070 | 1078 | #if CONFIG_IS_ENABLED(MMC_WRITE) |
1071 | 1079 | U_BOOT_CMD_MKENT(write, 4, 0, do_mmc_write, "", ""), |
1072 | 1080 | U_BOOT_CMD_MKENT(erase, 3, 0, do_mmc_erase, "", ""), |
@@ -1140,7 +1148,11 @@ U_BOOT_CMD( | ||
1140 | 1148 | " [MMC_LEGACY, MMC_HS, SD_HS, MMC_HS_52, MMC_DDR_52, UHS_SDR12, UHS_SDR25,\n" |
1141 | 1149 | " UHS_SDR50, UHS_DDR50, UHS_SDR104, MMC_HS_200, MMC_HS_400, MMC_HS_400_ES]\n" |
1142 | 1150 | "mmc list - lists available devices\n" |
1143 | - "mmc wp - power on write protect boot partitions\n" | |
1151 | + "mmc wp [PART] - power on write protect boot partitions\n" | |
1152 | + " arguments:\n" | |
1153 | + " PART - [0|1]\n" | |
1154 | + " : 0 - first boot partition, 1 - second boot partition\n" | |
1155 | + " if not assigned, write protect all boot partitions\n" | |
1144 | 1156 | #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) |
1145 | 1157 | "mmc hwpartition <USER> <GP> <MODE> - does hardware partitioning\n" |
1146 | 1158 | " arguments (sizes in 512-byte blocks):\n" |
@@ -618,6 +618,18 @@ config MMC_SDHCI_MV | ||
618 | 618 | |
619 | 619 | If unsure, say N. |
620 | 620 | |
621 | +config MMC_SDHCI_NPCM | |
622 | + bool "SDHCI support on Nuvoton NPCM device" | |
623 | + depends on MMC_SDHCI | |
624 | + depends on DM_MMC | |
625 | + help | |
626 | + This selects the Secure Digital Host Controller Interface (SDHCI) | |
627 | + on Nuvoton NPCM device. | |
628 | + | |
629 | + If you have a controller with this interface, say Y here. | |
630 | + | |
631 | + If unsure, say N. | |
632 | + | |
621 | 633 | config MMC_SDHCI_PIC32 |
622 | 634 | bool "Microchip PIC32 on-chip SDHCI support" |
623 | 635 | depends on DM_MMC && MACH_PIC32 |
@@ -66,6 +66,7 @@ obj-$(CONFIG_MMC_SDHCI_IPROC) += iproc_sdhci.o | ||
66 | 66 | obj-$(CONFIG_MMC_SDHCI_KONA) += kona_sdhci.o |
67 | 67 | obj-$(CONFIG_MMC_SDHCI_MSM) += msm_sdhci.o |
68 | 68 | obj-$(CONFIG_MMC_SDHCI_MV) += mv_sdhci.o |
69 | +obj-$(CONFIG_MMC_SDHCI_NPCM) += npcm_sdhci.o | |
69 | 70 | obj-$(CONFIG_MMC_SDHCI_PIC32) += pic32_sdhci.o |
70 | 71 | obj-$(CONFIG_MMC_SDHCI_ROCKCHIP) += rockchip_sdhci.o |
71 | 72 | obj-$(CONFIG_MMC_SDHCI_S5P) += s5p_sdhci.o |
@@ -504,6 +504,7 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock) | ||
504 | 504 | u32 time_out; |
505 | 505 | u32 value; |
506 | 506 | uint clk; |
507 | + u32 hostver; | |
507 | 508 | |
508 | 509 | if (clock < mmc->cfg->f_min) |
509 | 510 | clock = mmc->cfg->f_min; |
@@ -544,6 +545,14 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock) | ||
544 | 545 | |
545 | 546 | esdhc_clrsetbits32(®s->sysctl, SYSCTL_CLOCK_MASK, clk); |
546 | 547 | |
548 | + /* Only newer eSDHC controllers set PRSSTAT_SDSTB flag */ | |
549 | + hostver = esdhc_read32(&priv->esdhc_regs->hostver); | |
550 | + if (HOSTVER_VENDOR(hostver) <= VENDOR_V_22) { | |
551 | + udelay(10000); | |
552 | + esdhc_setbits32(®s->sysctl, SYSCTL_PEREN | SYSCTL_CKEN); | |
553 | + return; | |
554 | + } | |
555 | + | |
547 | 556 | time_out = 20; |
548 | 557 | value = PRSSTAT_SDSTB; |
549 | 558 | while (!(esdhc_read32(®s->prsstat) & value)) { |
@@ -563,6 +572,7 @@ static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) | ||
563 | 572 | struct fsl_esdhc *regs = priv->esdhc_regs; |
564 | 573 | u32 value; |
565 | 574 | u32 time_out; |
575 | + u32 hostver; | |
566 | 576 | |
567 | 577 | value = esdhc_read32(®s->sysctl); |
568 | 578 |
@@ -573,6 +583,13 @@ static void esdhc_clock_control(struct fsl_esdhc_priv *priv, bool enable) | ||
573 | 583 | |
574 | 584 | esdhc_write32(®s->sysctl, value); |
575 | 585 | |
586 | + /* Only newer eSDHC controllers set PRSSTAT_SDSTB flag */ | |
587 | + hostver = esdhc_read32(&priv->esdhc_regs->hostver); | |
588 | + if (HOSTVER_VENDOR(hostver) <= VENDOR_V_22) { | |
589 | + udelay(10000); | |
590 | + return; | |
591 | + } | |
592 | + | |
576 | 593 | time_out = 20; |
577 | 594 | value = PRSSTAT_SDSTB; |
578 | 595 | while (!(esdhc_read32(®s->prsstat) & value)) { |
@@ -863,6 +863,33 @@ int mmc_boot_wp(struct mmc *mmc) | ||
863 | 863 | return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, 1); |
864 | 864 | } |
865 | 865 | |
866 | +int mmc_boot_wp_single_partition(struct mmc *mmc, int partition) | |
867 | +{ | |
868 | + u8 value; | |
869 | + int ret; | |
870 | + | |
871 | + value = EXT_CSD_BOOT_WP_B_PWR_WP_EN; | |
872 | + | |
873 | + if (partition == 0) { | |
874 | + value |= EXT_CSD_BOOT_WP_B_SEC_WP_SEL; | |
875 | + ret = mmc_switch(mmc, | |
876 | + EXT_CSD_CMD_SET_NORMAL, | |
877 | + EXT_CSD_BOOT_WP, | |
878 | + value); | |
879 | + } else if (partition == 1) { | |
880 | + value |= EXT_CSD_BOOT_WP_B_SEC_WP_SEL; | |
881 | + value |= EXT_CSD_BOOT_WP_B_PWR_WP_SEC_SEL; | |
882 | + ret = mmc_switch(mmc, | |
883 | + EXT_CSD_CMD_SET_NORMAL, | |
884 | + EXT_CSD_BOOT_WP, | |
885 | + value); | |
886 | + } else { | |
887 | + ret = mmc_boot_wp(mmc); | |
888 | + } | |
889 | + | |
890 | + return ret; | |
891 | +} | |
892 | + | |
866 | 893 | #if !CONFIG_IS_ENABLED(MMC_TINY) |
867 | 894 | static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode, |
868 | 895 | bool hsdowngrade) |
@@ -0,0 +1,86 @@ | ||
1 | +// SPDX-License-Identifier: GPL-2.0+ | |
2 | +/* | |
3 | + * Copyright (c) 2022 Nuvoton Technology Corp. | |
4 | + */ | |
5 | + | |
6 | +#include <common.h> | |
7 | +#include <dm.h> | |
8 | +#include <sdhci.h> | |
9 | +#include <clk.h> | |
10 | +#include <power/regulator.h> | |
11 | + | |
12 | +#define NPCM_SDHC_MIN_FREQ 400000 | |
13 | + | |
14 | +struct npcm_sdhci_plat { | |
15 | + struct mmc_config cfg; | |
16 | + struct mmc mmc; | |
17 | +}; | |
18 | + | |
19 | +static int npcm_sdhci_probe(struct udevice *dev) | |
20 | +{ | |
21 | + struct npcm_sdhci_plat *plat = dev_get_plat(dev); | |
22 | + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); | |
23 | + struct sdhci_host *host = dev_get_priv(dev); | |
24 | + struct udevice *vqmmc_supply; | |
25 | + int vqmmc_uv, ret; | |
26 | + struct clk clk; | |
27 | + | |
28 | + host->name = dev->name; | |
29 | + host->ioaddr = dev_read_addr_ptr(dev); | |
30 | + host->max_clk = dev_read_u32_default(dev, "clock-frequency", 0); | |
31 | + | |
32 | + ret = clk_get_by_index(dev, 0, &clk); | |
33 | + if (!ret && host->max_clk) { | |
34 | + ret = clk_set_rate(&clk, host->max_clk); | |
35 | + if (ret < 0) | |
36 | + return ret; | |
37 | + } | |
38 | + | |
39 | + if (IS_ENABLED(CONFIG_DM_REGULATOR)) { | |
40 | + device_get_supply_regulator(dev, "vqmmc-supply", &vqmmc_supply); | |
41 | + vqmmc_uv = dev_read_u32_default(dev, "vqmmc-microvolt", 0); | |
42 | + /* Set IO voltage */ | |
43 | + if (vqmmc_supply && vqmmc_uv) | |
44 | + regulator_set_value(vqmmc_supply, vqmmc_uv); | |
45 | + } | |
46 | + | |
47 | + host->index = dev_read_u32_default(dev, "index", 0); | |
48 | + ret = mmc_of_parse(dev, &plat->cfg); | |
49 | + if (ret) | |
50 | + return ret; | |
51 | + | |
52 | + host->mmc = &plat->mmc; | |
53 | + host->mmc->priv = host; | |
54 | + host->mmc->dev = dev; | |
55 | + upriv->mmc = host->mmc; | |
56 | + | |
57 | + ret = sdhci_setup_cfg(&plat->cfg, host, 0, NPCM_SDHC_MIN_FREQ); | |
58 | + if (ret) | |
59 | + return ret; | |
60 | + | |
61 | + return sdhci_probe(dev); | |
62 | +} | |
63 | + | |
64 | +static int npcm_sdhci_bind(struct udevice *dev) | |
65 | +{ | |
66 | + struct npcm_sdhci_plat *plat = dev_get_plat(dev); | |
67 | + | |
68 | + return sdhci_bind(dev, &plat->mmc, &plat->cfg); | |
69 | +} | |
70 | + | |
71 | +static const struct udevice_id npcm_mmc_ids[] = { | |
72 | + { .compatible = "nuvoton,npcm750-sdhci" }, | |
73 | + { .compatible = "nuvoton,npcm845-sdhci" }, | |
74 | + { } | |
75 | +}; | |
76 | + | |
77 | +U_BOOT_DRIVER(npcm_sdhci_drv) = { | |
78 | + .name = "npcm_sdhci", | |
79 | + .id = UCLASS_MMC, | |
80 | + .of_match = npcm_mmc_ids, | |
81 | + .ops = &sdhci_ops, | |
82 | + .bind = npcm_sdhci_bind, | |
83 | + .probe = npcm_sdhci_probe, | |
84 | + .priv_auto = sizeof(struct sdhci_host), | |
85 | + .plat_auto = sizeof(struct npcm_sdhci_plat), | |
86 | +}; |
@@ -86,6 +86,7 @@ static int pci_mmc_bind(struct udevice *dev) | ||
86 | 86 | return sdhci_bind(dev, &plat->mmc, &plat->cfg); |
87 | 87 | } |
88 | 88 | |
89 | +__maybe_unused | |
89 | 90 | static int pci_mmc_acpi_fill_ssdt(const struct udevice *dev, |
90 | 91 | struct acpi_ctx *ctx) |
91 | 92 | { |
@@ -138,7 +139,9 @@ static int pci_mmc_acpi_fill_ssdt(const struct udevice *dev, | ||
138 | 139 | } |
139 | 140 | |
140 | 141 | struct acpi_ops pci_mmc_acpi_ops = { |
142 | +#ifdef CONFIG_ACPIGEN | |
141 | 143 | .fill_ssdt = pci_mmc_acpi_fill_ssdt, |
144 | +#endif | |
142 | 145 | }; |
143 | 146 | |
144 | 147 | static const struct udevice_id pci_mmc_match[] = { |
@@ -308,6 +308,10 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx) | ||
308 | 308 | |
309 | 309 | #define EXT_CSD_HS_CTRL_REL (1 << 0) /* host controlled WR_REL_SET */ |
310 | 310 | |
311 | +#define EXT_CSD_BOOT_WP_B_SEC_WP_SEL (0x80) /* enable partition selector */ | |
312 | +#define EXT_CSD_BOOT_WP_B_PWR_WP_SEC_SEL (0x02) /* partition selector to protect */ | |
313 | +#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01) /* power-on write-protect */ | |
314 | + | |
311 | 315 | #define EXT_CSD_WR_DATA_REL_USR (1 << 0) /* user data area WR_REL */ |
312 | 316 | #define EXT_CSD_WR_DATA_REL_GP(x) (1 << ((x)+1)) /* GP part (x+1) WR_REL */ |
313 | 317 |
@@ -991,6 +995,18 @@ int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd); | ||
991 | 995 | */ |
992 | 996 | int mmc_boot_wp(struct mmc *mmc); |
993 | 997 | |
998 | +/** | |
999 | + * mmc_boot_wp_single_partition() - set write protection to a boot partition. | |
1000 | + * | |
1001 | + * This function sets a single boot partition to protect and leave the | |
1002 | + * other partition writable. | |
1003 | + * | |
1004 | + * @param mmc the mmc device. | |
1005 | + * @param partition 0 - first boot partition, 1 - second boot partition. | |
1006 | + * @return 0 for success | |
1007 | + */ | |
1008 | +int mmc_boot_wp_single_partition(struct mmc *mmc, int partition); | |
1009 | + | |
994 | 1010 | static inline enum dma_data_direction mmc_get_dma_dir(struct mmc_data *data) |
995 | 1011 | { |
996 | 1012 | return data->flags & MMC_DATA_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE; |