#include <errno.h>
#include <libfdt.h>
#include <fdt_support.h>
+#include <i2c.h>
#include <lcd.h>
#include <netdev.h>
#include <mmc.h>
print_reset_cause();
}
+enum LTC3589_REGS {
+ LTC3589_SCR1 = 0x07,
+ LTC3589_CLIRQ = 0x21,
+ LTC3589_B1DTV1 = 0x23,
+ LTC3589_B1DTV2 = 0x24,
+ LTC3589_VRRCR = 0x25,
+ LTC3589_B2DTV1 = 0x26,
+ LTC3589_B2DTV2 = 0x27,
+ LTC3589_B3DTV1 = 0x29,
+ LTC3589_B3DTV2 = 0x2a,
+ LTC3589_L2DTV1 = 0x32,
+ LTC3589_L2DTV2 = 0x33,
+};
+
+#define LTC3589_PGOOD_MASK (1 << 5)
+
+#define LTC3589_CLK_RATE_LOW (1 << 5)
+
+#define VDD_LDO2_VAL mV_to_regval(vout_to_vref(1325 * 10, 2))
+#define VDD_CORE_VAL mV_to_regval(vout_to_vref(1240 * 10, 3))
+#define VDD_SOC_VAL mV_to_regval(vout_to_vref(1325 * 10, 4))
+#define VDD_BUCK3_VAL mV_to_regval(vout_to_vref(2500 * 10, 5))
+
+#ifndef CONFIG_SYS_TX53_HWREV_2
+/* LDO2 vref divider */
+#define R1_2 180
+#define R2_2 191
+/* BUCK1 vref divider */
+#define R1_3 150
+#define R2_3 180
+/* BUCK2 vref divider */
+#define R1_4 180
+#define R2_4 191
+/* BUCK3 vref divider */
+#define R1_5 270
+#define R2_5 100
+#else
+/* no dividers on vref */
+#define R1_2 0
+#define R2_2 1
+#define R1_3 0
+#define R2_3 1
+#define R1_4 0
+#define R2_4 1
+#define R1_5 0
+#define R2_5 1
+#endif
+
+/* calculate voltages in 10mV */
+#define R1(idx) R1_##idx
+#define R2(idx) R2_##idx
+
+#define vout_to_vref(vout, idx) ((vout) * R2(idx) / (R1(idx) + R2(idx)))
+#define vref_to_vout(vref, idx) ((vref) * (R1(idx) + R2(idx)) / R2(idx))
+
+#define mV_to_regval(mV) (((((mV) < 3625) ? 3625 : (mV)) - 3625) / 125)
+#define regval_to_mV(v) (((v) * 125 + 3625))
+
+static struct pmic_regs {
+ enum LTC3589_REGS addr;
+ u8 val;
+} ltc3589_regs[] = {
+ { LTC3589_SCR1, 0x15, }, /* burst mode for all regulators */
+
+ { LTC3589_L2DTV1, VDD_LDO2_VAL | LTC3589_PGOOD_MASK, },
+ { LTC3589_L2DTV2, VDD_LDO2_VAL | LTC3589_CLK_RATE_LOW, },
+
+ { LTC3589_B1DTV1, VDD_CORE_VAL | LTC3589_PGOOD_MASK, },
+ { LTC3589_B1DTV2, VDD_CORE_VAL, },
+
+ { LTC3589_B2DTV1, VDD_SOC_VAL | LTC3589_PGOOD_MASK, },
+ { LTC3589_B2DTV2, VDD_SOC_VAL, },
+
+ { LTC3589_B3DTV1, VDD_BUCK3_VAL | LTC3589_PGOOD_MASK, },
+ { LTC3589_B3DTV2, VDD_BUCK3_VAL, },
+
+ { LTC3589_CLIRQ, 0, }, /* clear all interrupt flags */
+};
+
+static int setup_pmic_voltages(void)
+{
+ int ret;
+ unsigned char value;
+ int i;
+
+ ret = i2c_probe(CONFIG_SYS_I2C_SLAVE);
+ if (ret != 0) {
+ printf("Failed to initialize I2C\n");
+ return ret;
+ }
+
+ ret = i2c_read(CONFIG_SYS_I2C_SLAVE, 0x11, 1, &value, 1);
+ if (ret) {
+ printf("%s: i2c_read error: %d\n", __func__, ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ltc3589_regs); i++) {
+ ret = i2c_read(CONFIG_SYS_I2C_SLAVE, ltc3589_regs[i].addr, 1,
+ &value, 1);
+ debug("Writing %02x to reg %02x (%02x)\n",
+ ltc3589_regs[i].val, ltc3589_regs[i].addr, value);
+ ret = i2c_write(CONFIG_SYS_I2C_SLAVE, ltc3589_regs[i].addr, 1,
+ <c3589_regs[i].val, 1);
+ if (ret) {
+ printf("%s: failed to write PMIC register %02x: %d\n",
+ __func__, ltc3589_regs[i].addr, ret);
+ return ret;
+ }
+ }
+ printf("VDDCORE set to %umV\n",
+ DIV_ROUND(vref_to_vout(regval_to_mV(VDD_CORE_VAL), 3), 10));
+
+ printf("VDDSOC set to %umV\n",
+ DIV_ROUND(vref_to_vout(regval_to_mV(VDD_SOC_VAL), 4), 10));
+ return 0;
+}
+
int board_early_init_f(void)
{
struct mxc_ccm_reg *ccm_regs = (void *)CCM_BASE_ADDR;
int board_init(void)
{
+ int ret;
+
/* Address of boot parameters */
gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x1000;
+
+ if (ctrlc() || (wrsr & WRSR_TOUT)) {
+ printf("CTRL-C detected; Skipping PMIC setup\n");
+ return 1;
+ }
+
+ ret = setup_pmic_voltages();
+ if (ret) {
+ printf("Failed to setup PMIC voltages\n");
+ hang();
+ }
return 0;
}
int board_eth_init(bd_t *bis)
{
int ret;
- unsigned char mac[ETH_ALEN];
/* delay at least 21ms for the PHY internal POR signal to deassert */
udelay(22000);
gpio_set_value(TX53_FEC_RST_GPIO, 1);
ret = cpu_eth_init(bis);
- if (ret) {
+ if (ret)
printf("cpu_eth_init() failed: %d\n", ret);
- return ret;
- }
-
- imx_get_mac_from_fuse(0, mac);
- eth_setenv_enetaddr("ethaddr", mac);
- printf("MAC addr from fuse: %pM\n", mac);
-
return ret;
}
#endif /* CONFIG_FEC_MXC */
void lcd_ctrl_init(void *lcdbase)
{
int color_depth = 24;
- char *vm;
+ const char *video_mode = getenv("video_mode");
+ const char *vm;
unsigned long val;
int refresh = 60;
struct fb_videomode *p = &tx53_fb_modes[0];
return;
}
- if (tstc() || (wrsr & WRSR_TOUT)) {
+ if (had_ctrlc() || (wrsr & WRSR_TOUT)) {
debug("Disabling LCD\n");
lcd_enabled = 0;
setenv("splashimage", NULL);
karo_fdt_move_fdt();
- vm = getenv("video_mode");
+ vm = karo_fdt_set_display(video_mode, "/soc", "/soc/aips/ldb");
if (vm == NULL) {
debug("Disabling LCD\n");
lcd_enabled = 0;
return;
}
+ video_mode = vm;
if (karo_fdt_get_fb_mode(working_fdt, vm, &fb_mode) == 0) {
p = &fb_mode;
debug("Using video mode from FDT\n");
vm += strlen(vm);
- if (fb_mode.xres < panel_info.vl_col)
- panel_info.vl_col = fb_mode.xres;
- if (fb_mode.yres < panel_info.vl_row)
- panel_info.vl_row = fb_mode.yres;
+ if (fb_mode.xres > panel_info.vl_col ||
+ fb_mode.yres > panel_info.vl_row) {
+ printf("video resolution from DT: %dx%d exceeds hardware limits: %dx%d\n",
+ fb_mode.xres, fb_mode.yres,
+ panel_info.vl_col, panel_info.vl_row);
+ lcd_enabled = 0;
+ return;
+ }
}
if (p->name != NULL)
debug("Trying compiled-in video modes\n");
printf("\n");
return;
}
+ if (p->xres > panel_info.vl_col || p->yres > panel_info.vl_row) {
+ printf("video resolution: %dx%d exceeds hardware limits: %dx%d\n",
+ p->xres, p->yres, panel_info.vl_col, panel_info.vl_row);
+ lcd_enabled = 0;
+ return;
+ }
+ panel_info.vl_col = p->xres;
+ panel_info.vl_row = p->yres;
+
+ switch (color_depth) {
+ case 8:
+ panel_info.vl_bpix = LCD_COLOR8;
+ break;
+ case 16:
+ panel_info.vl_bpix = LCD_COLOR16;
+ break;
+ default:
+ panel_info.vl_bpix = LCD_COLOR24;
+ }
p->pixclock = KHZ2PICOS(refresh *
(p->xres + p->left_margin + p->right_margin + p->hsync_len) *
if (p != &fb_mode) {
int ret;
- char *modename = getenv("video_mode");
- printf("Creating new display-timing node from '%s'\n",
- modename);
- ret = karo_fdt_create_fb_mode(working_fdt, modename, p);
+ debug("Creating new display-timing node from '%s'\n",
+ video_mode);
+ ret = karo_fdt_create_fb_mode(working_fdt, video_mode, p);
if (ret)
printf("Failed to create new display-timing node from '%s': %d\n",
- modename, ret);
+ video_mode, ret);
}
gpio_request_array(stk5_lcd_gpios, ARRAY_SIZE(stk5_lcd_gpios));
unsigned long cpu_clk = getenv_ulong("cpu_clk", 10, 0);
int ret;
- if (tstc() || (wrsr & WRSR_TOUT))
+ if (had_ctrlc() || (wrsr & WRSR_TOUT))
return;
if (cpu_clk == 0 || cpu_clk == mxc_get_clock(MXC_ARM_CLK) / 1000000)
mxc_get_clock(MXC_ARM_CLK) / 1000 % 1000);
}
+static void tx53_init_mac(void)
+{
+ u8 mac[ETH_ALEN];
+
+ imx_get_mac_from_fuse(0, mac);
+ if (!is_valid_ether_addr(mac)) {
+ printf("No valid MAC address programmed\n");
+ return;
+ }
+
+ eth_setenv_enetaddr("ethaddr", mac);
+ printf("MAC addr from fuse: %pM\n", mac);
+}
+
int board_late_init(void)
{
int ret = 0;
}
exit:
+ tx53_init_mac();
gpio_set_value(TX53_RESET_OUT_GPIO, 1);
+ clear_ctrlc();
return ret;
}
#define fdt_fixup_mtdparts(b,n,c) do { } while (0)
#endif
-static void tx53_fixup_flexcan(void *blob)
-{
- const char *baseboard = getenv("baseboard");
-
- if (baseboard && strcmp(baseboard, "stk5-v5") == 0)
- return;
-
- karo_fdt_del_prop(blob, "fsl,p1010-flexcan", 0x53fc8000, "transceiver-switch");
- karo_fdt_del_prop(blob, "fsl,p1010-flexcan", 0x53fcc000, "transceiver-switch");
-}
-
#ifdef CONFIG_SYS_TX53_HWREV_2
void tx53_fixup_rtc(void *blob)
{
void ft_board_setup(void *blob, bd_t *bd)
{
+ const char *baseboard = getenv("baseboard");
+ int stk5_v5 = baseboard != NULL && (strcmp(baseboard, "stk5-v5") == 0);
+ const char *video_mode = getenv("video_mode");
+
fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
fdt_fixup_ethernet(blob);
karo_fdt_fixup_touchpanel(blob);
karo_fdt_fixup_usb_otg(blob, "fsl,imx-otg", "fsl,usbphy");
- tx53_fixup_flexcan(blob);
+ karo_fdt_fixup_flexcan(blob, stk5_v5);
tx53_fixup_rtc(blob);
- karo_fdt_update_fb_mode(blob, getenv("video_mode"));
+ video_mode = karo_fdt_set_display(video_mode, "/soc", "/soc/aips/ldb");
+ karo_fdt_update_fb_mode(blob, video_mode);
}
#endif /* CONFIG_OF_BOARD_SETUP */