Adding support for a new SOC device. Signed-off-by: Michael Dege <michael.dege@xxxxxxxxxxx> --- drivers/phy/renesas/renesas-ether-serdes.c | 55 +++++++++++++++++----- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/drivers/phy/renesas/renesas-ether-serdes.c b/drivers/phy/renesas/renesas-ether-serdes.c index 683409d5e0f9..4c53c81903ef 100644 --- a/drivers/phy/renesas/renesas-ether-serdes.c +++ b/drivers/phy/renesas/renesas-ether-serdes.c @@ -14,11 +14,13 @@ #include <linux/platform_device.h> #include <linux/reset.h> +#define RENESAS_ETH_SERDES_MAX_NUM R8A78000_ETH_SERDES_NUM #define R8A779F0_ETH_SERDES_NUM 3 +#define R8A78000_ETH_SERDES_NUM 8 #define RENESAS_ETH_SERDES_OFFSET 0x0400 #define RENESAS_ETH_SERDES_BANK_SELECT 0x03fc #define RENESAS_ETH_SERDES_TIMEOUT_US 100000 -#define RENESAS_ETH_SERDES_LOCAL_OFFSET 0x2600 +#define RENESAS_ETH_SERDES_LOCAL_OFFSET 0x2600 #define RENESAS_ETH_SERDES_NUM_RETRY_LINKUP 3 struct renesas_eth_serdes_drv_data; @@ -35,10 +37,21 @@ struct renesas_eth_serdes_drv_data { void __iomem *addr; struct platform_device *pdev; struct reset_control *reset; - struct renesas_eth_serdes_channel channel[R8A779F0_ETH_SERDES_NUM]; + struct renesas_eth_serdes_channel channel[RENESAS_ETH_SERDES_MAX_NUM]; + const struct renesas_serdes_hw_info *info; bool initialized; }; +enum DEVICE_CODE { + r8a779f0, + r8a78000, +}; + +struct renesas_serdes_hw_info { + int renesas_eth_serdes_num; + int device_type; +}; + /* * The datasheet describes initialization procedure without any information * about registers' name/bits. So, this is all black magic to initialize @@ -82,7 +95,7 @@ renesas_eth_serdes_common_init_ram(struct renesas_eth_serdes_drv_data *dd) struct renesas_eth_serdes_channel *channel; int i, ret; - for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) { + for (i = 0; i < dd->info->renesas_eth_serdes_num; i++) { channel = &dd->channel[i]; ret = renesas_eth_serdes_reg_wait(channel, 0x026c, 0x180, BIT(0), 0x01); if (ret) @@ -265,32 +278,34 @@ static int renesas_eth_serdes_hw_init(struct renesas_eth_serdes_channel *channel reset_control_reset(dd->reset); + mdelay(1); + /* There is a slight difference in SerDes hardware behavior between * each version after resetting. This step is to ensure the stable * condition of initialization, especially for R-Car S4 v1.1. */ - mdelay(1); - iowrite32(0, dd->addr + RENESAS_ETH_SERDES_LOCAL_OFFSET); + if (dd->info->renesas_eth_serdes_num == r8a779f0) + iowrite32(0, dd->addr + RENESAS_ETH_SERDES_LOCAL_OFFSET); ret = renesas_eth_serdes_common_init_ram(dd); if (ret) return ret; - for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) { + for (i = 0; i < dd->info->renesas_eth_serdes_num; i++) { ret = renesas_eth_serdes_reg_wait(&dd->channel[i], 0x0000, 0x300, BIT(15), 0); if (ret) return ret; } - for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) + for (i = 0; i < dd->info->renesas_eth_serdes_num; i++) renesas_eth_serdes_write32(dd->channel[i].addr, 0x03d4, 0x380, 0x0443); ret = renesas_eth_serdes_common_setting(channel); if (ret) return ret; - for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) + for (i = 0; i < dd->info->renesas_eth_serdes_num; i++) renesas_eth_serdes_write32(dd->channel[i].addr, 0x03d0, 0x380, 0x0001); @@ -414,14 +429,25 @@ static struct phy *renesas_eth_serdes_xlate(struct device *dev, { struct renesas_eth_serdes_drv_data *dd = dev_get_drvdata(dev); - if (args->args[0] >= R8A779F0_ETH_SERDES_NUM) + if (args->args[0] >= dd->info->renesas_eth_serdes_num) return ERR_PTR(-ENODEV); return dd->channel[args->args[0]].phy; } +static const struct renesas_serdes_hw_info r8a779f0_hw_info = { + .renesas_eth_serdes_num = R8A779F0_ETH_SERDES_NUM, + .device_type = r8a779f0, +}; + +static const struct renesas_serdes_hw_info r8a78000_hw_info = { + .renesas_eth_serdes_num = R8A78000_ETH_SERDES_NUM, + .device_type = r8a78000, +}; + static const struct of_device_id renesas_eth_serdes_of_table[] = { - { .compatible = "renesas,r8a779f0-ether-serdes", }, + { .compatible = "renesas,r8a779f0-ether-serdes", .data = &r8a779f0_hw_info }, + { .compatible = "renesas,r8a78000-ether-serdes", .data = &r8a78000_hw_info }, { } }; MODULE_DEVICE_TABLE(of, renesas_eth_serdes_of_table); @@ -430,12 +456,19 @@ static int renesas_eth_serdes_probe(struct platform_device *pdev) { struct renesas_eth_serdes_drv_data *dd; struct phy_provider *provider; + const struct renesas_serdes_hw_info *info; int i; dd = devm_kzalloc(&pdev->dev, sizeof(*dd), GFP_KERNEL); if (!dd) return -ENOMEM; + info = of_device_get_match_data(&pdev->dev); + if (info > 0) + dd->info = info; + else + return PTR_ERR(info); + platform_set_drvdata(pdev, dd); dd->pdev = pdev; dd->addr = devm_platform_ioremap_resource(pdev, 0); @@ -446,7 +479,7 @@ static int renesas_eth_serdes_probe(struct platform_device *pdev) if (IS_ERR(dd->reset)) return PTR_ERR(dd->reset); - for (i = 0; i < R8A779F0_ETH_SERDES_NUM; i++) { + for (i = 0; i < dd->info->renesas_eth_serdes_num; i++) { struct renesas_eth_serdes_channel *channel = &dd->channel[i]; channel->phy = devm_phy_create(&pdev->dev, NULL, -- 2.34.1 ________________________________ Renesas Electronics Europe GmbH Registered Office: Arcadiastrasse 10 DE-40472 Duesseldorf Commercial Registry: Duesseldorf, HRB 3708 Managing Director: Carsten Jauch VAT-No.: DE 14978647 Tax-ID-No: 105/5839/1793 Legal Disclaimer: This e-mail communication (and any attachment/s) is confidential and contains proprietary information, some or all of which may be legally privileged. It is intended solely for the use of the individual or entity to which it is addressed. Access to this email by anyone else is unauthorized. If you are not the intended recipient, any disclosure, copying, distribution or any action taken or omitted to be taken in reliance on it, is prohibited and may be unlawful.