/* * (C) Copyright 2005 * Stefan Strobl, GERSYS GmbH, stefan.strobl@gersys.de * * (C) Copyright 2005 * Martin Krause, TQ-Systems GmbH, martin.krause@tqs.de. * * SPDX-License-Identifier: GPL-2.0+ */ #include #include /* * 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 \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 \n" " - turns the CCFL backlight of the display on/off\n" "fp \n" " - turns the whole display on/off" #ifdef CONFIG_BC3450_CRT "\n" "fp crt \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