Commit cdab22ac02ba4a2f9d2df4518695a5322b97c569

Authored by Ye Li
Committed by guoyin.chen
1 parent 22338e28ca

MLK-12483-3 mx6: Add a module fuse checking

Implement a functionality to read the soc fuses and check if any module
is fused. For fused module, we have to disable it in u-boot dynamically,
and change the its node in FDT to "disabled" status before starting the kernel.

In this patch, we implement the ft_system_setup for FDT fixup. This function will
be called during boot process or by "fdt systemsetup" command.

To enable the module fuse checking, two configurations must be defined:
CONFIG_MODULE_FUSE
CONFIG_OF_SYSTEM_SETUP

Signed-off-by: Ye Li <ye.li@nxp.com>
(cherry picked from commit 2bce02298d755af0ef7b2aaecc56bcebc1fda61b)

Showing 4 changed files with 385 additions and 0 deletions Side-by-side Diff

arch/arm/cpu/armv7/mx6/Makefile
... ... @@ -14,4 +14,5 @@
14 14 ifdef CONFIG_MX6UL
15 15 obj-$(CONFIG_CMD_BEE) += bee.o
16 16 endif
  17 +obj-$(CONFIG_MODULE_FUSE) += module_fuse.o
arch/arm/cpu/armv7/mx6/module_fuse.c
  1 +/*
  2 + * (C) Copyright 2016 Freescale Semiconductor, Inc.
  3 + *
  4 + * SPDX-License-Identifier: GPL-2.0+
  5 + */
  6 +
  7 +#include <common.h>
  8 +#include <fdt_support.h>
  9 +#include <asm/io.h>
  10 +#include <asm/errno.h>
  11 +#include <asm/arch/sys_proto.h>
  12 +#include <asm/arch/imx-regs.h>
  13 +#include <asm/arch/module_fuse.h>
  14 +
  15 +struct fuse_entry_desc {
  16 + enum fuse_module_type module;
  17 + const char* node_path;
  18 + u32 fuse_word_offset;
  19 + u32 fuse_bit_offset;
  20 + u32 status;
  21 +};
  22 +
  23 +static struct fuse_entry_desc mx6_fuse_descs[] = {
  24 +#ifdef CONFIG_MX6UL
  25 + {MX6_MODULE_TSC, "/soc/aips-bus@02000000/tsc@02040000", 0x430, 22},
  26 + {MX6_MODULE_ADC2, "/soc/aips-bus@02100000/adc@0219c000", 0x430, 23},
  27 + {MX6_MODULE_SIM1, "/soc/aips-bus@02100000/sim@0218c000", 0x430, 24},
  28 + {MX6_MODULE_SIM2, "/soc/aips-bus@02100000/sim@021b4000", 0x430, 25},
  29 + {MX6_MODULE_FLEXCAN1, "/soc/aips-bus@02000000/can@02090000", 0x430, 26},
  30 + {MX6_MODULE_FLEXCAN2, "/soc/aips-bus@02000000/can@02094000", 0x430, 27},
  31 + {MX6_MODULE_SPDIF, "/soc/aips-bus@02000000/spba-bus@02000000/spdif@02004000", 0x440, 2},
  32 + {MX6_MODULE_EIM, "/soc/aips-bus@02100000/weim@021b8000", 0x440, 3},
  33 + {MX6_MODULE_SD1, "/soc/aips-bus@02100000/usdhc@02190000", 0x440, 4},
  34 + {MX6_MODULE_SD2, "/soc/aips-bus@02100000/usdhc@02194000", 0x440, 5},
  35 + {MX6_MODULE_QSPI1, "/soc/aips-bus@02100000/qspi@021e0000", 0x440, 6},
  36 + {MX6_MODULE_GPMI, "/soc/gpmi-nand@01806000", 0x440, 7},
  37 + {MX6_MODULE_APBHDMA, "/soc/dma-apbh@01804000", 0x440, 7},
  38 + {MX6_MODULE_LCDIF, "/soc/aips-bus@02100000/lcdif@021c8000", 0x440, 8},
  39 + {MX6_MODULE_PXP, "/soc/aips-bus@02100000/pxp@021cc000", 0x440, 9},
  40 + {MX6_MODULE_CSI, "/soc/aips-bus@02100000/csi@021c4000", 0x440, 10},
  41 + {MX6_MODULE_ADC1, "/soc/aips-bus@02100000/adc@02198000", 0x440, 11},
  42 + {MX6_MODULE_ENET1, "/soc/aips-bus@02100000/ethernet@02188000", 0x440, 12},
  43 + {MX6_MODULE_ENET2, "/soc/aips-bus@02000000/ethernet@020b4000", 0x440, 13},
  44 + {MX6_MODULE_CAAM, "/soc/aips-bus@02100000/caam@2140000", 0x440, 14},
  45 + {MX6_MODULE_USB_OTG2, "/soc/aips-bus@02100000/usb@02184200", 0x440, 15},
  46 + {MX6_MODULE_SAI2, "/soc/aips-bus@02000000/spba-bus@02000000/sai@0202c000", 0x440, 24},
  47 + {MX6_MODULE_SAI3, "/soc/aips-bus@02000000/spba-bus@02000000/sai@02030000", 0x440, 24},
  48 + {MX6_MODULE_BEE, "/soc/aips-bus@02000000/bee@02044000", 0x440, 25},
  49 + {MX6_MODULE_UART5, "/soc/aips-bus@02100000/serial@021f4000", 0x440, 26},
  50 + {MX6_MODULE_UART6, "/soc/aips-bus@02100000/serial@021fc000", 0x440, 26},
  51 + {MX6_MODULE_UART7, "/soc/aips-bus@02000000/spba-bus@02000000/serial@02018000", 0x440, 26},
  52 + {MX6_MODULE_UART8, "/soc/aips-bus@02000000/spba-bus@02000000/serial@02024000", 0x440, 26},
  53 + {MX6_MODULE_PWM5, "/soc/aips-bus@02000000/pwm@020f0000", 0x440, 27},
  54 + {MX6_MODULE_PWM6, "/soc/aips-bus@02000000/pwm@020f4000", 0x440, 27},
  55 + {MX6_MODULE_PWM7, "/soc/aips-bus@02000000/pwm@020f8000", 0x440, 27},
  56 + {MX6_MODULE_PWM8, "/soc/aips-bus@02000000/pwm@020fc000", 0x440, 27},
  57 + {MX6_MODULE_ECSPI3, "/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02010000", 0x440, 28},
  58 + {MX6_MODULE_ECSPI4, "/soc/aips-bus@02000000/spba-bus@02000000/ecspi@02014000", 0x440, 28},
  59 + {MX6_MODULE_I2C3, "/soc/aips-bus@02100000/i2c@021a8000", 0x440, 29},
  60 + {MX6_MODULE_I2C4, "/soc/aips-bus@02100000/i2c@021f8000", 0x440, 29},
  61 + {MX6_MODULE_GPT2, "/soc/aips-bus@02000000/gpt@020e8000", 0x440, 30},
  62 + {MX6_MODULE_EPIT2, "/soc/aips-bus@02000000/epit@020d4000", 0x440, 31},
  63 +#endif
  64 +};
  65 +
  66 +u32 check_module_fused(enum fuse_module_type module)
  67 +{
  68 + u32 i, reg;
  69 + for (i = 0; i < ARRAY_SIZE(mx6_fuse_descs); i++) {
  70 + if (mx6_fuse_descs[i].module == module) {
  71 + reg = readl(OCOTP_BASE_ADDR + mx6_fuse_descs[i].fuse_word_offset);
  72 + if (reg & (1 << mx6_fuse_descs[i].fuse_bit_offset))
  73 + return 1; /* disabled */
  74 + else
  75 + return 0; /* enabled */
  76 + }
  77 + }
  78 +
  79 + return 0; /* Not has a fuse, always enabled */
  80 +}
  81 +
  82 +#ifdef DEBUG
  83 +void print_fuse_status()
  84 +{
  85 + u32 i, reg;
  86 +
  87 + for (i = 0; i < ARRAY_SIZE(mx6_fuse_descs); i++) {
  88 + reg = readl(OCOTP_BASE_ADDR + mx6_fuse_descs[i].fuse_word_offset);
  89 + if (reg & (1 << mx6_fuse_descs[i].fuse_bit_offset)) {
  90 + printf("%s, disabled\n", mx6_fuse_descs[i].node_path);
  91 + }
  92 + }
  93 +}
  94 +
  95 +void simulate_fuse()
  96 +{
  97 + u32 i, reg;
  98 +
  99 + for (i = 0; i < ARRAY_SIZE(mx6_fuse_descs); i++) {
  100 + if (MX6_MODULE_SD2 == mx6_fuse_descs[i].module)
  101 + continue;
  102 +
  103 + reg = readl(OCOTP_BASE_ADDR + mx6_fuse_descs[i].fuse_word_offset);
  104 + reg |= (1 << mx6_fuse_descs[i].fuse_bit_offset);
  105 + writel(reg, OCOTP_BASE_ADDR + mx6_fuse_descs[i].fuse_word_offset);
  106 + }
  107 +}
  108 +#endif
  109 +
  110 +#ifdef CONFIG_OF_SYSTEM_SETUP
  111 +int ft_system_setup(void *blob, bd_t *bd)
  112 +{
  113 + u32 i, reg;
  114 + const char *status = "disabled";
  115 + int rc;
  116 +
  117 + for (i = 0; i < ARRAY_SIZE(mx6_fuse_descs); i++) {
  118 + reg = readl(OCOTP_BASE_ADDR + mx6_fuse_descs[i].fuse_word_offset);
  119 + if (reg & (1 << mx6_fuse_descs[i].fuse_bit_offset)) {
  120 +
  121 + int nodeoff = fdt_path_offset(blob, mx6_fuse_descs[i].node_path);
  122 + if (nodeoff < 0)
  123 + continue; /* Not found, skip it */
  124 +add_status:
  125 + rc = fdt_setprop(blob, nodeoff, "status", status, strlen(status) + 1);
  126 + if (rc) {
  127 + if (rc == -FDT_ERR_NOSPACE) {
  128 + rc = fdt_increase_size(blob, 512);
  129 + if (!rc)
  130 + goto add_status;
  131 + }
  132 + printf("Unable to update property %s:%s, err=%s\n",
  133 + mx6_fuse_descs[i].node_path, "status", fdt_strerror(rc));
  134 + } else {
  135 + printf("Modify %s:%s disabled\n",
  136 + mx6_fuse_descs[i].node_path, "status");
  137 + }
  138 + }
  139 + }
  140 +
  141 + printf("ft_system_setup for mx6\n");
  142 +
  143 + return 0;
  144 +}
  145 +#endif
  146 +
  147 +u32 mx6_esdhc_fused(u32 base_addr)
  148 +{
  149 + switch (base_addr) {
  150 + case USDHC1_BASE_ADDR:
  151 + return check_module_fused(MX6_MODULE_SD1);
  152 + case USDHC2_BASE_ADDR:
  153 + return check_module_fused(MX6_MODULE_SD2);
  154 +#ifdef USDHC3_BASE_ADDR
  155 + case USDHC3_BASE_ADDR:
  156 + return check_module_fused(MX6_MODULE_SD3);
  157 +#endif
  158 +#ifdef USDHC4_BASE_ADDR
  159 + case USDHC4_BASE_ADDR:
  160 + return check_module_fused(MX6_MODULE_SD4);
  161 +#endif
  162 + default:
  163 + return 0;
  164 + }
  165 +}
  166 +
  167 +u32 mx6_ecspi_fused(u32 base_addr)
  168 +{
  169 + switch (base_addr) {
  170 + case ECSPI1_BASE_ADDR:
  171 + return check_module_fused(MX6_MODULE_ECSPI1);
  172 + case ECSPI2_BASE_ADDR:
  173 + return check_module_fused(MX6_MODULE_ECSPI2);
  174 + case ECSPI3_BASE_ADDR:
  175 + return check_module_fused(MX6_MODULE_ECSPI3);
  176 + case ECSPI4_BASE_ADDR:
  177 + return check_module_fused(MX6_MODULE_ECSPI4);
  178 +#ifdef ECSPI5_BASE_ADDR
  179 + case ECSPI5_BASE_ADDR:
  180 + return check_module_fused(MX6_MODULE_ECSPI5);
  181 +#endif
  182 + default:
  183 + return 0;
  184 + }
  185 +}
  186 +
  187 +u32 mx6_uart_fused(u32 base_addr)
  188 +{
  189 + switch (base_addr) {
  190 + case UART1_BASE:
  191 + return check_module_fused(MX6_MODULE_UART1);
  192 + case UART2_BASE:
  193 + return check_module_fused(MX6_MODULE_UART2);
  194 + case UART3_BASE:
  195 + return check_module_fused(MX6_MODULE_UART3);
  196 + case UART4_BASE:
  197 + return check_module_fused(MX6_MODULE_UART4);
  198 + case UART5_BASE:
  199 + return check_module_fused(MX6_MODULE_UART5);
  200 +#ifdef UART6_BASE_ADDR
  201 + case UART6_BASE_ADDR:
  202 + return check_module_fused(MX6_MODULE_UART6);
  203 +#endif
  204 +#ifdef UART7_IPS_BASE_ADDR
  205 + case UART7_IPS_BASE_ADDR:
  206 + return check_module_fused(MX6_MODULE_UART7);
  207 +#endif
  208 +#ifdef UART8_IPS_BASE_ADDR
  209 + case UART8_IPS_BASE_ADDR:
  210 + return check_module_fused(MX6_MODULE_UART8);
  211 +#endif
  212 + }
  213 +
  214 + return 0;
  215 +}
  216 +
  217 +u32 mx6_usb_fused(u32 base_addr)
  218 +{
  219 + int i = (base_addr - USB_BASE_ADDR) / 0x200;
  220 + return check_module_fused(MX6_MODULE_USB_OTG1 + i);
  221 +}
  222 +
  223 +u32 mx6_qspi_fused(u32 base_addr)
  224 +{
  225 + switch (base_addr) {
  226 +#ifdef QSPI1_BASE_ADDR
  227 + case QSPI1_BASE_ADDR:
  228 + return check_module_fused(MX6_MODULE_QSPI1);
  229 +#endif
  230 +
  231 +#ifdef QSPI2_BASE_ADDR
  232 + case QSPI2_BASE_ADDR:
  233 + return check_module_fused(MX6_MODULE_QSPI2);
  234 +#endif
  235 + default:
  236 + return 0;
  237 + }
  238 +}
  239 +
  240 +u32 mx6_i2c_fused(u32 base_addr)
  241 +{
  242 + switch (base_addr) {
  243 + case I2C1_BASE_ADDR:
  244 + return check_module_fused(MX6_MODULE_I2C1);
  245 + case I2C2_BASE_ADDR:
  246 + return check_module_fused(MX6_MODULE_I2C2);
  247 + case I2C3_BASE_ADDR:
  248 + return check_module_fused(MX6_MODULE_I2C3);
  249 +#ifdef I2C4_BASE_ADDR
  250 + case I2C4_BASE_ADDR:
  251 + return check_module_fused(MX6_MODULE_I2C4);
  252 +#endif
  253 + }
  254 +
  255 + return 0;
  256 +}
  257 +
  258 +u32 mx6_enet_fused(u32 base_addr)
  259 +{
  260 + switch (base_addr) {
  261 + case ENET_BASE_ADDR:
  262 + return check_module_fused(MX6_MODULE_ENET1);
  263 +#ifdef ENET2_BASE_ADDR
  264 + case ENET2_BASE_ADDR:
  265 + return check_module_fused(MX6_MODULE_ENET2);
  266 +#endif
  267 + default:
  268 + return 0;
  269 + }
  270 +}
arch/arm/include/asm/arch-mx6/module_fuse.h
  1 +/*
  2 + * Copyright (C) 2011 Freescale Semiconductor, Inc.
  3 + */
  4 +
  5 +/*
  6 + * SPDX-License-Identifier: GPL-2.0+
  7 + */
  8 +
  9 +#ifndef __MODULE_FUSE_H__
  10 +#define __MODULE_FUSE_H__
  11 +
  12 +enum fuse_module_type{
  13 + MX6_MODULE_TSC,
  14 + MX6_MODULE_ADC1,
  15 + MX6_MODULE_ADC2,
  16 + MX6_MODULE_SIM1,
  17 + MX6_MODULE_SIM2,
  18 + MX6_MODULE_FLEXCAN1,
  19 + MX6_MODULE_FLEXCAN2,
  20 + MX6_MODULE_SPDIF,
  21 + MX6_MODULE_EIM,
  22 + MX6_MODULE_SD1,
  23 + MX6_MODULE_SD2,
  24 + MX6_MODULE_SD3,
  25 + MX6_MODULE_SD4,
  26 + MX6_MODULE_QSPI1,
  27 + MX6_MODULE_QSPI2,
  28 + MX6_MODULE_GPMI,
  29 + MX6_MODULE_APBHDMA,
  30 + MX6_MODULE_LCDIF,
  31 + MX6_MODULE_PXP,
  32 + MX6_MODULE_CSI,
  33 + MX6_MODULE_ENET1,
  34 + MX6_MODULE_ENET2,
  35 + MX6_MODULE_CAAM,
  36 + MX6_MODULE_USB_OTG1,
  37 + MX6_MODULE_USB_OTG2,
  38 + MX6_MODULE_SAI2,
  39 + MX6_MODULE_SAI3,
  40 + MX6_MODULE_BEE,
  41 + MX6_MODULE_UART1,
  42 + MX6_MODULE_UART2,
  43 + MX6_MODULE_UART3,
  44 + MX6_MODULE_UART4,
  45 + MX6_MODULE_UART5,
  46 + MX6_MODULE_UART6,
  47 + MX6_MODULE_UART7,
  48 + MX6_MODULE_UART8,
  49 + MX6_MODULE_PWM5,
  50 + MX6_MODULE_PWM6,
  51 + MX6_MODULE_PWM7,
  52 + MX6_MODULE_PWM8,
  53 + MX6_MODULE_ECSPI1,
  54 + MX6_MODULE_ECSPI2,
  55 + MX6_MODULE_ECSPI3,
  56 + MX6_MODULE_ECSPI4,
  57 + MX6_MODULE_ECSPI5,
  58 + MX6_MODULE_I2C1,
  59 + MX6_MODULE_I2C2,
  60 + MX6_MODULE_I2C3,
  61 + MX6_MODULE_I2C4,
  62 + MX6_MODULE_GPT1,
  63 + MX6_MODULE_GPT2,
  64 + MX6_MODULE_EPIT1,
  65 + MX6_MODULE_EPIT2,
  66 +};
  67 +
  68 +#if !defined(CONFIG_MODULE_FUSE)
  69 +static inline u32 check_module_fused(enum fuse_module_type module) {
  70 + return 0;
  71 +};
  72 +
  73 +static inline u32 mx6_esdhc_fused(u32 base_addr) {
  74 + return 0;
  75 +};
  76 +
  77 +static inline u32 mx6_ecspi_fused(u32 base_addr){
  78 + return 0;
  79 +};
  80 +static inline u32 mx6_uart_fused(u32 base_addr){
  81 + return 0;
  82 +};
  83 +static inline u32 mx6_usb_fused(u32 base_addr){
  84 + return 0;
  85 +};
  86 +static inline u32 mx6_qspi_fused(u32 base_addr){
  87 + return 0;
  88 +};
  89 +static inline u32 mx6_i2c_fused(u32 base_addr){
  90 + return 0;
  91 +};
  92 +static inline u32 mx6_enet_fused(u32 base_addr){
  93 + return 0;
  94 +};
  95 +
  96 +#else
  97 +u32 check_module_fused(enum fuse_module_type module);
  98 +u32 mx6_esdhc_fused(u32 base_addr);
  99 +u32 mx6_ecspi_fused(u32 base_addr);
  100 +u32 mx6_uart_fused(u32 base_addr);
  101 +u32 mx6_usb_fused(u32 base_addr);
  102 +u32 mx6_qspi_fused(u32 base_addr);
  103 +u32 mx6_i2c_fused(u32 base_addr);
  104 +u32 mx6_enet_fused(u32 base_addr);
  105 +#endif
  106 +
  107 +#ifdef DEBUG
  108 +void print_fuse_status();
  109 +void simulate_fuse();
  110 +#endif
  111 +
  112 +#endif /* __MODULE_FUSE_H__ */
arch/arm/include/asm/arch-mx6/sys_proto.h
... ... @@ -12,6 +12,7 @@
12 12  
13 13 #include <asm/imx-common/regs-common.h>
14 14 #include "../arch-imx/cpu.h"
  15 +#include <asm/arch/module_fuse.h>
15 16  
16 17 #define soc_rev() (get_cpu_rev() & 0xFF)
17 18 #define is_soc_rev(rev) (int)(soc_rev() - rev)