150dcf89dSDirk Eibach /*
250dcf89dSDirk Eibach * (C) Copyright 2014
350dcf89dSDirk Eibach * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de
450dcf89dSDirk Eibach *
550dcf89dSDirk Eibach * SPDX-License-Identifier: GPL-2.0+
650dcf89dSDirk Eibach */
750dcf89dSDirk Eibach
850dcf89dSDirk Eibach #include <common.h>
950dcf89dSDirk Eibach #include <hwconfig.h>
1050dcf89dSDirk Eibach #include <i2c.h>
1150dcf89dSDirk Eibach #include <spi.h>
12*0e00a84cSMasahiro Yamada #include <linux/libfdt.h>
1350dcf89dSDirk Eibach #include <fdt_support.h>
1450dcf89dSDirk Eibach #include <pci.h>
1550dcf89dSDirk Eibach #include <mpc83xx.h>
1650dcf89dSDirk Eibach #include <fsl_esdhc.h>
1750dcf89dSDirk Eibach #include <asm/io.h>
1850dcf89dSDirk Eibach #include <asm/fsl_serdes.h>
1950dcf89dSDirk Eibach #include <asm/fsl_mpc83xx_serdes.h>
2050dcf89dSDirk Eibach
2150dcf89dSDirk Eibach #include "mpc8308.h"
2250dcf89dSDirk Eibach
2350dcf89dSDirk Eibach #include <gdsys_fpga.h>
2450dcf89dSDirk Eibach
25d4e58888SDirk Eibach #include "../common/ioep-fpga.h"
2650dcf89dSDirk Eibach #include "../common/osd.h"
2750dcf89dSDirk Eibach #include "../common/mclink.h"
2850dcf89dSDirk Eibach #include "../common/phy.h"
295c3b6dc1SDirk Eibach #include "../common/fanctrl.h"
3050dcf89dSDirk Eibach
3150dcf89dSDirk Eibach #include <pca953x.h>
3250dcf89dSDirk Eibach #include <pca9698.h>
3350dcf89dSDirk Eibach
3450dcf89dSDirk Eibach #include <miiphy.h>
3550dcf89dSDirk Eibach
3650dcf89dSDirk Eibach DECLARE_GLOBAL_DATA_PTR;
3750dcf89dSDirk Eibach
3850dcf89dSDirk Eibach #define MAX_MUX_CHANNELS 2
3950dcf89dSDirk Eibach
4050dcf89dSDirk Eibach enum {
4150dcf89dSDirk Eibach MCFPGA_DONE = 1 << 0,
4250dcf89dSDirk Eibach MCFPGA_INIT_N = 1 << 1,
4350dcf89dSDirk Eibach MCFPGA_PROGRAM_N = 1 << 2,
4450dcf89dSDirk Eibach MCFPGA_UPDATE_ENABLE_N = 1 << 3,
4550dcf89dSDirk Eibach MCFPGA_RESET_N = 1 << 4,
4650dcf89dSDirk Eibach };
4750dcf89dSDirk Eibach
4850dcf89dSDirk Eibach enum {
4950dcf89dSDirk Eibach GPIO_MDC = 1 << 14,
5050dcf89dSDirk Eibach GPIO_MDIO = 1 << 15,
5150dcf89dSDirk Eibach };
5250dcf89dSDirk Eibach
5350dcf89dSDirk Eibach unsigned int mclink_fpgacount;
5450dcf89dSDirk Eibach struct ihs_fpga *fpga_ptr[] = CONFIG_SYS_FPGA_PTR;
5550dcf89dSDirk Eibach
565c3b6dc1SDirk Eibach struct {
575c3b6dc1SDirk Eibach u8 bus;
585c3b6dc1SDirk Eibach u8 addr;
595c3b6dc1SDirk Eibach } hrcon_fans[] = CONFIG_HRCON_FANS;
605c3b6dc1SDirk Eibach
fpga_set_reg(u32 fpga,u16 * reg,off_t regoff,u16 data)6150dcf89dSDirk Eibach int fpga_set_reg(u32 fpga, u16 *reg, off_t regoff, u16 data)
6250dcf89dSDirk Eibach {
6350dcf89dSDirk Eibach int res;
6450dcf89dSDirk Eibach
6550dcf89dSDirk Eibach switch (fpga) {
6650dcf89dSDirk Eibach case 0:
6750dcf89dSDirk Eibach out_le16(reg, data);
6850dcf89dSDirk Eibach break;
6950dcf89dSDirk Eibach default:
7050dcf89dSDirk Eibach res = mclink_send(fpga - 1, regoff, data);
7150dcf89dSDirk Eibach if (res < 0) {
7250dcf89dSDirk Eibach printf("mclink_send reg %02lx data %04x returned %d\n",
7350dcf89dSDirk Eibach regoff, data, res);
7450dcf89dSDirk Eibach return res;
7550dcf89dSDirk Eibach }
7650dcf89dSDirk Eibach break;
7750dcf89dSDirk Eibach }
7850dcf89dSDirk Eibach
7950dcf89dSDirk Eibach return 0;
8050dcf89dSDirk Eibach }
8150dcf89dSDirk Eibach
fpga_get_reg(u32 fpga,u16 * reg,off_t regoff,u16 * data)8250dcf89dSDirk Eibach int fpga_get_reg(u32 fpga, u16 *reg, off_t regoff, u16 *data)
8350dcf89dSDirk Eibach {
8450dcf89dSDirk Eibach int res;
8550dcf89dSDirk Eibach
8650dcf89dSDirk Eibach switch (fpga) {
8750dcf89dSDirk Eibach case 0:
8850dcf89dSDirk Eibach *data = in_le16(reg);
8950dcf89dSDirk Eibach break;
9050dcf89dSDirk Eibach default:
9150dcf89dSDirk Eibach if (fpga > mclink_fpgacount)
9250dcf89dSDirk Eibach return -EINVAL;
9350dcf89dSDirk Eibach res = mclink_receive(fpga - 1, regoff, data);
9450dcf89dSDirk Eibach if (res < 0) {
9550dcf89dSDirk Eibach printf("mclink_receive reg %02lx returned %d\n",
9650dcf89dSDirk Eibach regoff, res);
9750dcf89dSDirk Eibach return res;
9850dcf89dSDirk Eibach }
9950dcf89dSDirk Eibach }
10050dcf89dSDirk Eibach
10150dcf89dSDirk Eibach return 0;
10250dcf89dSDirk Eibach }
10350dcf89dSDirk Eibach
checkboard(void)10450dcf89dSDirk Eibach int checkboard(void)
10550dcf89dSDirk Eibach {
10600caae6dSSimon Glass char *s = env_get("serial#");
10750dcf89dSDirk Eibach bool hw_type_cat = pca9698_get_value(0x20, 20);
10850dcf89dSDirk Eibach
10950dcf89dSDirk Eibach puts("Board: ");
11050dcf89dSDirk Eibach
11150dcf89dSDirk Eibach printf("HRCon %s", hw_type_cat ? "CAT" : "Fiber");
11250dcf89dSDirk Eibach
11350dcf89dSDirk Eibach if (s != NULL) {
11450dcf89dSDirk Eibach puts(", serial# ");
11550dcf89dSDirk Eibach puts(s);
11650dcf89dSDirk Eibach }
11750dcf89dSDirk Eibach
11850dcf89dSDirk Eibach puts("\n");
11950dcf89dSDirk Eibach
12050dcf89dSDirk Eibach return 0;
12150dcf89dSDirk Eibach }
12250dcf89dSDirk Eibach
last_stage_init(void)12350dcf89dSDirk Eibach int last_stage_init(void)
12450dcf89dSDirk Eibach {
12550dcf89dSDirk Eibach int slaves;
12650dcf89dSDirk Eibach unsigned int k;
12750dcf89dSDirk Eibach unsigned int mux_ch;
128b847f5b6SDirk Eibach unsigned char mclink_controllers[] = { 0x3c, 0x3d, 0x3e };
12950dcf89dSDirk Eibach u16 fpga_features;
13050dcf89dSDirk Eibach bool hw_type_cat = pca9698_get_value(0x20, 20);
13150dcf89dSDirk Eibach bool ch0_rgmii2_present = false;
13250dcf89dSDirk Eibach
13350dcf89dSDirk Eibach FPGA_GET_REG(0, fpga_features, &fpga_features);
13450dcf89dSDirk Eibach
13550dcf89dSDirk Eibach /* Turn on Parade DP501 */
13650dcf89dSDirk Eibach pca9698_direction_output(0x20, 10, 1);
1377ed45d3dSDirk Eibach pca9698_direction_output(0x20, 11, 1);
13850dcf89dSDirk Eibach
13950dcf89dSDirk Eibach ch0_rgmii2_present = !pca9698_get_value(0x20, 30);
14050dcf89dSDirk Eibach
141b847f5b6SDirk Eibach /* wait for FPGA done, then reset FPGA */
14250dcf89dSDirk Eibach for (k = 0; k < ARRAY_SIZE(mclink_controllers); ++k) {
14350dcf89dSDirk Eibach unsigned int ctr = 0;
14450dcf89dSDirk Eibach
14550dcf89dSDirk Eibach if (i2c_probe(mclink_controllers[k]))
14650dcf89dSDirk Eibach continue;
14750dcf89dSDirk Eibach
14850dcf89dSDirk Eibach while (!(pca953x_get_val(mclink_controllers[k])
14950dcf89dSDirk Eibach & MCFPGA_DONE)) {
15050dcf89dSDirk Eibach udelay(100000);
15150dcf89dSDirk Eibach if (ctr++ > 5) {
15250dcf89dSDirk Eibach printf("no done for mclink_controller %d\n", k);
15350dcf89dSDirk Eibach break;
15450dcf89dSDirk Eibach }
15550dcf89dSDirk Eibach }
156b847f5b6SDirk Eibach
157b847f5b6SDirk Eibach pca953x_set_dir(mclink_controllers[k], MCFPGA_RESET_N, 0);
158b847f5b6SDirk Eibach pca953x_set_val(mclink_controllers[k], MCFPGA_RESET_N, 0);
159b847f5b6SDirk Eibach udelay(10);
160b847f5b6SDirk Eibach pca953x_set_val(mclink_controllers[k], MCFPGA_RESET_N,
161b847f5b6SDirk Eibach MCFPGA_RESET_N);
16250dcf89dSDirk Eibach }
16350dcf89dSDirk Eibach
16450dcf89dSDirk Eibach if (hw_type_cat) {
1655a49f174SJoe Hershberger int retval;
1665a49f174SJoe Hershberger struct mii_dev *mdiodev = mdio_alloc();
1675a49f174SJoe Hershberger if (!mdiodev)
1685a49f174SJoe Hershberger return -ENOMEM;
1695a49f174SJoe Hershberger strncpy(mdiodev->name, bb_miiphy_buses[0].name, MDIO_NAME_LEN);
1705a49f174SJoe Hershberger mdiodev->read = bb_miiphy_read;
1715a49f174SJoe Hershberger mdiodev->write = bb_miiphy_write;
1725a49f174SJoe Hershberger
1735a49f174SJoe Hershberger retval = mdio_register(mdiodev);
1745a49f174SJoe Hershberger if (retval < 0)
1755a49f174SJoe Hershberger return retval;
17650dcf89dSDirk Eibach for (mux_ch = 0; mux_ch < MAX_MUX_CHANNELS; ++mux_ch) {
17750dcf89dSDirk Eibach if ((mux_ch == 1) && !ch0_rgmii2_present)
17850dcf89dSDirk Eibach continue;
17950dcf89dSDirk Eibach
18050dcf89dSDirk Eibach setup_88e1514(bb_miiphy_buses[0].name, mux_ch);
18150dcf89dSDirk Eibach }
18250dcf89dSDirk Eibach }
18350dcf89dSDirk Eibach
18450dcf89dSDirk Eibach /* give slave-PLLs and Parade DP501 some time to be up and running */
18550dcf89dSDirk Eibach udelay(500000);
18650dcf89dSDirk Eibach
18750dcf89dSDirk Eibach mclink_fpgacount = CONFIG_SYS_MCLINK_MAX;
18850dcf89dSDirk Eibach slaves = mclink_probe();
18950dcf89dSDirk Eibach mclink_fpgacount = 0;
19050dcf89dSDirk Eibach
191d4e58888SDirk Eibach ioep_fpga_print_info(0);
19250dcf89dSDirk Eibach osd_probe(0);
1937ed45d3dSDirk Eibach #ifdef CONFIG_SYS_OSD_DH
1947ed45d3dSDirk Eibach osd_probe(4);
1957ed45d3dSDirk Eibach #endif
19650dcf89dSDirk Eibach
19750dcf89dSDirk Eibach if (slaves <= 0)
19850dcf89dSDirk Eibach return 0;
19950dcf89dSDirk Eibach
20050dcf89dSDirk Eibach mclink_fpgacount = slaves;
20150dcf89dSDirk Eibach
20250dcf89dSDirk Eibach for (k = 1; k <= slaves; ++k) {
20350dcf89dSDirk Eibach FPGA_GET_REG(k, fpga_features, &fpga_features);
20450dcf89dSDirk Eibach
205d4e58888SDirk Eibach ioep_fpga_print_info(k);
20650dcf89dSDirk Eibach osd_probe(k);
2077ed45d3dSDirk Eibach #ifdef CONFIG_SYS_OSD_DH
2087ed45d3dSDirk Eibach osd_probe(k + 4);
2097ed45d3dSDirk Eibach #endif
21050dcf89dSDirk Eibach if (hw_type_cat) {
2115a49f174SJoe Hershberger int retval;
2125a49f174SJoe Hershberger struct mii_dev *mdiodev = mdio_alloc();
2135a49f174SJoe Hershberger if (!mdiodev)
2145a49f174SJoe Hershberger return -ENOMEM;
2155a49f174SJoe Hershberger strncpy(mdiodev->name, bb_miiphy_buses[k].name,
2165a49f174SJoe Hershberger MDIO_NAME_LEN);
2175a49f174SJoe Hershberger mdiodev->read = bb_miiphy_read;
2185a49f174SJoe Hershberger mdiodev->write = bb_miiphy_write;
2195a49f174SJoe Hershberger
2205a49f174SJoe Hershberger retval = mdio_register(mdiodev);
2215a49f174SJoe Hershberger if (retval < 0)
2225a49f174SJoe Hershberger return retval;
22350dcf89dSDirk Eibach setup_88e1514(bb_miiphy_buses[k].name, 0);
22450dcf89dSDirk Eibach }
22550dcf89dSDirk Eibach }
22650dcf89dSDirk Eibach
2275c3b6dc1SDirk Eibach for (k = 0; k < ARRAY_SIZE(hrcon_fans); ++k) {
2285c3b6dc1SDirk Eibach i2c_set_bus_num(hrcon_fans[k].bus);
2295c3b6dc1SDirk Eibach init_fan_controller(hrcon_fans[k].addr);
2305c3b6dc1SDirk Eibach }
2315c3b6dc1SDirk Eibach
23250dcf89dSDirk Eibach return 0;
23350dcf89dSDirk Eibach }
23450dcf89dSDirk Eibach
23550dcf89dSDirk Eibach /*
2367ed45d3dSDirk Eibach * provide access to fpga gpios and controls (for I2C bitbang)
23750dcf89dSDirk Eibach * (these may look all too simple but make iocon.h much more readable)
23850dcf89dSDirk Eibach */
fpga_gpio_set(unsigned int bus,int pin)23950dcf89dSDirk Eibach void fpga_gpio_set(unsigned int bus, int pin)
24050dcf89dSDirk Eibach {
2417ed45d3dSDirk Eibach FPGA_SET_REG(bus >= 4 ? (bus - 4) : bus, gpio.set, pin);
24250dcf89dSDirk Eibach }
24350dcf89dSDirk Eibach
fpga_gpio_clear(unsigned int bus,int pin)24450dcf89dSDirk Eibach void fpga_gpio_clear(unsigned int bus, int pin)
24550dcf89dSDirk Eibach {
2467ed45d3dSDirk Eibach FPGA_SET_REG(bus >= 4 ? (bus - 4) : bus, gpio.clear, pin);
24750dcf89dSDirk Eibach }
24850dcf89dSDirk Eibach
fpga_gpio_get(unsigned int bus,int pin)24950dcf89dSDirk Eibach int fpga_gpio_get(unsigned int bus, int pin)
25050dcf89dSDirk Eibach {
25150dcf89dSDirk Eibach u16 val;
25250dcf89dSDirk Eibach
2537ed45d3dSDirk Eibach FPGA_GET_REG(bus >= 4 ? (bus - 4) : bus, gpio.read, &val);
25450dcf89dSDirk Eibach
25550dcf89dSDirk Eibach return val & pin;
25650dcf89dSDirk Eibach }
25750dcf89dSDirk Eibach
fpga_control_set(unsigned int bus,int pin)2587ed45d3dSDirk Eibach void fpga_control_set(unsigned int bus, int pin)
2597ed45d3dSDirk Eibach {
2607ed45d3dSDirk Eibach u16 val;
2617ed45d3dSDirk Eibach
2627ed45d3dSDirk Eibach FPGA_GET_REG(bus >= 4 ? (bus - 4) : bus, control, &val);
2637ed45d3dSDirk Eibach FPGA_SET_REG(bus >= 4 ? (bus - 4) : bus, control, val | pin);
2647ed45d3dSDirk Eibach }
2657ed45d3dSDirk Eibach
fpga_control_clear(unsigned int bus,int pin)2667ed45d3dSDirk Eibach void fpga_control_clear(unsigned int bus, int pin)
2677ed45d3dSDirk Eibach {
2687ed45d3dSDirk Eibach u16 val;
2697ed45d3dSDirk Eibach
2707ed45d3dSDirk Eibach FPGA_GET_REG(bus >= 4 ? (bus - 4) : bus, control, &val);
2717ed45d3dSDirk Eibach FPGA_SET_REG(bus >= 4 ? (bus - 4) : bus, control, val & ~pin);
2727ed45d3dSDirk Eibach }
2737ed45d3dSDirk Eibach
mpc8308_init(void)27450dcf89dSDirk Eibach void mpc8308_init(void)
27550dcf89dSDirk Eibach {
27650dcf89dSDirk Eibach pca9698_direction_output(0x20, 4, 1);
27750dcf89dSDirk Eibach }
27850dcf89dSDirk Eibach
mpc8308_set_fpga_reset(unsigned state)27950dcf89dSDirk Eibach void mpc8308_set_fpga_reset(unsigned state)
28050dcf89dSDirk Eibach {
28150dcf89dSDirk Eibach pca9698_set_value(0x20, 4, state ? 0 : 1);
28250dcf89dSDirk Eibach }
28350dcf89dSDirk Eibach
mpc8308_setup_hw(void)28450dcf89dSDirk Eibach void mpc8308_setup_hw(void)
28550dcf89dSDirk Eibach {
28650dcf89dSDirk Eibach immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
28750dcf89dSDirk Eibach
28850dcf89dSDirk Eibach /*
28950dcf89dSDirk Eibach * set "startup-finished"-gpios
29050dcf89dSDirk Eibach */
29150dcf89dSDirk Eibach setbits_be32(&immr->gpio[0].dir, (1 << (31-11)) | (1 << (31-12)));
29250dcf89dSDirk Eibach setbits_be32(&immr->gpio[0].dat, 1 << (31-12));
29350dcf89dSDirk Eibach }
29450dcf89dSDirk Eibach
mpc8308_get_fpga_done(unsigned fpga)29550dcf89dSDirk Eibach int mpc8308_get_fpga_done(unsigned fpga)
29650dcf89dSDirk Eibach {
29750dcf89dSDirk Eibach return pca9698_get_value(0x20, 19);
29850dcf89dSDirk Eibach }
29950dcf89dSDirk Eibach
30050dcf89dSDirk Eibach #ifdef CONFIG_FSL_ESDHC
board_mmc_init(bd_t * bd)30150dcf89dSDirk Eibach int board_mmc_init(bd_t *bd)
30250dcf89dSDirk Eibach {
30350dcf89dSDirk Eibach immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
30450dcf89dSDirk Eibach sysconf83xx_t *sysconf = &immr->sysconf;
30550dcf89dSDirk Eibach
30650dcf89dSDirk Eibach /* Enable cache snooping in eSDHC system configuration register */
30750dcf89dSDirk Eibach out_be32(&sysconf->sdhccr, 0x02000000);
30850dcf89dSDirk Eibach
30950dcf89dSDirk Eibach return fsl_esdhc_mmc_init(bd);
31050dcf89dSDirk Eibach }
31150dcf89dSDirk Eibach #endif
31250dcf89dSDirk Eibach
31350dcf89dSDirk Eibach static struct pci_region pcie_regions_0[] = {
31450dcf89dSDirk Eibach {
31550dcf89dSDirk Eibach .bus_start = CONFIG_SYS_PCIE1_MEM_BASE,
31650dcf89dSDirk Eibach .phys_start = CONFIG_SYS_PCIE1_MEM_PHYS,
31750dcf89dSDirk Eibach .size = CONFIG_SYS_PCIE1_MEM_SIZE,
31850dcf89dSDirk Eibach .flags = PCI_REGION_MEM,
31950dcf89dSDirk Eibach },
32050dcf89dSDirk Eibach {
32150dcf89dSDirk Eibach .bus_start = CONFIG_SYS_PCIE1_IO_BASE,
32250dcf89dSDirk Eibach .phys_start = CONFIG_SYS_PCIE1_IO_PHYS,
32350dcf89dSDirk Eibach .size = CONFIG_SYS_PCIE1_IO_SIZE,
32450dcf89dSDirk Eibach .flags = PCI_REGION_IO,
32550dcf89dSDirk Eibach },
32650dcf89dSDirk Eibach };
32750dcf89dSDirk Eibach
pci_init_board(void)32850dcf89dSDirk Eibach void pci_init_board(void)
32950dcf89dSDirk Eibach {
33050dcf89dSDirk Eibach immap_t *immr = (immap_t *)CONFIG_SYS_IMMR;
33150dcf89dSDirk Eibach sysconf83xx_t *sysconf = &immr->sysconf;
33250dcf89dSDirk Eibach law83xx_t *pcie_law = sysconf->pcielaw;
33350dcf89dSDirk Eibach struct pci_region *pcie_reg[] = { pcie_regions_0 };
33450dcf89dSDirk Eibach
33550dcf89dSDirk Eibach fsl_setup_serdes(CONFIG_FSL_SERDES1, FSL_SERDES_PROTO_PEX,
33650dcf89dSDirk Eibach FSL_SERDES_CLK_100, FSL_SERDES_VDD_1V);
33750dcf89dSDirk Eibach
33850dcf89dSDirk Eibach /* Deassert the resets in the control register */
33950dcf89dSDirk Eibach out_be32(&sysconf->pecr1, 0xE0008000);
34050dcf89dSDirk Eibach udelay(2000);
34150dcf89dSDirk Eibach
34250dcf89dSDirk Eibach /* Configure PCI Express Local Access Windows */
34350dcf89dSDirk Eibach out_be32(&pcie_law[0].bar, CONFIG_SYS_PCIE1_BASE & LAWBAR_BAR);
34450dcf89dSDirk Eibach out_be32(&pcie_law[0].ar, LBLAWAR_EN | LBLAWAR_512MB);
34550dcf89dSDirk Eibach
34650dcf89dSDirk Eibach mpc83xx_pcie_init(1, pcie_reg);
34750dcf89dSDirk Eibach }
34850dcf89dSDirk Eibach
board_flash_get_legacy(ulong base,int banknum,flash_info_t * info)34950dcf89dSDirk Eibach ulong board_flash_get_legacy(ulong base, int banknum, flash_info_t *info)
35050dcf89dSDirk Eibach {
35150dcf89dSDirk Eibach info->portwidth = FLASH_CFI_16BIT;
35250dcf89dSDirk Eibach info->chipwidth = FLASH_CFI_BY16;
35350dcf89dSDirk Eibach info->interface = FLASH_CFI_X16;
35450dcf89dSDirk Eibach return 1;
35550dcf89dSDirk Eibach }
35650dcf89dSDirk Eibach
35750dcf89dSDirk Eibach #if defined(CONFIG_OF_BOARD_SETUP)
ft_board_setup(void * blob,bd_t * bd)358e895a4b0SSimon Glass int ft_board_setup(void *blob, bd_t *bd)
35950dcf89dSDirk Eibach {
36050dcf89dSDirk Eibach ft_cpu_setup(blob, bd);
361a5c289b9SSriram Dash fsl_fdt_fixup_dr_usb(blob, bd);
36250dcf89dSDirk Eibach fdt_fixup_esdhc(blob, bd);
363e895a4b0SSimon Glass
364e895a4b0SSimon Glass return 0;
36550dcf89dSDirk Eibach }
36650dcf89dSDirk Eibach #endif
36750dcf89dSDirk Eibach
36850dcf89dSDirk Eibach /*
36950dcf89dSDirk Eibach * FPGA MII bitbang implementation
37050dcf89dSDirk Eibach */
37150dcf89dSDirk Eibach
37250dcf89dSDirk Eibach struct fpga_mii {
37350dcf89dSDirk Eibach unsigned fpga;
37450dcf89dSDirk Eibach int mdio;
37550dcf89dSDirk Eibach } fpga_mii[] = {
37650dcf89dSDirk Eibach { 0, 1},
37750dcf89dSDirk Eibach { 1, 1},
37850dcf89dSDirk Eibach { 2, 1},
37950dcf89dSDirk Eibach { 3, 1},
38050dcf89dSDirk Eibach };
38150dcf89dSDirk Eibach
mii_dummy_init(struct bb_miiphy_bus * bus)38250dcf89dSDirk Eibach static int mii_dummy_init(struct bb_miiphy_bus *bus)
38350dcf89dSDirk Eibach {
38450dcf89dSDirk Eibach return 0;
38550dcf89dSDirk Eibach }
38650dcf89dSDirk Eibach
mii_mdio_active(struct bb_miiphy_bus * bus)38750dcf89dSDirk Eibach static int mii_mdio_active(struct bb_miiphy_bus *bus)
38850dcf89dSDirk Eibach {
38950dcf89dSDirk Eibach struct fpga_mii *fpga_mii = bus->priv;
39050dcf89dSDirk Eibach
39150dcf89dSDirk Eibach if (fpga_mii->mdio)
39250dcf89dSDirk Eibach FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDIO);
39350dcf89dSDirk Eibach else
39450dcf89dSDirk Eibach FPGA_SET_REG(fpga_mii->fpga, gpio.clear, GPIO_MDIO);
39550dcf89dSDirk Eibach
39650dcf89dSDirk Eibach return 0;
39750dcf89dSDirk Eibach }
39850dcf89dSDirk Eibach
mii_mdio_tristate(struct bb_miiphy_bus * bus)39950dcf89dSDirk Eibach static int mii_mdio_tristate(struct bb_miiphy_bus *bus)
40050dcf89dSDirk Eibach {
40150dcf89dSDirk Eibach struct fpga_mii *fpga_mii = bus->priv;
40250dcf89dSDirk Eibach
40350dcf89dSDirk Eibach FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDIO);
40450dcf89dSDirk Eibach
40550dcf89dSDirk Eibach return 0;
40650dcf89dSDirk Eibach }
40750dcf89dSDirk Eibach
mii_set_mdio(struct bb_miiphy_bus * bus,int v)40850dcf89dSDirk Eibach static int mii_set_mdio(struct bb_miiphy_bus *bus, int v)
40950dcf89dSDirk Eibach {
41050dcf89dSDirk Eibach struct fpga_mii *fpga_mii = bus->priv;
41150dcf89dSDirk Eibach
41250dcf89dSDirk Eibach if (v)
41350dcf89dSDirk Eibach FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDIO);
41450dcf89dSDirk Eibach else
41550dcf89dSDirk Eibach FPGA_SET_REG(fpga_mii->fpga, gpio.clear, GPIO_MDIO);
41650dcf89dSDirk Eibach
41750dcf89dSDirk Eibach fpga_mii->mdio = v;
41850dcf89dSDirk Eibach
41950dcf89dSDirk Eibach return 0;
42050dcf89dSDirk Eibach }
42150dcf89dSDirk Eibach
mii_get_mdio(struct bb_miiphy_bus * bus,int * v)42250dcf89dSDirk Eibach static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v)
42350dcf89dSDirk Eibach {
42450dcf89dSDirk Eibach u16 gpio;
42550dcf89dSDirk Eibach struct fpga_mii *fpga_mii = bus->priv;
42650dcf89dSDirk Eibach
42750dcf89dSDirk Eibach FPGA_GET_REG(fpga_mii->fpga, gpio.read, &gpio);
42850dcf89dSDirk Eibach
42950dcf89dSDirk Eibach *v = ((gpio & GPIO_MDIO) != 0);
43050dcf89dSDirk Eibach
43150dcf89dSDirk Eibach return 0;
43250dcf89dSDirk Eibach }
43350dcf89dSDirk Eibach
mii_set_mdc(struct bb_miiphy_bus * bus,int v)43450dcf89dSDirk Eibach static int mii_set_mdc(struct bb_miiphy_bus *bus, int v)
43550dcf89dSDirk Eibach {
43650dcf89dSDirk Eibach struct fpga_mii *fpga_mii = bus->priv;
43750dcf89dSDirk Eibach
43850dcf89dSDirk Eibach if (v)
43950dcf89dSDirk Eibach FPGA_SET_REG(fpga_mii->fpga, gpio.set, GPIO_MDC);
44050dcf89dSDirk Eibach else
44150dcf89dSDirk Eibach FPGA_SET_REG(fpga_mii->fpga, gpio.clear, GPIO_MDC);
44250dcf89dSDirk Eibach
44350dcf89dSDirk Eibach return 0;
44450dcf89dSDirk Eibach }
44550dcf89dSDirk Eibach
mii_delay(struct bb_miiphy_bus * bus)44650dcf89dSDirk Eibach static int mii_delay(struct bb_miiphy_bus *bus)
44750dcf89dSDirk Eibach {
44850dcf89dSDirk Eibach udelay(1);
44950dcf89dSDirk Eibach
45050dcf89dSDirk Eibach return 0;
45150dcf89dSDirk Eibach }
45250dcf89dSDirk Eibach
45350dcf89dSDirk Eibach struct bb_miiphy_bus bb_miiphy_buses[] = {
45450dcf89dSDirk Eibach {
45550dcf89dSDirk Eibach .name = "board0",
45650dcf89dSDirk Eibach .init = mii_dummy_init,
45750dcf89dSDirk Eibach .mdio_active = mii_mdio_active,
45850dcf89dSDirk Eibach .mdio_tristate = mii_mdio_tristate,
45950dcf89dSDirk Eibach .set_mdio = mii_set_mdio,
46050dcf89dSDirk Eibach .get_mdio = mii_get_mdio,
46150dcf89dSDirk Eibach .set_mdc = mii_set_mdc,
46250dcf89dSDirk Eibach .delay = mii_delay,
46350dcf89dSDirk Eibach .priv = &fpga_mii[0],
46450dcf89dSDirk Eibach },
46550dcf89dSDirk Eibach {
46650dcf89dSDirk Eibach .name = "board1",
46750dcf89dSDirk Eibach .init = mii_dummy_init,
46850dcf89dSDirk Eibach .mdio_active = mii_mdio_active,
46950dcf89dSDirk Eibach .mdio_tristate = mii_mdio_tristate,
47050dcf89dSDirk Eibach .set_mdio = mii_set_mdio,
47150dcf89dSDirk Eibach .get_mdio = mii_get_mdio,
47250dcf89dSDirk Eibach .set_mdc = mii_set_mdc,
47350dcf89dSDirk Eibach .delay = mii_delay,
47450dcf89dSDirk Eibach .priv = &fpga_mii[1],
47550dcf89dSDirk Eibach },
47650dcf89dSDirk Eibach {
47750dcf89dSDirk Eibach .name = "board2",
47850dcf89dSDirk Eibach .init = mii_dummy_init,
47950dcf89dSDirk Eibach .mdio_active = mii_mdio_active,
48050dcf89dSDirk Eibach .mdio_tristate = mii_mdio_tristate,
48150dcf89dSDirk Eibach .set_mdio = mii_set_mdio,
48250dcf89dSDirk Eibach .get_mdio = mii_get_mdio,
48350dcf89dSDirk Eibach .set_mdc = mii_set_mdc,
48450dcf89dSDirk Eibach .delay = mii_delay,
48550dcf89dSDirk Eibach .priv = &fpga_mii[2],
48650dcf89dSDirk Eibach },
48750dcf89dSDirk Eibach {
48850dcf89dSDirk Eibach .name = "board3",
48950dcf89dSDirk Eibach .init = mii_dummy_init,
49050dcf89dSDirk Eibach .mdio_active = mii_mdio_active,
49150dcf89dSDirk Eibach .mdio_tristate = mii_mdio_tristate,
49250dcf89dSDirk Eibach .set_mdio = mii_set_mdio,
49350dcf89dSDirk Eibach .get_mdio = mii_get_mdio,
49450dcf89dSDirk Eibach .set_mdc = mii_set_mdc,
49550dcf89dSDirk Eibach .delay = mii_delay,
49650dcf89dSDirk Eibach .priv = &fpga_mii[3],
49750dcf89dSDirk Eibach },
49850dcf89dSDirk Eibach };
49950dcf89dSDirk Eibach
50050dcf89dSDirk Eibach int bb_miiphy_buses_num = sizeof(bb_miiphy_buses) /
50150dcf89dSDirk Eibach sizeof(bb_miiphy_buses[0]);
502