+
+void boot_mode_apply(unsigned cfg_val)
+{
+ unsigned reg;
+ struct src *psrc = (struct src *)SRC_BASE_ADDR;
+ writel(cfg_val, &psrc->gpr9);
+ reg = readl(&psrc->gpr10);
+ if (cfg_val)
+ reg |= 1 << 28;
+ else
+ reg &= ~(1 << 28);
+ writel(reg, &psrc->gpr10);
+}
+/*
+ * cfg_val will be used for
+ * Boot_cfg4[7:0]:Boot_cfg3[7:0]:Boot_cfg2[7:0]:Boot_cfg1[7:0]
+ * After reset, if GPR10[28] is 1, ROM will copy GPR9[25:0]
+ * to SBMR1, which will determine the boot device.
+ */
+const struct boot_mode soc_boot_modes[] = {
+ {"normal", MAKE_CFGVAL(0x00, 0x00, 0x00, 0x00)},
+ /* reserved value should start rom usb */
+ {"usb", MAKE_CFGVAL(0x01, 0x00, 0x00, 0x00)},
+ {"sata", MAKE_CFGVAL(0x20, 0x00, 0x00, 0x00)},
+ {"escpi1:0", MAKE_CFGVAL(0x30, 0x00, 0x00, 0x08)},
+ {"escpi1:1", MAKE_CFGVAL(0x30, 0x00, 0x00, 0x18)},
+ {"escpi1:2", MAKE_CFGVAL(0x30, 0x00, 0x00, 0x28)},
+ {"escpi1:3", MAKE_CFGVAL(0x30, 0x00, 0x00, 0x38)},
+ /* 4 bit bus width */
+ {"esdhc1", MAKE_CFGVAL(0x40, 0x20, 0x00, 0x00)},
+ {"esdhc2", MAKE_CFGVAL(0x40, 0x28, 0x00, 0x00)},
+ {"esdhc3", MAKE_CFGVAL(0x40, 0x30, 0x00, 0x00)},
+ {"esdhc4", MAKE_CFGVAL(0x40, 0x38, 0x00, 0x00)},
+ {NULL, 0},
+};
+#define RESET_MAX_TIMEOUT 1000000
+#define MXS_BLOCK_SFTRST (1 << 31)
+#define MXS_BLOCK_CLKGATE (1 << 30)
+#include <div64.h>
+
+static const int scale = 1;
+
+int mxs_wait_mask_set(struct mx6_register_32 *mx6_reg, uint32_t mask, unsigned long timeout)
+{
+ unsigned long loops = 0;
+
+ timeout /= scale;
+ if (timeout == 0)
+ timeout++;
+
+ /* Wait for at least one microsecond for the bit mask to be set */
+ while ((readl(&mx6_reg->reg) & mask) != mask) {
+ if ((loops += scale) >= timeout) {
+ printf("MASK %08x in %p not set after %lu ticks\n",
+ mask, &mx6_reg->reg, loops * scale);
+ return 1;
+ }
+ udelay(scale);
+ }
+ if (loops == 0)
+ udelay(1);
+
+ return 0;
+}
+
+int mxs_wait_mask_clr(struct mx6_register_32 *mx6_reg, uint32_t mask, unsigned long timeout)
+{
+ unsigned long loops = 0;
+
+ timeout /= scale;
+ if (timeout == 0)
+ timeout++;
+
+ /* Wait for at least one microsecond for the bit mask to be cleared */
+ while ((readl(&mx6_reg->reg) & mask) != 0) {
+ if ((loops += scale) >= timeout) {
+ printf("MASK %08x in %p not cleared after %lu ticks\n",
+ mask, &mx6_reg->reg, loops * scale);
+ return 1;
+ }
+ udelay(scale);
+ }
+ if (loops == 0)
+ udelay(1);
+
+ return 0;
+}
+
+int mxs_reset_block(struct mx6_register_32 *mx6_reg)
+{
+ /* Clear SFTRST */
+ writel(MXS_BLOCK_SFTRST, &mx6_reg->reg_clr);
+
+ if (mxs_wait_mask_clr(mx6_reg, MXS_BLOCK_SFTRST, RESET_MAX_TIMEOUT)) {
+ printf("TIMEOUT waiting for SFTRST[%p] to clear: %08x\n",
+ &mx6_reg->reg, readl(&mx6_reg->reg));
+ return 1;
+ }
+
+ /* Clear CLKGATE */
+ writel(MXS_BLOCK_CLKGATE, &mx6_reg->reg_clr);
+
+ /* Set SFTRST */
+ writel(MXS_BLOCK_SFTRST, &mx6_reg->reg_set);
+
+ /* Wait for CLKGATE being set */
+ if (mxs_wait_mask_set(mx6_reg, MXS_BLOCK_CLKGATE, RESET_MAX_TIMEOUT)) {
+ printf("TIMEOUT waiting for CLKGATE[%p] to set: %08x\n",
+ &mx6_reg->reg, readl(&mx6_reg->reg));
+ return 0;
+ }
+
+ /* Clear SFTRST */
+ writel(MXS_BLOCK_SFTRST, &mx6_reg->reg_clr);
+
+ if (mxs_wait_mask_clr(mx6_reg, MXS_BLOCK_SFTRST, RESET_MAX_TIMEOUT)) {
+ printf("TIMEOUT waiting for SFTRST[%p] to clear: %08x\n",
+ &mx6_reg->reg, readl(&mx6_reg->reg));
+ return 1;
+ }
+
+ /* Clear CLKGATE */
+ writel(MXS_BLOCK_CLKGATE, &mx6_reg->reg_clr);
+
+ if (mxs_wait_mask_clr(mx6_reg, MXS_BLOCK_CLKGATE, RESET_MAX_TIMEOUT)) {
+ printf("TIMEOUT waiting for CLKGATE[%p] to clear: %08x\n",
+ &mx6_reg->reg, readl(&mx6_reg->reg));
+ return 1;
+ }
+
+ return 0;
+}