<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      學無止境--U-boot下的ETH PHY驅動探索

      備注:學習記錄所用,若有高手不吝賜教,萬分感謝!

      一、概括

      環境:

      cpu:fsl91030m

      phy:yt8512(motorcomm廠)

      完整的phy驅動需要eth phy驅動、mdio驅動、mii驅動(一般ic原廠自帶),并且需要將其嵌入到eth驅動中。

       

      二、外部phy驅動

      1、驅動位置

      drivers/net/phy中添加motorcomm.c文件

      2、驅動實現:

      static int yt8512_config(struct phy_device *phydev)
      {
      	int ctl = 0;
      	
      	ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
      	if (ctl < 0)
      		return ctl;
      	ctl &= ~(BMCR_SPEED10 | BMCR_SPEED1000 | BMCR_ANENABLE);
      	ctl |= BMCR_FULLDPLX | BMCR_SPEED100;
      		
      	/* First clear the PHY */
      	//phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl | BMCR_RESET);
      
      	return genphy_config_aneg(phydev);
      }
      
      static int yt8512_parse_status(struct phy_device *phydev)
      {
      	int mii_reg;
      	int speed;
      
      	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, PHY_REG_SPEC_STATUS);
      
      	if (mii_reg & YT8512_DUPLEX_STATUS)
      		phydev->duplex = DUPLEX_FULL;
      	else
      		phydev->duplex = DUPLEX_HALF;
      
      	speed = mii_reg & YT8512_SPEED_MASK;
      	switch (speed) {
      	case YT8512_SPEED_1000:
      		phydev->speed = SPEED_1000;
      		break;
      	case YT8512_SPEED_100:
      		phydev->speed = SPEED_100;
      		break;
      	case YT8512_SPEED_10:
      		phydev->speed = SPEED_10;
      		break;
      	default:
      		phydev->speed = SPEED_100;
      		break;
      	}
      
      	return 0;
      }
      
      static int yt8512_startup(struct phy_device *phydev)
      {
      	unsigned phy_ctl;
      	int ret;
      
      	ret = genphy_update_link(phydev);
      	if (ret)
      		return ret;
      
      	return yt8512_parse_status(phydev);
      }
      
      
      static struct phy_driver yt8512_driver = {
      	.name = "motocomm,yt8512b",
      	.uid = PHY_ID_YT8512B,
      	.mask = PHY_ID_MASK,
      	.features = PHY_BASIC_FEATURES,
      	.config = &yt8512_config,
      	.startup = &yt8512_startup,
      	.shutdown = &genphy_shutdown,
      };
      
       /*該函數在driver/net/phy/phy.c/phy_init()中調用*/
      int phy_motorcomm_init(void)
      {
      	phy_register(&yt8512_driver);
      	
      	return 0;
      }

      3、設備樹

      mdio: mdio@62000000{
          compatible = "nuclei,ux600fd_mdio";
          reg = <0x0 0x62000000 0x0 0x100>;
          #address-cells = <0x1>;
          #size-cells = <0x0>;
          status = "okay";
              yt8512b@0 {
              compatible = "motocomm,yt8512b";
              reg = <0>;
              };
      };

       

      三、MDIO驅動

      ??1、驅動位置

      ????drivers/net、中添加xy1000_mdio.c文件

      ??2、驅動實現:非DM方式

      #define NUCLEI_UX600FD_MII_DEBUG
      
      #define FSLRAL_MDIO_INNER 			0
      #define FSLRAL_MDIO_EXTRAL 			1
      
      /****************************************reg define****************************************/
      #define LOCAL_BUS_BASE						(0x60000000)
      #define MDIO_INITIATOR_REG_BASE				(LOCAL_BUS_BASE + 0x02000000)
      
      #define MDIO_INITIATOR_REG_MDIO_FRM_FIELDr   (MDIO_INITIATOR_REG_BASE + 0x00)
      #define MDIO_INITIATOR_REG_MDIO_FRM_CTRLr    (MDIO_INITIATOR_REG_BASE + 0x04)
      #define MDIO_INITIATOR_REG_MDIO_CMDm         (MDIO_INITIATOR_REG_BASE + 0x08)
      #define MDIO_INITIATOR_REG_MDIO_MASTER_CTRLr (MDIO_INITIATOR_REG_BASE + 0x0C)
      
      #define PAD_CONFIG_REG_PAD_SDAr              (0x640090e8)
      #define PAD_CONFIG_REG_PAD_SCLr              (0x640090e4)
      #define TOP_CFG_REG_INVISIBLE_REGr           (0x60000040)
      
      #define BITS(start, end)             ((0xFFFFFFFFUL << (start)) & (0xFFFFFFFFUL >> (31U - (uint32_t)(end)))) 
      
      #ifdef CONFIG_DM_MDIO
      struct mdio_nuclei_ux600fd_plat {
      	void *base;
      };
      
      static int mdio_nuclei_ux600fd_read(struct udevice *dev, int addr, int devad, int reg)
      {
      	struct mdio_nuclei_ux600fd_plat *plat = dev_get_platdata(dev);
      
      	return 0;
      }
      
      static int mdio_nuclei_ux600fd_write(struct udevice *dev, int addr, int devad, int reg,
      			      u16 val)
      {
      	struct mdio_nuclei_ux600fd_plat *plat = dev_get_platdata(dev);
      
      	return 0;
      }
      
      static int mdio_nuclei_ux600fd_reset(struct udevice *dev)
      {
      	struct mdio_nuclei_ux600fd_plat *plat = dev_get_platdata(dev);
      
      	fslral_mdio_mode_cfg(FSLRAL_MDIO_INNER);
      	
      	return 0;
      }
      
      static const struct mdio_ops mdio_nuclei_ux600fd_ops = {
      	.read = mdio_nuclei_ux600fd_read,
      	.write = mdio_nuclei_ux600fd_write,
      	.reset = mdio_nuclei_ux600fd_reset,
      };
      
      static int mdio_nuclei_ux600fd_probe(struct udevice *dev)
      {
      	struct mdio_nuclei_ux600fd_plat *plat = dev_get_platdata(dev);
      	fdt_addr_t addr;
      
      	addr = devfdt_get_addr(dev);
      	if (addr == FDT_ADDR_T_NONE)
      		return -EINVAL;
      
      	plat->base = (void *)addr;
      
      	fslral_mdio_mode_cfg(FSLRAL_MDIO_EXTRAL);
      
      	return 0;
      }
      
      static int mdio_nuclei_ux600fd_ofdata_to_platdata(struct udevice *dev)
      {
      	struct mdio_nuclei_ux600fd_plat *plat = dev_get_platdata(dev);
      	fdt_addr_t addr;
      
      	addr = devfdt_get_addr(dev);
      	if (addr == FDT_ADDR_T_NONE)
      		return -EINVAL;
      
      	plat->base = (void *)addr;
      	return 0;
      }
      
      static const struct udevice_id mdio_nuclei_ux600fd_ids[] = {
      	{ .compatible = "nuclei,ux600fdmdio" },
      	{ }
      };
      
      U_BOOT_DRIVER(ux600fd_mdio) = {
      	.name		= "ux600fd_mdio",
      	.id		= UCLASS_MDIO,
      	.of_match	= mdio_nuclei_ux600fd_ids,
      	.ofdata_to_platdata = of_match_ptr(mdio_nuclei_ux600fd_ofdata_to_platdata),
      	.probe		= mdio_nuclei_ux600fd_probe,
      	.ops		= &mdio_nuclei_ux600fd_ops,
      	.priv_auto_alloc_size = sizeof(struct mdio_nuclei_ux600fd_priv),
      };
      #else /*非DM方式*/
      
      /**/
      int fslral_mdio_mode_cfg(struct xy1000_mii_mng __iomem *phyregs, int unit, uint8_t mode)
      {
      	/*該平臺mido可以控制內部phy與外部hpy
            此處切換
          */	
      	
      	return 0;
      }
      
      int fslral_mdio_master_read(struct xy1000_mii_mng __iomem *phyregs, int phy_ad, int reg_ad, int *val)
      {
          /*按照平臺的操作流程控制寄存器,實現從外部phy讀取數據*/
      	return rv;
      }
      
      int fslral_mdio_master_write(struct xy1000_mii_mng __iomem *phyregs, int phy_ad, int reg_ad, int value)
      {
      	/*按照平臺的操作流程控制寄存器,實現向外部phy寫入數據*/
      	return 0;
      }
      
      int fslral_mdio_master_read_extern(struct mii_dev *bus, int addr, int devaddr, int reg)
      {
      	int val = 0;
      	struct xy1000_mii_mng __iomem *phyregs =
      		(struct xy1000_mii_mng __iomem *)bus->priv;
      	
      	fslral_mdio_mode_cfg(phyregs, 0, FSLRAL_MDIO_EXTRAL);
      	fslral_mdio_master_read(phyregs, addr, reg, &val);
      	fslral_mdio_mode_cfg(phyregs, 0, FSLRAL_MDIO_INNER);
      	
      	return val;
      }
      
      
      int fslral_mdio_master_write_extern(struct mii_dev *bus, int addr, int devaddr,  int reg, u16 value)
      {
      	int rv = 0;
      	struct xy1000_mii_mng __iomem *phyregs =
      		(struct xy1000_mii_mng __iomem *)bus->priv;
      	
      	fslral_mdio_mode_cfg(phyregs, 0, FSLRAL_MDIO_EXTRAL);
      	rv = fslral_mdio_master_write(phyregs, addr, reg, value);
      	fslral_mdio_mode_cfg(phyregs, 0, FSLRAL_MDIO_INNER);
      	return rv;
      }
      
      int fslral_mdio_master_reset_extern(struct mii_dev *bus)
      {
      	int rv = 0;
      	struct xy1000_mii_mng __iomem *phyregs =
      		(struct xy1000_mii_mng __iomem *)bus->priv;
      
      	return rv;
      };
      
      
      int mdio_nuclei_ux600fd_init(bd_t *bis, struct xy1000_mdio_info *mdio_info)
      {
      	struct mii_dev *bus;
      	uint32_t regvalue = 0;
      	
      	bus = mdio_alloc();
      	if (!bus) {
      		printf("Failed to allocate NUCLEI_UX600FD-MDIO bus\n");
      		return -ENOMEM;
      	}
      
      	bus->read = fslral_mdio_master_read_extern;
      	bus->write = fslral_mdio_master_write_extern;
      	bus->reset = fslral_mdio_master_reset_extern;
      	strncpy(bus->name, mdio_info->name, sizeof(bus->name));
      	bus->priv = (void *)mdio_info->regs;
      
      	return mdio_register(bus);
      }
      #endif

       

      四、嵌入ETH驅動

      ??1、mdio注冊:在eth初始化中調用mdio_nuclei_ux600fd_init()

      ??2、在網卡驅動初始化中配置phy

      ????2.1、結構體初始化

      priv->regs = UX600FD_TOP_CFG_REGS_BASE; /* for rgmii cfg */
      priv->miiregs_sgmii = XY1000_MDIO_REGS_BASE;
      priv->phyname = XY1000_PHY_NAME;
      priv->phyaddr = XY1000_PHY_ADDR;
      priv->mii_devname = XY1000_MII_NAME;
      priv->ethdev = dev;

      ????2.2、ETH板級初始化流程

      /*
      * Discover which PHY is attached to the device, and configure it
      * properly. If the PHY is not recognized, then return 0
      * (failure). Otherwise, return 1
      */
      
      static int fslral_init_phy(struct mac_eth_priv *priv)
      {
          struct phy_device *phydev = NULL;
          struct mii_dev *bus;
          u32 rgmii_csr;
      
          bus = miiphy_get_dev_by_name(priv->mii_devname);
      
          priv->interface = PHY_INTERFACE_MODE_MII;
          phydev = phy_connect(bus, priv->phyaddr, priv->ethdev, priv->interface);
      
          if (!phydev)
          {
              priv->phydev = NULL;
              return0;
          }
      
          phydev->supported &= PHY_BASIC_FEATURES;
          //phydev->advertising = phydev->supported;
          priv->phydev = phydev;
      
          return phy_config(phydev); /*實際調用了yt8512_config()*/
      }
      
      //網卡驅動初始化
      int fslral_eth_init(bd_t *bis)
      {
      	struct eth_device *dev;
      	struct mac_eth_priv *priv;
      	uint32_t tmp;
      
      //	printf("switch_en 0x%x\n",*(volatile uint32_t *)(0x60000000 + INVISIBLE_CFG));
      	//適配新的socket板子,不然網口不通,manage_mode  寫0,再復位,解復位,added by pfliu
      	tmp = *(volatile uint32_t *)(0x60000000 + 0x4);
      	tmp &= (~(1<<14));
      	*(volatile uint32_t *)(0x60000000 + 0x4) = tmp;
      	ndelay(1000);
      
      	*(volatile uint32_t *)(0x60000000 + 0x28) = 0;
      	ndelay(1000);
      	*(volatile uint32_t *)(0x60000000 + 0x28) = 0x3;
      /**/	 
      
      	//判斷switch_en
      	if ((*(volatile uint32_t *)(0x60000000 + INVISIBLE_CFG) & 0x01) != 0x01)
      	{
      		printf("error: switch_en is off\n");
      		//set_words((volatile uint32_t *)(0x60000000 + INVISIBLE_CFG), 1, 0, 0, 0x01);
      	}
      	else
      	{	
      		set_words((volatile uint32_t *)(0x67800000 + DMA_AXI_WR_CFG), 1, 0, 7, 0x0F);
      		set_words((volatile uint32_t *)(0x67800000 + DMA_AXI_RD_CFG), 1, 0, 7, 0x0F);
      
      		//分配網卡設備空間
      		dev = (struct eth_device *)malloc(sizeof(*dev));
      		if (dev == NULL)
      		{
      			printf("malloc dev failed\n");
      			return 0;
      		}
      		memset(dev, 0, sizeof(*dev));
      		
      		//分配私有數據空間
      		priv = (struct mac_eth_priv *)malloc(sizeof(*priv));
      		if (priv == NULL)
      		{
      			printf("malloc priv failed\n");
      			return 0;
      		}
      		memcpy(dev->enetaddr, host_addr, 6);
      		
      		//時鐘與復位
      		
      		//網卡設備IO地址
      		priv->io_addr = (void __iomem *)0x67800000;
      		sprintf(dev->name, "xy1000_eth");
      		
      		#ifdef CONFIG_UX600FD_MDIO
      		/*added by xiahui, for external phy, 20230718*/
      		priv->regs = UX600FD_TOP_CFG_REGS_BASE; /* for rgmii cfg */
      		priv->miiregs_sgmii = XY1000_MDIO_REGS_BASE;
      		priv->phyname = XY1000_PHY_NAME;
      		priv->phyaddr = XY1000_PHY_ADDR;
      		priv->mii_devname = XY1000_MII_NAME;
      		priv->ethdev = dev;
      		#endif		
      		//網卡操作集
      		dev->priv = priv;
      		dev->init = fh_init;
      		dev->halt = fh_halt;
      		dev->send = fh_send;
      		dev->recv = fh_recv;
      		
      		//分配dma空間
      		//有cache,不能完全同步數據
      		//dma_addr = (unsigned char *)kmalloc(DMA_PKT_MAX_SIZE * 2, 0);
      	 	//dma_addr = (unsigned char *)malloc(DMA_PKT_MAX_SIZE * 2);
      		//使用無cache地址:0x40000000 ~ 0x40008000
      		dma_addr = ioremap(0x40000000, DMA_PKT_MAX_SIZE * 2);
      		if (dma_addr == NULL)
      			printf("dma_alloc fail\n");
      		
      		dma_rx_buf = dma_addr;
      		dma_tx_buf = dma_addr + DMA_PKT_MAX_SIZE;
      		memset(dma_rx_buf, 0x00, DMA_PKT_MAX_SIZE);
      		memset(dma_tx_buf, 0x00, DMA_PKT_MAX_SIZE);
      		
      		eth_register(dev);
      	
      		#ifdef CONFIG_UX600FD_MDIO
      		fslral_init_phy(priv);
      		#endif
      	
      	}
      }
      
      int fh_net_initialize(bd_t *bis)
      {
      	#ifdef CONFIG_UX600FD_MDIO
      	struct xy1000_mdio_info info;
      
      	info.regs = XY1000_MDIO_REGS_BASE;
      	info.name = XY1000_MII_NAME;
      	
      	mdio_nuclei_ux600fd_init(bis, &info);
      	#endif
      	
      	fslral_eth_init(bis);
      
      	return 0;
      }

      ??3、初始化網卡(eth_device的init 實現)中添加以下代碼初始化phy和rgmii

      /* Start up the PHY */
          if (priv->phydev)
          {
              ret = phy_startup(priv->phydev); /*實際調用了yt8512_startup()*/
              if (ret) {
              printf("Could not initialize PHY %s\n",
              priv->phydev->dev->name);
      
              return 0;
          }
          fslral_adjust_link(priv);
      }

      ????初始化rgmii函數:

      /*
      * Configure rgmii on negotiated speed and duplex
      * reported by PHY handling code
      */
      static void fslral_adjust_link(struct mac_eth_priv *priv)
      {
          void __iomem *regs = priv->regs;
          struct phy_device *phydev = priv->phydev;
          u32 duplex, speed, mode, xmii_state;
      
          if (!phydev->link) {
              printf("%s: No link.\n", phydev->dev->name);
              return;
          }
      
          if (phydev->duplex)
              duplex = UX600FD_RGMII_FULL_DUPLEX;
      
          switch (phydev->speed) {
              case1000:
                  mode = UX600FD_INTERFACE_MODE_RGMII;
                  break;
              case100:
                  mode = UX600FD_INTERFACE_MODE_MII_MAC;
                  speed = UX600FD_RGMII_SPEED_100;
                  xmii_state = 2;
                  break;
              case10:
                  mode = UX600FD_INTERFACE_MODE_MII_MAC;
                  speed = UX600FD_RGMII_SPEED_10;
                  xmii_state = 2;
                  break;
              default:
                  printf("%s: Speed was bad\n", phydev->dev->name);
              break;
          }
      
          set_words(regs + UX600FD_RGMII_CSR_REGS_OFFSET, 1, UX600FD_RGMII0_MODE_STRT_BIT, \
                    UX600FD_RGMII0_MODE_END_BIT, mode);
          set_words(regs + UX600FD_RGMII_CSR_REGS_OFFSET, 1, UX600FD_RGMII0_SPEED_STRT_BIT, \
                    UX600FD_RGMII0_SPEED_END_BIT, speed );
          set_words(regs + UX600FD_RGMII_CSR_REGS_OFFSET, 1, 4, 5, xmii_state);
          set_words(regs + UX600FD_RGMII_DUPLEX_REGS_OFFSET, 1, UX600FD_RGMII0_DUPLEX_STRT_BIT, \
                    UX600FD_RGMII0_DUPLEX_END_BIT, duplex);
      
          printf("Speed: %d, %s duplex%s\n", phydev->speed,
          (phydev->duplex) ? "full" : "half",
          (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
      }

      ??4、關閉網卡(eth_device的halt實現)時添加以下代碼關閉phy

      /* Shut down the PHY, as needed */
      if (priv->phydev)
          phy_shutdown(priv->phydev); /*實際調用了genphy_shutdown()*/

      ??5、

      五、板級ETH初始化

      eth_initialize()中的board_eth_init()函數需要自己實現

      extern int fh_net_initialize(bd_t *bis);
      int board_eth_init(bd_t *bis)
      {
          int ret;
          int gpio_rst_phy = 9;
      
          ret = gpio_request(gpio_rst_phy, "phy_reset");
      
          if (ret && ret != -EBUSY) {
              printf("gpio: requesting pin %d failed\n", gpio_rst_phy);
              return -1;
          }
      
          gpio_direction_output(gpio_rst_phy, 0);
          mdelay(200);
          gpio_direction_output(gpio_rst_phy, 1);
      
          return fh_net_initialize(bis);
      }

       

      posted @ 2024-01-16 17:05  xMofang  閱讀(1656)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产精品毛片一区二区| 国产成人精品亚洲日本在线观看| 精品乱人伦一区二区三区| 无码国内精品人妻少妇| 亚洲综合网中文字幕在线| 亚洲国产午夜福利精品| 亚洲av无码精品蜜桃| 欧美成人精品三级网站| 最新国内精品自在自线视频| 精品嫩模福利一区二区蜜臀| 精品综合久久久久久97| 国产日韩精品欧美一区灰| 久久亚洲精品中文字幕| 日韩精品久久一区二区三| 亚洲午夜成人精品电影在线观看 | 99久久精品国产亚洲精品| bt天堂新版中文在线| 国产熟女精品一区二区三区| 中文字幕无码精品亚洲35| 国模雨珍浓密毛大尺度150p| 中文文字幕文字幕亚洲色| 男人扒开添女人下部免费视频| 免费看黄色片| 亚洲成在人线AⅤ中文字幕| 成人一区二区人妻不卡视频| 河北真实伦对白精彩脏话| 日本高清中文字幕免费一区二区| 国产对白叫床清晰在线播放| 国产在线一区二区不卡| 99久久婷婷国产综合精品青草漫画 | 老司机午夜精品视频资源| 日韩精品一区二区蜜臀av| 老鸭窝在钱视频| 精品日韩亚洲av无码| 国产AV影片麻豆精品传媒| 永平县| 无码中文字幕热热久久| 免费人成视频x8x8国产| 青川县| 国产精品毛片一区二区 | 久久天堂无码av网站|