]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - board/lwmon5/lwmon5.c
Merge branch 'u-boot-imx/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / board / lwmon5 / lwmon5.c
index 415e036c006456e51a42321eb8a95ebdd4fbd12f..9cf0fa167c81348114970db341a59acd5b12fdec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * (C) Copyright 2007
+ * (C) Copyright 2007-2013
  * Stefan Roese, DENX Software Engineering, sr@denx.de.
  *
  * This program is free software; you can redistribute it and/or
 
 #include <common.h>
 #include <command.h>
-#include <ppc440.h>
+#include <asm/ppc440.h>
 #include <asm/processor.h>
-#include <asm/gpio.h>
+#include <asm/ppc4xx-gpio.h>
 #include <asm/io.h>
+#include <post.h>
+#include <flash.h>
+#include <mtd/cfi_flash.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-extern flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; /* info for FLASH chips    */
+static phys_addr_t lwmon5_cfi_flash_bank_addr[2] = CONFIG_SYS_FLASH_BANKS_LIST;
 
 ulong flash_get_size(ulong base, int banknum);
 int misc_init_r_kbd(void);
@@ -38,8 +41,8 @@ int board_early_init_f(void)
        u32 reg;
 
        /* PLB Write pipelining disabled. Denali Core workaround */
-       mtdcr(PLB0_ACR, 0xDE000000);
-       mtdcr(PLB1_ACR, 0xDE000000);
+       mtdcr(PLB4A0_ACR, 0xDE000000);
+       mtdcr(PLB4A1_ACR, 0xDE000000);
 
        /*--------------------------------------------------------------------
         * Setup the interrupt controller polarities, triggers, etc.
@@ -97,16 +100,18 @@ int board_early_init_f(void)
        gpio_write_bit(CONFIG_SYS_GPIO_FLASH_WP, 1);
 
 #if CONFIG_POST & CONFIG_SYS_POST_BSPEC1
-       gpio_write_bit(CONFIG_SYS_GPIO_HIGHSIDE, 1);
+       /* enable the LSB transmitter */
+       gpio_write_bit(CONFIG_SYS_GPIO_LSB_ENABLE, 1);
+       /* enable the CAN transmitter */
+       gpio_write_bit(CONFIG_SYS_GPIO_CAN_ENABLE, 1);
 
        reg = 0; /* reuse as counter */
        out_be32((void *)CONFIG_SYS_DSPIC_TEST_ADDR,
                in_be32((void *)CONFIG_SYS_DSPIC_TEST_ADDR)
                        & ~CONFIG_SYS_DSPIC_TEST_MASK);
-       while (!gpio_read_in_bit(CONFIG_SYS_GPIO_DSPIC_READY) && reg++ < 1000) {
+       while (gpio_read_in_bit(CONFIG_SYS_GPIO_DSPIC_READY) && reg++ < 1000) {
                udelay(1000);
        }
-       gpio_write_bit(CONFIG_SYS_GPIO_HIGHSIDE, 0);
        if (gpio_read_in_bit(CONFIG_SYS_GPIO_DSPIC_READY)) {
                /* set "boot error" flag */
                out_be32((void *)CONFIG_SYS_DSPIC_TEST_ADDR,
@@ -135,17 +140,71 @@ int board_early_init_f(void)
        return 0;
 }
 
-/*---------------------------------------------------------------------------+
-  | misc_init_r.
-  +---------------------------------------------------------------------------*/
+/*
+ * Override weak default with board specific version
+ */
+phys_addr_t cfi_flash_bank_addr(int bank)
+{
+       return lwmon5_cfi_flash_bank_addr[bank];
+}
+
+/*
+ * Override the weak default mapping function with a board specific one
+ */
+u32 flash_get_bank_size(int cs, int idx)
+{
+       return flash_info[idx].size;
+}
+
+int board_early_init_r(void)
+{
+       u32 val0, val1;
+
+       /*
+        * lwmon5 is manufactured in 2 different board versions:
+        * The lwmon5a board has 64MiB NOR flash instead of the
+        * 128MiB of the original lwmon5. Unfortunately the CFI driver
+        * will report 2 banks of 64MiB even for the smaller flash
+        * chip, since the bank is mirrored. To fix this, we bring
+        * one bank into CFI query mode and read its response. This
+        * enables us to detect the real number of flash devices/
+        * banks which will be used later on by the common CFI driver.
+        */
+
+       /* Put bank 0 into CFI command mode and read */
+       out_be32((void *)CONFIG_SYS_FLASH0, 0x00980098);
+       val0 = in_be32((void *)CONFIG_SYS_FLASH0 + FLASH_OFFSET_CFI_RESP);
+       val1 = in_be32((void *)CONFIG_SYS_FLASH1 + FLASH_OFFSET_CFI_RESP);
+
+       /* Reset flash again out of query mode */
+       out_be32((void *)CONFIG_SYS_FLASH0, 0x00f000f0);
+
+       /* When not identical, we have 2 different flash devices/banks */
+       if (val0 != val1)
+               return 0;
+
+       /*
+        * Now we're sure that we're running on a LWMON5a board with
+        * only 64MiB NOR flash in one bank:
+        *
+        * Set flash base address and bank count for CFI driver probing.
+        */
+       cfi_flash_num_flash_banks = 1;
+       lwmon5_cfi_flash_bank_addr[0] = CONFIG_SYS_FLASH0;
+
+       return 0;
+}
+
 int misc_init_r(void)
 {
        u32 pbcr;
        int size_val = 0;
        u32 reg;
+#ifndef CONFIG_LCD4_LWMON5
        unsigned long usb2d0cr = 0;
        unsigned long usb2phy0cr, usb2h0cr = 0;
-       unsigned long sdr0_pfc1;
+       unsigned long sdr0_pfc1, sdr0_srst;
+#endif
 
        /*
         * FLASH stuff...
@@ -158,32 +217,7 @@ int misc_init_r(void)
        gd->bd->bi_flashoffset = 0;
 
        mfebc(PB0CR, pbcr);
-       switch (gd->bd->bi_flashsize) {
-       case 1 << 20:
-               size_val = 0;
-               break;
-       case 2 << 20:
-               size_val = 1;
-               break;
-       case 4 << 20:
-               size_val = 2;
-               break;
-       case 8 << 20:
-               size_val = 3;
-               break;
-       case 16 << 20:
-               size_val = 4;
-               break;
-       case 32 << 20:
-               size_val = 5;
-               break;
-       case 64 << 20:
-               size_val = 6;
-               break;
-       case 128 << 20:
-               size_val = 7;
-               break;
-       }
+       size_val = ffs(gd->bd->bi_flashsize) - 21;
        pbcr = (pbcr & 0x0001ffff) | gd->bd->bi_flashstart | (size_val << 17);
        mtebc(PB0CR, pbcr);
 
@@ -193,82 +227,128 @@ int misc_init_r(void)
        flash_get_size(gd->bd->bi_flashstart, 0);
 
        /* Monitor protection ON by default */
-       (void)flash_protect(FLAG_PROTECT_SET,
-                           -CONFIG_SYS_MONITOR_LEN,
-                           0xffffffff,
-                           &flash_info[1]);
+       flash_protect(FLAG_PROTECT_SET, -CONFIG_SYS_MONITOR_LEN, 0xffffffff,
+                     &flash_info[cfi_flash_num_flash_banks - 1]);
 
        /* Env protection ON by default */
-       (void)flash_protect(FLAG_PROTECT_SET,
-                           CONFIG_ENV_ADDR_REDUND,
-                           CONFIG_ENV_ADDR_REDUND + 2*CONFIG_ENV_SECT_SIZE - 1,
-                           &flash_info[1]);
+       flash_protect(FLAG_PROTECT_SET, CONFIG_ENV_ADDR_REDUND,
+                     CONFIG_ENV_ADDR_REDUND + 2 * CONFIG_ENV_SECT_SIZE - 1,
+                     &flash_info[cfi_flash_num_flash_banks - 1]);
 
+#ifndef CONFIG_LCD4_LWMON5
        /*
         * USB suff...
         */
+
+       /* Reset USB */
+       /* Reset of USB2PHY0 must be active at least 10 us  */
+       mtsdr(SDR0_SRST0, SDR0_SRST0_USB2H | SDR0_SRST0_USB2D);
+       udelay(2000);
+
+       mtsdr(SDR0_SRST1, SDR0_SRST1_USB20PHY | SDR0_SRST1_USB2HUTMI |
+             SDR0_SRST1_USB2HPHY | SDR0_SRST1_OPBA2 |
+             SDR0_SRST1_PLB42OPB1 | SDR0_SRST1_OPB2PLB40);
+       udelay(2000);
+
+       /* Errata CHIP_6 */
+
+       /* 1. Set internal PHY configuration */
        /* SDR Setting */
        mfsdr(SDR0_PFC1, sdr0_pfc1);
        mfsdr(SDR0_USB0, usb2d0cr);
        mfsdr(SDR0_USB2PHY0CR, usb2phy0cr);
        mfsdr(SDR0_USB2H0CR, usb2h0cr);
 
-       usb2phy0cr = usb2phy0cr &~SDR0_USB2PHY0CR_XOCLK_MASK;
-       usb2phy0cr = usb2phy0cr | SDR0_USB2PHY0CR_XOCLK_EXTERNAL;       /*0*/
-       usb2phy0cr = usb2phy0cr &~SDR0_USB2PHY0CR_WDINT_MASK;
-       usb2phy0cr = usb2phy0cr | SDR0_USB2PHY0CR_WDINT_16BIT_30MHZ;    /*1*/
-       usb2phy0cr = usb2phy0cr &~SDR0_USB2PHY0CR_DVBUS_MASK;
-       usb2phy0cr = usb2phy0cr | SDR0_USB2PHY0CR_DVBUS_PURDIS;         /*0*/
-       usb2phy0cr = usb2phy0cr &~SDR0_USB2PHY0CR_DWNSTR_MASK;
-       usb2phy0cr = usb2phy0cr | SDR0_USB2PHY0CR_DWNSTR_HOST;          /*1*/
-       usb2phy0cr = usb2phy0cr &~SDR0_USB2PHY0CR_UTMICN_MASK;
-       usb2phy0cr = usb2phy0cr | SDR0_USB2PHY0CR_UTMICN_HOST;          /*1*/
-
-       /* An 8-bit/60MHz interface is the only possible alternative
-          when connecting the Device to the PHY */
-       usb2h0cr   = usb2h0cr &~SDR0_USB2H0CR_WDINT_MASK;
-       usb2h0cr   = usb2h0cr | SDR0_USB2H0CR_WDINT_16BIT_30MHZ;        /*1*/
+       usb2phy0cr = usb2phy0cr & ~SDR0_USB2PHY0CR_XOCLK_MASK;
+       usb2phy0cr = usb2phy0cr |  SDR0_USB2PHY0CR_XOCLK_EXTERNAL;      /*0*/
+       usb2phy0cr = usb2phy0cr & ~SDR0_USB2PHY0CR_WDINT_MASK;
+       usb2phy0cr = usb2phy0cr |  SDR0_USB2PHY0CR_WDINT_16BIT_30MHZ;   /*1*/
+       usb2phy0cr = usb2phy0cr & ~SDR0_USB2PHY0CR_DVBUS_MASK;
+       usb2phy0cr = usb2phy0cr |  SDR0_USB2PHY0CR_DVBUS_PUREN;         /*1*/
+       usb2phy0cr = usb2phy0cr & ~SDR0_USB2PHY0CR_DWNSTR_MASK;
+       usb2phy0cr = usb2phy0cr |  SDR0_USB2PHY0CR_DWNSTR_HOST;         /*1*/
+       usb2phy0cr = usb2phy0cr & ~SDR0_USB2PHY0CR_UTMICN_MASK;
+       usb2phy0cr = usb2phy0cr |  SDR0_USB2PHY0CR_UTMICN_HOST;         /*1*/
+
+       /*
+        * An 8-bit/60MHz interface is the only possible alternative
+        * when connecting the Device to the PHY
+        */
+       usb2h0cr   = usb2h0cr & ~SDR0_USB2H0CR_WDINT_MASK;
+       usb2h0cr   = usb2h0cr |  SDR0_USB2H0CR_WDINT_16BIT_30MHZ;       /*1*/
 
        mtsdr(SDR0_PFC1, sdr0_pfc1);
        mtsdr(SDR0_USB0, usb2d0cr);
        mtsdr(SDR0_USB2PHY0CR, usb2phy0cr);
        mtsdr(SDR0_USB2H0CR, usb2h0cr);
 
+       /* 2. De-assert internal PHY reset */
+       mfsdr(SDR0_SRST1, sdr0_srst);
+       sdr0_srst = sdr0_srst & ~SDR0_SRST1_USB20PHY;
+       mtsdr(SDR0_SRST1, sdr0_srst);
+
+       /* 3. Wait for more than 1 ms */
+       udelay(2000);
+
+       /* 4. De-assert USB 2.0 Host main reset */
+       mfsdr(SDR0_SRST0, sdr0_srst);
+       sdr0_srst = sdr0_srst &~ SDR0_SRST0_USB2H;
+       mtsdr(SDR0_SRST0, sdr0_srst);
+       udelay(1000);
+
+       /* 5. De-assert reset of OPB2 cores */
+       mfsdr(SDR0_SRST1, sdr0_srst);
+       sdr0_srst = sdr0_srst &~ SDR0_SRST1_PLB42OPB1;
+       sdr0_srst = sdr0_srst &~ SDR0_SRST1_OPB2PLB40;
+       sdr0_srst = sdr0_srst &~ SDR0_SRST1_OPBA2;
+       mtsdr(SDR0_SRST1, sdr0_srst);
+       udelay(1000);
+
+       /* 6. Set EHCI Configure FLAG */
+
+       /* 7. Reassert internal PHY reset: */
+       mtsdr(SDR0_SRST1, SDR0_SRST1_USB20PHY);
+       udelay(1000);
+#endif
+
        /*
         * Clear resets
         */
-       udelay (1000);
        mtsdr(SDR0_SRST1, 0x00000000);
-       udelay (1000);
        mtsdr(SDR0_SRST0, 0x00000000);
 
+#ifndef CONFIG_LCD4_LWMON5
        printf("USB:   Host(int phy) Device(ext phy)\n");
+#endif
 
        /*
         * Clear PLB4A0_ACR[WRP]
         * This fix will make the MAL burst disabling patch for the Linux
         * EMAC driver obsolete.
         */
-       reg = mfdcr(PLB4_ACR) & ~PLB4_ACR_WRP;
-       mtdcr(PLB4_ACR, reg);
+       reg = mfdcr(PLB4A0_ACR) & ~PLB4Ax_ACR_WRP_MASK;
+       mtdcr(PLB4A0_ACR, reg);
 
+#ifndef CONFIG_LCD4_LWMON5
        /*
         * Init matrix keyboard
         */
        misc_init_r_kbd();
+#endif
 
        return 0;
 }
 
 int checkboard(void)
 {
-       char *s = getenv("serial#");
+       char buf[64];
+       int i = getenv_f("serial#", buf, sizeof(buf));
 
-       printf("Board: lwmon5");
+       printf("Board: %s", __stringify(CONFIG_HOSTNAME));
 
-       if (s != NULL) {
+       if (i > 0) {
                puts(", serial# ");
-               puts(s);
+               puts(buf);
        }
        putc('\n');
 
@@ -285,16 +365,16 @@ void hw_watchdog_reset(void)
         * Don't allow watch-dog triggering more frequently than
         * the predefined value CONFIG_WD_MAX_RATE [ticks].
         */
-       if (ct >= gd->wdt_last) {
-               if ((ct - gd->wdt_last) < CONFIG_WD_MAX_RATE)
+       if (ct >= gd->arch.wdt_last) {
+               if ((ct - gd->arch.wdt_last) < CONFIG_WD_MAX_RATE)
                        return;
        } else {
                /* Time base counter had been reset */
-               if (((unsigned long long)(-1) - gd->wdt_last + ct) <
+               if (((unsigned long long)(-1) - gd->arch.wdt_last + ct) <
                    CONFIG_WD_MAX_RATE)
                        return;
        }
-       gd->wdt_last = get_ticks();
+       gd->arch.wdt_last = get_ticks();
 #endif
 
        /*
@@ -304,22 +384,17 @@ void hw_watchdog_reset(void)
        gpio_write_bit(CONFIG_SYS_GPIO_WATCHDOG, val);
 }
 
-int do_eeprom_wp(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+int do_eeprom_wp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-       if (argc < 2) {
-               cmd_usage(cmdtp);
-               return 1;
-       }
+       if (argc < 2)
+               return cmd_usage(cmdtp);
 
-       if ((strcmp(argv[1], "on") == 0)) {
+       if ((strcmp(argv[1], "on") == 0))
                gpio_write_bit(CONFIG_SYS_GPIO_EEPROM_EXT_WP, 1);
-       } else if ((strcmp(argv[1], "off") == 0)) {
+       else if ((strcmp(argv[1], "off") == 0))
                gpio_write_bit(CONFIG_SYS_GPIO_EEPROM_EXT_WP, 0);
-       } else {
-               cmd_usage(cmdtp);
-               return 1;
-       }
-
+       else
+               return cmd_usage(cmdtp);
 
        return 0;
 }
@@ -336,34 +411,33 @@ U_BOOT_CMD(
 
 extern GraphicDevice mb862xx;
 
-static const gdc_regs init_regs [] =
-{
-       {0x0100, 0x00000f00},
-       {0x0020, 0x801401df},
-       {0x0024, 0x00000000},
-       {0x0028, 0x00000000},
-       {0x002c, 0x00000000},
-       {0x0110, 0x00000000},
-       {0x0114, 0x00000000},
-       {0x0118, 0x01df0280},
-       {0x0004, 0x031f0000},
-       {0x0008, 0x027f027f},
-       {0x000c, 0x015f028f},
-       {0x0010, 0x020c0000},
-       {0x0014, 0x01df01ea},
-       {0x0018, 0x00000000},
-       {0x001c, 0x01e00280},
-       {0x0100, 0x80010f00},
-       {0x0, 0x0}
+static const gdc_regs init_regs [] = {
+       { 0x0100, 0x00000f00 },
+       { 0x0020, 0x801401df },
+       { 0x0024, 0x00000000 },
+       { 0x0028, 0x00000000 },
+       { 0x002c, 0x00000000 },
+       { 0x0110, 0x00000000 },
+       { 0x0114, 0x00000000 },
+       { 0x0118, 0x01df0280 },
+       { 0x0004, 0x031f0000 },
+       { 0x0008, 0x027f027f },
+       { 0x000c, 0x015f028f },
+       { 0x0010, 0x020c0000 },
+       { 0x0014, 0x01df01ea },
+       { 0x0018, 0x00000000 },
+       { 0x001c, 0x01e00280 },
+       { 0x0100, 0x80010f00 },
+       { 0x0, 0x0 }
 };
 
-const gdc_regs *board_get_regs (void)
+const gdc_regs *board_get_regs(void)
 {
        return init_regs;
 }
 
 /* Returns Lime base address */
-unsigned int board_video_init (void)
+unsigned int board_video_init(void)
 {
        /*
         * Reset Lime controller
@@ -380,7 +454,7 @@ unsigned int board_video_init (void)
        return CONFIG_SYS_LIME_BASE_0;
 }
 
-#define DEFAULT_BRIGHTNESS 0x64
+#define DEFAULT_BRIGHTNESS     0x64
 
 static void board_backlight_brightness(int brightness)
 {
@@ -395,7 +469,7 @@ static void board_backlight_brightness(int brightness)
        }
 }
 
-void board_backlight_switch (int flag)
+void board_backlight_switch(int flag)
 {
        char * param;
        int rc;
@@ -415,18 +489,80 @@ void board_backlight_switch (int flag)
 /*
  * Return text to be printed besides the logo.
  */
-void video_get_info_str (int line_number, char *info)
+void video_get_info_str(int line_number, char *info)
 {
-       if (line_number == 1) {
-               strcpy (info, " Board: Lwmon5 (Liebherr Elektronik GmbH)");
-       } else {
+       if (line_number == 1)
+               strcpy(info, " Board: Lwmon5 (Liebherr Elektronik GmbH)");
+       else
                info [0] = '\0';
-       }
 }
-#endif
+#endif /* CONFIG_CONSOLE_EXTRA_INFO */
 #endif /* CONFIG_VIDEO */
 
 void board_reset(void)
 {
        gpio_write_bit(CONFIG_SYS_GPIO_BOARD_RESET, 1);
 }
+
+#ifdef CONFIG_SPL_OS_BOOT
+/*
+ * lwmon5 specific implementation of spl_start_uboot()
+ *
+ * RETURN
+ * 0 if booting into OS is selected (default)
+ * 1 if booting into U-Boot is selected
+ */
+int spl_start_uboot(void)
+{
+       char s[8];
+
+       env_init();
+       getenv_f("boot_os", s, sizeof(s));
+       if ((s != NULL) && (strcmp(s, "yes") == 0))
+               return 0;
+
+       return 1;
+}
+
+/*
+ * This function is called from the SPL U-Boot version for
+ * early init stuff, that needs to be done for OS (e.g. Linux)
+ * booting. Doing it later in the real U-Boot would not work
+ * in case that the SPL U-Boot boots Linux directly.
+ */
+void spl_board_init(void)
+{
+       const gdc_regs *regs = board_get_regs();
+
+       /*
+        * Setup PFC registers, mainly for ethernet support
+        * later on in Linux
+        */
+       board_early_init_f();
+
+       /*
+        * Clear resets
+        */
+       mtsdr(SDR0_SRST1, 0x00000000);
+       mtsdr(SDR0_SRST0, 0x00000000);
+
+       /*
+        * Reset Lime controller
+        */
+       gpio_write_bit(CONFIG_SYS_GPIO_LIME_S, 1);
+       udelay(500);
+       gpio_write_bit(CONFIG_SYS_GPIO_LIME_RST, 1);
+
+       out_be32((void *)CONFIG_SYS_LIME_SDRAM_CLOCK, CONFIG_SYS_MB862xx_CCF);
+       udelay(300);
+       out_be32((void *)CONFIG_SYS_LIME_MMR, CONFIG_SYS_MB862xx_MMR);
+
+       while (regs->index) {
+               out_be32((void *)(CONFIG_SYS_LIME_BASE_0 + GC_DISP_BASE) +
+                        regs->index, regs->value);
+               regs++;
+       }
+
+       board_backlight_brightness(DEFAULT_BRIGHTNESS);
+}
+#endif