diff options
Diffstat (limited to 'board/gdsys/mpc8308')
-rw-r--r-- | board/gdsys/mpc8308/Kconfig | 13 | ||||
-rw-r--r-- | board/gdsys/mpc8308/MAINTAINERS | 3 | ||||
-rw-r--r-- | board/gdsys/mpc8308/Makefile | 1 | ||||
-rw-r--r-- | board/gdsys/mpc8308/strider.c | 501 |
4 files changed, 518 insertions, 0 deletions
diff --git a/board/gdsys/mpc8308/Kconfig b/board/gdsys/mpc8308/Kconfig index 43e1663..9a1a3a2 100644 --- a/board/gdsys/mpc8308/Kconfig +++ b/board/gdsys/mpc8308/Kconfig @@ -10,3 +10,16 @@ config SYS_CONFIG_NAME default "hrcon" endif + +if TARGET_STRIDER + +config SYS_BOARD + default "mpc8308" + +config SYS_VENDOR + default "gdsys" + +config SYS_CONFIG_NAME + default "strider" + +endif diff --git a/board/gdsys/mpc8308/MAINTAINERS b/board/gdsys/mpc8308/MAINTAINERS index a7853a5..35704bc 100644 --- a/board/gdsys/mpc8308/MAINTAINERS +++ b/board/gdsys/mpc8308/MAINTAINERS @@ -4,3 +4,6 @@ S: Maintained F: board/gdsys/mpc8308/ F: include/configs/hrcon.h F: configs/hrcon_defconfig +F: include/configs/strider.h +F: configs/strider_cpu_defconfig +F: configs/strider_con_defconfig diff --git a/board/gdsys/mpc8308/Makefile b/board/gdsys/mpc8308/Makefile index b5dfdbb..42702fb 100644 --- a/board/gdsys/mpc8308/Makefile +++ b/board/gdsys/mpc8308/Makefile @@ -7,3 +7,4 @@ obj-y := mpc8308.o sdram.o obj-$(CONFIG_HRCON) += hrcon.o +obj-$(CONFIG_STRIDER) += strider.o diff --git a/board/gdsys/mpc8308/strider.c b/board/gdsys/mpc8308/strider.c new file mode 100644 index 0000000..8e5d5de --- /dev/null +++ b/board/gdsys/mpc8308/strider.c @@ -0,0 +1,501 @@ +/* + * (C) Copyright 2014 + * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <hwconfig.h> +#include <i2c.h> +#include <spi.h> +#include <libfdt.h> +#include <fdt_support.h> +#include <pci.h> +#include <mpc83xx.h> +#include <fsl_esdhc.h> +#include <asm/io.h> +#include <asm/fsl_serdes.h> +#include <asm/fsl_mpc83xx_serdes.h> + +#include "mpc8308.h" + +#include <gdsys_fpga.h> + +#include "../common/adv7611.h" +#include "../common/ch7301.h" +#include "../common/ioep-fpga.h" +#include "../common/mclink.h" +#include "../common/osd.h" +#include "../common/phy.h" + +#include <pca953x.h> +#include <pca9698.h> + +#include <miiphy.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define MAX_MUX_CHANNELS 2 + +enum { + MCFPGA_DONE = 1 << 0, + MCFPGA_INIT_N = 1 << 1, + MCFPGA_PROGRAM_N = 1 << 2, + MCFPGA_UPDATE_ENABLE_N = 1 << 3, + MCFPGA_RESET_N = 1 << 4, +}; + +enum { + GPIO_MDC = 1 << 14, + GPIO_MDIO = 1 << 15, +}; + +enum { + FAN_CONFIG = 0x03, + FAN_TACHLIM_LSB = 0x48, + FAN_TACHLIM_MSB = 0x49, + FAN_PWM_FREQ = 0x4D, +}; + +unsigned int mclink_fpgacount; +struct ihs_fpga *fpga_ptr[] = CONFIG_SYS_FPGA_PTR; + +struct { + u8 bus; + u8 addr; +} strider_fans[] = CONFIG_STRIDER_FANS; + +int fpga_set_reg(u32 fpga, u16 *reg, off_t regoff, u16 data) +{ + int res; + + switch (fpga) { + case 0: + out_le16(reg, data); + break; + default: + res = mclink_send(fpga - 1, regoff, data); + if (res < 0) { + printf("mclink_send reg %02lx data %04x returned %d\n", + regoff, data, res); + return res; + } + break; + } + + return 0; +} + +int fpga_get_reg(u32 fpga, u16 *reg, off_t regoff, u16 *data) +{ + int res; + + switch (fpga) { + case 0: + *data = in_le16(reg); + break; + default: + if (fpga > mclink_fpgacount) + return -EINVAL; + res = mclink_receive(fpga - 1, regoff, data); + if (res < 0) { + printf("mclink_receive reg %02lx returned %d\n", + regoff, res); + return res; + } + } + + return 0; +} + +int checkboard(void) +{ + char *s = getenv("serial#"); + bool hw_type_cat = pca9698_get_value(0x20, 18); + + puts("Board: "); + + printf("Strider %s", hw_type_cat ? "CAT" : "Fiber"); + + if (s != NULL) { + puts(", serial# "); + puts(s); + } + + puts("\n"); + + return 0; +} + +static void init_fan_controller(u8 addr) +{ + int val; + + /* set PWM Frequency to 2.5% resolution */ + i2c_reg_write(addr, FAN_PWM_FREQ, 20); + + /* set Tachometer Limit */ + i2c_reg_write(addr, FAN_TACHLIM_LSB, 0x10); + i2c_reg_write(addr, FAN_TACHLIM_MSB, 0x0a); + + /* enable Tach input */ + val = i2c_reg_read(addr, FAN_CONFIG) | 0x04; + i2c_reg_write(addr, FAN_CONFIG, val); +} + +int last_stage_init(void) +{ + int slaves; + unsigned int k; + unsigned int mux_ch; + unsigned char mclink_controllers[] = { 0x3c, 0x3d, 0x3e }; + bool hw_type_cat = pca9698_get_value(0x20, 18); + bool ch0_sgmii2_present = false; + + /* Turn on Analog Devices ADV7611 */ + pca9698_direction_output(0x20, 8, 0); + + /* Turn on Parade DP501 */ + pca9698_direction_output(0x20, 9, 1); + + ch0_sgmii2_present = !pca9698_get_value(0x20, 37); + + /* wait for FPGA done, then reset FPGA */ + for (k = 0; k < ARRAY_SIZE(mclink_controllers); ++k) { + unsigned int ctr = 0; + + if (i2c_probe(mclink_controllers[k])) + continue; + + while (!(pca953x_get_val(mclink_controllers[k]) + & MCFPGA_DONE)) { + udelay(100000); + if (ctr++ > 5) { + printf("no done for mclink_controller %d\n", k); + break; + } + } + + pca953x_set_dir(mclink_controllers[k], MCFPGA_RESET_N, 0); + pca953x_set_val(mclink_controllers[k], MCFPGA_RESET_N, 0); + udelay(10); + pca953x_set_val(mclink_controllers[k], MCFPGA_RESET_N, + MCFPGA_RESET_N); + } + + if (hw_type_cat) { + miiphy_register(bb_miiphy_buses[0].name, bb_miiphy_read, + bb_miiphy_write); + for (mux_ch = 0; mux_ch < MAX_MUX_CHANNELS; ++mux_ch) { + if ((mux_ch == 1) && !ch0_sgmii2_present) + continue; + + setup_88e1514(bb_miiphy_buses[0].name, mux_ch); + } + } + + /* give slave-PLLs and Parade DP501 some time to be up and running */ + udelay(500000); + + mclink_fpgacount = CONFIG_SYS_MCLINK_MAX; + slaves = mclink_probe(); + mclink_fpgacount = 0; + + ioep_fpga_print_info(0); + + if (!adv7611_probe(0)) + printf(" Advantiv ADV7611 HDMI Receiver\n"); + +#ifdef CONFIG_STRIDER_CON + if (ioep_fpga_has_osd(0)) + osd_probe(0); +#endif + +#ifdef CONFIG_STRIDER_CPU + ch7301_probe(0, false); +#endif + + if (slaves <= 0) + return 0; + + mclink_fpgacount = slaves; + + for (k = 1; k <= slaves; ++k) { + ioep_fpga_print_info(k); +#ifdef CONFIG_STRIDER_CON + if (ioep_fpga_has_osd(k)) + osd_probe(k); +#endif +#ifdef CONFIG_STRIDER_CPU + FPGA_SET_REG(k, extended_control, 0); /* enable video in*/ + if (!adv7611_probe(k)) + printf(" Advantiv ADV7611 HDMI Receiver\n"); + ch7301_probe(k, false); +#endif + if (hw_type_cat) { + miiphy_register(bb_miiphy_buses[k].name, + bb_miiphy_read, bb_miiphy_write); + setup_88e1514(bb_miiphy_buses[k].name, 0); + } + } + + for (k = 0; k < ARRAY_SIZE(strider_fans); ++k) { + i2c_set_bus_num(strider_fans[k].bus); + init_fan_controller(strider_fans[k].addr); + } + + return 0; +} + +/* + * provide access to fpga gpios (for I2C bitbang) + * (these may look all too simple but make iocon.h much more readable) + */ +void fpga_gpio_set(unsigned int bus, int pin) +{ + FPGA_SET_REG(bus, gpio.set, pin); +} + +void fpga_gpio_clear(unsigned int bus, int pin) +{ + FPGA_SET_REG(bus, gpio.clear, pin); +} + +int fpga_gpio_get(unsigned int bus, int pin) +{ + u16 val; + + FPGA_GET_REG(bus, gpio.read, &val); + + return val & pin; +} + +void mpc8308_init(void) +{ + pca9698_direction_output(0x20, 26, 1); +} + +void mpc8308_set_fpga_reset(unsigned state) +{ + pca9698_set_value(0x20, 26, state ? 0 : 1); +} + +void mpc8308_setup_hw(void) +{ + immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; + + /* + * set "startup-finished"-gpios + */ + setbits_be32(&immr->gpio[0].dir, (1 << (31-11)) | (1 << (31-12))); + setbits_be32(&immr->gpio[0].dat, 1 << (31-12)); +} + +int mpc8308_get_fpga_done(unsigned fpga) +{ + return pca9698_get_value(0x20, 20); +} + +#ifdef CONFIG_FSL_ESDHC +int board_mmc_init(bd_t *bd) +{ + immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; + sysconf83xx_t *sysconf = &immr->sysconf; + + /* Enable cache snooping in eSDHC system configuration register */ + out_be32(&sysconf->sdhccr, 0x02000000); + + return fsl_esdhc_mmc_init(bd); +} +#endif + +static struct pci_region pcie_regions_0[] = { + { + .bus_start = CONFIG_SYS_PCIE1_MEM_BASE, + .phys_start = CONFIG_SYS_PCIE1_MEM_PHYS, + .size = CONFIG_SYS_PCIE1_MEM_SIZE, + .flags = PCI_REGION_MEM, + }, + { + .bus_start = CONFIG_SYS_PCIE1_IO_BASE, + .phys_start = CONFIG_SYS_PCIE1_IO_PHYS, + .size = CONFIG_SYS_PCIE1_IO_SIZE, + .flags = PCI_REGION_IO, + }, +}; + +void pci_init_board(void) +{ + immap_t *immr = (immap_t *)CONFIG_SYS_IMMR; + sysconf83xx_t *sysconf = &immr->sysconf; + law83xx_t *pcie_law = sysconf->pcielaw; + struct pci_region *pcie_reg[] = { pcie_regions_0 }; + + fsl_setup_serdes(CONFIG_FSL_SERDES1, FSL_SERDES_PROTO_PEX, + FSL_SERDES_CLK_100, FSL_SERDES_VDD_1V); + + /* Deassert the resets in the control register */ + out_be32(&sysconf->pecr1, 0xE0008000); + udelay(2000); + + /* Configure PCI Express Local Access Windows */ + out_be32(&pcie_law[0].bar, CONFIG_SYS_PCIE1_BASE & LAWBAR_BAR); + out_be32(&pcie_law[0].ar, LBLAWAR_EN | LBLAWAR_512MB); + + mpc83xx_pcie_init(1, pcie_reg); +} + +ulong board_flash_get_legacy(ulong base, int banknum, flash_info_t *info) +{ + info->portwidth = FLASH_CFI_16BIT; + info->chipwidth = FLASH_CFI_BY16; + info->interface = FLASH_CFI_X16; + return 1; +} + +#if defined(CONFIG_OF_BOARD_SETUP) +int ft_board_setup(void *blob, bd_t *bd) +{ + ft_cpu_setup(blob, bd); + fdt_fixup_dr_usb(blob, bd); + fdt_fixup_esdhc(blob, bd); + + return 0; +} +#endif + +/* + * FPGA MII bitbang implementation + */ + +struct fpga_mii { + unsigned fpga; + int mdio; +} fpga_mii[] = { + { 0, 1}, + { 1, 1}, + { 2, 1}, + { 3, 1}, +}; + +static int mii_dummy_init(struct bb_miiphy_bus *bus) +{ + return 0; +} + +static int mii_mdio_active(struct bb_miiphy_bus *bus) +{ + struct fpga_mii *fpga_mii = bus->priv; + + if (fpga_mii->mdio) + FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDIO); + else + FPGA_SET_REG(fpga_mii->fpga, gpio.clear, GPIO_MDIO); + + return 0; +} + +static int mii_mdio_tristate(struct bb_miiphy_bus *bus) +{ + struct fpga_mii *fpga_mii = bus->priv; + + FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDIO); + + return 0; +} + +static int mii_set_mdio(struct bb_miiphy_bus *bus, int v) +{ + struct fpga_mii *fpga_mii = bus->priv; + + if (v) + FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDIO); + else + FPGA_SET_REG(fpga_mii->fpga, gpio.clear, GPIO_MDIO); + + fpga_mii->mdio = v; + + return 0; +} + +static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v) +{ + u16 gpio; + struct fpga_mii *fpga_mii = bus->priv; + + FPGA_GET_REG(fpga_mii->fpga, gpio.read, &gpio); + + *v = ((gpio & GPIO_MDIO) != 0); + + return 0; +} + +static int mii_set_mdc(struct bb_miiphy_bus *bus, int v) +{ + struct fpga_mii *fpga_mii = bus->priv; + + if (v) + FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDC); + else + FPGA_SET_REG(fpga_mii->fpga, gpio.clear, GPIO_MDC); + + return 0; +} + +static int mii_delay(struct bb_miiphy_bus *bus) +{ + udelay(1); + + return 0; +} + +struct bb_miiphy_bus bb_miiphy_buses[] = { + { + .name = "board0", + .init = mii_dummy_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &fpga_mii[0], + }, + { + .name = "board1", + .init = mii_dummy_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &fpga_mii[1], + }, + { + .name = "board2", + .init = mii_dummy_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &fpga_mii[2], + }, + { + .name = "board3", + .init = mii_dummy_init, + .mdio_active = mii_mdio_active, + .mdio_tristate = mii_mdio_tristate, + .set_mdio = mii_set_mdio, + .get_mdio = mii_get_mdio, + .set_mdc = mii_set_mdc, + .delay = mii_delay, + .priv = &fpga_mii[3], + }, +}; + +int bb_miiphy_buses_num = sizeof(bb_miiphy_buses) / + sizeof(bb_miiphy_buses[0]); |