| /* | |
| * (C) Copyright 2005 | |
| * Stefan Strobl, GERSYS GmbH, stefan.strobl@gersys.de | |
| * | |
| * (C) Copyright 2005 | |
| * Martin Krause, TQ-Systems GmbH, martin.krause@tqs.de. | |
| * | |
| * See file CREDITS for list of people who contributed to this | |
| * project. | |
| * | |
| * This program is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU General Public License as | |
| * published by the Free Software Foundation; either version 2 of | |
| * the License, or (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU General Public License | |
| * along with this program; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
| * MA 02111-1307 USA | |
| */ | |
| #include <common.h> | |
| #include <command.h> | |
| /* | |
| * BC3450 specific commands | |
| */ | |
| #if defined(CONFIG_CMD_BSP) | |
| /* | |
| * Definitions for DS1620 chip | |
| */ | |
| #define THERM_START_CONVERT 0xee | |
| #define THERM_RESET 0xaf | |
| #define THERM_READ_CONFIG 0xac | |
| #define THERM_READ_TEMP 0xaa | |
| #define THERM_READ_TL 0xa2 | |
| #define THERM_READ_TH 0xa1 | |
| #define THERM_WRITE_CONFIG 0x0c | |
| #define THERM_WRITE_TL 0x02 | |
| #define THERM_WRITE_TH 0x01 | |
| #define CONFIG_SYS_1SHOT 1 | |
| #define CONFIG_SYS_STANDALONE 0 | |
| struct therm { | |
| int hi; | |
| int lo; | |
| }; | |
| /* | |
| * SM501 Register | |
| */ | |
| #define SM501_GPIO_CTRL_LOW 0x00000008UL /* gpio pins 0..31 */ | |
| #define SM501_GPIO_CTRL_HIGH 0x0000000CUL /* gpio pins 32..63 */ | |
| #define SM501_POWER_MODE0_GATE 0x00000040UL | |
| #define SM501_POWER_MODE1_GATE 0x00000048UL | |
| #define POWER_MODE_GATE_GPIO_PWM_I2C 0x00000040UL | |
| #define SM501_GPIO_DATA_LOW 0x00010000UL | |
| #define SM501_GPIO_DATA_HIGH 0x00010004UL | |
| #define SM501_GPIO_DATA_DIR_LOW 0x00010008UL | |
| #define SM501_GPIO_DATA_DIR_HIGH 0x0001000CUL | |
| #define SM501_PANEL_DISPLAY_CONTROL 0x00080000UL | |
| #define SM501_CRT_DISPLAY_CONTROL 0x00080200UL | |
| /* SM501 CRT Display Control Bits */ | |
| #define SM501_CDC_SEL (1 << 9) | |
| #define SM501_CDC_TE (1 << 8) | |
| #define SM501_CDC_E (1 << 2) | |
| /* SM501 Panel Display Control Bits */ | |
| #define SM501_PDC_FPEN (1 << 27) | |
| #define SM501_PDC_BIAS (1 << 26) | |
| #define SM501_PDC_DATA (1 << 25) | |
| #define SM501_PDC_VDDEN (1 << 24) | |
| /* SM501 GPIO Data LOW Bits */ | |
| #define SM501_GPIO24 0x01000000 | |
| #define SM501_GPIO25 0x02000000 | |
| #define SM501_GPIO26 0x04000000 | |
| #define SM501_GPIO27 0x08000000 | |
| #define SM501_GPIO28 0x10000000 | |
| #define SM501_GPIO29 0x20000000 | |
| #define SM501_GPIO30 0x40000000 | |
| #define SM501_GPIO31 0x80000000 | |
| /* SM501 GPIO Data HIGH Bits */ | |
| #define SM501_GPIO46 0x00004000 | |
| #define SM501_GPIO47 0x00008000 | |
| #define SM501_GPIO48 0x00010000 | |
| #define SM501_GPIO49 0x00020000 | |
| #define SM501_GPIO50 0x00040000 | |
| #define SM501_GPIO51 0x00080000 | |
| /* BC3450 GPIOs @ SM501 Data LOW */ | |
| #define DIP (SM501_GPIO24 | SM501_GPIO25 | SM501_GPIO26 | SM501_GPIO27) | |
| #define DS1620_DQ SM501_GPIO29 /* I/O */ | |
| #define DS1620_CLK SM501_GPIO30 /* High active O/P */ | |
| #define DS1620_RES SM501_GPIO31 /* Low active O/P */ | |
| /* BC3450 GPIOs @ SM501 Data HIGH */ | |
| #define BUZZER SM501_GPIO47 /* Low active O/P */ | |
| #define DS1620_TLOW SM501_GPIO48 /* High active I/P */ | |
| #define PWR_OFF SM501_GPIO49 /* Low active O/P */ | |
| #define FP_DATA_TRI SM501_GPIO50 /* High active O/P */ | |
| /* | |
| * Initialise GPIO on SM501 | |
| * | |
| * This function may be called from several other functions. | |
| * Yet, the initialisation sequence is executed only the first | |
| * time the function is called. | |
| */ | |
| int sm501_gpio_init (void) | |
| { | |
| static int init_done = 0; | |
| if (init_done) { | |
| debug("sm501_gpio_init: nothing to be done.\n"); | |
| return 1; | |
| } | |
| /* enable SM501 GPIO control (in both power modes) */ | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_POWER_MODE0_GATE) |= | |
| POWER_MODE_GATE_GPIO_PWM_I2C; | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_POWER_MODE1_GATE) |= | |
| POWER_MODE_GATE_GPIO_PWM_I2C; | |
| /* set up default O/Ps */ | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_LOW) &= | |
| ~(DS1620_RES | DS1620_CLK); | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_LOW) |= DS1620_DQ; | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_HIGH) &= | |
| ~(FP_DATA_TRI); | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_HIGH) |= | |
| (BUZZER | PWR_OFF); | |
| /* configure directions for SM501 GPIO pins */ | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_CTRL_LOW) &= ~(0xFF << 24); | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_CTRL_HIGH) &= | |
| ~(0x3F << 14); | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_DIR_LOW) &= | |
| ~(DIP | DS1620_DQ); | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_DIR_LOW) |= | |
| (DS1620_RES | DS1620_CLK); | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_DIR_HIGH) &= | |
| ~DS1620_TLOW; | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_DIR_HIGH) |= | |
| (PWR_OFF | BUZZER | FP_DATA_TRI); | |
| init_done = 1; | |
| debug("sm501_gpio_init: done.\n"); | |
| return 0; | |
| } | |
| /* | |
| * dip - read Config Inputs | |
| * | |
| * read and prints the dip switch | |
| * and/or external config inputs (4bits) 0...0x0F | |
| */ | |
| int cmd_dip (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) | |
| { | |
| vu_long rc = 0; | |
| sm501_gpio_init (); | |
| /* read dip switch */ | |
| rc = *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_LOW); | |
| rc = ~rc; | |
| rc &= DIP; | |
| rc = (int) (rc >> 24); | |
| /* plausibility check */ | |
| if (rc > 0x0F) | |
| return -1; | |
| printf ("0x%lx\n", rc); | |
| return 0; | |
| } | |
| U_BOOT_CMD (dip, 1, 1, cmd_dip, | |
| "read dip switch and config inputs", | |
| "\n" | |
| " - prints the state of the dip switch and/or\n" | |
| " external configuration inputs as hex value.\n" | |
| " - \"Config 1\" is the LSB"); | |
| /* | |
| * buz - turns Buzzer on/off | |
| */ | |
| #ifdef CONFIG_BC3450_BUZZER | |
| static int cmd_buz (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) | |
| { | |
| if (argc != 2) { | |
| printf ("Usage:\nspecify one argument: \"on\" or \"off\"\n"); | |
| return 1; | |
| } | |
| sm501_gpio_init (); | |
| if (strncmp (argv[1], "on", 2) == 0) { | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_HIGH) &= | |
| ~(BUZZER); | |
| return 0; | |
| } else if (strncmp (argv[1], "off", 3) == 0) { | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_HIGH) |= | |
| BUZZER; | |
| return 0; | |
| } | |
| printf ("Usage:\nspecify one argument: \"on\" or \"off\"\n"); | |
| return 1; | |
| } | |
| U_BOOT_CMD (buz, 2, 1, cmd_buz, | |
| "turns buzzer on/off", | |
| "\n" "buz <on/off>\n" " - turns the buzzer on or off"); | |
| #endif /* CONFIG_BC3450_BUZZER */ | |
| /* | |
| * fp - front panel commands | |
| */ | |
| static int cmd_fp (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) | |
| { | |
| sm501_gpio_init (); | |
| if (strncmp (argv[1], "on", 2) == 0) { | |
| /* turn on VDD first */ | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_PANEL_DISPLAY_CONTROL) |= SM501_PDC_VDDEN; | |
| udelay (1000); | |
| /* then put data on */ | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_PANEL_DISPLAY_CONTROL) |= SM501_PDC_DATA; | |
| /* wait some time and enable backlight */ | |
| udelay (1000); | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_PANEL_DISPLAY_CONTROL) |= SM501_PDC_BIAS; | |
| udelay (1000); | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_PANEL_DISPLAY_CONTROL) |= SM501_PDC_FPEN; | |
| return 0; | |
| } else if (strncmp (argv[1], "off", 3) == 0) { | |
| /* turn off the backlight first */ | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_PANEL_DISPLAY_CONTROL) &= ~SM501_PDC_FPEN; | |
| udelay (1000); | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_PANEL_DISPLAY_CONTROL) &= ~SM501_PDC_BIAS; | |
| udelay (200000); | |
| /* wait some time, then remove data */ | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_PANEL_DISPLAY_CONTROL) &= ~SM501_PDC_DATA; | |
| udelay (1000); | |
| /* and remove VDD last */ | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_PANEL_DISPLAY_CONTROL) &= | |
| ~SM501_PDC_VDDEN; | |
| return 0; | |
| } else if (strncmp (argv[1], "bl", 2) == 0) { | |
| /* turn on/off backlight only */ | |
| if (strncmp (argv[2], "on", 2) == 0) { | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_PANEL_DISPLAY_CONTROL) |= | |
| SM501_PDC_BIAS; | |
| udelay (1000); | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_PANEL_DISPLAY_CONTROL) |= | |
| SM501_PDC_FPEN; | |
| return 0; | |
| } else if (strncmp (argv[2], "off", 3) == 0) { | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_PANEL_DISPLAY_CONTROL) &= | |
| ~SM501_PDC_FPEN; | |
| udelay (1000); | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_PANEL_DISPLAY_CONTROL) &= | |
| ~SM501_PDC_BIAS; | |
| return 0; | |
| } | |
| } | |
| #ifdef CONFIG_BC3450_CRT | |
| else if (strncmp (argv[1], "crt", 3) == 0) { | |
| /* enables/disables the crt output (debug only) */ | |
| if (strncmp (argv[2], "on", 2) == 0) { | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_CRT_DISPLAY_CONTROL) |= | |
| (SM501_CDC_TE | SM501_CDC_E); | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_CRT_DISPLAY_CONTROL) &= | |
| ~SM501_CDC_SEL; | |
| return 0; | |
| } else if (strncmp (argv[2], "off", 3) == 0) { | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_CRT_DISPLAY_CONTROL) &= | |
| ~(SM501_CDC_TE | SM501_CDC_E); | |
| *(vu_long *) (SM501_MMIO_BASE + | |
| SM501_CRT_DISPLAY_CONTROL) |= | |
| SM501_CDC_SEL; | |
| return 0; | |
| } | |
| } | |
| #endif /* CONFIG_BC3450_CRT */ | |
| printf ("Usage:%s\n", cmdtp->help); | |
| return 1; | |
| } | |
| U_BOOT_CMD (fp, 3, 1, cmd_fp, | |
| "front panes access functions", | |
| "\n" | |
| "fp bl <on/off>\n" | |
| " - turns the CCFL backlight of the display on/off\n" | |
| "fp <on/off>\n" " - turns the whole display on/off" | |
| #ifdef CONFIG_BC3450_CRT | |
| "\n" | |
| "fp crt <on/off>\n" | |
| " - enables/disables the crt output (debug only)" | |
| #endif /* CONFIG_BC3450_CRT */ | |
| ); | |
| /* | |
| * temp - DS1620 thermometer | |
| */ | |
| /* GERSYS BC3450 specific functions */ | |
| static inline void bc_ds1620_set_clk (int clk) | |
| { | |
| if (clk) | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_LOW) |= | |
| DS1620_CLK; | |
| else | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_LOW) &= | |
| ~DS1620_CLK; | |
| } | |
| static inline void bc_ds1620_set_data (int dat) | |
| { | |
| if (dat) | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_LOW) |= | |
| DS1620_DQ; | |
| else | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_LOW) &= | |
| ~DS1620_DQ; | |
| } | |
| static inline int bc_ds1620_get_data (void) | |
| { | |
| vu_long rc; | |
| rc = *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_LOW); | |
| rc &= DS1620_DQ; | |
| if (rc != 0) | |
| rc = 1; | |
| return (int) rc; | |
| } | |
| static inline void bc_ds1620_set_data_dir (int dir) | |
| { | |
| if (dir) /* in */ | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_DIR_LOW) &= ~DS1620_DQ; | |
| else /* out */ | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_DIR_LOW) |= DS1620_DQ; | |
| } | |
| static inline void bc_ds1620_set_reset (int res) | |
| { | |
| if (res) | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_LOW) |= DS1620_RES; | |
| else | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_LOW) &= ~DS1620_RES; | |
| } | |
| /* hardware independent functions */ | |
| static void ds1620_send_bits (int nr, int value) | |
| { | |
| int i; | |
| for (i = 0; i < nr; i++) { | |
| bc_ds1620_set_data (value & 1); | |
| bc_ds1620_set_clk (0); | |
| udelay (1); | |
| bc_ds1620_set_clk (1); | |
| udelay (1); | |
| value >>= 1; | |
| } | |
| } | |
| static unsigned int ds1620_recv_bits (int nr) | |
| { | |
| unsigned int value = 0, mask = 1; | |
| int i; | |
| bc_ds1620_set_data (0); | |
| for (i = 0; i < nr; i++) { | |
| bc_ds1620_set_clk (0); | |
| udelay (1); | |
| if (bc_ds1620_get_data ()) | |
| value |= mask; | |
| mask <<= 1; | |
| bc_ds1620_set_clk (1); | |
| udelay (1); | |
| } | |
| return value; | |
| } | |
| static void ds1620_out (int cmd, int bits, int value) | |
| { | |
| bc_ds1620_set_clk (1); | |
| bc_ds1620_set_data_dir (0); | |
| bc_ds1620_set_reset (0); | |
| udelay (1); | |
| bc_ds1620_set_reset (1); | |
| udelay (1); | |
| ds1620_send_bits (8, cmd); | |
| if (bits) | |
| ds1620_send_bits (bits, value); | |
| udelay (1); | |
| /* go stand alone */ | |
| bc_ds1620_set_data_dir (1); | |
| bc_ds1620_set_reset (0); | |
| bc_ds1620_set_clk (0); | |
| udelay (10000); | |
| } | |
| static unsigned int ds1620_in (int cmd, int bits) | |
| { | |
| unsigned int value; | |
| bc_ds1620_set_clk (1); | |
| bc_ds1620_set_data_dir (0); | |
| bc_ds1620_set_reset (0); | |
| udelay (1); | |
| bc_ds1620_set_reset (1); | |
| udelay (1); | |
| ds1620_send_bits (8, cmd); | |
| bc_ds1620_set_data_dir (1); | |
| value = ds1620_recv_bits (bits); | |
| /* go stand alone */ | |
| bc_ds1620_set_data_dir (1); | |
| bc_ds1620_set_reset (0); | |
| bc_ds1620_set_clk (0); | |
| return value; | |
| } | |
| static int cvt_9_to_int (unsigned int val) | |
| { | |
| if (val & 0x100) | |
| val |= 0xfffffe00; | |
| return val; | |
| } | |
| /* set thermostate thresholds */ | |
| static void ds1620_write_state (struct therm *therm) | |
| { | |
| ds1620_out (THERM_WRITE_TL, 9, therm->lo); | |
| ds1620_out (THERM_WRITE_TH, 9, therm->hi); | |
| ds1620_out (THERM_START_CONVERT, 0, 0); | |
| } | |
| static int cmd_temp (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) | |
| { | |
| int i; | |
| struct therm therm; | |
| sm501_gpio_init (); | |
| /* print temperature */ | |
| if (argc == 1) { | |
| i = cvt_9_to_int (ds1620_in (THERM_READ_TEMP, 9)); | |
| printf ("%d.%d C\n", i >> 1, i & 1 ? 5 : 0); | |
| return 0; | |
| } | |
| /* set to default operation */ | |
| if (strncmp (argv[1], "set", 3) == 0) { | |
| if (strncmp (argv[2], "default", 3) == 0) { | |
| therm.hi = +88; | |
| therm.lo = -20; | |
| therm.hi <<= 1; | |
| therm.lo <<= 1; | |
| ds1620_write_state (&therm); | |
| ds1620_out (THERM_WRITE_CONFIG, 8, CONFIG_SYS_STANDALONE); | |
| return 0; | |
| } | |
| } | |
| printf ("Usage:%s\n", cmdtp->help); | |
| return 1; | |
| } | |
| U_BOOT_CMD (temp, 3, 1, cmd_temp, | |
| "print current temperature", | |
| "\n" "temp\n" " - print current temperature"); | |
| #ifdef CONFIG_BC3450_CAN | |
| /* | |
| * Initialise CAN interface | |
| * | |
| * return 1 on CAN initialization failure | |
| * return 0 if no failure | |
| */ | |
| int can_init (void) | |
| { | |
| static int init_done = 0; | |
| int i; | |
| struct mpc5xxx_mscan *can1 = | |
| (struct mpc5xxx_mscan *) (CONFIG_SYS_MBAR + 0x0900); | |
| struct mpc5xxx_mscan *can2 = | |
| (struct mpc5xxx_mscan *) (CONFIG_SYS_MBAR + 0x0980); | |
| /* GPIO configuration of the CAN pins is done in BC3450.h */ | |
| if (!init_done) { | |
| /* init CAN 1 */ | |
| can1->canctl1 |= 0x80; /* CAN enable */ | |
| udelay (100); | |
| i = 0; | |
| can1->canctl0 |= 0x02; /* sleep mode */ | |
| /* wait until sleep mode reached */ | |
| while (!(can1->canctl1 & 0x02)) { | |
| udelay (10); | |
| i++; | |
| if (i == 10) { | |
| printf ("%s: CAN1 initialize error, " | |
| "can not enter sleep mode!\n", | |
| __FUNCTION__); | |
| return 1; | |
| } | |
| } | |
| i = 0; | |
| can1->canctl0 = 0x01; /* enter init mode */ | |
| /* wait until init mode reached */ | |
| while (!(can1->canctl1 & 0x01)) { | |
| udelay (10); | |
| i++; | |
| if (i == 10) { | |
| printf ("%s: CAN1 initialize error, " | |
| "can not enter init mode!\n", | |
| __FUNCTION__); | |
| return 1; | |
| } | |
| } | |
| can1->canctl1 = 0x80; | |
| can1->canctl1 |= 0x40; | |
| can1->canbtr0 = 0x0F; | |
| can1->canbtr1 = 0x7F; | |
| can1->canidac &= ~(0x30); | |
| can1->canidar1 = 0x00; | |
| can1->canidar3 = 0x00; | |
| can1->canidar5 = 0x00; | |
| can1->canidar7 = 0x00; | |
| can1->canidmr0 = 0xFF; | |
| can1->canidmr1 = 0xFF; | |
| can1->canidmr2 = 0xFF; | |
| can1->canidmr3 = 0xFF; | |
| can1->canidmr4 = 0xFF; | |
| can1->canidmr5 = 0xFF; | |
| can1->canidmr6 = 0xFF; | |
| can1->canidmr7 = 0xFF; | |
| i = 0; | |
| can1->canctl0 &= ~(0x01); /* leave init mode */ | |
| can1->canctl0 &= ~(0x02); | |
| /* wait until init and sleep mode left */ | |
| while ((can1->canctl1 & 0x01) || (can1->canctl1 & 0x02)) { | |
| udelay (10); | |
| i++; | |
| if (i == 10) { | |
| printf ("%s: CAN1 initialize error, " | |
| "can not leave init/sleep mode!\n", | |
| __FUNCTION__); | |
| return 1; | |
| } | |
| } | |
| /* init CAN 2 */ | |
| can2->canctl1 |= 0x80; /* CAN enable */ | |
| udelay (100); | |
| i = 0; | |
| can2->canctl0 |= 0x02; /* sleep mode */ | |
| /* wait until sleep mode reached */ | |
| while (!(can2->canctl1 & 0x02)) { | |
| udelay (10); | |
| i++; | |
| if (i == 10) { | |
| printf ("%s: CAN2 initialize error, " | |
| "can not enter sleep mode!\n", | |
| __FUNCTION__); | |
| return 1; | |
| } | |
| } | |
| i = 0; | |
| can2->canctl0 = 0x01; /* enter init mode */ | |
| /* wait until init mode reached */ | |
| while (!(can2->canctl1 & 0x01)) { | |
| udelay (10); | |
| i++; | |
| if (i == 10) { | |
| printf ("%s: CAN2 initialize error, " | |
| "can not enter init mode!\n", | |
| __FUNCTION__); | |
| return 1; | |
| } | |
| } | |
| can2->canctl1 = 0x80; | |
| can2->canctl1 |= 0x40; | |
| can2->canbtr0 = 0x0F; | |
| can2->canbtr1 = 0x7F; | |
| can2->canidac &= ~(0x30); | |
| can2->canidar1 = 0x00; | |
| can2->canidar3 = 0x00; | |
| can2->canidar5 = 0x00; | |
| can2->canidar7 = 0x00; | |
| can2->canidmr0 = 0xFF; | |
| can2->canidmr1 = 0xFF; | |
| can2->canidmr2 = 0xFF; | |
| can2->canidmr3 = 0xFF; | |
| can2->canidmr4 = 0xFF; | |
| can2->canidmr5 = 0xFF; | |
| can2->canidmr6 = 0xFF; | |
| can2->canidmr7 = 0xFF; | |
| can2->canctl0 &= ~(0x01); /* leave init mode */ | |
| can2->canctl0 &= ~(0x02); | |
| i = 0; | |
| /* wait until init mode left */ | |
| while ((can2->canctl1 & 0x01) || (can2->canctl1 & 0x02)) { | |
| udelay (10); | |
| i++; | |
| if (i == 10) { | |
| printf ("%s: CAN2 initialize error, " | |
| "can not leave init/sleep mode!\n", | |
| __FUNCTION__); | |
| return 1; | |
| } | |
| } | |
| init_done = 1; | |
| } | |
| return 0; | |
| } | |
| /* | |
| * Do CAN test | |
| * by sending message between CAN1 and CAN2 | |
| * | |
| * return 1 on CAN failure | |
| * return 0 if no failure | |
| */ | |
| int do_can (char * const argv[]) | |
| { | |
| int i; | |
| struct mpc5xxx_mscan *can1 = | |
| (struct mpc5xxx_mscan *) (CONFIG_SYS_MBAR + 0x0900); | |
| struct mpc5xxx_mscan *can2 = | |
| (struct mpc5xxx_mscan *) (CONFIG_SYS_MBAR + 0x0980); | |
| /* send a message on CAN1 */ | |
| can1->cantbsel = 0x01; | |
| can1->cantxfg.idr[0] = 0x55; | |
| can1->cantxfg.idr[1] = 0x00; | |
| can1->cantxfg.idr[1] &= ~0x8; | |
| can1->cantxfg.idr[1] &= ~0x10; | |
| can1->cantxfg.dsr[0] = 0xCC; | |
| can1->cantxfg.dlr = 1; | |
| can1->cantxfg.tbpr = 0; | |
| can1->cantflg = 0x01; | |
| i = 0; | |
| while ((can1->cantflg & 0x01) == 0) { | |
| i++; | |
| if (i == 10) { | |
| printf ("%s: CAN1 send timeout, " | |
| "can not send message!\n", __FUNCTION__); | |
| return 1; | |
| } | |
| udelay (1000); | |
| } | |
| udelay (1000); | |
| i = 0; | |
| while (!(can2->canrflg & 0x01)) { | |
| i++; | |
| if (i == 10) { | |
| printf ("%s: CAN2 receive timeout, " | |
| "no message received!\n", __FUNCTION__); | |
| return 1; | |
| } | |
| udelay (1000); | |
| } | |
| if (can2->canrxfg.dsr[0] != 0xCC) { | |
| printf ("%s: CAN2 receive error, " | |
| "data mismatch!\n", __FUNCTION__); | |
| return 1; | |
| } | |
| /* send a message on CAN2 */ | |
| can2->cantbsel = 0x01; | |
| can2->cantxfg.idr[0] = 0x55; | |
| can2->cantxfg.idr[1] = 0x00; | |
| can2->cantxfg.idr[1] &= ~0x8; | |
| can2->cantxfg.idr[1] &= ~0x10; | |
| can2->cantxfg.dsr[0] = 0xCC; | |
| can2->cantxfg.dlr = 1; | |
| can2->cantxfg.tbpr = 0; | |
| can2->cantflg = 0x01; | |
| i = 0; | |
| while ((can2->cantflg & 0x01) == 0) { | |
| i++; | |
| if (i == 10) { | |
| printf ("%s: CAN2 send error, " | |
| "can not send message!\n", __FUNCTION__); | |
| return 1; | |
| } | |
| udelay (1000); | |
| } | |
| udelay (1000); | |
| i = 0; | |
| while (!(can1->canrflg & 0x01)) { | |
| i++; | |
| if (i == 10) { | |
| printf ("%s: CAN1 receive timeout, " | |
| "no message received!\n", __FUNCTION__); | |
| return 1; | |
| } | |
| udelay (1000); | |
| } | |
| if (can1->canrxfg.dsr[0] != 0xCC) { | |
| printf ("%s: CAN1 receive error 0x%02x\n", | |
| __FUNCTION__, (can1->canrxfg.dsr[0])); | |
| return 1; | |
| } | |
| return 0; | |
| } | |
| #endif /* CONFIG_BC3450_CAN */ | |
| /* | |
| * test - BC3450 HW test routines | |
| */ | |
| int cmd_test (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) | |
| { | |
| #ifdef CONFIG_BC3450_CAN | |
| int rcode; | |
| can_init (); | |
| #endif /* CONFIG_BC3450_CAN */ | |
| sm501_gpio_init (); | |
| if (argc != 2) { | |
| printf ("Usage:%s\n", cmdtp->help); | |
| return 1; | |
| } | |
| if (strncmp (argv[1], "unit-off", 8) == 0) { | |
| printf ("waiting 2 seconds...\n"); | |
| udelay (2000000); | |
| *(vu_long *) (SM501_MMIO_BASE + SM501_GPIO_DATA_HIGH) &= | |
| ~PWR_OFF; | |
| return 0; | |
| } | |
| #ifdef CONFIG_BC3450_CAN | |
| else if (strncmp (argv[1], "can", 2) == 0) { | |
| rcode = do_can (argv); | |
| if (simple_strtoul (argv[2], NULL, 10) == 2) { | |
| if (rcode == 0) | |
| printf ("OK\n"); | |
| else | |
| printf ("Error\n"); | |
| } | |
| return rcode; | |
| } | |
| #endif /* CONFIG_BC3450_CAN */ | |
| printf ("Usage:%s\n", cmdtp->help); | |
| return 1; | |
| } | |
| U_BOOT_CMD (test, 2, 1, cmd_test, "unit test routines", "\n" | |
| #ifdef CONFIG_BC3450_CAN | |
| "test can\n" | |
| " - connect CAN1 (X8) with CAN2 (X9) for this test\n" | |
| #endif /* CONFIG_BC3450_CAN */ | |
| "test unit-off\n" | |
| " - turns off the BC3450 unit\n" | |
| " WARNING: Unsaved environment variables will be lost!" | |
| ); | |
| #endif |