From 080bcc5cc18dd8f667e1386de5428d4e98f253e9 Mon Sep 17 00:00:00 2001 From: Angelo Durgehello Date: Fri, 15 Nov 2019 23:54:17 +0100 Subject: drivers: net: add mcf fec dm Kconfig support Add ColdFire fec to Kconfig. Signed-off-by: Angelo Durgehello --- drivers/net/Kconfig | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 142a2c69538..01d087f229f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -278,6 +278,22 @@ config FTGMAC100 applications. +config MCFFEC + bool "ColdFire Ethernet Support" + depends on DM_ETH + select PHYLIB + help + This driver supports the network interface units in the + ColdFire family. + +config FSLDMAFEC + bool "ColdFire DMA Ethernet Support" + depends on DM_ETH + select PHYLIB + help + This driver supports the network interface units in the + ColdFire family. + config MVGBE bool "Marvell Orion5x/Kirkwood network interface support" depends on KIRKWOOD || ORION5X -- cgit v1.3.1 From a7bcace28a7c966f14e2049d8a1027c9f0097593 Mon Sep 17 00:00:00 2001 From: Angelo Durgehello Date: Fri, 15 Nov 2019 23:54:18 +0100 Subject: drivers: mcffec: conversion to dm Full conversion to dm for all boards, legacy code removed. Signed-off-by: Angelo Durgehello --- doc/device-tree-bindings/net/fsl,mcf-fec.txt | 22 + drivers/net/mcffec.c | 587 +++++++++++++-------------- 2 files changed, 315 insertions(+), 294 deletions(-) create mode 100644 doc/device-tree-bindings/net/fsl,mcf-fec.txt (limited to 'drivers') diff --git a/doc/device-tree-bindings/net/fsl,mcf-fec.txt b/doc/device-tree-bindings/net/fsl,mcf-fec.txt new file mode 100644 index 00000000000..39bbaa52f32 --- /dev/null +++ b/doc/device-tree-bindings/net/fsl,mcf-fec.txt @@ -0,0 +1,22 @@ +* Freescale ColdFire FEC ethernet controller + +Required properties: +- compatible: should be "fsl,mcf-fec" +- reg: address and length of the register set for the device. + +Optional properties: +- mii-base: index of FEC reg area, 0 for FEC0, 1 for FEC1 +- max-speed: max speedm Mbits/sec +- phy-addr: phy address +- timeout-loop: integer value for driver loops time out + + +Example: + +fec0: ethernet@fc030000 { + compatible = "fsl,mcf-fec"; + reg = <0xfc030000 0x400>; + mii-base = <0>; + phy-addr = <0>; + timeout-loop = <5000>; +}; diff --git a/drivers/net/mcffec.c b/drivers/net/mcffec.c index 9a3a8455a11..4ec24362d06 100644 --- a/drivers/net/mcffec.c +++ b/drivers/net/mcffec.c @@ -5,17 +5,17 @@ * * (C) Copyright 2007 Freescale Semiconductor, Inc. * TsiChung Liew (Tsi-Chung.Liew@freescale.com) + * + * Conversion to DM + * (C) 2019 Angelo Dureghello */ #include #include #include - #include #include -#include #include - #include #include #include @@ -27,64 +27,68 @@ #define DBUF_LENGTH 1520 #define TX_BUF_CNT 2 #define PKT_MAXBUF_SIZE 1518 -#define PKT_MINBUF_SIZE 64 #define PKT_MAXBLR_SIZE 1520 #define LAST_PKTBUFSRX PKTBUFSRX - 1 #define BD_ENET_RX_W_E (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY) #define BD_ENET_TX_RDY_LST (BD_ENET_TX_READY | BD_ENET_TX_LAST) -struct fec_info_s fec_info[] = { -#ifdef CONFIG_SYS_FEC0_IOBASE - { - 0, /* index */ - CONFIG_SYS_FEC0_IOBASE, /* io base */ - CONFIG_SYS_FEC0_PINMUX, /* gpio pin muxing */ - CONFIG_SYS_FEC0_MIIBASE, /* mii base */ - -1, /* phy_addr */ - 0, /* duplex and speed */ - 0, /* phy name */ - 0, /* phyname init */ - 0, /* RX BD */ - 0, /* TX BD */ - 0, /* rx Index */ - 0, /* tx Index */ - 0, /* tx buffer */ - 0, /* initialized flag */ - (struct fec_info_s *)-1, - }, -#endif -#ifdef CONFIG_SYS_FEC1_IOBASE - { - 1, /* index */ - CONFIG_SYS_FEC1_IOBASE, /* io base */ - CONFIG_SYS_FEC1_PINMUX, /* gpio pin muxing */ - CONFIG_SYS_FEC1_MIIBASE, /* mii base */ - -1, /* phy_addr */ - 0, /* duplex and speed */ - 0, /* phy name */ - 0, /* phy name init */ +DECLARE_GLOBAL_DATA_PTR; + +static void init_eth_info(struct fec_info_s *info) +{ #ifdef CONFIG_SYS_FEC_BUF_USE_SRAM - (cbd_t *)DBUF_LENGTH, /* RX BD */ + static u32 tmp; + + if (info->index == 0) + tmp = CONFIG_SYS_INIT_RAM_ADDR + 0x1000; + else + info->rxbd = (cbd_t *)DBUF_LENGTH; + + /* setup Receive and Transmit buffer descriptor */ + info->rxbd = (cbd_t *)((u32)info->rxbd + tmp); + tmp = (u32)info->rxbd; + info->txbd = + (cbd_t *)((u32)info->txbd + tmp + + (PKTBUFSRX * sizeof(cbd_t))); + tmp = (u32)info->txbd; + info->txbuf = + (char *)((u32)info->txbuf + tmp + + (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t))); + tmp = (u32)info->txbuf; #else - 0, /* RX BD */ + info->rxbd = + (cbd_t *)memalign(CONFIG_SYS_CACHELINE_SIZE, + (PKTBUFSRX * sizeof(cbd_t))); + info->txbd = + (cbd_t *)memalign(CONFIG_SYS_CACHELINE_SIZE, + (TX_BUF_CNT * sizeof(cbd_t))); + info->txbuf = + (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH); #endif - 0, /* TX BD */ - 0, /* rx Index */ - 0, /* tx Index */ - 0, /* tx buffer */ - 0, /* initialized flag */ - (struct fec_info_s *)-1, - } + +#ifdef ET_DEBUG + printf("rxbd %x txbd %x\n", (int)info->rxbd, (int)info->txbd); #endif -}; + info->phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32); +} + +static void fec_reset(struct fec_info_s *info) +{ + volatile fec_t *fecp = (fec_t *)(info->iobase); + int i; + + fecp->ecr = FEC_ECR_RESET; + for (i = 0; (fecp->ecr & FEC_ECR_RESET) && (i < FEC_RESET_DELAY); ++i) + udelay(1); -int fec_recv(struct eth_device *dev); -int fec_init(struct eth_device *dev, bd_t * bd); -void fec_halt(struct eth_device *dev); -void fec_reset(struct eth_device *dev); + if (i == FEC_RESET_DELAY) + printf("FEC_RESET_DELAY timeout\n"); +} -void setFecDuplexSpeed(volatile fec_t * fecp, bd_t * bd, int dup_spd) +static void set_fec_duplex_speed(volatile fec_t *fecp, int dup_spd) { + bd_t *bd = gd->bd; + if ((dup_spd >> 16) == FULL) { /* Set maximum frame length */ fecp->rcr = FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE) | FEC_RCR_MII_MODE | @@ -116,138 +120,11 @@ void setFecDuplexSpeed(volatile fec_t * fecp, bd_t * bd, int dup_spd) } } -static int fec_send(struct eth_device *dev, void *packet, int length) -{ - struct fec_info_s *info = dev->priv; - volatile fec_t *fecp = (fec_t *) (info->iobase); - int j, rc; - u16 phyStatus; - - miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phyStatus); - - /* section 16.9.23.3 - * Wait for ready - */ - j = 0; - while ((info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_READY) && - (j < MCFFEC_TOUT_LOOP)) { - udelay(1); - j++; - } - if (j >= MCFFEC_TOUT_LOOP) { - printf("TX not ready\n"); - } - - info->txbd[info->txIdx].cbd_bufaddr = (uint) packet; - info->txbd[info->txIdx].cbd_datlen = length; - info->txbd[info->txIdx].cbd_sc |= BD_ENET_TX_RDY_LST; - - /* Activate transmit Buffer Descriptor polling */ - fecp->tdar = 0x01000000; /* Descriptor polling active */ - -#ifndef CONFIG_SYS_FEC_BUF_USE_SRAM - /* - * FEC unable to initial transmit data packet. - * A nop will ensure the descriptor polling active completed. - * CF Internal RAM has shorter cycle access than DRAM. If use - * DRAM as Buffer descriptor and data, a nop is a must. - * Affect only V2 and V3. - */ - __asm__ ("nop"); - -#endif - -#ifdef CONFIG_SYS_UNIFY_CACHE - icache_invalid(); -#endif - - j = 0; - while ((info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_READY) && - (j < MCFFEC_TOUT_LOOP)) { - udelay(1); - j++; - } - if (j >= MCFFEC_TOUT_LOOP) { - printf("TX timeout\n"); - } - -#ifdef ET_DEBUG - printf("%s[%d] %s: cycles: %d status: %x retry cnt: %d\n", - __FILE__, __LINE__, __FUNCTION__, j, - info->txbd[info->txIdx].cbd_sc, - (info->txbd[info->txIdx].cbd_sc & 0x003C) >> 2); -#endif - - /* return only status bits */ - rc = (info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_STATS); - info->txIdx = (info->txIdx + 1) % TX_BUF_CNT; - - return rc; -} - -int fec_recv(struct eth_device *dev) -{ - struct fec_info_s *info = dev->priv; - volatile fec_t *fecp = (fec_t *) (info->iobase); - int length; - - for (;;) { -#ifndef CONFIG_SYS_FEC_BUF_USE_SRAM -#endif -#ifdef CONFIG_SYS_UNIFY_CACHE - icache_invalid(); -#endif - /* section 16.9.23.2 */ - if (info->rxbd[info->rxIdx].cbd_sc & BD_ENET_RX_EMPTY) { - length = -1; - break; /* nothing received - leave for() loop */ - } - - length = info->rxbd[info->rxIdx].cbd_datlen; - - if (info->rxbd[info->rxIdx].cbd_sc & 0x003f) { - printf("%s[%d] err: %x\n", - __FUNCTION__, __LINE__, - info->rxbd[info->rxIdx].cbd_sc); -#ifdef ET_DEBUG - printf("%s[%d] err: %x\n", - __FUNCTION__, __LINE__, - info->rxbd[info->rxIdx].cbd_sc); -#endif - } else { - - length -= 4; - /* Pass the packet up to the protocol layers. */ - net_process_received_packet(net_rx_packets[info->rxIdx], - length); - - fecp->eir |= FEC_EIR_RXF; - } - - /* Give the buffer back to the FEC. */ - info->rxbd[info->rxIdx].cbd_datlen = 0; - - /* wrap around buffer index when necessary */ - if (info->rxIdx == LAST_PKTBUFSRX) { - info->rxbd[PKTBUFSRX - 1].cbd_sc = BD_ENET_RX_W_E; - info->rxIdx = 0; - } else { - info->rxbd[info->rxIdx].cbd_sc = BD_ENET_RX_EMPTY; - info->rxIdx++; - } - - /* Try to fill Buffer Descriptors */ - fecp->rdar = 0x01000000; /* Descriptor polling active */ - } - - return length; -} - #ifdef ET_DEBUG -void dbgFecRegs(struct eth_device *dev) +static void dbg_fec_regs(struct udevice *dev) { struct fec_info_s *info = dev->priv; - volatile fec_t *fecp = (fec_t *) (info->iobase); + volatile fec_t *fecp = (fec_t *)(info->iobase); printf("=====\n"); printf("ievent %x - %x\n", (int)&fecp->eir, fecp->eir); @@ -394,28 +271,27 @@ void dbgFecRegs(struct eth_device *dev) } #endif -int fec_init(struct eth_device *dev, bd_t * bd) +int mcffec_init(struct udevice *dev) { struct fec_info_s *info = dev->priv; volatile fec_t *fecp = (fec_t *) (info->iobase); - int i; + int rval, i; uchar ea[6]; - fecpin_setclear(dev, 1); - - fec_reset(dev); + fecpin_setclear(info, 1); + fec_reset(info); #if defined(CONFIG_CMD_MII) || defined (CONFIG_MII) || \ defined (CONFIG_SYS_DISCOVER_PHY) mii_init(); - setFecDuplexSpeed(fecp, bd, info->dup_spd); + set_fec_duplex_speed(fecp, info->dup_spd); #else #ifndef CONFIG_SYS_DISCOVER_PHY - setFecDuplexSpeed(fecp, bd, (FECDUPLEX << 16) | FECSPEED); -#endif /* ifndef CONFIG_SYS_DISCOVER_PHY */ -#endif /* CONFIG_CMD_MII || CONFIG_MII */ + set_fec_duplex_speed(fecp, (FECDUPLEX << 16) | FECSPEED); +#endif /* ifndef CONFIG_SYS_DISCOVER_PHY */ +#endif /* CONFIG_CMD_MII || CONFIG_MII */ /* We use strictly polling mode only */ fecp->eimr = 0; @@ -424,34 +300,20 @@ int fec_init(struct eth_device *dev, bd_t * bd) fecp->eir = 0xffffffff; /* Set station address */ - if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE) { -#ifdef CONFIG_SYS_FEC1_IOBASE - volatile fec_t *fecp1 = (fec_t *) (CONFIG_SYS_FEC1_IOBASE); - eth_env_get_enetaddr("eth1addr", ea); - fecp1->palr = - (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]); - fecp1->paur = (ea[4] << 24) | (ea[5] << 16); -#endif - eth_env_get_enetaddr("ethaddr", ea); - fecp->palr = - (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]); - fecp->paur = (ea[4] << 24) | (ea[5] << 16); - } else { -#ifdef CONFIG_SYS_FEC0_IOBASE - volatile fec_t *fecp0 = (fec_t *) (CONFIG_SYS_FEC0_IOBASE); - eth_env_get_enetaddr("ethaddr", ea); - fecp0->palr = - (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]); - fecp0->paur = (ea[4] << 24) | (ea[5] << 16); -#endif -#ifdef CONFIG_SYS_FEC1_IOBASE - eth_env_get_enetaddr("eth1addr", ea); - fecp->palr = - (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]); - fecp->paur = (ea[4] << 24) | (ea[5] << 16); -#endif + if (info->index == 0) + rval = eth_env_get_enetaddr("ethaddr", ea); + else + rval = eth_env_get_enetaddr("eth1addr", ea); + + if (!rval) { + puts("Please set a valid MAC address\n"); + return -EINVAL; } + fecp->palr = + (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]); + fecp->paur = (ea[4] << 24) | (ea[5] << 16); + /* Clear unicast address hash table */ fecp->iaur = 0; fecp->ialr = 0; @@ -466,8 +328,8 @@ int fec_init(struct eth_device *dev, bd_t * bd) /* * Setup Buffers and Buffer Descriptors */ - info->rxIdx = 0; - info->txIdx = 0; + info->rx_idx = 0; + info->tx_idx = 0; /* * Setup Receiver Buffer Descriptors (13.14.24.18) @@ -500,119 +362,256 @@ int fec_init(struct eth_device *dev, bd_t * bd) /* Now enable the transmit and receive processing */ fecp->ecr |= FEC_ECR_ETHER_EN; - /* And last, try to fill Rx Buffer Descriptors */ - fecp->rdar = 0x01000000; /* Descriptor polling active */ + /* And last, try to fill Rx Buffer Descriptors + * Descriptor polling active + */ + fecp->rdar = 0x01000000; - return 1; + return 0; } -void fec_reset(struct eth_device *dev) +static int mcffec_send(struct udevice *dev, void *packet, int length) { struct fec_info_s *info = dev->priv; - volatile fec_t *fecp = (fec_t *) (info->iobase); - int i; + volatile fec_t *fecp = (fec_t *)info->iobase; + int j, rc; + u16 phy_status; - fecp->ecr = FEC_ECR_RESET; - for (i = 0; (fecp->ecr & FEC_ECR_RESET) && (i < FEC_RESET_DELAY); ++i) { + miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phy_status); + + /* section 16.9.23.3 + * Wait for ready + */ + j = 0; + while ((info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_READY) && + (j < info->to_loop)) { udelay(1); + j++; } - if (i == FEC_RESET_DELAY) { - printf("FEC_RESET_DELAY timeout\n"); + if (j >= info->to_loop) + printf("TX not ready\n"); + + info->txbd[info->tx_idx].cbd_bufaddr = (uint)packet; + info->txbd[info->tx_idx].cbd_datlen = length; + info->txbd[info->tx_idx].cbd_sc |= BD_ENET_TX_RDY_LST; + + /* Activate transmit Buffer Descriptor polling */ + fecp->tdar = 0x01000000; /* Descriptor polling active */ + +#ifndef CONFIG_SYS_FEC_BUF_USE_SRAM + /* + * FEC unable to initial transmit data packet. + * A nop will ensure the descriptor polling active completed. + * CF Internal RAM has shorter cycle access than DRAM. If use + * DRAM as Buffer descriptor and data, a nop is a must. + * Affect only V2 and V3. + */ + __asm__ ("nop"); +#endif + +#ifdef CONFIG_SYS_UNIFY_CACHE + icache_invalid(); +#endif + + j = 0; + while ((info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_READY) && + (j < info->to_loop)) { + udelay(1); + j++; + } + if (j >= info->to_loop) + printf("TX timeout\n"); + +#ifdef ET_DEBUG + printf("%s[%d] %s: cycles: %d status: %x retry cnt: %d\n", + __FILE__, __LINE__, __func__, j, + info->txbd[info->tx_idx].cbd_sc, + (info->txbd[info->tx_idx].cbd_sc & 0x003C) >> 2); +#endif + + /* return only status bits */ + rc = (info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_STATS); + info->tx_idx = (info->tx_idx + 1) % TX_BUF_CNT; + + return rc; +} + +static int mcffec_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct fec_info_s *info = dev->priv; + volatile fec_t *fecp = (fec_t *)info->iobase; + int length = -1; + + for (;;) { +#ifdef CONFIG_SYS_UNIFY_CACHE + icache_invalid(); +#endif + /* If nothing received - leave for() loop */ + if (info->rxbd[info->rx_idx].cbd_sc & BD_ENET_RX_EMPTY) + break; + + length = info->rxbd[info->rx_idx].cbd_datlen; + + if (info->rxbd[info->rx_idx].cbd_sc & 0x003f) { + printf("%s[%d] err: %x\n", + __func__, __LINE__, + info->rxbd[info->rx_idx].cbd_sc); + } else { + length -= 4; + + /* + * Pass the buffer ptr up to the protocol layers. + */ + *packetp = net_rx_packets[info->rx_idx]; + + fecp->eir |= FEC_EIR_RXF; + } + + /* Give the buffer back to the FEC. */ + info->rxbd[info->rx_idx].cbd_datlen = 0; + + /* wrap around buffer index when necessary */ + if (info->rx_idx == LAST_PKTBUFSRX) { + info->rxbd[PKTBUFSRX - 1].cbd_sc = BD_ENET_RX_W_E; + info->rx_idx = 0; + } else { + info->rxbd[info->rx_idx].cbd_sc = BD_ENET_RX_EMPTY; + info->rx_idx++; + } + + /* Try to fill Buffer Descriptors + * Descriptor polling active + */ + fecp->rdar = 0x01000000; } + + return length; } -void fec_halt(struct eth_device *dev) +static void mcffec_halt(struct udevice *dev) { struct fec_info_s *info = dev->priv; - fec_reset(dev); + fec_reset(info); + fecpin_setclear(info, 0); - fecpin_setclear(dev, 0); + info->rx_idx = 0; + info->tx_idx = 0; - info->rxIdx = info->txIdx = 0; memset(info->rxbd, 0, PKTBUFSRX * sizeof(cbd_t)); memset(info->txbd, 0, TX_BUF_CNT * sizeof(cbd_t)); memset(info->txbuf, 0, DBUF_LENGTH); } -int mcffec_initialize(bd_t * bis) +static const struct eth_ops mcffec_ops = { + .start = mcffec_init, + .send = mcffec_send, + .recv = mcffec_recv, + .stop = mcffec_halt, +}; + +/* + * Boot sequence, called just after mcffec_ofdata_to_platdata, + * as DM way, it replaces old mcffec_initialize. + */ +static int mcffec_probe(struct udevice *dev) { - struct eth_device *dev; - int i; -#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM - u32 tmp = CONFIG_SYS_INIT_RAM_ADDR + 0x1000; -#endif + struct eth_pdata *pdata = dev_get_platdata(dev); + struct fec_info_s *info = dev->priv; + int node = dev_of_offset(dev); + int retval, fec_idx; + const u32 *val; - for (i = 0; i < ARRAY_SIZE(fec_info); i++) { + info->index = dev->seq; + info->iobase = pdata->iobase; + info->phy_addr = -1; - dev = - (struct eth_device *)memalign(CONFIG_SYS_CACHELINE_SIZE, - sizeof *dev); - if (dev == NULL) - hang(); + val = fdt_getprop(gd->fdt_blob, node, "mii-base", NULL); + if (val) { + u32 fec_iobase; - memset(dev, 0, sizeof(*dev)); + fec_idx = fdt32_to_cpu(*val); + if (fec_idx == info->index) { + fec_iobase = info->iobase; + } else { + printf("mii base != base address, fec_idx %d\n", + fec_idx); + retval = fec_get_base_addr(fec_idx, &fec_iobase); + if (retval) + return retval; + } + info->miibase = fec_iobase; + } - sprintf(dev->name, "FEC%d", fec_info[i].index); + val = fdt_getprop(gd->fdt_blob, node, "phy-addr", NULL); + if (val) + info->phy_addr = fdt32_to_cpu(*val); - dev->priv = &fec_info[i]; - dev->init = fec_init; - dev->halt = fec_halt; - dev->send = fec_send; - dev->recv = fec_recv; + val = fdt_getprop(gd->fdt_blob, node, "timeout-loop", NULL); + if (val) + info->to_loop = fdt32_to_cpu(*val); - /* setup Receive and Transmit buffer descriptor */ -#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM - fec_info[i].rxbd = (cbd_t *)((u32)fec_info[i].rxbd + tmp); - tmp = (u32)fec_info[i].rxbd; - fec_info[i].txbd = - (cbd_t *)((u32)fec_info[i].txbd + tmp + - (PKTBUFSRX * sizeof(cbd_t))); - tmp = (u32)fec_info[i].txbd; - fec_info[i].txbuf = - (char *)((u32)fec_info[i].txbuf + tmp + - (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t))); - tmp = (u32)fec_info[i].txbuf; -#else - fec_info[i].rxbd = - (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE, - (PKTBUFSRX * sizeof(cbd_t))); - fec_info[i].txbd = - (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE, - (TX_BUF_CNT * sizeof(cbd_t))); - fec_info[i].txbuf = - (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH); -#endif + init_eth_info(info); -#ifdef ET_DEBUG - printf("rxbd %x txbd %x\n", - (int)fec_info[i].rxbd, (int)fec_info[i].txbd); +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + info->bus = mdio_alloc(); + if (!info->bus) + return -ENOMEM; + strcpy(info->bus->name, dev->name); + info->bus->read = mcffec_miiphy_read; + info->bus->write = mcffec_miiphy_write; + + retval = mdio_register(info->bus); + if (retval < 0) + return retval; #endif - fec_info[i].phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32); + return 0; +} - eth_register(dev); +static int mcffec_remove(struct udevice *dev) +{ + struct fec_info_s *priv = dev_get_priv(dev); -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) - int retval; - struct mii_dev *mdiodev = mdio_alloc(); - if (!mdiodev) - return -ENOMEM; - strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); - mdiodev->read = mcffec_miiphy_read; - mdiodev->write = mcffec_miiphy_write; - - retval = mdio_register(mdiodev); - if (retval < 0) - return retval; -#endif - if (i > 0) - fec_info[i - 1].next = &fec_info[i]; - } - fec_info[i - 1].next = &fec_info[0]; + mdio_unregister(priv->bus); + mdio_free(priv->bus); + + return 0; +} + +/* + * Boot sequence, called 1st + */ +static int mcffec_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + const u32 *val; - /* default speed */ - bis->bi_ethspeed = 10; + pdata->iobase = (phys_addr_t)devfdt_get_addr(dev); + /* Default to 10Mbit/s */ + pdata->max_speed = 10; + + val = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), + "max-speed", NULL); + if (val) + pdata->max_speed = fdt32_to_cpu(*val); return 0; } + +static const struct udevice_id mcffec_ids[] = { + { .compatible = "fsl,mcf-fec" }, + { } +}; + +U_BOOT_DRIVER(mcffec) = { + .name = "mcffec", + .id = UCLASS_ETH, + .of_match = mcffec_ids, + .ofdata_to_platdata = mcffec_ofdata_to_platdata, + .probe = mcffec_probe, + .remove = mcffec_remove, + .ops = &mcffec_ops, + .priv_auto_alloc_size = sizeof(struct fec_info_s), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; -- cgit v1.3.1 From 05ffdc85cac85825ed0dc525ab28f4fa12a84574 Mon Sep 17 00:00:00 2001 From: Angelo Durgehello Date: Fri, 15 Nov 2019 23:54:19 +0100 Subject: drivers: fsl_mcdmafec: conversion to dm Full conversion to dm for all boards, legacy code removed. Signed-off-by: Angelo Durgehello --- doc/device-tree-bindings/net/fsl,mcf-dma-fec.txt | 35 ++ drivers/net/fsl_mcdmafec.c | 691 ++++++++++++----------- 2 files changed, 389 insertions(+), 337 deletions(-) create mode 100644 doc/device-tree-bindings/net/fsl,mcf-dma-fec.txt (limited to 'drivers') diff --git a/doc/device-tree-bindings/net/fsl,mcf-dma-fec.txt b/doc/device-tree-bindings/net/fsl,mcf-dma-fec.txt new file mode 100644 index 00000000000..e237825bac6 --- /dev/null +++ b/doc/device-tree-bindings/net/fsl,mcf-dma-fec.txt @@ -0,0 +1,35 @@ +* Freescale ColdFire DMA-FEC ethernet controller + +Required properties: +- compatible: should be "fsl,mcf-dma-fec" +- reg: address and length of the register set for the device. +- rx-task: dma channel +- tx-task: dma channel +- rx-priority: dma channel +- tx-priority: dma channel +- rx-init: dma channel +- tx-init: dma channel + +Optional properties: +- mii-base: index of FEC reg area, 0 for FEC0, 1 for FEC1 +- max-speed: max speedm Mbits/sec +- phy-addr: phy address +- timeout-loop: integer value for driver loops time out + + +Example: + +fec0: ethernet@9000 { + compatible = "fsl,mcf-dma-fec"; + reg = <0x9000 0x800>; + mii-base = <0>; + phy-addr = <0>; + timeout-loop = <5000>; + rx-task = <0>; + tx-task = <1>; + rx-piority = <6>; + tx-piority = <7>; + rx-init = <16>; + tx-init = <17>; + status = "disabled"; +}; diff --git a/drivers/net/fsl_mcdmafec.c b/drivers/net/fsl_mcdmafec.c index b2936b78d7b..7838fb5c10a 100644 --- a/drivers/net/fsl_mcdmafec.c +++ b/drivers/net/fsl_mcdmafec.c @@ -5,6 +5,9 @@ * * (C) Copyright 2007 Freescale Semiconductor, Inc. * TsiChung Liew (Tsi-Chung.Liew@freescale.com) + * + * Conversion to DM + * (C) 2019 Angelo Dureghello */ #include @@ -15,6 +18,10 @@ #include #include #include +#include +#include + +#include "MCD_dma.h" #undef ET_DEBUG #undef MII_DEBUG @@ -22,93 +29,94 @@ /* Ethernet Transmit and Receive Buffers */ #define DBUF_LENGTH 1520 #define PKT_MAXBUF_SIZE 1518 -#define PKT_MINBUF_SIZE 64 -#define PKT_MAXBLR_SIZE 1536 -#define LAST_PKTBUFSRX PKTBUFSRX - 1 -#define BD_ENET_RX_W_E (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY) -#define BD_ENET_TX_RDY_LST (BD_ENET_TX_READY | BD_ENET_TX_LAST) #define FIFO_ERRSTAT (FIFO_STAT_RXW | FIFO_STAT_UF | FIFO_STAT_OF) /* RxBD bits definitions */ #define BD_ENET_RX_ERR (BD_ENET_RX_LG | BD_ENET_RX_NO | BD_ENET_RX_CR | \ BD_ENET_RX_OV | BD_ENET_RX_TR) -#include -#include +DECLARE_GLOBAL_DATA_PTR; -#include "MCD_dma.h" +static void init_eth_info(struct fec_info_dma *info) +{ + /* setup Receive and Transmit buffer descriptor */ +#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM + static u32 tmp; -struct fec_info_dma fec_info[] = { -#ifdef CONFIG_SYS_FEC0_IOBASE - { - 0, /* index */ - CONFIG_SYS_FEC0_IOBASE, /* io base */ - CONFIG_SYS_FEC0_PINMUX, /* gpio pin muxing */ - CONFIG_SYS_FEC0_MIIBASE, /* mii base */ - -1, /* phy_addr */ - 0, /* duplex and speed */ - 0, /* phy name */ - 0, /* phyname init */ - 0, /* RX BD */ - 0, /* TX BD */ - 0, /* rx Index */ - 0, /* tx Index */ - 0, /* tx buffer */ - 0, /* initialized flag */ - (struct fec_info_dma *)-1, /* next */ - FEC0_RX_TASK, /* rxTask */ - FEC0_TX_TASK, /* txTask */ - FEC0_RX_PRIORITY, /* rxPri */ - FEC0_TX_PRIORITY, /* txPri */ - FEC0_RX_INIT, /* rxInit */ - FEC0_TX_INIT, /* txInit */ - 0, /* usedTbdIndex */ - 0, /* cleanTbdNum */ - }, -#endif -#ifdef CONFIG_SYS_FEC1_IOBASE - { - 1, /* index */ - CONFIG_SYS_FEC1_IOBASE, /* io base */ - CONFIG_SYS_FEC1_PINMUX, /* gpio pin muxing */ - CONFIG_SYS_FEC1_MIIBASE, /* mii base */ - -1, /* phy_addr */ - 0, /* duplex and speed */ - 0, /* phy name */ - 0, /* phy name init */ -#ifdef CONFIG_SYS_DMA_USE_INTSRAM - (cbd_t *)DBUF_LENGTH, /* RX BD */ + if (info->index == 0) + tmp = CONFIG_SYS_INIT_RAM_ADDR + 0x1000; + else + info->rxbd = (cbd_t *)DBUF_LENGTH; + + info->rxbd = (cbd_t *)((u32)info->rxbd + tmp); + tmp = (u32)info->rxbd; + info->txbd = + (cbd_t *)((u32)info->txbd + tmp + + (PKTBUFSRX * sizeof(cbd_t))); + tmp = (u32)info->txbd; + info->txbuf = + (char *)((u32)info->txbuf + tmp + + (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t))); + tmp = (u32)info->txbuf; #else - 0, /* RX BD */ + info->rxbd = + (cbd_t *)memalign(CONFIG_SYS_CACHELINE_SIZE, + (PKTBUFSRX * sizeof(cbd_t))); + info->txbd = + (cbd_t *)memalign(CONFIG_SYS_CACHELINE_SIZE, + (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t))); + info->txbuf = + (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH); #endif - 0, /* TX BD */ - 0, /* rx Index */ - 0, /* tx Index */ - 0, /* tx buffer */ - 0, /* initialized flag */ - (struct fec_info_dma *)-1, /* next */ - FEC1_RX_TASK, /* rxTask */ - FEC1_TX_TASK, /* txTask */ - FEC1_RX_PRIORITY, /* rxPri */ - FEC1_TX_PRIORITY, /* txPri */ - FEC1_RX_INIT, /* rxInit */ - FEC1_TX_INIT, /* txInit */ - 0, /* usedTbdIndex */ - 0, /* cleanTbdNum */ - } + +#ifdef ET_DEBUG + printf("rxbd %x txbd %x\n", (int)info->rxbd, (int)info->txbd); #endif -}; + info->phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32); +} + +static void fec_halt(struct udevice *dev) +{ + struct fec_info_dma *info = dev->priv; + volatile fecdma_t *fecp = (fecdma_t *)info->iobase; + int counter = 0xffff; + + /* issue graceful stop command to the FEC transmitter if necessary */ + fecp->tcr |= FEC_TCR_GTS; + + /* wait for graceful stop to register */ + while ((counter--) && (!(fecp->eir & FEC_EIR_GRA))) + ; + + /* Disable DMA tasks */ + MCD_killDma(info->tx_task); + MCD_killDma(info->rx_task); + + /* Disable the Ethernet Controller */ + fecp->ecr &= ~FEC_ECR_ETHER_EN; + + /* Clear FIFO status registers */ + fecp->rfsr &= FIFO_ERRSTAT; + fecp->tfsr &= FIFO_ERRSTAT; + + fecp->frst = 0x01000000; -static int fec_send(struct eth_device *dev, void *packet, int length); -static int fec_recv(struct eth_device *dev); -static int fec_init(struct eth_device *dev, bd_t * bd); -static void fec_halt(struct eth_device *dev); + /* Issue a reset command to the FEC chip */ + fecp->ecr |= FEC_ECR_RESET; + + /* wait at least 20 clock cycles */ + mdelay(10); + +#ifdef ET_DEBUG + printf("Ethernet task stopped\n"); +#endif +} #ifdef ET_DEBUG static void dbg_fec_regs(struct eth_device *dev) { struct fec_info_dma *info = dev->priv; - volatile fecdma_t *fecp = (fecdma_t *) (info->iobase); + volatile fecdma_t *fecp = (fecdma_t *)info->iobase; printf("=====\n"); printf("ievent %x - %x\n", (int)&fecp->eir, fecp->eir); @@ -149,9 +157,10 @@ static void dbg_fec_regs(struct eth_device *dev) } #endif -static void set_fec_duplex_speed(volatile fecdma_t * fecp, bd_t * bd, - int dup_spd) +static void set_fec_duplex_speed(volatile fecdma_t *fecp, int dup_spd) { + bd_t *bd = gd->bd; + if ((dup_spd >> 16) == FULL) { /* Set maximum frame length */ fecp->rcr = FEC_RCR_MAX_FL(PKT_MAXBUF_SIZE) | FEC_RCR_MII_MODE | @@ -177,153 +186,23 @@ static void set_fec_duplex_speed(volatile fecdma_t * fecp, bd_t * bd, } } -static int fec_send(struct eth_device *dev, void *packet, int length) -{ - struct fec_info_dma *info = dev->priv; - cbd_t *pTbd, *pUsedTbd; - u16 phyStatus; - - miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phyStatus); - - /* process all the consumed TBDs */ - while (info->cleanTbdNum < CONFIG_SYS_TX_ETH_BUFFER) { - pUsedTbd = &info->txbd[info->usedTbdIdx]; - if (pUsedTbd->cbd_sc & BD_ENET_TX_READY) { -#ifdef ET_DEBUG - printf("Cannot clean TBD %d, in use\n", - info->cleanTbdNum); -#endif - return 0; - } - - /* clean this buffer descriptor */ - if (info->usedTbdIdx == (CONFIG_SYS_TX_ETH_BUFFER - 1)) - pUsedTbd->cbd_sc = BD_ENET_TX_WRAP; - else - pUsedTbd->cbd_sc = 0; - - /* update some indeces for a correct handling of the TBD ring */ - info->cleanTbdNum++; - info->usedTbdIdx = (info->usedTbdIdx + 1) % CONFIG_SYS_TX_ETH_BUFFER; - } - - /* Check for valid length of data. */ - if ((length > 1500) || (length <= 0)) { - return -1; - } - - /* Check the number of vacant TxBDs. */ - if (info->cleanTbdNum < 1) { - printf("No available TxBDs ...\n"); - return -1; - } - - /* Get the first TxBD to send the mac header */ - pTbd = &info->txbd[info->txIdx]; - pTbd->cbd_datlen = length; - pTbd->cbd_bufaddr = (u32) packet; - pTbd->cbd_sc |= BD_ENET_TX_LAST | BD_ENET_TX_TC | BD_ENET_TX_READY; - info->txIdx = (info->txIdx + 1) % CONFIG_SYS_TX_ETH_BUFFER; - - /* Enable DMA transmit task */ - MCD_continDma(info->txTask); - - info->cleanTbdNum -= 1; - - /* wait until frame is sent . */ - while (pTbd->cbd_sc & BD_ENET_TX_READY) { - udelay(10); - } - - return (int)(info->txbd[info->txIdx].cbd_sc & BD_ENET_TX_STATS); -} - -static int fec_recv(struct eth_device *dev) -{ - struct fec_info_dma *info = dev->priv; - volatile fecdma_t *fecp = (fecdma_t *) (info->iobase); - - cbd_t *prbd = &info->rxbd[info->rxIdx]; - u32 ievent; - int frame_length, len = 0; - - /* Check if any critical events have happened */ - ievent = fecp->eir; - if (ievent != 0) { - fecp->eir = ievent; - - if (ievent & (FEC_EIR_BABT | FEC_EIR_TXERR | FEC_EIR_RXERR)) { - printf("fec_recv: error\n"); - fec_halt(dev); - fec_init(dev, NULL); - return 0; - } - - if (ievent & FEC_EIR_HBERR) { - /* Heartbeat error */ - fecp->tcr |= FEC_TCR_GTS; - } - - if (ievent & FEC_EIR_GRA) { - /* Graceful stop complete */ - if (fecp->tcr & FEC_TCR_GTS) { - printf("fec_recv: tcr_gts\n"); - fec_halt(dev); - fecp->tcr &= ~FEC_TCR_GTS; - fec_init(dev, NULL); - } - } - } - - if (!(prbd->cbd_sc & BD_ENET_RX_EMPTY)) { - if ((prbd->cbd_sc & BD_ENET_RX_LAST) && - !(prbd->cbd_sc & BD_ENET_RX_ERR) && - ((prbd->cbd_datlen - 4) > 14)) { - - /* Get buffer address and size */ - frame_length = prbd->cbd_datlen - 4; - - /* Fill the buffer and pass it to upper layers */ - net_process_received_packet((uchar *)prbd->cbd_bufaddr, - frame_length); - len = frame_length; - } - - /* Reset buffer descriptor as empty */ - if ((info->rxIdx) == (PKTBUFSRX - 1)) - prbd->cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY); - else - prbd->cbd_sc = BD_ENET_RX_EMPTY; - - prbd->cbd_datlen = PKTSIZE_ALIGN; - - /* Now, we have an empty RxBD, restart the DMA receive task */ - MCD_continDma(info->rxTask); - - /* Increment BD count */ - info->rxIdx = (info->rxIdx + 1) % PKTBUFSRX; - } - - return len; -} - -static void fec_set_hwaddr(volatile fecdma_t * fecp, u8 * mac) +static void fec_set_hwaddr(volatile fecdma_t *fecp, u8 *mac) { - u8 currByte; /* byte for which to compute the CRC */ + u8 curr_byte; /* byte for which to compute the CRC */ int byte; /* loop - counter */ int bit; /* loop - counter */ u32 crc = 0xffffffff; /* initial value */ for (byte = 0; byte < 6; byte++) { - currByte = mac[byte]; + curr_byte = mac[byte]; for (bit = 0; bit < 8; bit++) { - if ((currByte & 0x01) ^ (crc & 0x01)) { + if ((curr_byte & 0x01) ^ (crc & 0x01)) { crc >>= 1; crc = crc ^ 0xedb88320; } else { crc >>= 1; } - currByte >>= 1; + curr_byte >>= 1; } } @@ -347,30 +226,28 @@ static void fec_set_hwaddr(volatile fecdma_t * fecp, u8 * mac) fecp->galr = 0; } -static int fec_init(struct eth_device *dev, bd_t * bd) +static int fec_init(struct udevice *dev) { struct fec_info_dma *info = dev->priv; - volatile fecdma_t *fecp = (fecdma_t *) (info->iobase); - int i; + volatile fecdma_t *fecp = (fecdma_t *)info->iobase; + int rval, i; uchar enetaddr[6]; #ifdef ET_DEBUG printf("fec_init: iobase 0x%08x ...\n", info->iobase); #endif - fecpin_setclear(dev, 1); - + fecpin_setclear(info, 1); fec_halt(dev); #if defined(CONFIG_CMD_MII) || defined (CONFIG_MII) || \ defined (CONFIG_SYS_DISCOVER_PHY) mii_init(); - - set_fec_duplex_speed(fecp, bd, info->dup_spd); + set_fec_duplex_speed(fecp, info->dup_spd); #else #ifndef CONFIG_SYS_DISCOVER_PHY - set_fec_duplex_speed(fecp, bd, (FECDUPLEX << 16) | FECSPEED); + set_fec_duplex_speed(fecp, (FECDUPLEX << 16) | FECSPEED); #endif /* ifndef CONFIG_SYS_DISCOVER_PHY */ #endif /* CONFIG_CMD_MII || CONFIG_MII */ @@ -381,18 +258,24 @@ static int fec_init(struct eth_device *dev, bd_t * bd) fecp->eir = 0xffffffff; /* Set station address */ - if ((u32) fecp == CONFIG_SYS_FEC0_IOBASE) - eth_env_get_enetaddr("ethaddr", enetaddr); + if (info->index == 0) + rval = eth_env_get_enetaddr("ethaddr", enetaddr); else - eth_env_get_enetaddr("eth1addr", enetaddr); + rval = eth_env_get_enetaddr("eth1addr", enetaddr); + + if (!rval) { + puts("Please set a valid MAC address\n"); + return -EINVAL; + } + fec_set_hwaddr(fecp, enetaddr); /* Set Opcode/Pause Duration Register */ fecp->opd = 0x00010020; /* Setup Buffers and Buffer Descriptors */ - info->rxIdx = 0; - info->txIdx = 0; + info->rx_idx = 0; + info->tx_idx = 0; /* Setup Receiver Buffer Descriptors (13.14.24.18) * Settings: Empty, Wrap */ @@ -412,8 +295,8 @@ static int fec_init(struct eth_device *dev, bd_t * bd) } info->txbd[CONFIG_SYS_TX_ETH_BUFFER - 1].cbd_sc |= BD_ENET_TX_WRAP; - info->usedTbdIdx = 0; - info->cleanTbdNum = CONFIG_SYS_TX_ETH_BUFFER; + info->used_tbd_idx = 0; + info->clean_tbd_num = CONFIG_SYS_TX_ETH_BUFFER; /* Set Rx FIFO alarm and granularity value */ fecp->rfcr = 0x0c000000; @@ -427,154 +310,288 @@ static int fec_init(struct eth_device *dev, bd_t * bd) fecp->ctcwr = 0x03000000; /* Enable DMA receive task */ - MCD_startDma(info->rxTask, /* Dma channel */ - (s8 *) info->rxbd, /*Source Address */ - 0, /* Source increment */ - (s8 *) (&fecp->rfdr), /* dest */ - 4, /* dest increment */ - 0, /* DMA size */ - 4, /* xfer size */ - info->rxInit, /* initiator */ - info->rxPri, /* priority */ - (MCD_FECRX_DMA | MCD_TT_FLAGS_DEF), /* Flags */ - (MCD_NO_CSUM | MCD_NO_BYTE_SWAP) /* Function description */ + MCD_startDma(info->rx_task, + (s8 *)info->rxbd, + 0, + (s8 *)&fecp->rfdr, + 4, + 0, + 4, + info->rx_init, + info->rx_pri, + (MCD_FECRX_DMA | MCD_TT_FLAGS_DEF), + (MCD_NO_CSUM | MCD_NO_BYTE_SWAP) ); /* Enable DMA tx task with no ready buffer descriptors */ - MCD_startDma(info->txTask, /* Dma channel */ - (s8 *) info->txbd, /*Source Address */ - 0, /* Source increment */ - (s8 *) (&fecp->tfdr), /* dest */ - 4, /* dest incr */ - 0, /* DMA size */ - 4, /* xfer size */ - info->txInit, /* initiator */ - info->txPri, /* priority */ - (MCD_FECTX_DMA | MCD_TT_FLAGS_DEF), /* Flags */ - (MCD_NO_CSUM | MCD_NO_BYTE_SWAP) /* Function description */ + MCD_startDma(info->tx_task, + (s8 *)info->txbd, + 0, + (s8 *)&fecp->tfdr, + 4, + 0, + 4, + info->tx_init, + info->tx_pri, + (MCD_FECTX_DMA | MCD_TT_FLAGS_DEF), + (MCD_NO_CSUM | MCD_NO_BYTE_SWAP) ); /* Now enable the transmit and receive processing */ fecp->ecr |= FEC_ECR_ETHER_EN; - return 1; + return 0; +} + +static int mcdmafec_init(struct udevice *dev) +{ + return fec_init(dev); } -static void fec_halt(struct eth_device *dev) +static int mcdmafec_send(struct udevice *dev, void *packet, int length) { struct fec_info_dma *info = dev->priv; - volatile fecdma_t *fecp = (fecdma_t *) (info->iobase); - int counter = 0xffff; + cbd_t *p_tbd, *p_used_tbd; + u16 phy_status; - /* issue graceful stop command to the FEC transmitter if necessary */ - fecp->tcr |= FEC_TCR_GTS; + miiphy_read(dev->name, info->phy_addr, MII_BMSR, &phy_status); - /* wait for graceful stop to register */ - while ((counter--) && (!(fecp->eir & FEC_EIR_GRA))) ; + /* process all the consumed TBDs */ + while (info->clean_tbd_num < CONFIG_SYS_TX_ETH_BUFFER) { + p_used_tbd = &info->txbd[info->used_tbd_idx]; + if (p_used_tbd->cbd_sc & BD_ENET_TX_READY) { +#ifdef ET_DEBUG + printf("Cannot clean TBD %d, in use\n", + info->clean_tbd_num); +#endif + return 0; + } - /* Disable DMA tasks */ - MCD_killDma(info->txTask); - MCD_killDma(info->rxTask); + /* clean this buffer descriptor */ + if (info->used_tbd_idx == (CONFIG_SYS_TX_ETH_BUFFER - 1)) + p_used_tbd->cbd_sc = BD_ENET_TX_WRAP; + else + p_used_tbd->cbd_sc = 0; - /* Disable the Ethernet Controller */ - fecp->ecr &= ~FEC_ECR_ETHER_EN; + /* update some indeces for a correct handling of TBD ring */ + info->clean_tbd_num++; + info->used_tbd_idx = (info->used_tbd_idx + 1) + % CONFIG_SYS_TX_ETH_BUFFER; + } - /* Clear FIFO status registers */ - fecp->rfsr &= FIFO_ERRSTAT; - fecp->tfsr &= FIFO_ERRSTAT; + /* Check for valid length of data. */ + if (length > 1500 || length <= 0) + return -1; - fecp->frst = 0x01000000; + /* Check the number of vacant TxBDs. */ + if (info->clean_tbd_num < 1) { + printf("No available TxBDs ...\n"); + return -1; + } - /* Issue a reset command to the FEC chip */ - fecp->ecr |= FEC_ECR_RESET; + /* Get the first TxBD to send the mac header */ + p_tbd = &info->txbd[info->tx_idx]; + p_tbd->cbd_datlen = length; + p_tbd->cbd_bufaddr = (u32)packet; + p_tbd->cbd_sc |= BD_ENET_TX_LAST | BD_ENET_TX_TC | BD_ENET_TX_READY; + info->tx_idx = (info->tx_idx + 1) % CONFIG_SYS_TX_ETH_BUFFER; - /* wait at least 20 clock cycles */ - udelay(10000); + /* Enable DMA transmit task */ + MCD_continDma(info->tx_task); -#ifdef ET_DEBUG - printf("Ethernet task stopped\n"); -#endif + info->clean_tbd_num -= 1; + + /* wait until frame is sent . */ + while (p_tbd->cbd_sc & BD_ENET_TX_READY) + udelay(10); + + return (int)(info->txbd[info->tx_idx].cbd_sc & BD_ENET_TX_STATS); } -int mcdmafec_initialize(bd_t * bis) +static int mcdmafec_recv(struct udevice *dev, int flags, uchar **packetp) { - struct eth_device *dev; - int i; -#ifdef CONFIG_SYS_DMA_USE_INTSRAM - u32 tmp = CONFIG_SYS_INTSRAM + 0x2000; -#endif + struct fec_info_dma *info = dev->priv; + volatile fecdma_t *fecp = (fecdma_t *)info->iobase; - for (i = 0; i < ARRAY_SIZE(fec_info); i++) { - - dev = - (struct eth_device *)memalign(CONFIG_SYS_CACHELINE_SIZE, - sizeof *dev); - if (dev == NULL) - hang(); - - memset(dev, 0, sizeof(*dev)); - - sprintf(dev->name, "FEC%d", fec_info[i].index); - - dev->priv = &fec_info[i]; - dev->init = fec_init; - dev->halt = fec_halt; - dev->send = fec_send; - dev->recv = fec_recv; - - /* setup Receive and Transmit buffer descriptor */ -#ifdef CONFIG_SYS_DMA_USE_INTSRAM - fec_info[i].rxbd = (cbd_t *)((u32)fec_info[i].rxbd + tmp); - tmp = (u32)fec_info[i].rxbd; - fec_info[i].txbd = - (cbd_t *)((u32)fec_info[i].txbd + tmp + - (PKTBUFSRX * sizeof(cbd_t))); - tmp = (u32)fec_info[i].txbd; - fec_info[i].txbuf = - (char *)((u32)fec_info[i].txbuf + tmp + - (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t))); - tmp = (u32)fec_info[i].txbuf; -#else - fec_info[i].rxbd = - (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE, - (PKTBUFSRX * sizeof(cbd_t))); - fec_info[i].txbd = - (cbd_t *) memalign(CONFIG_SYS_CACHELINE_SIZE, - (CONFIG_SYS_TX_ETH_BUFFER * sizeof(cbd_t))); - fec_info[i].txbuf = - (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, DBUF_LENGTH); -#endif + cbd_t *prbd = &info->rxbd[info->rx_idx]; + u32 ievent; + int frame_length, len = 0; -#ifdef ET_DEBUG - printf("rxbd %x txbd %x\n", - (int)fec_info[i].rxbd, (int)fec_info[i].txbd); -#endif + /* Check if any critical events have happened */ + ievent = fecp->eir; + if (ievent != 0) { + fecp->eir = ievent; - fec_info[i].phy_name = (char *)memalign(CONFIG_SYS_CACHELINE_SIZE, 32); + if (ievent & (FEC_EIR_BABT | FEC_EIR_TXERR | FEC_EIR_RXERR)) { + printf("fec_recv: error\n"); + fec_halt(dev); + fec_init(dev); + return 0; + } - eth_register(dev); + if (ievent & FEC_EIR_HBERR) { + /* Heartbeat error */ + fecp->tcr |= FEC_TCR_GTS; + } + + if (ievent & FEC_EIR_GRA) { + /* Graceful stop complete */ + if (fecp->tcr & FEC_TCR_GTS) { + printf("fec_recv: tcr_gts\n"); + fec_halt(dev); + fecp->tcr &= ~FEC_TCR_GTS; + fec_init(dev); + } + } + } + + if (!(prbd->cbd_sc & BD_ENET_RX_EMPTY)) { + if ((prbd->cbd_sc & BD_ENET_RX_LAST) && + !(prbd->cbd_sc & BD_ENET_RX_ERR) && + ((prbd->cbd_datlen - 4) > 14)) { + /* Get buffer address and size */ + frame_length = prbd->cbd_datlen - 4; + + /* Fill the buffer and pass it to upper layers */ + net_process_received_packet((uchar *)prbd->cbd_bufaddr, + frame_length); + len = frame_length; + } + + /* Reset buffer descriptor as empty */ + if (info->rx_idx == (PKTBUFSRX - 1)) + prbd->cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY); + else + prbd->cbd_sc = BD_ENET_RX_EMPTY; + + prbd->cbd_datlen = PKTSIZE_ALIGN; + + /* Now, we have an empty RxBD, restart the DMA receive task */ + MCD_continDma(info->rx_task); + + /* Increment BD count */ + info->rx_idx = (info->rx_idx + 1) % PKTBUFSRX; + } + + return len; +} + +static void mcdmafec_halt(struct udevice *dev) +{ + fec_halt(dev); +} + +static const struct eth_ops mcdmafec_ops = { + .start = mcdmafec_init, + .send = mcdmafec_send, + .recv = mcdmafec_recv, + .stop = mcdmafec_halt, +}; + +/* + * Boot sequence, called just after mcffec_ofdata_to_platdata, + * as DM way, it replaces old mcffec_initialize. + */ +static int mcdmafec_probe(struct udevice *dev) +{ + struct fec_info_dma *info = dev->priv; + struct eth_pdata *pdata = dev_get_platdata(dev); + int node = dev_of_offset(dev); + int retval; + const u32 *val; + + info->index = dev->seq; + info->iobase = pdata->iobase; + info->miibase = pdata->iobase; + info->phy_addr = -1; + + val = fdt_getprop(gd->fdt_blob, node, "rx-task", NULL); + if (val) + info->rx_task = fdt32_to_cpu(*val); + + val = fdt_getprop(gd->fdt_blob, node, "tx-task", NULL); + if (val) + info->tx_task = fdt32_to_cpu(*val); + + val = fdt_getprop(gd->fdt_blob, node, "rx-prioprity", NULL); + if (val) + info->rx_pri = fdt32_to_cpu(*val); + + val = fdt_getprop(gd->fdt_blob, node, "tx-prioprity", NULL); + if (val) + info->tx_pri = fdt32_to_cpu(*val); + + val = fdt_getprop(gd->fdt_blob, node, "rx-init", NULL); + if (val) + info->rx_init = fdt32_to_cpu(*val); + + val = fdt_getprop(gd->fdt_blob, node, "tx-init", NULL); + if (val) + info->tx_init = fdt32_to_cpu(*val); + +#ifdef CONFIG_SYS_FEC_BUF_USE_SRAM + u32 tmp = CONFIG_SYS_INIT_RAM_ADDR + 0x1000; +#endif + init_eth_info(info); #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) - int retval; - struct mii_dev *mdiodev = mdio_alloc(); - if (!mdiodev) - return -ENOMEM; - strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN); - mdiodev->read = mcffec_miiphy_read; - mdiodev->write = mcffec_miiphy_write; - - retval = mdio_register(mdiodev); - if (retval < 0) - return retval; + info->bus = mdio_alloc(); + if (!info->bus) + return -ENOMEM; + strncpy(info->bus->name, dev->name, MDIO_NAME_LEN); + info->bus->read = mcffec_miiphy_read; + info->bus->write = mcffec_miiphy_write; + + retval = mdio_register(info->bus); + if (retval < 0) + return retval; #endif - if (i > 0) - fec_info[i - 1].next = &fec_info[i]; - } - fec_info[i - 1].next = &fec_info[0]; + return 0; +} - /* default speed */ - bis->bi_ethspeed = 10; +static int mcdmafec_remove(struct udevice *dev) +{ + struct fec_info_dma *priv = dev_get_priv(dev); + + mdio_unregister(priv->bus); + mdio_free(priv->bus); return 0; } + +/* + * Boot sequence, called 1st + */ +static int mcdmafec_ofdata_to_platdata(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + const u32 *val; + + pdata->iobase = (phys_addr_t)devfdt_get_addr(dev); + /* Default to 10Mbit/s */ + pdata->max_speed = 10; + + val = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "max-speed", NULL); + if (val) + pdata->max_speed = fdt32_to_cpu(*val); + + return 0; +} + +static const struct udevice_id mcdmafec_ids[] = { + { .compatible = "fsl,mcf-dma-fec" }, + { } +}; + +U_BOOT_DRIVER(mcffec) = { + .name = "mcdmafec", + .id = UCLASS_ETH, + .of_match = mcdmafec_ids, + .ofdata_to_platdata = mcdmafec_ofdata_to_platdata, + .probe = mcdmafec_probe, + .remove = mcdmafec_remove, + .ops = &mcdmafec_ops, + .priv_auto_alloc_size = sizeof(struct fec_info_dma), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; -- cgit v1.3.1 From 48f885ae406a6a3369e6a110255337625369f581 Mon Sep 17 00:00:00 2001 From: Angelo Durgehello Date: Fri, 15 Nov 2019 23:54:20 +0100 Subject: drivers: mcfmii: add dm support Add specific dm code, but maintaining this driver as is, so more in the shape of a mii library. Can be moved to dm in a further step. Signed-off-by: Angelo Durgehello --- drivers/net/mcfmii.c | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mcfmii.c b/drivers/net/mcfmii.c index b8af2cc44be..3b8ee07c13a 100644 --- a/drivers/net/mcfmii.c +++ b/drivers/net/mcfmii.c @@ -41,14 +41,6 @@ DECLARE_GLOBAL_DATA_PTR; # define CONFIG_SYS_UNSPEC_STRID 0 #endif -#ifdef CONFIG_MCF547x_8x -typedef struct fec_info_dma FEC_INFO_T; -#define FEC_T fecdma_t -#else -typedef struct fec_info_s FEC_INFO_T; -#define FEC_T fec_t -#endif - typedef struct phy_info_struct { u32 phyid; char *strid; @@ -78,7 +70,7 @@ phy_info_t phyinfo[] = { * mii_init -- Initialize the MII for MII command without ethernet * This function is a subset of eth_init */ -void mii_reset(FEC_INFO_T *info) +void mii_reset(fec_info_t *info) { volatile FEC_T *fecp = (FEC_T *) (info->miibase); int i; @@ -95,9 +87,13 @@ void mii_reset(FEC_INFO_T *info) /* send command to phy using mii, wait for result */ uint mii_send(uint mii_cmd) { - FEC_INFO_T *info; - volatile FEC_T *ep; +#ifdef CONFIG_DM_ETH + struct udevice *dev; +#else struct eth_device *dev; +#endif + fec_info_t *info; + volatile FEC_T *ep; uint mii_reply; int j = 0; @@ -110,11 +106,11 @@ uint mii_send(uint mii_cmd) ep->mmfr = mii_cmd; /* command to phy */ /* wait for mii complete */ - while (!(ep->eir & FEC_EIR_MII) && (j < MCFFEC_TOUT_LOOP)) { + while (!(ep->eir & FEC_EIR_MII) && (j < info->to_loop)) { udelay(1); j++; } - if (j >= MCFFEC_TOUT_LOOP) { + if (j >= info->to_loop) { printf("MII not complete\n"); return -1; } @@ -131,10 +127,9 @@ uint mii_send(uint mii_cmd) #endif /* CONFIG_SYS_DISCOVER_PHY || (CONFIG_MII) */ #if defined(CONFIG_SYS_DISCOVER_PHY) -int mii_discover_phy(struct eth_device *dev) +int mii_discover_phy(fec_info_t *info) { #define MAX_PHY_PASSES 11 - FEC_INFO_T *info = dev->priv; int phyaddr, pass; uint phyno, phytype; int i, found = 0; @@ -157,7 +152,7 @@ int mii_discover_phy(struct eth_device *dev) phytype = mii_send(mk_mii_read(phyno, MII_PHYSID1)); #ifdef ET_DEBUG - printf("PHY type 0x%x pass %d type\n", phytype, pass); + printf("PHY type 0x%x pass %d\n", phytype, pass); #endif if (phytype == 0xffff) continue; @@ -207,9 +202,13 @@ void mii_init(void) __attribute__((weak,alias("__mii_init"))); void __mii_init(void) { - FEC_INFO_T *info; - volatile FEC_T *fecp; +#ifdef CONFIG_DM_ETH + struct udevice *dev; +#else struct eth_device *dev; +#endif + fec_info_t *info; + volatile FEC_T *fecp; int miispd = 0, i = 0; u16 status = 0; u16 linkgood = 0; @@ -220,7 +219,7 @@ void __mii_init(void) fecp = (FEC_T *) info->miibase; - fecpin_setclear(dev, 1); + fecpin_setclear(info, 1); mii_reset(info); @@ -234,9 +233,13 @@ void __mii_init(void) miispd = (gd->bus_clk / 1000000) / 5; fecp->mscr = miispd << 1; - info->phy_addr = mii_discover_phy(dev); +#ifdef CONFIG_SYS_DISCOVER_PHY + info->phy_addr = mii_discover_phy(info); +#endif + if (info->phy_addr == -1) + return; - while (i < MCFFEC_TOUT_LOOP) { + while (i < info->to_loop) { status = 0; i++; /* Read PHY control register */ @@ -257,9 +260,8 @@ void __mii_init(void) udelay(1); } - if (i >= MCFFEC_TOUT_LOOP) { + if (i >= info->to_loop) printf("Link UP timeout\n"); - } /* adapt to the duplex and speed settings of the phy */ info->dup_spd = miiphy_duplex(dev->name, info->phy_addr) << 16; -- cgit v1.3.1 From ae3d38f3187143673d60852d527369e290c0c29d Mon Sep 17 00:00:00 2001 From: Robert Beckett Date: Mon, 28 Oct 2019 18:44:06 +0000 Subject: bootcount: add a DM i2c eeprom backing store for bootcount This driver allows the use of i2c eeprom device or partition as backing store for boot counter values with DM enabled. Signed-off-by: Robert Beckett --- drivers/bootcount/Kconfig | 10 +++++ drivers/bootcount/Makefile | 1 + drivers/bootcount/i2c-eeprom.c | 95 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 drivers/bootcount/i2c-eeprom.c (limited to 'drivers') diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig index b7c29f2fd30..0e506c9ea2a 100644 --- a/drivers/bootcount/Kconfig +++ b/drivers/bootcount/Kconfig @@ -96,6 +96,16 @@ config DM_BOOTCOUNT_RTC Accesses to the backing store are performed using the write16 and read16 ops of DM RTC devices. +config DM_BOOTCOUNT_I2C_EEPROM + bool "Support i2c eeprom devices as a backing store for bootcount" + depends on I2C_EEPROM + help + Enabled reading/writing the bootcount in a DM i2c eeprom device. + The wrapper device is to be specified with the compatible string + 'u-boot,bootcount-i2c-eeprom' and the 'i2c-eeprom'-property (a phandle + pointing to the underlying i2c eeprom device) and an optional 'offset' + property are supported. + endmenu endif diff --git a/drivers/bootcount/Makefile b/drivers/bootcount/Makefile index f9841d86156..73ccfb5a088 100644 --- a/drivers/bootcount/Makefile +++ b/drivers/bootcount/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_BOOTCOUNT_EXT) += bootcount_ext.o obj-$(CONFIG_DM_BOOTCOUNT) += bootcount-uclass.o obj-$(CONFIG_DM_BOOTCOUNT_RTC) += rtc.o +obj-$(CONFIG_DM_BOOTCOUNT_I2C_EEPROM) += i2c-eeprom.o diff --git a/drivers/bootcount/i2c-eeprom.c b/drivers/bootcount/i2c-eeprom.c new file mode 100644 index 00000000000..ee760a2742b --- /dev/null +++ b/drivers/bootcount/i2c-eeprom.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2019 Collabora + * (C) Copyright 2019 GE + */ + +#include +#include +#include +#include + +static const u8 bootcount_magic = 0xbc; + +struct bootcount_i2c_eeprom_priv { + struct udevice *i2c_eeprom; + u32 offset; +}; + +static int bootcount_i2c_eeprom_set(struct udevice *dev, const u32 a) +{ + struct bootcount_i2c_eeprom_priv *priv = dev_get_priv(dev); + const u16 val = bootcount_magic << 8 | (a & 0xff); + + if (i2c_eeprom_write(priv->i2c_eeprom, priv->offset, + (uint8_t *)&val, 2) < 0) { + debug("%s: write failed\n", __func__); + return -EIO; + } + + return 0; +} + +static int bootcount_i2c_eeprom_get(struct udevice *dev, u32 *a) +{ + struct bootcount_i2c_eeprom_priv *priv = dev_get_priv(dev); + u16 val; + + if (i2c_eeprom_read(priv->i2c_eeprom, priv->offset, + (uint8_t *)&val, 2) < 0) { + debug("%s: read failed\n", __func__); + return -EIO; + } + + if (val >> 8 == bootcount_magic) { + *a = val & 0xff; + return 0; + } + + debug("%s: bootcount magic does not match on %04x\n", __func__, val); + return -EIO; +} + +static int bootcount_i2c_eeprom_probe(struct udevice *dev) +{ + struct ofnode_phandle_args phandle_args; + struct bootcount_i2c_eeprom_priv *priv = dev_get_priv(dev); + struct udevice *i2c_eeprom; + + if (dev_read_phandle_with_args(dev, "i2c-eeprom", NULL, 0, 0, + &phandle_args)) { + debug("%s: i2c-eeprom backing device not specified\n", + dev->name); + return -ENOENT; + } + + if (uclass_get_device_by_ofnode(UCLASS_I2C_EEPROM, phandle_args.node, + &i2c_eeprom)) { + debug("%s: could not get backing device\n", dev->name); + return -ENODEV; + } + + priv->i2c_eeprom = i2c_eeprom; + priv->offset = dev_read_u32_default(dev, "offset", 0); + + return 0; +} + +static const struct bootcount_ops bootcount_i2c_eeprom_ops = { + .get = bootcount_i2c_eeprom_get, + .set = bootcount_i2c_eeprom_set, +}; + +static const struct udevice_id bootcount_i2c_eeprom_ids[] = { + { .compatible = "u-boot,bootcount-i2c-eeprom" }, + { } +}; + +U_BOOT_DRIVER(bootcount_spi_flash) = { + .name = "bootcount-i2c-eeprom", + .id = UCLASS_BOOTCOUNT, + .priv_auto_alloc_size = sizeof(struct bootcount_i2c_eeprom_priv), + .probe = bootcount_i2c_eeprom_probe, + .of_match = bootcount_i2c_eeprom_ids, + .ops = &bootcount_i2c_eeprom_ops, +}; -- cgit v1.3.1 From 0b326fc296435ce27aa41320b6f7eb9266da39ef Mon Sep 17 00:00:00 2001 From: Han Nandor Date: Tue, 12 Nov 2019 08:39:38 +0000 Subject: rtc: add support for DS3232 device DS3232 is an i2c RTC with 236 bytes of battery-backed SRAM. Add an RTC driver for DS3232 device, which provides time and date support. Also read and write functions are provided, which can be used to access the SRAM memory. Signed-off-by: Nandor Han --- doc/device-tree-bindings/rtc/ds3232.txt | 15 ++ drivers/rtc/Kconfig | 8 + drivers/rtc/Makefile | 1 + drivers/rtc/ds3232.c | 274 ++++++++++++++++++++++++++++++++ 4 files changed, 298 insertions(+) create mode 100644 doc/device-tree-bindings/rtc/ds3232.txt create mode 100644 drivers/rtc/ds3232.c (limited to 'drivers') diff --git a/doc/device-tree-bindings/rtc/ds3232.txt b/doc/device-tree-bindings/rtc/ds3232.txt new file mode 100644 index 00000000000..254b7bc3c3e --- /dev/null +++ b/doc/device-tree-bindings/rtc/ds3232.txt @@ -0,0 +1,15 @@ +DS3232 Real-Time Clock with SRAM + +The RTC driver provides time and date functionality. Also read and write +functions are provided that can be used to access the SRAM memory. + +Required properties: +- compatible : should contain "dallas,ds3232" +- reg : the I2C RTC address + +Example: + +rtc@68 { + compatible = "dallas,ds3232"; + reg = <0x68>; +}; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 89e71cc7ebe..59e2fc44ba9 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -55,6 +55,14 @@ config RTC_DS1307 Support for Dallas Semiconductor (now Maxim) DS1307 and DS1338/9 and compatible Real Time Clock devices. +config RTC_DS3232 + bool "Enable DS3232 driver" + depends on DM_RTC + depends on DM_I2C + help + Support for Dallas Semiconductor (now Maxim) DS3232 compatible + Real Time Clock devices. + config RTC_ISL1208 bool "Enable ISL1208 driver" depends on DM_RTC diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index e8875ce10f5..12eb449583a 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_RTC_DS1556) += ds1556.o obj-$(CONFIG_RTC_DS164x) += ds164x.o obj-$(CONFIG_RTC_DS174x) += ds174x.o obj-$(CONFIG_RTC_DS3231) += ds3231.o +obj-$(CONFIG_RTC_DS3232) += ds3232.o obj-$(CONFIG_RTC_FTRTC010) += ftrtc010.o obj-$(CONFIG_SANDBOX) += i2c_rtc_emul.o obj-$(CONFIG_RTC_IMXDI) += imxdi.o diff --git a/drivers/rtc/ds3232.c b/drivers/rtc/ds3232.c new file mode 100644 index 00000000000..09a106aa4e9 --- /dev/null +++ b/drivers/rtc/ds3232.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2019, Vaisala Oyj + */ + +#include +#include +#include +#include +#include + +/* + * RTC register addresses + */ +#define RTC_SEC_REG_ADDR 0x00 +#define RTC_MIN_REG_ADDR 0x01 +#define RTC_HR_REG_ADDR 0x02 +#define RTC_DAY_REG_ADDR 0x03 +#define RTC_DATE_REG_ADDR 0x04 +#define RTC_MON_REG_ADDR 0x05 +#define RTC_YR_REG_ADDR 0x06 +#define RTC_CTL_REG_ADDR 0x0e +#define RTC_STAT_REG_ADDR 0x0f +#define RTC_TEST_REG_ADDR 0x13 + +/* + * RTC control register bits + */ +#define RTC_CTL_BIT_A1IE BIT(0) /* Alarm 1 interrupt enable */ +#define RTC_CTL_BIT_A2IE BIT(1) /* Alarm 2 interrupt enable */ +#define RTC_CTL_BIT_INTCN BIT(2) /* Interrupt control */ +#define RTC_CTL_BIT_DOSC BIT(7) /* Disable Oscillator */ + +/* + * RTC status register bits + */ +#define RTC_STAT_BIT_A1F BIT(0) /* Alarm 1 flag */ +#define RTC_STAT_BIT_A2F BIT(1) /* Alarm 2 flag */ +#define RTC_STAT_BIT_EN32KHZ BIT(3) /* Enable 32KHz Output */ +#define RTC_STAT_BIT_BB32KHZ BIT(6) /* Battery backed 32KHz Output */ +#define RTC_STAT_BIT_OSF BIT(7) /* Oscillator stop flag */ + +/* + * RTC test register bits + */ +#define RTC_TEST_BIT_SWRST BIT(7) /* Software reset */ + +#define RTC_DATE_TIME_REG_SIZE 7 +#define RTC_SRAM_START 0x14 +#define RTC_SRAM_END 0xFF +#define RTC_SRAM_SIZE 236 + +struct ds3232_priv_data { + u8 max_register; + u8 sram_start; + int sram_size; +}; + +static int ds3232_rtc_read8(struct udevice *dev, unsigned int reg) +{ + int ret; + u8 buf; + struct ds3232_priv_data *priv_data; + + priv_data = dev_get_priv(dev); + if (!priv_data) + return -EINVAL; + + if (reg > priv_data->max_register) + return -EINVAL; + + ret = dm_i2c_read(dev, reg, &buf, sizeof(buf)); + if (ret < 0) + return ret; + + return buf; +} + +static int ds3232_rtc_write8(struct udevice *dev, unsigned int reg, int val) +{ + u8 buf = (u8)val; + struct ds3232_priv_data *priv_data; + + priv_data = dev_get_priv(dev); + if (!priv_data) + return -EINVAL; + + if (reg > priv_data->max_register) + return -EINVAL; + + return dm_i2c_write(dev, reg, &buf, sizeof(buf)); +} + +static int reset_sram(struct udevice *dev) +{ + int ret, sram_end, reg; + struct ds3232_priv_data *priv_data; + + priv_data = dev_get_priv(dev); + if (!priv_data) + return -EINVAL; + + sram_end = priv_data->sram_start + priv_data->sram_size; + + for (reg = priv_data->sram_start; reg < sram_end; reg++) { + ret = ds3232_rtc_write8(dev, reg, 0x00); + if (ret < 0) + return ret; + } + + return 0; +} + +static int verify_osc(struct udevice *dev) +{ + int ret, rtc_status; + + ret = ds3232_rtc_read8(dev, RTC_STAT_REG_ADDR); + if (ret < 0) + return ret; + + rtc_status = ret; + + if (rtc_status & RTC_STAT_BIT_OSF) { + dev_warn(dev, + "oscillator discontinuity flagged, time unreliable\n"); + /* + * In case OSC was off we cannot trust the SRAM data anymore. + * Reset it to 0x00. + */ + ret = reset_sram(dev); + if (ret < 0) + return ret; + } + + return 0; +} + +static int ds3232_rtc_set(struct udevice *dev, const struct rtc_time *tm) +{ + u8 buf[RTC_DATE_TIME_REG_SIZE]; + u8 is_century; + + if (tm->tm_year < 1900 || tm->tm_year > 2099) + dev_warn(dev, "WARNING: year should be between 1900 and 2099!\n"); + + is_century = (tm->tm_year >= 2000) ? 0x80 : 0; + + buf[RTC_SEC_REG_ADDR] = bin2bcd(tm->tm_sec); + buf[RTC_MIN_REG_ADDR] = bin2bcd(tm->tm_min); + buf[RTC_HR_REG_ADDR] = bin2bcd(tm->tm_hour); + buf[RTC_DAY_REG_ADDR] = bin2bcd(tm->tm_wday + 1); + buf[RTC_DATE_REG_ADDR] = bin2bcd(tm->tm_mday); + buf[RTC_MON_REG_ADDR] = bin2bcd(tm->tm_mon) | is_century; + buf[RTC_YR_REG_ADDR] = bin2bcd(tm->tm_year % 100); + + return dm_i2c_write(dev, 0, buf, sizeof(buf)); +} + +static int ds3232_rtc_get(struct udevice *dev, struct rtc_time *tm) +{ + int ret; + u8 buf[RTC_DATE_TIME_REG_SIZE]; + u8 is_twelve_hr; + u8 is_pm; + u8 is_century; + + ret = verify_osc(dev); + if (ret < 0) + return ret; + + ret = dm_i2c_read(dev, 0, buf, sizeof(buf)); + if (ret < 0) + return ret; + + /* Extract additional information for AM/PM and century */ + is_twelve_hr = buf[RTC_HR_REG_ADDR] & 0x40; + is_pm = buf[RTC_HR_REG_ADDR] & 0x20; + is_century = buf[RTC_MON_REG_ADDR] & 0x80; + + tm->tm_sec = bcd2bin(buf[RTC_SEC_REG_ADDR] & 0x7F); + tm->tm_min = bcd2bin(buf[RTC_MIN_REG_ADDR] & 0x7F); + + if (is_twelve_hr) + tm->tm_hour = bcd2bin(buf[RTC_HR_REG_ADDR] & 0x1F) + + (is_pm ? 12 : 0); + else + tm->tm_hour = bcd2bin(buf[RTC_HR_REG_ADDR]); + + tm->tm_wday = bcd2bin((buf[RTC_DAY_REG_ADDR] & 0x07) - 1); + tm->tm_mday = bcd2bin(buf[RTC_DATE_REG_ADDR] & 0x3F); + tm->tm_mon = bcd2bin((buf[RTC_MON_REG_ADDR] & 0x7F)); + tm->tm_year = bcd2bin(buf[RTC_YR_REG_ADDR]) + + (is_century ? 2000 : 1900); + tm->tm_yday = 0; + tm->tm_isdst = 0; + + return 0; +} + +static int ds3232_rtc_reset(struct udevice *dev) +{ + int ret; + + ret = reset_sram(dev); + if (ret < 0) + return ret; + + /* + * From datasheet + * (https://datasheets.maximintegrated.com/en/ds/DS3232M.pdf): + * + * The device reset occurs during the normal acknowledge time slot + * following the receipt of the data byte carrying that + * SWRST instruction a NACK occurs due to the resetting action. + * + * Therefore we don't verify the result of I2C write operation since it + * will fail due the NACK. + */ + ds3232_rtc_write8(dev, RTC_TEST_REG_ADDR, RTC_TEST_BIT_SWRST); + + return 0; +} + +static int ds3232_probe(struct udevice *dev) +{ + int rtc_status; + int ret; + struct ds3232_priv_data *priv_data; + + priv_data = dev_get_priv(dev); + if (!priv_data) + return -EINVAL; + + priv_data->sram_start = RTC_SRAM_START; + priv_data->max_register = RTC_SRAM_END; + priv_data->sram_size = RTC_SRAM_SIZE; + + ret = ds3232_rtc_read8(dev, RTC_STAT_REG_ADDR); + if (ret < 0) + return ret; + + rtc_status = ret; + + ret = verify_osc(dev); + if (ret < 0) + return ret; + + rtc_status &= ~(RTC_STAT_BIT_OSF | RTC_STAT_BIT_A1F | RTC_STAT_BIT_A2F); + + return ds3232_rtc_write8(dev, RTC_STAT_REG_ADDR, rtc_status); +} + +static const struct rtc_ops ds3232_rtc_ops = { + .get = ds3232_rtc_get, + .set = ds3232_rtc_set, + .reset = ds3232_rtc_reset, + .read8 = ds3232_rtc_read8, + .write8 = ds3232_rtc_write8 +}; + +static const struct udevice_id ds3232_rtc_ids[] = { + { .compatible = "dallas,ds3232" }, + { } +}; + +U_BOOT_DRIVER(rtc_ds3232) = { + .name = "rtc-ds3232", + .id = UCLASS_RTC, + .probe = ds3232_probe, + .of_match = ds3232_rtc_ids, + .ops = &ds3232_rtc_ops, + .priv_auto_alloc_size = sizeof(struct ds3232_priv_data), +}; -- cgit v1.3.1 From 36b8b5d3adf7f8de6e5692c21b23a980da50884c Mon Sep 17 00:00:00 2001 From: Frank Wunderlich Date: Fri, 22 Nov 2019 15:32:24 +0100 Subject: poweroff: add poweroff for mt6323 pmic this adds poweroff to bananapi r2 / mt7623 / mt6323 pmic Signed-off-by: Frank Wunderlich --- drivers/power/Kconfig | 7 +++++++ drivers/power/Makefile | 1 + drivers/power/mt6323.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 drivers/power/mt6323.c (limited to 'drivers') diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index cb2c6fe3ebe..5910926faca 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -366,4 +366,11 @@ config TWL4030_POWER The TWL4030 in a combination audio CODEC/power management with GPIO and it is commonly used with the OMAP3 family of processors +config POWER_MT6323 + bool "Poweroff driver for mediatek mt6323" + select CMD_POWEROFF + help + This adds poweroff driver for mt6323 + this pmic is used on mt7623 / Bananapi R2 + endmenu diff --git a/drivers/power/Makefile b/drivers/power/Makefile index dd5bc0dc44e..2dcc7bb99d0 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_DIALOG_POWER) += power_dialog.o obj-$(CONFIG_POWER_FSL) += power_fsl.o obj-$(CONFIG_POWER_I2C) += power_i2c.o obj-$(CONFIG_POWER_SPI) += power_spi.o +obj-$(CONFIG_POWER_MT6323) += mt6323.o diff --git a/drivers/power/mt6323.c b/drivers/power/mt6323.c new file mode 100644 index 00000000000..566be5f39e5 --- /dev/null +++ b/drivers/power/mt6323.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Frank Wunderlich + */ + +#include +#include +#include + +#define PWRAP_BASE 0x1000d000 +#define PWRAP_WACS2_CMD 0x9c + +#define PWRAP_CALC(adr, wdata) ((1 << 31) | (((adr) >> 1) << 16) | (wdata)) + +#define MT6323_PWRC_BASE 0x8000 +#define RTC_BBPU 0x0000 +#define RTC_BBPU_KEY (0x43 << 8) +#define RTC_WRTGR 0x003c + +int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + u32 addr, val; + + addr = PWRAP_BASE + PWRAP_WACS2_CMD; + val = PWRAP_CALC(MT6323_PWRC_BASE + RTC_BBPU, RTC_BBPU_KEY); + writel(val, addr); + + mdelay(10); + + val = PWRAP_CALC(MT6323_PWRC_BASE + RTC_WRTGR, 1); + writel(val, addr); + + // wait some time and then print error + mdelay(10000); + printf("Failed to power off!!!\n"); + return 1; +} -- cgit v1.3.1 From 27a38a6e71817243d71da8d798ec9daa31b3c49d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 24 Dec 2019 12:21:09 +0100 Subject: virtio: fix typo devicd %s/devicd/device Signed-off-by: Heinrich Schuchardt Reviewed-by: Bin Meng --- drivers/virtio/virtio_mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 7b738703b82..a67b3541224 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -363,7 +363,7 @@ static int virtio_mmio_probe(struct udevice *udev) return 0; } - /* Check devicd ID */ + /* Check device ID */ uc_priv->device = readl(priv->base + VIRTIO_MMIO_DEVICE_ID); if (uc_priv->device == 0) { /* -- cgit v1.3.1