123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929 |
- From 70157a6148ad47734f1dc646b4157ca83cc5df9f Mon Sep 17 00:00:00 2001
- From: Weijie Gao <[email protected]>
- Date: Thu, 13 Jul 2023 16:34:48 +0800
- Subject: [PATCH] net: phy: add support for Airoha ethernet PHY driver
- This patch adds support for Airoha ethernet PHY driver.
- If GMAC2 of your board connects to Airoha EN8801S, please change the eth
- node as follow:
- ð {
- status = "okay";
- mediatek,gmac-id = <1>;
- mediatek,sgmiisys = <&sgmiisys1>;
- phy-mode = "sgmii";
- phy-handle = <&phy5>;
- phy5: eth-phy@5 {
- reg = <24>;
- };
- };
- If GMAC2 of your board connects to Airoha EN8811H, please change the eth
- node as follow:
- ð {
- status = "okay";
- mediatek,gmac-id = <1>;
- mediatek,sgmiisys = <&sgmiisys1>;
- phy-mode = "2500base-x";
- phy-handle = <&phy5>;
- fixed-link {
- speed = <2500>;
- full-duplex;
- };
- phy5: eth-phy@5 {
- reg = <15>;
- };
- };
- Signed-off-by: Weijie Gao <[email protected]>
- ---
- .../drivers/net/phy/Kconfig | 15 +
- .../drivers/net/phy/Makefile | 2 +
- .../drivers/net/phy/air_en8801s.c | 633 ++
- .../drivers/net/phy/air_en8801s.h | 267 +
- .../drivers/net/phy/air_en8811h.c | 649 ++
- .../drivers/net/phy/air_en8811h.h | 160 +
- .../drivers/net/phy/air_en8811h_fw.h | 9227 +++++++++++++++++
- 7 files changed, 10953 insertions(+)
- create mode 100644 drivers/net/phy/air_en8801s.c
- create mode 100644 drivers/net/phy/air_en8801s.h
- create mode 100644 drivers/net/phy/air_en8811h.c
- create mode 100644 drivers/net/phy/air_en8811h.h
- create mode 100644 drivers/net/phy/air_en8811h_fw.h
- --- a/drivers/net/phy/Kconfig
- +++ b/drivers/net/phy/Kconfig
- @@ -77,6 +77,37 @@ config PHY_ADIN
- help
- Add support for configuring RGMII on Analog Devices ADIN PHYs.
-
- +menuconfig PHY_AIROHA
- + bool "Airoha Ethernet PHYs support"
- +
- +config PHY_AIROHA_EN8801S
- + bool "Airoha Ethernet EN8801S support"
- + depends on PHY_AIROHA
- + help
- + AIROHA EN8801S supported.
- +
- +config PHY_AIROHA_EN8811H
- + bool "Airoha Ethernet EN8811H support"
- + depends on PHY_AIROHA
- + help
- + AIROHA EN8811H supported.
- +
- +choice
- + prompt "Location of the Airoha PHY firmware"
- + default PHY_AIROHA_FW_IN_UBI
- + depends on PHY_AIROHA_EN8811H
- +
- +config PHY_AIROHA_FW_IN_MMC
- + bool "Airoha firmware in MMC boot1 partition"
- +
- +config PHY_AIROHA_FW_IN_UBI
- + bool "Airoha firmware in UBI volume en8811h-fw on NAND flash"
- +
- +config PHY_AIROHA_FW_IN_MTD
- + bool "Airoha firmware in MTD partition on raw flash"
- +
- +endchoice
- +
- menuconfig PHY_AQUANTIA
- bool "Aquantia Ethernet PHYs support"
- select PHY_GIGE
- --- a/drivers/net/phy/Makefile
- +++ b/drivers/net/phy/Makefile
- @@ -11,6 +11,8 @@ obj-$(CONFIG_MV88E6352_SWITCH) += mv88e6
- obj-$(CONFIG_PHYLIB) += phy.o
- obj-$(CONFIG_PHYLIB_10G) += generic_10g.o
- obj-$(CONFIG_PHY_ADIN) += adin.o
- +obj-$(CONFIG_PHY_AIROHA_EN8801S) += air_en8801s.o
- +obj-$(CONFIG_PHY_AIROHA_EN8811H) += air_en8811h.o
- obj-$(CONFIG_PHY_AQUANTIA) += aquantia.o
- obj-$(CONFIG_PHY_ATHEROS) += atheros.o
- obj-$(CONFIG_PHY_BROADCOM) += broadcom.o
- --- /dev/null
- +++ b/drivers/net/phy/air_en8801s.c
- @@ -0,0 +1,633 @@
- +// SPDX-License-Identifier: GPL-2.0
- +/*************************************************
- + * FILE NAME: air_en8801s.c
- + * PURPOSE:
- + * EN8801S PHY Driver for Uboot
- + * NOTES:
- + *
- + * Copyright (C) 2023 Airoha Technology Corp.
- + *************************************************/
- +
- +/* INCLUDE FILE DECLARATIONS
- + */
- +#include <common.h>
- +#include <phy.h>
- +#include <errno.h>
- +#include <version.h>
- +#include "air_en8801s.h"
- +
- +#if AIR_UBOOT_REVISION > 0x202004
- +#include <linux/delay.h>
- +#endif
- +
- +static struct phy_device *s_phydev = 0;
- +/******************************************************
- + * The following led_cfg example is for reference only.
- + * LED5 1000M/LINK/ACT (GPIO5) <-> BASE_T_LED0,
- + * LED6 10/100M/LINK/ACT (GPIO9) <-> BASE_T_LED1,
- + * LED4 100M/LINK/ACT (GPIO8) <-> BASE_T_LED2,
- + ******************************************************/
- +/* User-defined.B */
- +#define AIR_LED_SUPPORT
- +#ifdef AIR_LED_SUPPORT
- +static const AIR_BASE_T_LED_CFG_T led_cfg[4] =
- +{
- + /*
- + * LED Enable, GPIO, LED Polarity, LED ON, LED Blink
- + */
- + {LED_ENABLE, 5, AIR_ACTIVE_LOW, BASE_T_LED0_ON_CFG, BASE_T_LED0_BLK_CFG}, /* BASE-T LED0 */
- + {LED_ENABLE, 9, AIR_ACTIVE_LOW, BASE_T_LED1_ON_CFG, BASE_T_LED1_BLK_CFG}, /* BASE-T LED1 */
- + {LED_ENABLE, 8, AIR_ACTIVE_LOW, BASE_T_LED2_ON_CFG, BASE_T_LED2_BLK_CFG}, /* BASE-T LED2 */
- + {LED_DISABLE, 1, AIR_ACTIVE_LOW, BASE_T_LED3_ON_CFG, BASE_T_LED3_BLK_CFG} /* BASE-T LED3 */
- +};
- +static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M;
- +#endif
- +/* User-defined.E */
- +/************************************************************************
- + * F U N C T I O N S
- + ************************************************************************/
- +/* Airoha MII read function */
- +static int airoha_cl22_read(struct mii_dev *bus, int phy_addr, int phy_register)
- +{
- + int read_data = bus->read(bus, phy_addr, MDIO_DEVAD_NONE, phy_register);
- +
- + if (read_data < 0)
- + return -EIO;
- + return read_data;
- +}
- +
- +/* Airoha MII write function */
- +static int airoha_cl22_write(struct mii_dev *bus, int phy_addr, int phy_register, int write_data)
- +{
- + int ret = bus->write(bus, phy_addr, MDIO_DEVAD_NONE, phy_register, write_data);
- +
- + return ret;
- +}
- +
- +static int airoha_cl45_write(struct phy_device *phydev, int devad, int reg, int val)
- +{
- + int ret = 0;
- +
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, devad);
- + AIR_RTN_ERR(ret);
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG, reg);
- + AIR_RTN_ERR(ret);
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
- + AIR_RTN_ERR(ret);
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG, val);
- + AIR_RTN_ERR(ret);
- + return ret;
- +}
- +
- +static int airoha_cl45_read(struct phy_device *phydev, int devad, int reg)
- +{
- + int read_data, ret;
- +
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, devad);
- + AIR_RTN_ERR(ret);
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG, reg);
- + AIR_RTN_ERR(ret);
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
- + AIR_RTN_ERR(ret);
- + read_data = phy_read(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG);
- + if (read_data < 0)
- + return -EIO;
- + return read_data;
- +}
- +
- +/* EN8801 PBUS write function */
- +int airoha_pbus_write(struct mii_dev *bus, int pbus_addr, int pbus_reg, unsigned long pbus_data)
- +{
- + int ret = 0;
- +
- + ret = airoha_cl22_write(bus, pbus_addr, 0x1F, (pbus_reg >> 6));
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl22_write(bus, pbus_addr, ((pbus_reg >> 2) & 0xf), (pbus_data & 0xFFFF));
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl22_write(bus, pbus_addr, 0x10, (pbus_data >> 16));
- + AIR_RTN_ERR(ret);
- + return ret;
- +}
- +
- +/* EN8801 PBUS read function */
- +unsigned long airoha_pbus_read(struct mii_dev *bus, int pbus_addr, int pbus_reg)
- +{
- + unsigned long pbus_data;
- + unsigned int pbus_data_low, pbus_data_high;
- +
- + airoha_cl22_write(bus, pbus_addr, 0x1F, (pbus_reg >> 6));
- + pbus_data_low = airoha_cl22_read(bus, pbus_addr, ((pbus_reg >> 2) & 0xf));
- + pbus_data_high = airoha_cl22_read(bus, pbus_addr, 0x10);
- + pbus_data = (pbus_data_high << 16) + pbus_data_low;
- + return pbus_data;
- +}
- +
- +/* Airoha Token Ring Write function */
- +static int airoha_tr_reg_write(struct phy_device *phydev, unsigned long tr_address, unsigned long tr_data)
- +{
- + int ret;
- +
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, 0x52b5); /* page select */
- + AIR_RTN_ERR(ret);
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x11, (int)(tr_data & 0xffff));
- + AIR_RTN_ERR(ret);
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x12, (int)(tr_data >> 16));
- + AIR_RTN_ERR(ret);
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x10, (int)(tr_address | TrReg_WR));
- + AIR_RTN_ERR(ret);
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, 0x0); /* page resetore */
- + AIR_RTN_ERR(ret);
- + return ret;
- +}
- +
- +int airoha_phy_process(void)
- +{
- + int ret = 0, pbus_addr = EN8801S_PBUS_PHY_ID;
- + unsigned long pbus_data;
- + struct mii_dev *mbus;
- +
- + mbus = s_phydev->bus;
- + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x19e0);
- + pbus_data |= BIT(0);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x19e0, pbus_data);
- + if(ret)
- + printf("error: airoha_pbus_write fail ret: %d\n", ret);
- + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x19e0);
- + pbus_data &= ~BIT(0);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x19e0, pbus_data);
- + if(ret)
- + printf("error: airoha_pbus_write fail ret: %d\n", ret);
- +
- + if(ret)
- + printf("error: FCM regs reset fail, ret: %d\n", ret);
- + else
- + debug("FCM regs reset successful\n");
- + return ret;
- +}
- +
- +#ifdef AIR_LED_SUPPORT
- +static int airoha_led_set_usr_def(struct phy_device *phydev, u8 entity, int polar,
- + u16 on_evt, u16 blk_evt)
- +{
- + int ret = 0;
- +
- + if (AIR_ACTIVE_HIGH == polar) {
- + on_evt |= LED_ON_POL;
- + } else {
- + on_evt &= ~LED_ON_POL;
- + }
- + ret = airoha_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), on_evt | LED_ON_EN);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1f, LED_BLK_CTRL(entity), blk_evt);
- + AIR_RTN_ERR(ret);
- + return 0;
- +}
- +
- +static int airoha_led_set_mode(struct phy_device *phydev, u8 mode)
- +{
- + u16 cl45_data;
- + int err = 0;
- +
- + cl45_data = airoha_cl45_read(phydev, 0x1f, LED_BCR);
- + switch (mode) {
- + case AIR_LED_MODE_DISABLE:
- + cl45_data &= ~LED_BCR_EXT_CTRL;
- + cl45_data &= ~LED_BCR_MODE_MASK;
- + cl45_data |= LED_BCR_MODE_DISABLE;
- + break;
- + case AIR_LED_MODE_USER_DEFINE:
- + cl45_data |= LED_BCR_EXT_CTRL;
- + cl45_data |= LED_BCR_CLK_EN;
- + break;
- + default:
- + printf("LED mode%d is not supported!\n", mode);
- + return -EINVAL;
- + }
- + err = airoha_cl45_write(phydev, 0x1f, LED_BCR, cl45_data);
- + AIR_RTN_ERR(err);
- + return 0;
- +}
- +
- +static int airoha_led_set_state(struct phy_device *phydev, u8 entity, u8 state)
- +{
- + u16 cl45_data;
- + int err;
- +
- + cl45_data = airoha_cl45_read(phydev, 0x1f, LED_ON_CTRL(entity));
- + if (LED_ENABLE == state) {
- + cl45_data |= LED_ON_EN;
- + } else {
- + cl45_data &= ~LED_ON_EN;
- + }
- +
- + err = airoha_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), cl45_data);
- + AIR_RTN_ERR(err);
- + return 0;
- +}
- +
- +static int en8801s_led_init(struct phy_device *phydev)
- +{
- +
- + unsigned long led_gpio = 0, reg_value = 0;
- + int ret = 0, led_id;
- + struct mii_dev *mbus = phydev->bus;
- + int gpio_led_rg[3] = {0x1870, 0x1874, 0x1878};
- + u16 cl45_data = led_dur;
- +
- + ret = airoha_cl45_write(phydev, 0x1f, LED_BLK_DUR, cl45_data);
- + AIR_RTN_ERR(ret);
- + cl45_data >>= 1;
- + ret = airoha_cl45_write(phydev, 0x1f, LED_ON_DUR, cl45_data);
- + AIR_RTN_ERR(ret);
- + ret = airoha_led_set_mode(phydev, AIR_LED_MODE_USER_DEFINE);
- + if (ret != 0) {
- + printf("LED fail to set mode, ret %d !\n", ret);
- + return ret;
- + }
- + for(led_id = 0; led_id < EN8801S_LED_COUNT; led_id++) {
- + reg_value = 0;
- + ret = airoha_led_set_state(phydev, led_id, led_cfg[led_id].en);
- + if (ret != 0) {
- + printf("LED fail to set state, ret %d !\n", ret);
- + return ret;
- + }
- + if (LED_ENABLE == led_cfg[led_id].en) {
- + if ( (led_cfg[led_id].gpio < 0) || led_cfg[led_id].gpio > 9) {
- + printf("GPIO%d is out of range!! GPIO number is 0~9.\n", led_cfg[led_id].gpio);
- + return -EIO;
- + }
- + led_gpio |= BIT(led_cfg[led_id].gpio);
- + reg_value = airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, gpio_led_rg[led_cfg[led_id].gpio / 4]);
- + LED_SET_GPIO_SEL(led_cfg[led_id].gpio, led_id, reg_value);
- + debug("[Airoha] gpio%d, reg_value 0x%lx\n", led_cfg[led_id].gpio, reg_value);
- + ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, gpio_led_rg[led_cfg[led_id].gpio / 4], reg_value);
- + AIR_RTN_ERR(ret);
- + ret = airoha_led_set_usr_def(phydev, led_id, led_cfg[led_id].pol, led_cfg[led_id].on_cfg, led_cfg[led_id].blk_cfg);
- + if (ret != 0) {
- + printf("LED fail to set usr def, ret %d !\n", ret);
- + return ret;
- + }
- + }
- + }
- + reg_value = (airoha_pbus_read(mbus, EN8801S_PBUS_PHY_ID, 0x1880) & ~led_gpio);
- + ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x1880, reg_value);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, EN8801S_PBUS_PHY_ID, 0x186c, led_gpio);
- + AIR_RTN_ERR(ret);
- +
- + printf("LED initialize OK !\n");
- + return 0;
- +}
- +#endif /* AIR_LED_SUPPORT */
- +
- +static int en8801s_config(struct phy_device *phydev)
- +{
- + int reg_value = 0, ret = 0;
- + struct mii_dev *mbus = phydev->bus;
- + int retry, pbus_addr = EN8801S_PBUS_DEFAULT_ID;
- + int phy_addr = EN8801S_MDIO_PHY_ID;
- + unsigned long pbus_data = 0;
- + gephy_all_REG_LpiReg1Ch GPHY_RG_LPI_1C;
- + gephy_all_REG_dev1Eh_reg324h GPHY_RG_1E_324;
- + gephy_all_REG_dev1Eh_reg012h GPHY_RG_1E_012;
- + gephy_all_REG_dev1Eh_reg017h GPHY_RG_1E_017;
- +
- + s_phydev = phydev;
- + retry = MAX_OUI_CHECK;
- + while (1) {
- + /* PHY OUI */
- + pbus_data = airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_ETHER_PHY_OUI);
- + if (EN8801S_PBUS_OUI == pbus_data) {
- + printf("PBUS addr 0x%x: Start initialized.\n", pbus_addr);
- + ret = airoha_pbus_write(mbus, pbus_addr, EN8801S_RG_BUCK_CTL, 0x03);
- + AIR_RTN_ERR(ret);
- + break;
- + } else
- + pbus_addr = EN8801S_PBUS_PHY_ID;
- +
- + if (0 == --retry) {
- + printf("EN8801S Probe fail !\n");
- + return 0;
- + }
- + }
- +
- + /* SMI ADDR */
- + pbus_data = airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_SMI_ADDR);
- + pbus_data = (pbus_data & 0xffff0000) | (unsigned long)(pbus_addr << 8) | (unsigned long)(EN8801S_MDIO_DEFAULT_ID);
- + ret = airoha_pbus_write(mbus, pbus_addr, EN8801S_RG_SMI_ADDR, pbus_data);
- + AIR_RTN_ERR(ret);
- + mdelay(10);
- +
- + pbus_data = (airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_LTR_CTL) & (~0x3)) | BIT(2) ;
- + ret = airoha_pbus_write(mbus, pbus_addr, EN8801S_RG_LTR_CTL, pbus_data);
- + AIR_RTN_ERR(ret);
- + mdelay(500);
- + pbus_data = (pbus_data & ~BIT(2)) | EN8801S_RX_POLARITY_NORMAL | EN8801S_TX_POLARITY_NORMAL;
- + ret = airoha_pbus_write(mbus, pbus_addr, EN8801S_RG_LTR_CTL, pbus_data);
- + AIR_RTN_ERR(ret);
- + mdelay(500);
- + /* SMI ADDR */
- + pbus_data = airoha_pbus_read(mbus, pbus_addr, EN8801S_RG_SMI_ADDR);
- + pbus_data = (pbus_data & 0xffff0000) | (unsigned long)(EN8801S_PBUS_PHY_ID << 8) | (unsigned long)(EN8801S_MDIO_PHY_ID);
- + ret = airoha_pbus_write(mbus, pbus_addr, EN8801S_RG_SMI_ADDR, pbus_data);
- + pbus_addr = EN8801S_PBUS_PHY_ID;
- + AIR_RTN_ERR(ret);
- + mdelay(10);
- +
- + /* Optimze 10M IoT */
- + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1690);
- + pbus_data |= (1 << 31);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x1690, pbus_data);
- + AIR_RTN_ERR(ret);
- + /* set SGMII Base Page */
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x10, 0xD801);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x0, 0x9140);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, 0x0003);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00);
- + AIR_RTN_ERR(ret);
- + /* Set FCM control */
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, 0x004b);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, 0x0007);
- + AIR_RTN_ERR(ret);
- +
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x142c, 0x05050505);
- + AIR_RTN_ERR(ret);
- + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1440);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x1440, pbus_data & ~BIT(11));
- + AIR_RTN_ERR(ret);
- +
- + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1408);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x1408, pbus_data | BIT(5));
- + AIR_RTN_ERR(ret);
- +
- + /* Set GPHY Perfomance*/
- + /* Token Ring */
- + ret = airoha_tr_reg_write(phydev, RgAddr_R1000DEC_15h, 0x0055A0);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_R1000DEC_17h, 0x07FF3F);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_PMA_00h, 0x00001E);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_PMA_01h, 0x6FB90A);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_PMA_17h, 0x060671);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_PMA_18h, 0x0E2F00);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_TR_26h, 0x444444);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_03h, 0x000000);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_06h, 0x2EBAEF);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_08h, 0x00000B);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Ch, 0x00504D);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Dh, 0x02314F);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_0Fh, 0x003028);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_10h, 0x005010);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_11h, 0x040001);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_13h, 0x018670);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_14h, 0x00024A);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_1Bh, 0x000072);
- + AIR_RTN_ERR(ret);
- + ret = airoha_tr_reg_write(phydev, RgAddr_DSPF_1Ch, 0x003210);
- + AIR_RTN_ERR(ret);
- + /* CL22 & CL45 */
- + ret = airoha_cl22_write(mbus, phy_addr, 0x1f, 0x03);
- + AIR_RTN_ERR(ret);
- + GPHY_RG_LPI_1C.DATA = airoha_cl22_read(mbus, phy_addr, RgAddr_LPI_1Ch);
- + if (GPHY_RG_LPI_1C.DATA < 0)
- + return -EIO;
- + GPHY_RG_LPI_1C.DataBitField.smi_deton_th = 0x0C;
- + ret = airoha_cl22_write(mbus, phy_addr, RgAddr_LPI_1Ch, GPHY_RG_LPI_1C.DATA);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl22_write(mbus, phy_addr, RgAddr_LPI_1Ch, 0xC92);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl22_write(mbus, phy_addr, RgAddr_AUXILIARY_1Dh, 0x1);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl22_write(mbus, phy_addr, 0x1f, 0x0);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x120, 0x8014);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x122, 0xffff);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x123, 0xffff);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x144, 0x0200);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x14A, 0xEE20);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x189, 0x0110);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x19B, 0x0111);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x234, 0x0181);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x238, 0x0120);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x239, 0x0117);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x268, 0x07F4);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x2D1, 0x0733);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x323, 0x0011);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x324, 0x013F);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x326, 0x0037);
- + AIR_RTN_ERR(ret);
- +
- + reg_value = airoha_cl45_read(phydev, 0x1E, 0x324);
- + if (reg_value < 0)
- + return -EIO;
- + GPHY_RG_1E_324.DATA = (int)reg_value;
- + GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = 0;
- + ret = airoha_cl45_write(phydev, 0x1E, 0x324, GPHY_RG_1E_324.DATA);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x19E, 0xC2);
- + AIR_RTN_ERR(ret);
- + ret = airoha_cl45_write(phydev, 0x1E, 0x013, 0x0);
- + AIR_RTN_ERR(ret);
- +
- + /* EFUSE */
- + airoha_pbus_write(mbus, pbus_addr, 0x1C08, 0x40000040);
- + retry = MAX_RETRY;
- + while (0 != retry) {
- + mdelay(1);
- + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C08);
- + if ((pbus_data & (1 << 30)) == 0) {
- + break;
- + }
- + retry--;
- + }
- + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C38); /* RAW#2 */
- + reg_value = airoha_cl45_read(phydev, 0x1E, 0x12);
- + if (reg_value < 0)
- + return -EIO;
- + GPHY_RG_1E_012.DATA = reg_value;
- + GPHY_RG_1E_012.DataBitField.da_tx_i2mpb_a_tbt = pbus_data & 0x03f;
- + ret = airoha_cl45_write(phydev, 0x1E, 0x12, GPHY_RG_1E_012.DATA);
- + AIR_RTN_ERR(ret);
- + reg_value = airoha_cl45_read(phydev, 0x1E, 0x17);
- + if (reg_value < 0)
- + return -EIO;
- + GPHY_RG_1E_017.DataBitField.da_tx_i2mpb_b_tbt = (reg_value >> 8) & 0x03f;
- + ret = airoha_cl45_write(phydev, 0x1E, 0x17, GPHY_RG_1E_017.DATA);
- + AIR_RTN_ERR(ret);
- +
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x1C08, 0x40400040);
- + AIR_RTN_ERR(ret);
- + retry = MAX_RETRY;
- + while (0 != retry) {
- + mdelay(1);
- + reg_value = airoha_pbus_read(mbus, pbus_addr, 0x1C08);
- + if ((reg_value & (1 << 30)) == 0) {
- + break;
- + }
- + retry--;
- + }
- + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1C30); /* RAW#16 */
- + GPHY_RG_1E_324.DataBitField.smi_det_deglitch_off = (pbus_data >> 12) & 0x01;
- + ret = airoha_cl45_write(phydev, 0x1E, 0x324, GPHY_RG_1E_324.DATA);
- + AIR_RTN_ERR(ret);
- +#ifdef AIR_LED_SUPPORT
- + ret = en8801s_led_init(phydev);
- + if (ret != 0){
- + printf("en8801s_led_init fail (ret:%d) !\n", ret);
- + }
- +#endif
- + printf("EN8801S initialize OK ! (%s)\n", EN8801S_DRIVER_VERSION);
- + return 0;
- +}
- +
- +int en8801s_read_status(struct phy_device *phydev)
- +{
- + int ret, pbus_addr = EN8801S_PBUS_PHY_ID;
- + struct mii_dev *mbus;
- + unsigned long pbus_data;
- +
- + mbus = phydev->bus;
- + if (SPEED_10 == phydev->speed) {
- + /* set the bit for Optimze 10M IoT */
- + debug("[Airoha] SPEED_10 0x1694\n");
- + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1694);
- + pbus_data |= (1 << 31);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x1694, pbus_data);
- + AIR_RTN_ERR(ret);
- + } else {
- + debug("[Airoha] SPEED_1000/100 0x1694\n");
- + /* clear the bit for other speeds */
- + pbus_data = airoha_pbus_read(mbus, pbus_addr, 0x1694);
- + pbus_data &= ~(1 << 31);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x1694, pbus_data);
- + AIR_RTN_ERR(ret);
- + }
- +
- + airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00);
- + if(SPEED_1000 == phydev->speed) {
- + debug("[Airoha] SPEED_1000\n");
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x10, 0xD801);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x0, 0x9140);
- + AIR_RTN_ERR(ret);
- +
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, 0x0003);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c000c00);
- + AIR_RTN_ERR(ret);
- + mdelay(2); /* delay 2 ms */
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, 0x004b);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, 0x0007);
- + AIR_RTN_ERR(ret);
- + }
- + else if (SPEED_100 == phydev->speed) {
- + debug("[Airoha] SPEED_100\n");
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x10, 0xD401);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x0, 0x9140);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, 0x0007);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c11);
- + AIR_RTN_ERR(ret);
- + mdelay(2); /* delay 2 ms */
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, 0x0027);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, 0x0007);
- + AIR_RTN_ERR(ret);
- + }
- + else {
- + debug("[Airoha] SPEED_10\n");
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x10, 0xD001);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x0, 0x9140);
- + AIR_RTN_ERR(ret);
- +
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x0A14, 0x000b);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x0600, 0x0c11);
- + AIR_RTN_ERR(ret);
- + mdelay(2); /* delay 2 ms */
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x1404, 0x0047);
- + AIR_RTN_ERR(ret);
- + ret = airoha_pbus_write(mbus, pbus_addr, 0x140c, 0x0007);
- + AIR_RTN_ERR(ret);
- + }
- + return 0;
- +}
- +
- +static int en8801s_startup(struct phy_device *phydev)
- +{
- + int ret;
- +
- + ret = genphy_update_link(phydev);
- + if (ret)
- + return ret;
- + ret = genphy_parse_link(phydev);
- + if (ret)
- + return ret;
- + return en8801s_read_status(phydev);
- +}
- +#if AIR_UBOOT_REVISION > 0x202303
- +U_BOOT_PHY_DRIVER(en8801s) = {
- + .name = "Airoha EN8801S",
- + .uid = EN8801S_PHY_ID,
- + .mask = 0x0ffffff0,
- + .features = PHY_GBIT_FEATURES,
- + .config = &en8801s_config,
- + .startup = &en8801s_startup,
- + .shutdown = &genphy_shutdown,
- +};
- +#else
- +static struct phy_driver AIR_EN8801S_driver = {
- + .name = "Airoha EN8801S",
- + .uid = EN8801S_PHY_ID,
- + .mask = 0x0ffffff0,
- + .features = PHY_GBIT_FEATURES,
- + .config = &en8801s_config,
- + .startup = &en8801s_startup,
- + .shutdown = &genphy_shutdown,
- +};
- +
- +int phy_air_en8801s_init(void)
- +{
- + phy_register(&AIR_EN8801S_driver);
- + return 0;
- +}
- +#endif
- --- /dev/null
- +++ b/drivers/net/phy/air_en8801s.h
- @@ -0,0 +1,267 @@
- +/* SPDX-License-Identifier: GPL-2.0 */
- +/*************************************************
- + * FILE NAME: air_en8801s.h
- + * PURPOSE:
- + * EN8801S PHY Driver for Uboot
- + * NOTES:
- + *
- + * Copyright (C) 2023 Airoha Technology Corp.
- + *************************************************/
- +
- +#ifndef __EN8801S_H
- +#define __EN8801S_H
- +
- +/************************************************************************
- +* D E F I N E S
- +************************************************************************/
- +#define AIR_UBOOT_REVISION ((((U_BOOT_VERSION_NUM / 1000) % 10) << 20) | \
- + (((U_BOOT_VERSION_NUM / 100) % 10) << 16) | \
- + (((U_BOOT_VERSION_NUM / 10) % 10) << 12) | \
- + ((U_BOOT_VERSION_NUM % 10) << 8) | \
- + (((U_BOOT_VERSION_NUM_PATCH / 10) % 10) << 4) | \
- + ((U_BOOT_VERSION_NUM_PATCH % 10) << 0))
- +
- +#define EN8801S_MDIO_DEFAULT_ID 0x1d
- +#define EN8801S_PBUS_DEFAULT_ID (EN8801S_MDIO_DEFAULT_ID + 1)
- +#define EN8801S_MDIO_PHY_ID 0x18 /* Range PHY_ADDRESS_RANGE .. 0x1e */
- +#define EN8801S_PBUS_PHY_ID (EN8801S_MDIO_PHY_ID + 1)
- +#define EN8801S_DRIVER_VERSION "v1.1.3"
- +
- +#define EN8801S_RG_ETHER_PHY_OUI 0x19a4
- +#define EN8801S_RG_SMI_ADDR 0x19a8
- +#define EN8801S_PBUS_OUI 0x17a5
- +#define EN8801S_RG_BUCK_CTL 0x1a20
- +#define EN8801S_RG_LTR_CTL 0x0cf8
- +
- +#define EN8801S_PHY_ID1 0x03a2
- +#define EN8801S_PHY_ID2 0x9461
- +#define EN8801S_PHY_ID (unsigned long)((EN8801S_PHY_ID1 << 16) | EN8801S_PHY_ID2)
- +
- +/*
- +SFP Sample for verification
- +Tx Reverse, Rx Reverse
- +*/
- +#define EN8801S_TX_POLARITY_NORMAL 0x0
- +#define EN8801S_TX_POLARITY_REVERSE 0x1
- +
- +#define EN8801S_RX_POLARITY_NORMAL (0x1 << 1)
- +#define EN8801S_RX_POLARITY_REVERSE (0x0 << 1)
- +
- +#ifndef BIT
- +#define BIT(nr) (1UL << (nr))
- +#endif
- +
- +#define MAX_RETRY 5
- +#define MAX_OUI_CHECK 2
- +
- +/* CL45 MDIO control */
- +#define MII_MMD_ACC_CTL_REG 0x0d
- +#define MII_MMD_ADDR_DATA_REG 0x0e
- +#define MMD_OP_MODE_DATA BIT(14)
- +
- +#define MAX_TRG_COUNTER 5
- +
- +/* TokenRing Reg Access */
- +#define TrReg_PKT_XMT_STA 0x8000
- +#define TrReg_WR 0x8000
- +#define TrReg_RD 0xA000
- +
- +#define RgAddr_LPI_1Ch 0x1c
- +#define RgAddr_AUXILIARY_1Dh 0x1d
- +#define RgAddr_PMA_00h 0x0f80
- +#define RgAddr_PMA_01h 0x0f82
- +#define RgAddr_PMA_17h 0x0fae
- +#define RgAddr_PMA_18h 0x0fb0
- +#define RgAddr_DSPF_03h 0x1686
- +#define RgAddr_DSPF_06h 0x168c
- +#define RgAddr_DSPF_08h 0x1690
- +#define RgAddr_DSPF_0Ch 0x1698
- +#define RgAddr_DSPF_0Dh 0x169a
- +#define RgAddr_DSPF_0Fh 0x169e
- +#define RgAddr_DSPF_10h 0x16a0
- +#define RgAddr_DSPF_11h 0x16a2
- +#define RgAddr_DSPF_13h 0x16a6
- +#define RgAddr_DSPF_14h 0x16a8
- +#define RgAddr_DSPF_1Bh 0x16b6
- +#define RgAddr_DSPF_1Ch 0x16b8
- +#define RgAddr_TR_26h 0x0ecc
- +#define RgAddr_R1000DEC_15h 0x03aa
- +#define RgAddr_R1000DEC_17h 0x03ae
- +
- +/*
- +The following led_cfg example is for reference only.
- +LED5 1000M/LINK/ACT (GPIO5) <-> BASE_T_LED0,
- +LED6 10/100M/LINK/ACT(GPIO9) <-> BASE_T_LED1,
- +LED4 100M/LINK/ACT (GPIO8) <-> BASE_T_LED2,
- +*/
- +/* User-defined.B */
- +#define BASE_T_LED0_ON_CFG (LED_ON_EVT_LINK_1000M)
- +#define BASE_T_LED0_BLK_CFG (LED_BLK_EVT_1000M_TX_ACT | LED_BLK_EVT_1000M_RX_ACT)
- +#define BASE_T_LED1_ON_CFG (LED_ON_EVT_LINK_100M | LED_ON_EVT_LINK_10M)
- +#define BASE_T_LED1_BLK_CFG (LED_BLK_EVT_100M_TX_ACT | LED_BLK_EVT_100M_RX_ACT | \
- + LED_BLK_EVT_10M_TX_ACT | LED_BLK_EVT_10M_RX_ACT )
- +#define BASE_T_LED2_ON_CFG (LED_ON_EVT_LINK_100M)
- +#define BASE_T_LED2_BLK_CFG (LED_BLK_EVT_100M_TX_ACT | LED_BLK_EVT_100M_RX_ACT)
- +#define BASE_T_LED3_ON_CFG (0x0)
- +#define BASE_T_LED3_BLK_CFG (0x0)
- +/* User-defined.E */
- +
- +#define EN8801S_LED_COUNT 4
- +
- +#define LED_BCR (0x021)
- +#define LED_BCR_EXT_CTRL (1 << 15)
- +#define LED_BCR_CLK_EN (1 << 3)
- +#define LED_BCR_TIME_TEST (1 << 2)
- +#define LED_BCR_MODE_MASK (3)
- +#define LED_BCR_MODE_DISABLE (0)
- +#define LED_ON_CTRL(i) (0x024 + ((i)*2))
- +#define LED_ON_EN (1 << 15)
- +#define LED_ON_POL (1 << 14)
- +#define LED_ON_EVT_MASK (0x7f)
- +/* LED ON Event Option.B */
- +#define LED_ON_EVT_FORCE (1 << 6)
- +#define LED_ON_EVT_LINK_DOWN (1 << 3)
- +#define LED_ON_EVT_LINK_10M (1 << 2)
- +#define LED_ON_EVT_LINK_100M (1 << 1)
- +#define LED_ON_EVT_LINK_1000M (1 << 0)
- +/* LED ON Event Option.E */
- +#define LED_BLK_CTRL(i) (0x025 + ((i)*2))
- +#define LED_BLK_EVT_MASK (0x3ff)
- +/* LED Blinking Event Option.B*/
- +#define LED_BLK_EVT_FORCE (1 << 9)
- +#define LED_BLK_EVT_10M_RX_ACT (1 << 5)
- +#define LED_BLK_EVT_10M_TX_ACT (1 << 4)
- +#define LED_BLK_EVT_100M_RX_ACT (1 << 3)
- +#define LED_BLK_EVT_100M_TX_ACT (1 << 2)
- +#define LED_BLK_EVT_1000M_RX_ACT (1 << 1)
- +#define LED_BLK_EVT_1000M_TX_ACT (1 << 0)
- +/* LED Blinking Event Option.E*/
- +#define LED_ON_DUR (0x022)
- +#define LED_ON_DUR_MASK (0xffff)
- +#define LED_BLK_DUR (0x023)
- +#define LED_BLK_DUR_MASK (0xffff)
- +
- +#define LED_ENABLE 1
- +#define LED_DISABLE 0
- +
- +#define UNIT_LED_BLINK_DURATION 1024
- +
- +#define AIR_RTN_ON_ERR(cond, err) \
- + do { if ((cond)) return (err); } while(0)
- +
- +#define AIR_RTN_ERR(err) AIR_RTN_ON_ERR(err < 0, err)
- +
- +#define LED_SET_EVT(reg, cod, result, bit) do \
- + { \
- + if(reg & cod) { \
- + result |= bit; \
- + } \
- + } while(0)
- +
- +#define LED_SET_GPIO_SEL(gpio, led, val) do \
- + { \
- + val |= (led << (8 * (gpio % 4))); \
- + } while(0)
- +
- +/* DATA TYPE DECLARATIONS
- + */
- +typedef struct
- +{
- + int DATA_Lo;
- + int DATA_Hi;
- +}TR_DATA_T;
- +
- +typedef union
- +{
- + struct
- + {
- + /* b[15:00] */
- + int smi_deton_wt : 3;
- + int smi_det_mdi_inv : 1;
- + int smi_detoff_wt : 3;
- + int smi_sigdet_debouncing_en : 1;
- + int smi_deton_th : 6;
- + int rsv_14 : 2;
- + } DataBitField;
- + int DATA;
- +} gephy_all_REG_LpiReg1Ch, *Pgephy_all_REG_LpiReg1Ch;
- +
- +typedef union
- +{
- + struct
- + {
- + /* b[15:00] */
- + int rg_smi_detcnt_max : 6;
- + int rsv_6 : 2;
- + int rg_smi_det_max_en : 1;
- + int smi_det_deglitch_off : 1;
- + int rsv_10 : 6;
- + } DataBitField;
- + int DATA;
- +} gephy_all_REG_dev1Eh_reg324h, *Pgephy_all_REG_dev1Eh_reg324h;
- +
- +typedef union
- +{
- + struct
- + {
- + /* b[15:00] */
- + int da_tx_i2mpb_a_tbt : 6;
- + int rsv_6 : 4;
- + int da_tx_i2mpb_a_gbe : 6;
- + } DataBitField;
- + int DATA;
- +} gephy_all_REG_dev1Eh_reg012h, *Pgephy_all_REG_dev1Eh_reg012h;
- +
- +typedef union
- +{
- + struct
- + {
- + /* b[15:00] */
- + int da_tx_i2mpb_b_tbt : 6;
- + int rsv_6 : 2;
- + int da_tx_i2mpb_b_gbe : 6;
- + int rsv_14 : 2;
- + } DataBitField;
- + int DATA;
- +} gephy_all_REG_dev1Eh_reg017h, *Pgephy_all_REG_dev1Eh_reg017h;
- +
- +typedef struct AIR_BASE_T_LED_CFG_S
- +{
- + u16 en;
- + u16 gpio;
- + u16 pol;
- + u16 on_cfg;
- + u16 blk_cfg;
- +}AIR_BASE_T_LED_CFG_T;
- +
- +typedef enum
- +{
- + AIR_LED_BLK_DUR_32M,
- + AIR_LED_BLK_DUR_64M,
- + AIR_LED_BLK_DUR_128M,
- + AIR_LED_BLK_DUR_256M,
- + AIR_LED_BLK_DUR_512M,
- + AIR_LED_BLK_DUR_1024M,
- + AIR_LED_BLK_DUR_LAST
- +} AIR_LED_BLK_DUT_T;
- +
- +typedef enum
- +{
- + AIR_ACTIVE_LOW,
- + AIR_ACTIVE_HIGH,
- +} AIR_LED_POLARITY;
- +typedef enum
- +{
- + AIR_LED_MODE_DISABLE,
- + AIR_LED_MODE_USER_DEFINE,
- + AIR_LED_MODE_LAST
- +} AIR_LED_MODE_T;
- +
- +/************************************************************************
- +* F U N C T I O N P R O T O T Y P E S
- +************************************************************************/
- +
- +unsigned long airoha_pbus_read(struct mii_dev *bus, int pbus_addr, int pbus_reg);
- +int airoha_pbus_write(struct mii_dev *bus, int pbus_addr, int pbus_reg, unsigned long pbus_data);
- +int airoha_phy_process(void);
- +#endif /* __EN8801S_H */
- --- /dev/null
- +++ b/drivers/net/phy/air_en8811h.c
- @@ -0,0 +1,725 @@
- +// SPDX-License-Identifier: GPL-2.0
- +/*************************************************
- + * FILE NAME: air_en8811h.c
- + * PURPOSE:
- + * EN8811H PHY Driver for Uboot
- + * NOTES:
- + *
- + * Copyright (C) 2023 Airoha Technology Corp.
- + *************************************************/
- +
- +/* INCLUDE FILE DECLARATIONS
- +*/
- +#include <common.h>
- +#include <eth_phy.h>
- +#include <phy.h>
- +#include <errno.h>
- +#include <malloc.h>
- +#include <version.h>
- +#include "air_en8811h.h"
- +
- +#ifdef CONFIG_PHY_AIROHA_FW_IN_UBI
- +#include <ubi_uboot.h>
- +#endif
- +
- +#ifdef CONFIG_PHY_AIROHA_FW_IN_MMC
- +#include <mmc.h>
- +#endif
- +
- +#ifdef CONFIG_PHY_AIROHA_FW_IN_MTD
- +#include <mtd.h>
- +#endif
- +
- +#if AIR_UBOOT_REVISION > 0x202004
- +#include <linux/delay.h>
- +#endif
- +
- +/**************************
- + * GPIO5 <-> BASE_T_LED0,
- + * GPIO4 <-> BASE_T_LED1,
- + * GPIO3 <-> BASE_T_LED2,
- + **************************/
- +/* User-defined.B */
- +#define AIR_LED_SUPPORT
- +#ifdef AIR_LED_SUPPORT
- +static const struct air_base_t_led_cfg_s led_cfg[3] = {
- +/*********************************************************************
- + *Enable, GPIO, LED Polarity, LED ON, LED Blink
- +**********************************************************************/
- + {1, AIR_LED0_GPIO5, AIR_ACTIVE_HIGH, AIR_LED0_ON, AIR_LED0_BLK},
- + {1, AIR_LED1_GPIO4, AIR_ACTIVE_HIGH, AIR_LED1_ON, AIR_LED1_BLK},
- + {1, AIR_LED2_GPIO3, AIR_ACTIVE_HIGH, AIR_LED2_ON, AIR_LED2_BLK},
- +};
- +static const u16 led_dur = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M;
- +#endif
- +/* User-defined.E */
- +/*************************************************************
- + * F U N C T I O N S
- + **************************************************************/
- +/* Airoha MII read function */
- +static int air_mii_cl22_read(struct mii_dev *bus, int phy_addr, int phy_register)
- +{
- + int read_data = bus->read(bus, phy_addr, MDIO_DEVAD_NONE, phy_register);
- +
- + if (read_data < 0)
- + return -EIO;
- + return read_data;
- +}
- +
- +/* Airoha MII write function */
- +static int air_mii_cl22_write(struct mii_dev *bus, int phy_addr, int phy_register, int write_data)
- +{
- + int ret = 0;
- +
- + ret = bus->write(bus, phy_addr, MDIO_DEVAD_NONE, phy_register, write_data);
- + if (ret < 0) {
- + printf("bus->write, ret: %d\n", ret);
- + return ret;
- + }
- + return ret;
- +}
- +
- +static int air_mii_cl45_read(struct phy_device *phydev, int devad, u16 reg)
- +{
- + int ret = 0;
- + int data;
- +
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, devad);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return INVALID_DATA;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG, reg);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return INVALID_DATA;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return INVALID_DATA;
- + }
- + data = phy_read(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG);
- + return data;
- +}
- +
- +static int air_mii_cl45_write(struct phy_device *phydev, int devad, u16 reg, u16 write_data)
- +{
- + int ret = 0;
- +
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, devad);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG, reg);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_ADDR_DATA_REG, write_data);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + return 0;
- +}
- +/* Use default PBUS_PHY_ID */
- +/* EN8811H PBUS write function */
- +static int air_pbus_reg_write(struct phy_device *phydev, unsigned long pbus_address, unsigned long pbus_data)
- +{
- + int ret = 0;
- + struct mii_dev *mbus = phydev->bus;
- +
- + ret = air_mii_cl22_write(mbus, ((phydev->addr) + 8), 0x1F, (unsigned int)(pbus_address >> 6));
- + if (ret < 0)
- + return ret;
- + ret = air_mii_cl22_write(mbus, ((phydev->addr) + 8), (unsigned int)((pbus_address >> 2) & 0xf), (unsigned int)(pbus_data & 0xFFFF));
- + if (ret < 0)
- + return ret;
- + ret = air_mii_cl22_write(mbus, ((phydev->addr) + 8), 0x10, (unsigned int)(pbus_data >> 16));
- + if (ret < 0)
- + return ret;
- + return 0;
- +}
- +
- +/* EN8811H BUCK write function */
- +static int air_buckpbus_reg_write(struct phy_device *phydev, unsigned long pbus_address, unsigned int pbus_data)
- +{
- + int ret = 0;
- +
- + /* page 4 */
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, (unsigned int)4);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x10, (unsigned int)0);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x11, (unsigned int)((pbus_address >> 16) & 0xffff));
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x12, (unsigned int)(pbus_address & 0xffff));
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x13, (unsigned int)((pbus_data >> 16) & 0xffff));
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x14, (unsigned int)(pbus_data & 0xffff));
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + return 0;
- +}
- +
- +/* EN8811H BUCK read function */
- +static unsigned int air_buckpbus_reg_read(struct phy_device *phydev, unsigned long pbus_address)
- +{
- + unsigned int pbus_data = 0, pbus_data_low, pbus_data_high;
- + int ret = 0;
- +
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, (unsigned int)4); /* page 4 */
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return PBUS_INVALID_DATA;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x10, (unsigned int)0);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return PBUS_INVALID_DATA;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x15, (unsigned int)((pbus_address >> 16) & 0xffff));
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return PBUS_INVALID_DATA;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x16, (unsigned int)(pbus_address & 0xffff));
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return PBUS_INVALID_DATA;
- + }
- +
- + pbus_data_high = phy_read(phydev, MDIO_DEVAD_NONE, 0x17);
- + pbus_data_low = phy_read(phydev, MDIO_DEVAD_NONE, 0x18);
- + pbus_data = (pbus_data_high << 16) + pbus_data_low;
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, (unsigned int)0);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + return pbus_data;
- +}
- +
- +static int MDIOWriteBuf(struct phy_device *phydev, unsigned long address, unsigned long array_size, const unsigned char *buffer)
- +{
- + unsigned int write_data, offset ;
- + int ret = 0;
- +
- + /* page 4 */
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, (unsigned int)4);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + /* address increment*/
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x10, (unsigned int)0x8000);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x11, (unsigned int)((address >> 16) & 0xffff));
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x12, (unsigned int)(address & 0xffff));
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- +
- + for (offset = 0; offset < array_size; offset += 4) {
- + write_data = (buffer[offset + 3] << 8) | buffer[offset + 2];
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x13, write_data);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + write_data = (buffer[offset + 1] << 8) | buffer[offset];
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x14, write_data);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + }
- + ret = phy_write(phydev, MDIO_DEVAD_NONE, 0x1F, (unsigned int)0);
- + if (ret < 0) {
- + printf("phy_write, ret: %d\n", ret);
- + return ret;
- + }
- + return 0;
- +}
- +
- +#ifdef AIR_LED_SUPPORT
- +static int airoha_led_set_usr_def(struct phy_device *phydev, u8 entity, int polar,
- + u16 on_evt, u16 blk_evt)
- +{
- + int ret = 0;
- +
- + if (AIR_ACTIVE_HIGH == polar)
- + on_evt |= LED_ON_POL;
- + else
- + on_evt &= ~LED_ON_POL;
- +
- + ret = air_mii_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), on_evt | LED_ON_EN);
- + if (ret < 0)
- + return ret;
- + ret = air_mii_cl45_write(phydev, 0x1f, LED_BLK_CTRL(entity), blk_evt);
- + if (ret < 0)
- + return ret;
- + return 0;
- +}
- +
- +static int airoha_led_set_mode(struct phy_device *phydev, u8 mode)
- +{
- + u16 cl45_data;
- + int err = 0;
- +
- + cl45_data = air_mii_cl45_read(phydev, 0x1f, LED_BCR);
- + switch (mode) {
- + case AIR_LED_MODE_DISABLE:
- + cl45_data &= ~LED_BCR_EXT_CTRL;
- + cl45_data &= ~LED_BCR_MODE_MASK;
- + cl45_data |= LED_BCR_MODE_DISABLE;
- + break;
- + case AIR_LED_MODE_USER_DEFINE:
- + cl45_data |= LED_BCR_EXT_CTRL;
- + cl45_data |= LED_BCR_CLK_EN;
- + break;
- + default:
- + printf("LED mode%d is not supported!\n", mode);
- + return -EINVAL;
- + }
- + err = air_mii_cl45_write(phydev, 0x1f, LED_BCR, cl45_data);
- + if (err < 0)
- + return err;
- + return 0;
- +}
- +
- +static int airoha_led_set_state(struct phy_device *phydev, u8 entity, u8 state)
- +{
- + u16 cl45_data;
- + int err;
- +
- + cl45_data = air_mii_cl45_read(phydev, 0x1f, LED_ON_CTRL(entity));
- + if (LED_ENABLE == state)
- + cl45_data |= LED_ON_EN;
- + else
- + cl45_data &= ~LED_ON_EN;
- +
- + err = air_mii_cl45_write(phydev, 0x1f, LED_ON_CTRL(entity), cl45_data);
- + if (err < 0)
- + return err;
- + return 0;
- +}
- +
- +static int en8811h_led_init(struct phy_device *phydev)
- +{
- + unsigned int led_gpio = 0, reg_value = 0;
- + u16 cl45_data = led_dur;
- + int ret, led_id;
- +
- + cl45_data = UNIT_LED_BLINK_DURATION << AIR_LED_BLK_DUR_64M;
- + ret = air_mii_cl45_write(phydev, 0x1f, LED_BLK_DUR, cl45_data);
- + if (ret < 0)
- + return ret;
- + cl45_data >>= 1;
- + ret = air_mii_cl45_write(phydev, 0x1f, LED_ON_DUR, cl45_data);
- + if (ret < 0)
- + return ret;
- +
- + ret = airoha_led_set_mode(phydev, AIR_LED_MODE_USER_DEFINE);
- + if (ret != 0) {
- + printf("LED fail to set mode, ret %d !\n", ret);
- + return ret;
- + }
- + for(led_id = 0; led_id < EN8811H_LED_COUNT; led_id++)
- + {
- + /* LED0 <-> GPIO5, LED1 <-> GPIO4, LED0 <-> GPIO3 */
- + if ( led_cfg[led_id].gpio != (led_id + (AIR_LED0_GPIO5 - (2 * led_id)))) {
- + printf("LED%d uses incorrect GPIO%d !\n", led_id, led_cfg[led_id].gpio);
- + return -EINVAL;
- + }
- + reg_value = 0;
- + if (led_cfg[led_id].en == LED_ENABLE)
- + {
- + led_gpio |= BIT(led_cfg[led_id].gpio);
- + ret = airoha_led_set_state(phydev, led_id, led_cfg[led_id].en);
- + if (ret != 0) {
- + printf("LED fail to set state, ret %d !\n", ret);
- + return ret;
- + }
- + ret = airoha_led_set_usr_def(phydev, led_id, led_cfg[led_id].pol, led_cfg[led_id].on_cfg, led_cfg[led_id].blk_cfg);
- + if (ret != 0) {
- + printf("LED fail to set default, ret %d !\n", ret);
- + return ret;
- + }
- + }
- + }
- + ret = air_buckpbus_reg_write(phydev, 0xcf8b8, led_gpio);
- + if (ret < 0)
- + return ret;
- + printf("LED initialize OK !\n");
- + return 0;
- +}
- +#endif /* AIR_LED_SUPPORT */
- +
- +static char *firmware_buf;
- +static int en8811h_load_firmware(struct phy_device *phydev)
- +{
- + u32 pbus_value;
- + int ret = 0;
- +
- + if (!firmware_buf) {
- + firmware_buf = malloc(EN8811H_MD32_DM_SIZE + EN8811H_MD32_DSP_SIZE);
- + if (!firmware_buf) {
- + printf("[Airoha] cannot allocated buffer for firmware.\n");
- + return -ENOMEM;
- + }
- +
- +#ifdef CONFIG_PHY_AIROHA_FW_IN_UBI
- + ret = ubi_volume_read("en8811h-fw", firmware_buf, EN8811H_MD32_DM_SIZE + EN8811H_MD32_DSP_SIZE);
- + if (ret) {
- + printf("[Airoha] read firmware from UBI failed.\n");
- + free(firmware_buf);
- + firmware_buf = NULL;
- + return ret;
- + }
- +#elif defined(CONFIG_PHY_AIROHA_FW_IN_MMC)
- + struct mmc *mmc = find_mmc_device(0);
- + if (!mmc) {
- + printf("[Airoha] opening MMC device failed.\n");
- + free(firmware_buf);
- + firmware_buf = NULL;
- + return -ENODEV;
- + }
- + if (mmc_init(mmc)) {
- + printf("[Airoha] initializing MMC device failed.\n");
- + free(firmware_buf);
- + firmware_buf = NULL;
- + return -ENODEV;
- + }
- + if (IS_SD(mmc)) {
- + printf("[Airoha] SD card is not supported.\n");
- + free(firmware_buf);
- + firmware_buf = NULL;
- + return -EINVAL;
- + }
- + ret = mmc_set_part_conf(mmc, 1, 2, 2);
- + if (ret) {
- + printf("[Airoha] cannot access eMMC boot1 hw partition.\n");
- + free(firmware_buf);
- + firmware_buf = NULL;
- + return ret;
- + }
- + ret = blk_dread(mmc_get_blk_desc(mmc), 0, 0x120, firmware_buf);
- + mmc_set_part_conf(mmc, 1, 1, 0);
- + if (ret != 0x120) {
- + printf("[Airoha] cannot read firmware from eMMC.\n");
- + free(firmware_buf);
- + firmware_buf = NULL;
- + return -EIO;
- + }
- +#else
- +#warning EN8811H firmware loading not implemented
- + free(firmware_buf);
- + firmware_buf = NULL;
- + return -EOPNOTSUPP;
- +#endif
- + }
- +
- + ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x0);
- + if (ret < 0)
- + return ret;
- + pbus_value = air_buckpbus_reg_read(phydev, 0x800000);
- + pbus_value |= BIT(11);
- + ret = air_buckpbus_reg_write(phydev, 0x800000, pbus_value);
- + if (ret < 0)
- + return ret;
- + /* Download DM */
- + ret = MDIOWriteBuf(phydev, 0x00000000, EN8811H_MD32_DM_SIZE, firmware_buf);
- + if (ret < 0) {
- + printf("[Airoha] MDIOWriteBuf 0x00000000 fail.\n");
- + return ret;
- + }
- + /* Download PM */
- + ret = MDIOWriteBuf(phydev, 0x00100000, EN8811H_MD32_DSP_SIZE, firmware_buf + EN8811H_MD32_DM_SIZE);
- + if (ret < 0) {
- + printf("[Airoha] MDIOWriteBuf 0x00100000 fail.\n");
- + return ret;
- + }
- + pbus_value = air_buckpbus_reg_read(phydev, 0x800000);
- + pbus_value &= ~BIT(11);
- + ret = air_buckpbus_reg_write(phydev, 0x800000, pbus_value);
- + if (ret < 0)
- + return ret;
- + ret = air_buckpbus_reg_write(phydev, 0x0f0018, 0x01);
- + if (ret < 0)
- + return ret;
- + return 0;
- +}
- +
- +static int en8811h_config(struct phy_device *phydev)
- +{
- + int ret = 0;
- + int pid1 = 0, pid2 = 0;
- +
- + ret = air_pbus_reg_write(phydev, 0xcf928 , 0x0);
- + if (ret < 0)
- + return ret;
- +
- + pid1 = phy_read(phydev, MDIO_DEVAD_NONE, MII_PHYSID1);
- + pid2 = phy_read(phydev, MDIO_DEVAD_NONE, MII_PHYSID2);
- + if ((EN8811H_PHY_ID1 != pid1) || (EN8811H_PHY_ID2 != pid2)) {
- + printf("EN8811H does not exist !\n");
- + return -ENODEV;
- + }
- +
- + return 0;
- +}
- +
- +static int en8811h_get_autonego(struct phy_device *phydev, int *an)
- +{
- + int reg;
- + reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
- + if (reg < 0)
- + return -EINVAL;
- + if (reg & BMCR_ANENABLE)
- + *an = AUTONEG_ENABLE;
- + else
- + *an = AUTONEG_DISABLE;
- + return 0;
- +}
- +
- +static int en8811h_startup(struct phy_device *phydev)
- +{
- + ofnode node = phy_get_ofnode(phydev);
- + int ret = 0, lpagb = 0, lpa = 0, common_adv_gb = 0, common_adv = 0, advgb = 0, adv = 0, reg = 0, an = AUTONEG_DISABLE, bmcr = 0, reg_value;
- + int old_link = phydev->link;
- + u32 pbus_value = 0, retry;
- +
- + eth_phy_reset(phydev->dev, 1);
- + mdelay(10);
- + eth_phy_reset(phydev->dev, 0);
- + mdelay(1);
- +
- + ret = en8811h_load_firmware(phydev);
- + if (ret) {
- + printf("EN8811H load firmware fail.\n");
- + return ret;
- + }
- + retry = MAX_RETRY;
- + do {
- + mdelay(300);
- + reg_value = air_mii_cl45_read(phydev, 0x1e, 0x8009);
- + if (EN8811H_PHY_READY == reg_value) {
- + printf("EN8811H PHY ready!\n");
- + break;
- + }
- + retry--;
- + } while (retry);
- + if (0 == retry) {
- + printf("EN8811H PHY is not ready. (MD32 FW Status reg: 0x%x)\n", reg_value);
- + pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c);
- + printf("Check MD32 FW Version(0x3b3c) : %08x\n", pbus_value);
- + printf("EN8811H initialize fail!\n");
- + return 0;
- + }
- + /* Mode selection*/
- + printf("EN8811H Mode 1 !\n");
- + ret = air_mii_cl45_write(phydev, 0x1e, 0x800c, 0x0);
- + if (ret < 0)
- + return ret;
- + ret = air_mii_cl45_write(phydev, 0x1e, 0x800d, 0x0);
- + if (ret < 0)
- + return ret;
- + ret = air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1101);
- + if (ret < 0)
- + return ret;
- + ret = air_mii_cl45_write(phydev, 0x1e, 0x800f, 0x0002);
- + if (ret < 0)
- + return ret;
- +
- + /* Serdes polarity */
- + pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
- + pbus_value &= 0xfffffffc;
- + pbus_value |= ofnode_read_bool(node, "airoha,rx-pol-reverse") ?
- + EN8811H_RX_POLARITY_REVERSE : EN8811H_RX_POLARITY_NORMAL;
- + pbus_value |= ofnode_read_bool(node, "airoha,tx-pol-reverse") ?
- + EN8811H_TX_POLARITY_REVERSE : EN8811H_TX_POLARITY_NORMAL;
- + ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_value);
- + if (ret < 0)
- + return ret;
- + pbus_value = air_buckpbus_reg_read(phydev, 0xca0f8);
- + printf("Tx, Rx Polarity(0xca0f8): %08x\n", pbus_value);
- + pbus_value = air_buckpbus_reg_read(phydev, 0x3b3c);
- + printf("MD32 FW Version(0x3b3c) : %08x\n", pbus_value);
- +#if defined(AIR_LED_SUPPORT)
- + ret = en8811h_led_init(phydev);
- + if (ret < 0) {
- + printf("en8811h_led_init fail\n");
- + }
- +#endif
- + printf("EN8811H initialize OK ! (%s)\n", EN8811H_DRIVER_VERSION);
- +
- + ret = genphy_update_link(phydev);
- + if (ret)
- + {
- + printf("ret %d!\n", ret);
- + return ret;
- + }
- +
- + ret = genphy_parse_link(phydev);
- + if (ret)
- + {
- + printf("ret %d!\n", ret);
- + return ret;
- + }
- +
- + if (old_link && phydev->link)
- + return 0;
- +
- + phydev->speed = SPEED_100;
- + phydev->duplex = DUPLEX_FULL;
- + phydev->pause = 0;
- + phydev->asym_pause = 0;
- +
- + reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
- + if (reg < 0)
- + {
- + printf("MII_BMSR reg %d!\n", reg);
- + return reg;
- + }
- + reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
- + if (reg < 0)
- + {
- + printf("MII_BMSR reg %d!\n", reg);
- + return reg;
- + }
- + if(reg & BMSR_LSTATUS)
- + {
- + pbus_value = air_buckpbus_reg_read(phydev, 0x109D4);
- + if (0x10 & pbus_value) {
- + phydev->speed = SPEED_2500;
- + phydev->duplex = DUPLEX_FULL;
- + }
- + else
- + {
- + ret = en8811h_get_autonego(phydev, &an);
- + if ((AUTONEG_ENABLE == an) && (0 == ret))
- + {
- + printf("AN mode!\n");
- + printf("SPEED 1000/100!\n");
- + lpagb = phy_read(phydev, MDIO_DEVAD_NONE, MII_STAT1000);
- + if (lpagb < 0 )
- + return lpagb;
- + advgb = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
- + if (adv < 0 )
- + return adv;
- + common_adv_gb = (lpagb & (advgb << 2));
- +
- + lpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA);
- + if (lpa < 0 )
- + return lpa;
- + adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
- + if (adv < 0 )
- + return adv;
- + common_adv = (lpa & adv);
- +
- + phydev->speed = SPEED_10;
- + phydev->duplex = DUPLEX_HALF;
- + if (common_adv_gb & (LPA_1000FULL | LPA_1000HALF))
- + {
- + phydev->speed = SPEED_1000;
- + if (common_adv_gb & LPA_1000FULL)
- +
- + phydev->duplex = DUPLEX_FULL;
- + }
- + else if (common_adv & (LPA_100FULL | LPA_100HALF))
- + {
- + phydev->speed = SPEED_100;
- + if (common_adv & LPA_100FULL)
- + phydev->duplex = DUPLEX_FULL;
- + }
- + else
- + {
- + if (common_adv & LPA_10FULL)
- + phydev->duplex = DUPLEX_FULL;
- + }
- + }
- + else
- + {
- + printf("Force mode!\n");
- + bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
- +
- + if (bmcr < 0)
- + return bmcr;
- +
- + if (bmcr & BMCR_FULLDPLX)
- + phydev->duplex = DUPLEX_FULL;
- + else
- + phydev->duplex = DUPLEX_HALF;
- +
- + if (bmcr & BMCR_SPEED1000)
- + phydev->speed = SPEED_1000;
- + else if (bmcr & BMCR_SPEED100)
- + phydev->speed = SPEED_100;
- + else
- + phydev->speed = SPEED_100;
- + }
- + }
- + }
- +
- + return ret;
- +}
- +
- +#if AIR_UBOOT_REVISION > 0x202303
- +U_BOOT_PHY_DRIVER(en8811h) = {
- + .name = "Airoha EN8811H",
- + .uid = EN8811H_PHY_ID,
- + .mask = 0x0ffffff0,
- + .config = &en8811h_config,
- + .startup = &en8811h_startup,
- + .shutdown = &genphy_shutdown,
- +};
- +#else
- +static struct phy_driver AIR_EN8811H_driver = {
- + .name = "Airoha EN8811H",
- + .uid = EN8811H_PHY_ID,
- + .mask = 0x0ffffff0,
- + .config = &en8811h_config,
- + .startup = &en8811h_startup,
- + .shutdown = &genphy_shutdown,
- +};
- +
- +int phy_air_en8811h_init(void)
- +{
- + phy_register(&AIR_EN8811H_driver);
- + return 0;
- +}
- +#endif
- --- /dev/null
- +++ b/drivers/net/phy/air_en8811h.h
- @@ -0,0 +1,163 @@
- +/* SPDX-License-Identifier: GPL-2.0 */
- +/*************************************************
- + * FILE NAME: air_en8811h.h
- + * PURPOSE:
- + * EN8811H PHY Driver for Uboot
- + * NOTES:
- + *
- + * Copyright (C) 2023 Airoha Technology Corp.
- + *************************************************/
- +
- +#ifndef __EN8811H_H
- +#define __EN8811H_H
- +
- +#define AIR_UBOOT_REVISION ((((U_BOOT_VERSION_NUM / 1000) % 10) << 20) | \
- + (((U_BOOT_VERSION_NUM / 100) % 10) << 16) | \
- + (((U_BOOT_VERSION_NUM / 10) % 10) << 12) | \
- + ((U_BOOT_VERSION_NUM % 10) << 8) | \
- + (((U_BOOT_VERSION_NUM_PATCH / 10) % 10) << 4) | \
- + ((U_BOOT_VERSION_NUM_PATCH % 10) << 0))
- +
- +#define EN8811H_PHY_ID1 0x03a2
- +#define EN8811H_PHY_ID2 0xa411
- +#define EN8811H_PHY_ID ((EN8811H_PHY_ID1 << 16) | EN8811H_PHY_ID2)
- +#define EN8811H_SPEED_2500 0x03
- +#define EN8811H_PHY_READY 0x02
- +#define MAX_RETRY 5
- +
- +#define EN8811H_MD32_DM_SIZE 0x4000
- +#define EN8811H_MD32_DSP_SIZE 0x20000
- +
- +#define EN8811H_TX_POLARITY_NORMAL 0x1
- +#define EN8811H_TX_POLARITY_REVERSE 0x0
- +
- +#define EN8811H_RX_POLARITY_NORMAL (0x0 << 1)
- +#define EN8811H_RX_POLARITY_REVERSE (0x1 << 1)
- +
- +#ifndef BIT
- +#define BIT(nr) (1UL << (nr))
- +#endif
- +
- +/* CL45 MDIO control */
- +#define MII_MMD_ACC_CTL_REG 0x0d
- +#define MII_MMD_ADDR_DATA_REG 0x0e
- +#define MMD_OP_MODE_DATA BIT(14)
- +/* MultiGBASE-T AN register */
- +#define MULTIG_ANAR_2500M (0x0080)
- +#define MULTIG_LPAR_2500M (0x0020)
- +
- +#define EN8811H_DRIVER_VERSION "v1.0.4"
- +
- +/************************************************************
- + * For reference only
- + * LED0 Link 2500/Blink 2500 TxRx (GPIO5) <-> BASE_T_LED0,
- + * LED1 Link 1000/Blink 1000 TxRx (GPIO4) <-> BASE_T_LED1,
- + * LED2 Link 100/Blink 100 TxRx (GPIO3) <-> BASE_T_LED2,
- + ************************************************************/
- +/* User-defined.B */
- +#define AIR_LED0_ON (LED_ON_EVT_LINK_2500M)
- +#define AIR_LED0_BLK (LED_BLK_EVT_2500M_TX_ACT | LED_BLK_EVT_2500M_RX_ACT)
- +#define AIR_LED1_ON (LED_ON_EVT_LINK_1000M)
- +#define AIR_LED1_BLK (LED_BLK_EVT_1000M_TX_ACT | LED_BLK_EVT_1000M_RX_ACT)
- +#define AIR_LED2_ON (LED_ON_EVT_LINK_100M)
- +#define AIR_LED2_BLK (LED_BLK_EVT_100M_TX_ACT | LED_BLK_EVT_100M_RX_ACT)
- +/* User-defined.E */
- +
- +#define LED_ON_CTRL(i) (0x024 + ((i)*2))
- +#define LED_ON_EN (1 << 15)
- +#define LED_ON_POL (1 << 14)
- +#define LED_ON_EVT_MASK (0x1ff)
- +/* LED ON Event Option.B */
- +#define LED_ON_EVT_LINK_2500M (1 << 8)
- +#define LED_ON_EVT_FORCE (1 << 6)
- +#define LED_ON_EVT_HDX (1 << 5)
- +#define LED_ON_EVT_FDX (1 << 4)
- +#define LED_ON_EVT_LINK_DOWN (1 << 3)
- +#define LED_ON_EVT_LINK_100M (1 << 1)
- +#define LED_ON_EVT_LINK_1000M (1 << 0)
- +/* LED ON Event Option.E */
- +
- +#define LED_BLK_CTRL(i) (0x025 + ((i)*2))
- +#define LED_BLK_EVT_MASK (0xfff)
- +/* LED Blinking Event Option.B*/
- +#define LED_BLK_EVT_2500M_RX_ACT (1 << 11)
- +#define LED_BLK_EVT_2500M_TX_ACT (1 << 10)
- +#define LED_BLK_EVT_FORCE (1 << 9)
- +#define LED_BLK_EVT_100M_RX_ACT (1 << 3)
- +#define LED_BLK_EVT_100M_TX_ACT (1 << 2)
- +#define LED_BLK_EVT_1000M_RX_ACT (1 << 1)
- +#define LED_BLK_EVT_1000M_TX_ACT (1 << 0)
- +/* LED Blinking Event Option.E*/
- +#define LED_ENABLE 1
- +#define LED_DISABLE 0
- +
- +#define EN8811H_LED_COUNT 3
- +
- +#define LED_BCR (0x021)
- +#define LED_BCR_EXT_CTRL (1 << 15)
- +#define LED_BCR_CLK_EN (1 << 3)
- +#define LED_BCR_TIME_TEST (1 << 2)
- +#define LED_BCR_MODE_MASK (3)
- +#define LED_BCR_MODE_DISABLE (0)
- +#define LED_BCR_MODE_2LED (1)
- +#define LED_BCR_MODE_3LED_1 (2)
- +#define LED_BCR_MODE_3LED_2 (3)
- +
- +#define LED_ON_DUR (0x022)
- +#define LED_ON_DUR_MASK (0xffff)
- +
- +#define LED_BLK_DUR (0x023)
- +#define LED_BLK_DUR_MASK (0xffff)
- +
- +#define LED_GPIO_SEL_MASK 0x7FFFFFF
- +
- +#define UNIT_LED_BLINK_DURATION 1024
- +
- +#define INVALID_DATA 0xffff
- +#define PBUS_INVALID_DATA 0xffffffff
- +
- +struct air_base_t_led_cfg_s {
- + u16 en;
- + u16 gpio;
- + u16 pol;
- + u16 on_cfg;
- + u16 blk_cfg;
- +};
- +
- +enum {
- + AIR_LED2_GPIO3 = 3,
- + AIR_LED1_GPIO4,
- + AIR_LED0_GPIO5,
- + AIR_LED_LAST
- +};
- +
- +enum {
- + AIR_BASE_T_LED0,
- + AIR_BASE_T_LED1,
- + AIR_BASE_T_LED2,
- + AIR_BASE_T_LED3
- +};
- +
- +enum {
- + AIR_LED_BLK_DUR_32M,
- + AIR_LED_BLK_DUR_64M,
- + AIR_LED_BLK_DUR_128M,
- + AIR_LED_BLK_DUR_256M,
- + AIR_LED_BLK_DUR_512M,
- + AIR_LED_BLK_DUR_1024M,
- + AIR_LED_BLK_DUR_LAST
- +};
- +
- +enum {
- + AIR_ACTIVE_LOW,
- + AIR_ACTIVE_HIGH,
- +};
- +
- +enum {
- + AIR_LED_MODE_DISABLE,
- + AIR_LED_MODE_USER_DEFINE,
- + AIR_LED_MODE_LAST
- +};
- +
- +#endif /* End of __EN8811H_MD32_H */
- +
- --- a/drivers/net/eth-phy-uclass.c
- +++ b/drivers/net/eth-phy-uclass.c
- @@ -155,7 +155,7 @@ static int eth_phy_of_to_plat(struct ude
- return 0;
- }
-
- -static void eth_phy_reset(struct udevice *dev, int value)
- +void eth_phy_reset(struct udevice *dev, int value)
- {
- struct eth_phy_device_priv *uc_priv = dev_get_uclass_priv(dev);
- u32 delay;
- --- a/include/eth_phy.h
- +++ b/include/eth_phy.h
- @@ -14,5 +14,6 @@ int eth_phy_binds_nodes(struct udevice *
- int eth_phy_set_mdio_bus(struct udevice *eth_dev, struct mii_dev *mdio_bus);
- struct mii_dev *eth_phy_get_mdio_bus(struct udevice *eth_dev);
- int eth_phy_get_addr(struct udevice *dev);
- +void eth_phy_reset(struct udevice *dev, int value);
-
- #endif
|