mirror of
https://github.com/openwrt/openwrt.git
synced 2025-12-21 17:04:28 +04:00
Use the correct identifier 'rtsds_of_match' instead of 'rtsds_mdio_of_match' because the latter doesn't exist. This doesn't cause an error for 6.12. However, with 6.18 the implementation of MODULE_DEVICE_TABLE has changed to use 'static' and 'used' [1] instead of 'extern' and 'unused' [2]. [1]7d0a66e4bb/include/linux/module.h (L260)[2]adc218676e/include/linux/module.h (L249)Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com> Link: https://github.com/openwrt/openwrt/pull/21182 Signed-off-by: Robert Marko <robimarko@gmail.com>
545 lines
16 KiB
C
545 lines
16 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include <linux/debugfs.h>
|
|
#include <linux/mfd/core.h>
|
|
#include <linux/mfd/syscon.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_mdio.h>
|
|
#include <linux/of_platform.h>
|
|
#include <linux/phy.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/regmap.h>
|
|
|
|
#define RTSDS_REG_CNT 32
|
|
#define RTSDS_VAL_MASK GENMASK(15, 0)
|
|
#define RTSDS_SUBPAGE(page) (page % 64)
|
|
|
|
#define RTSDS_MMD_PAGE_MASK GENMASK(15, 8)
|
|
#define RTSDS_MMD_REG_MASK GENMASK(7, 0)
|
|
|
|
#define RTSDS_838X_SDS_CNT 6
|
|
#define RTSDS_838X_PAGE_CNT 4
|
|
#define RTSDS_838X_BASE 0xe780
|
|
|
|
#define RTSDS_839X_SDS_CNT 14
|
|
#define RTSDS_839X_PAGE_CNT 12
|
|
#define RTSDS_839X_BASE 0xa000
|
|
|
|
#define RTSDS_930X_SDS_CNT 12
|
|
#define RTSDS_930X_PAGE_CNT 64
|
|
#define RTSDS_930X_BASE 0x03b0
|
|
|
|
#define RTSDS_931X_SDS_CNT 14
|
|
#define RTSDS_931X_PAGE_CNT 192
|
|
#define RTSDS_931X_BASE 0x5638
|
|
|
|
#define RTSDS_93XX_CMD_READ 0
|
|
#define RTSDS_93XX_CMD_WRITE BIT(1)
|
|
#define RTSDS_93XX_CMD_BUSY BIT(0)
|
|
#define RTSDS_93XX_CMD_SDS_MASK GENMASK(6, 2)
|
|
#define RTSDS_93XX_CMD_PAGE_MASK GENMASK(12, 7)
|
|
#define RTSDS_93XX_CMD_REG_MASK GENMASK(17, 13)
|
|
|
|
struct rtsds_ctrl {
|
|
struct device *dev;
|
|
struct regmap *map;
|
|
struct mii_bus *bus;
|
|
const struct rtsds_config *cfg;
|
|
};
|
|
|
|
struct rtsds_config {
|
|
int sds_cnt;
|
|
int page_cnt;
|
|
int base;
|
|
int (*get_backing_sds)(int sds, int page);
|
|
int (*read)(struct rtsds_ctrl *ctrl, int sds, int page, int regnum);
|
|
int (*write)(struct rtsds_ctrl *ctrl, int sds, int page, int regnum, u16 value);
|
|
};
|
|
|
|
static bool rtsds_mmd_to_sds(struct rtsds_ctrl *ctrl, int addr, int devad, int mmd_regnum,
|
|
int *sds_page, int *sds_regnum)
|
|
{
|
|
*sds_page = FIELD_GET(RTSDS_MMD_PAGE_MASK, mmd_regnum);
|
|
*sds_regnum = FIELD_GET(RTSDS_MMD_REG_MASK, mmd_regnum);
|
|
|
|
return !(addr < 0 || addr >= ctrl->cfg->sds_cnt ||
|
|
*sds_page < 0 || *sds_page >= ctrl->cfg->page_cnt ||
|
|
*sds_regnum < 0 || *sds_regnum >= RTSDS_REG_CNT ||
|
|
devad != MDIO_MMD_VEND1);
|
|
}
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
|
|
/*
|
|
* The SerDes offer a lot of magic that sill needs to be uncovered. Getting this info manually
|
|
* with mdio command line tools can be time consuming. Provide a convenient register dump.
|
|
*/
|
|
|
|
#define RTSDS_DBG_PAGE_NAMES 48
|
|
#define RTSDS_DBG_ROOT_DIR "realtek_otto_serdes"
|
|
|
|
struct rtsds_debug_info {
|
|
struct rtsds_ctrl *ctrl;
|
|
int sds;
|
|
};
|
|
|
|
static const char * const rtsds_page_name[RTSDS_DBG_PAGE_NAMES] = {
|
|
[0] = "SDS", [1] = "SDS_EXT",
|
|
[2] = "FIB", [3] = "FIB_EXT",
|
|
[4] = "DTE", [5] = "DTE_EXT",
|
|
[6] = "TGX", [7] = "TGX_EXT",
|
|
[8] = "ANA_RG", [9] = "ANA_RG_EXT",
|
|
[10] = "ANA_TG", [11] = "ANA_TG_EXT",
|
|
[31] = "ANA_WDIG",
|
|
[32] = "ANA_MISC", [33] = "ANA_COM",
|
|
[34] = "ANA_SP", [35] = "ANA_SP_EXT",
|
|
[36] = "ANA_1G", [37] = "ANA_1G_EXT",
|
|
[38] = "ANA_2G", [39] = "ANA_2G_EXT",
|
|
[40] = "ANA_3G", [41] = "ANA_3G_EXT",
|
|
[42] = "ANA_5G", [43] = "ANA_5G_EXT",
|
|
[44] = "ANA_6G", [45] = "ANA_6G_EXT",
|
|
[46] = "ANA_10G", [47] = "ANA_10G_EXT",
|
|
};
|
|
|
|
static int rtsds_sds_to_mmd(int sds_page, int sds_regnum)
|
|
{
|
|
return FIELD_PREP(RTSDS_MMD_PAGE_MASK, sds_page) |
|
|
FIELD_PREP(RTSDS_MMD_REG_MASK, sds_regnum);
|
|
}
|
|
|
|
static int rtsds_dbg_registers_show(struct seq_file *seqf, void *unused)
|
|
{
|
|
struct rtsds_debug_info *dbg_info = seqf->private;
|
|
struct rtsds_ctrl *ctrl = dbg_info->ctrl;
|
|
struct mii_bus *bus = ctrl->bus;
|
|
int sds = dbg_info->sds;
|
|
int regnum, page = 0;
|
|
int subpage;
|
|
|
|
do {
|
|
subpage = RTSDS_SUBPAGE(page);
|
|
if (!subpage) {
|
|
seq_printf(seqf, "Back SDS %02d:", ctrl->cfg->get_backing_sds(sds, page));
|
|
for (regnum = 0; regnum < RTSDS_REG_CNT; regnum++)
|
|
seq_printf(seqf, " %02X", regnum);
|
|
seq_puts(seqf, "\n");
|
|
}
|
|
|
|
if (subpage < RTSDS_DBG_PAGE_NAMES && rtsds_page_name[subpage])
|
|
seq_printf(seqf, "%*s: ", -11, rtsds_page_name[subpage]);
|
|
else
|
|
seq_printf(seqf, "PAGE %02X : ", page);
|
|
|
|
for (regnum = 0; regnum < RTSDS_REG_CNT; regnum++)
|
|
seq_printf(seqf, "%04X ",
|
|
mdiobus_c45_read(bus, sds, MDIO_MMD_VEND1,
|
|
rtsds_sds_to_mmd(page, regnum)));
|
|
seq_puts(seqf, "\n");
|
|
} while (++page < ctrl->cfg->page_cnt);
|
|
|
|
return 0;
|
|
}
|
|
DEFINE_SHOW_ATTRIBUTE(rtsds_dbg_registers);
|
|
|
|
static int rtsds_debug_init(struct rtsds_ctrl *ctrl)
|
|
{
|
|
struct rtsds_debug_info *dbg_info;
|
|
struct dentry *dir, *root;
|
|
char dirname[32];
|
|
|
|
root = debugfs_create_dir(RTSDS_DBG_ROOT_DIR, NULL);
|
|
if (IS_ERR(root))
|
|
return PTR_ERR(root);
|
|
|
|
for (int sds = 0; sds < ctrl->cfg->sds_cnt; sds++) {
|
|
dbg_info = devm_kzalloc(ctrl->dev, sizeof(*dbg_info), GFP_KERNEL);
|
|
if (!dbg_info)
|
|
return -ENOMEM;
|
|
|
|
dbg_info->ctrl = ctrl;
|
|
dbg_info->sds = sds;
|
|
|
|
snprintf(dirname, sizeof(dirname), "serdes.%d", sds);
|
|
dir = debugfs_create_dir(dirname, root);
|
|
|
|
debugfs_create_file("registers", 0600, dir, dbg_info,
|
|
&rtsds_dbg_registers_fops);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* CONFIG_DEBUG_FS */
|
|
|
|
/*
|
|
* The RTL838x has 6 SerDes. The 16 bit registers start at 0xbb00e780 and are mapped directly into
|
|
* 32 bit memory addresses. High 16 bits are always empty. A "lower" memory block serves pages 0/3
|
|
* a "higher" memory block pages 1/2.
|
|
*/
|
|
|
|
static int rtsds_838x_reg_offset(int sds, int page, int regnum)
|
|
{
|
|
if (page == 0 || page == 3)
|
|
return (sds << 9) + (page << 7) + (regnum << 2);
|
|
|
|
/* (page == 1 || page == 2) */
|
|
return 0xb80 + (sds << 8) + (page << 7) + (regnum << 2);
|
|
}
|
|
|
|
static int rtsds_838x_read(struct rtsds_ctrl *ctrl, int sds, int page, int regnum)
|
|
{
|
|
int offset = rtsds_838x_reg_offset(sds, page, regnum);
|
|
int ret, value;
|
|
|
|
ret = regmap_read(ctrl->map, ctrl->cfg->base + offset, &value);
|
|
|
|
return ret ? ret : value & RTSDS_VAL_MASK;
|
|
}
|
|
|
|
static int rtsds_838x_write(struct rtsds_ctrl *ctrl, int sds, int page, int regnum, u16 value)
|
|
{
|
|
int offset = rtsds_838x_reg_offset(sds, page, regnum);
|
|
|
|
return regmap_write(ctrl->map, ctrl->cfg->base + offset, value);
|
|
}
|
|
|
|
/*
|
|
* The RTL839x has 14 SerDes starting at 0xbb00a000. 0-7, 10, 11 are 5GBit, 8, 9, 12, 13 are
|
|
* 10 GBit. Two adjacent SerDes are tightly coupled and share a 1024 bytes register area. Per 32
|
|
* bit address two registers are stored. The first register is stored in the lower 2 bytes ("on
|
|
* the right" due to big endian) and the second register in the upper 2 bytes. The following
|
|
* register areas are known:
|
|
*
|
|
* - XSG0 (4 pages @ offset 0x000): for even SerDes
|
|
* - XSG1 (4 pages @ offset 0x100): for odd SerDes
|
|
* - TGRX (4 pages @ offset 0x200): for even 10G SerDes
|
|
* - ANA_RG (2 pages @ offset 0x300): for even 5G SerDes
|
|
* - ANA_RG (2 pages @ offset 0x380): for odd 5G SerDes
|
|
* - ANA_TG (2 pages @ offset 0x300): for even 10G SerDes
|
|
* - ANA_TG (2 pages @ offset 0x380): for odd 10G SerDes
|
|
*
|
|
* The most consistent mapping that aligns to the RTL93xx devices is:
|
|
*
|
|
* even 5G SerDes odd 5G SerDes even 10G SerDes odd 10G SerDes
|
|
* Page 0: XSG0/0 XSG1/0 XSG0/0 XSG1/0
|
|
* Page 1: XSG0/1 XSG1/1 XSG0/1 XSG1/1
|
|
* Page 2: XSG0/2 XSG1/2 XSG0/2 XSG1/2
|
|
* Page 3: XSG0/3 XSG1/3 XSG0/3 XSG1/3
|
|
* Page 4: <zero> <zero> TGRX/0 <zero>
|
|
* Page 5: <zero> <zero> TGRX/1 <zero>
|
|
* Page 6: <zero> <zero> TGRX/2 <zero>
|
|
* Page 7: <zero> <zero> TGRX/3 <zero>
|
|
* Page 8: ANA_RG ANA_RG <zero> <zero>
|
|
* Page 9: ANA_RG_EXT ANA_RG_EXT <zero> <zero>
|
|
* Page 10: <zero> <zero> ANA_TG ANA_TG
|
|
* Page 11: <zero> <zero> ANA_TG_EXT ANA_TG_EXT
|
|
*/
|
|
|
|
static int rtsds_839x_reg_offset(int sds, int page, int regnum)
|
|
{
|
|
int offset = ((sds & 0xfe) << 9) + ((regnum & 0xfe) << 1) + (page << 6);
|
|
int sds5g = (GENMASK(11, 10) | GENMASK(7, 0)) & BIT(sds);
|
|
|
|
if (page < 4)
|
|
return offset + ((sds & 1) << 8);
|
|
else if ((page & 4) && (sds == 8 || sds == 12))
|
|
return offset + 0x100;
|
|
else if (page >= 8 && page <= 9 && sds5g)
|
|
return offset + 0x100 + ((sds & 1) << 7);
|
|
else if (page >= 10 && !sds5g)
|
|
return offset + 0x80 + ((sds & 1) << 7);
|
|
|
|
return -EINVAL; /* hole */
|
|
}
|
|
|
|
static int rtsds_839x_read(struct rtsds_ctrl *ctrl, int sds, int page, int regnum)
|
|
{
|
|
int offset = rtsds_839x_reg_offset(sds, page, regnum);
|
|
int shift = regnum & 1 ? 16 : 0;
|
|
int ret, value;
|
|
|
|
if (offset < 0)
|
|
return 0;
|
|
|
|
ret = regmap_read(ctrl->map, ctrl->cfg->base + offset, &value);
|
|
|
|
return ret ? ret : (value >> shift) & RTSDS_VAL_MASK;
|
|
}
|
|
|
|
static int rtsds_839x_write(struct rtsds_ctrl *ctrl, int sds, int page, int regnum, u16 value)
|
|
{
|
|
int offset = rtsds_839x_reg_offset(sds, page, regnum);
|
|
int write_value = value;
|
|
int neigh_value;
|
|
|
|
if (offset < 0)
|
|
return 0;
|
|
|
|
neigh_value = rtsds_839x_read(ctrl, sds, page, regnum ^ 1);
|
|
if (neigh_value < 0)
|
|
return neigh_value;
|
|
|
|
if (regnum & 1)
|
|
write_value = (write_value << 16) + neigh_value;
|
|
else
|
|
write_value = (neigh_value << 16) + write_value;
|
|
|
|
return regmap_write(ctrl->map, ctrl->cfg->base + offset, write_value);
|
|
}
|
|
|
|
static int rtsds_83xx_get_backing_sds(int sds, int page)
|
|
{
|
|
return sds;
|
|
}
|
|
|
|
static int rtsds_rt93xx_io(struct rtsds_ctrl *ctrl, int sds, int page, int regnum, int cmd)
|
|
{
|
|
int ret, op, value;
|
|
|
|
op = FIELD_PREP(RTSDS_93XX_CMD_SDS_MASK, sds) |
|
|
FIELD_PREP(RTSDS_93XX_CMD_PAGE_MASK, page) |
|
|
FIELD_PREP(RTSDS_93XX_CMD_REG_MASK, regnum) |
|
|
RTSDS_93XX_CMD_BUSY | cmd;
|
|
|
|
regmap_write(ctrl->map, ctrl->cfg->base, op);
|
|
ret = regmap_read_poll_timeout(ctrl->map, ctrl->cfg->base, value,
|
|
!(value & RTSDS_93XX_CMD_BUSY), 30, 1000000);
|
|
|
|
if (ret < 0) {
|
|
dev_err(ctrl->dev, "SerDes I/O timed out\n");
|
|
return -ETIMEDOUT;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* RTL93xx targets use a shared implementation. Their SerDes data is accessed through two IO
|
|
* registers which simulate commands to an internal MDIO bus.
|
|
*
|
|
* The RTL930x family has 12 SerDes of three types.
|
|
*
|
|
* - SerDes 0-1 exist on the RTL9301 and 9302B and are QSGMII capable
|
|
* - SerDes 2-9 are USXGMII capabable with either quad or single configuration
|
|
* - SerDes 10-11 are 10GBase-R capable
|
|
*/
|
|
static int rtsds_930x_get_backing_sds(int sds, int page)
|
|
{
|
|
if (sds == 3 && page < 4)
|
|
return 10;
|
|
|
|
return sds;
|
|
}
|
|
|
|
/*
|
|
* The RTL931x family has 14 "frontend" SerDes that are cascaded. All operations (e.g. reset) work
|
|
* on this frontend view while their registers are distributed over a total of least 26 background
|
|
* SerDes with 64 pages and 32 registers. Three types of SerDes exist:
|
|
*
|
|
* - Serdes 0,1 are "simple" and work on one background serdes.
|
|
* - "Even" SerDes with numbers 2, 4, 6, 8, 10, 12 work on two background SerDes. One analog and
|
|
* one digital.
|
|
* - "Odd" SerDes with numbers 3, 5, 7, 9, 11, 13 work on a total of 3 background SerDes (one
|
|
* analog and two digital)
|
|
*
|
|
* This maps to:
|
|
*
|
|
* Frontend SerDes | 0 1 2 3 4 5 6 7 8 9 10 11 12 13
|
|
* -----------------+------------------------------------------
|
|
* Backend SerDes 1 | 0 1 2 3 6 7 10 11 14 15 18 19 22 23
|
|
* Backend SerDes 2 | 0 1 2 4 6 8 10 12 14 16 18 20 22 24
|
|
* Backend SerDes 3 | 0 1 3 5 7 9 11 13 15 17 19 21 23 25
|
|
*
|
|
* Note: In Realtek proprietary XSGMII mode (10G pumped SGMII) the frontend SerDes works on the
|
|
* two digital SerDes while in all other modes it works on the analog and the first digital
|
|
* SerDes. Overlapping (e.g. backend SerDes 7 can be analog or digital 2) is avoided by the
|
|
* existing hardware designs.
|
|
*
|
|
* Align this for readability by simulating a total of 192 pages and mix them as follows.
|
|
*
|
|
* frontend page "even" frontend SerDes "odd" frontend SerDes
|
|
* page 0x00-0x3f (analog): page 0x00-0x3f back SDS page 0x00-0x3f back SDS
|
|
* page 0x40-0x7f (digi 1): page 0x00-0x3f back SDS page 0x00-0x3f back SDS+1
|
|
* page 0x80-0xbf (digi 2): page 0x00-0x3f back SDS+1 page 0x00-0x3f back SDS+2
|
|
*/
|
|
static int rtsds_931x_get_backing_sds(int sds, int page)
|
|
{
|
|
int map[] = { 0, 1, 2, 3, 6, 7, 10, 11, 14, 15, 18, 19, 22, 23 };
|
|
int backsds;
|
|
|
|
/* First two RTL931x SerDes have 1:1 frontend/backend mapping */
|
|
if (sds < 2)
|
|
return sds;
|
|
|
|
backsds = map[sds];
|
|
if (sds & 1)
|
|
backsds += (page >> 6); /* distribute "odd" to 3 background SerDes */
|
|
else
|
|
backsds += (page >> 7); /* distribute "even" to 2 background SerDes */
|
|
|
|
return backsds;
|
|
}
|
|
|
|
static int rtsds_93xx_read(struct rtsds_ctrl *ctrl, int sds, int page, int regnum)
|
|
{
|
|
int subpage = RTSDS_SUBPAGE(page);
|
|
int ret, backsds, value;
|
|
|
|
backsds = ctrl->cfg->get_backing_sds(sds, page);
|
|
ret = rtsds_rt93xx_io(ctrl, backsds, subpage, regnum, RTSDS_93XX_CMD_READ);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = regmap_read(ctrl->map, ctrl->cfg->base + 4, &value);
|
|
|
|
return ret ? ret : value & RTSDS_VAL_MASK;
|
|
}
|
|
|
|
static int rtsds_93xx_write(struct rtsds_ctrl *ctrl, int sds, int page, int regnum, u16 value)
|
|
{
|
|
int subpage = RTSDS_SUBPAGE(page);
|
|
int ret, backsds;
|
|
|
|
backsds = ctrl->cfg->get_backing_sds(sds, page);
|
|
ret = regmap_write(ctrl->map, ctrl->cfg->base + 4, value);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return rtsds_rt93xx_io(ctrl, backsds, subpage, regnum, RTSDS_93XX_CMD_WRITE);
|
|
}
|
|
|
|
static int rtsds_read(struct mii_bus *bus, int addr, int devad, int regnum)
|
|
{
|
|
struct rtsds_ctrl *ctrl = bus->priv;
|
|
int sds_page, sds_regnum;
|
|
|
|
if (!rtsds_mmd_to_sds(ctrl, addr, devad, regnum, &sds_page, &sds_regnum))
|
|
return -EINVAL;
|
|
|
|
return ctrl->cfg->read(ctrl, addr, sds_page, sds_regnum);
|
|
}
|
|
|
|
static int rtsds_write(struct mii_bus *bus, int addr, int devad, int regnum, u16 value)
|
|
{
|
|
struct rtsds_ctrl *ctrl = bus->priv;
|
|
int sds_page, sds_regnum;
|
|
|
|
if (!rtsds_mmd_to_sds(ctrl, addr, devad, regnum, &sds_page, &sds_regnum))
|
|
return -EINVAL;
|
|
|
|
return ctrl->cfg->write(ctrl, addr, sds_page, sds_regnum, value);
|
|
}
|
|
|
|
static int rtsds_probe(struct platform_device *pdev)
|
|
{
|
|
struct device_node *np = pdev->dev.of_node;
|
|
struct device *dev = &pdev->dev;
|
|
struct rtsds_ctrl *ctrl;
|
|
struct mii_bus *bus;
|
|
int ret;
|
|
|
|
bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*ctrl));
|
|
if (!bus)
|
|
return -ENOMEM;
|
|
|
|
ctrl = bus->priv;
|
|
ctrl->map = syscon_node_to_regmap(np->parent);
|
|
if (IS_ERR(ctrl->map))
|
|
return PTR_ERR(ctrl->map);
|
|
|
|
ctrl->dev = dev;
|
|
ctrl->cfg = (const struct rtsds_config *)device_get_match_data(ctrl->dev);
|
|
ctrl->bus = bus;
|
|
|
|
snprintf(bus->id, MII_BUS_ID_SIZE, "realtek-serdes-mdio");
|
|
bus->name = "Realtek SerDes MDIO bus";
|
|
bus->parent = dev;
|
|
bus->read_c45 = rtsds_read;
|
|
bus->write_c45 = rtsds_write;
|
|
bus->phy_mask = ~0ULL;
|
|
|
|
ret = devm_of_mdiobus_register(dev, bus, dev->of_node);
|
|
if (ret)
|
|
return ret;
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
rtsds_debug_init(ctrl);
|
|
#endif
|
|
|
|
dev_info(dev, "Realtek SerDes mdio bus initialized, %d SerDes, %d pages, %d registers\n",
|
|
ctrl->cfg->sds_cnt, ctrl->cfg->page_cnt, RTSDS_REG_CNT);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct rtsds_config rtsds_838x_cfg = {
|
|
.sds_cnt = RTSDS_838X_SDS_CNT,
|
|
.page_cnt = RTSDS_838X_PAGE_CNT,
|
|
.base = RTSDS_838X_BASE,
|
|
.get_backing_sds = rtsds_83xx_get_backing_sds,
|
|
.read = rtsds_838x_read,
|
|
.write = rtsds_838x_write,
|
|
};
|
|
|
|
static const struct rtsds_config rtsds_839x_cfg = {
|
|
.sds_cnt = RTSDS_839X_SDS_CNT,
|
|
.page_cnt = RTSDS_839X_PAGE_CNT,
|
|
.base = RTSDS_839X_BASE,
|
|
.get_backing_sds = rtsds_83xx_get_backing_sds,
|
|
.read = rtsds_839x_read,
|
|
.write = rtsds_839x_write,
|
|
};
|
|
|
|
static const struct rtsds_config rtsds_930x_cfg = {
|
|
.sds_cnt = RTSDS_930X_SDS_CNT,
|
|
.page_cnt = RTSDS_930X_PAGE_CNT,
|
|
.base = RTSDS_930X_BASE,
|
|
.get_backing_sds = rtsds_930x_get_backing_sds,
|
|
.read = rtsds_93xx_read,
|
|
.write = rtsds_93xx_write,
|
|
};
|
|
|
|
static const struct rtsds_config rtsds_931x_cfg = {
|
|
.sds_cnt = RTSDS_931X_SDS_CNT,
|
|
.page_cnt = RTSDS_931X_PAGE_CNT,
|
|
.base = RTSDS_931X_BASE,
|
|
.get_backing_sds = rtsds_931x_get_backing_sds,
|
|
.read = rtsds_93xx_read,
|
|
.write = rtsds_93xx_write,
|
|
};
|
|
|
|
static const struct of_device_id rtsds_of_match[] = {
|
|
{
|
|
.compatible = "realtek,rtl8380-serdes-mdio",
|
|
.data = &rtsds_838x_cfg,
|
|
},
|
|
{
|
|
.compatible = "realtek,rtl8392-serdes-mdio",
|
|
.data = &rtsds_839x_cfg,
|
|
},
|
|
{
|
|
.compatible = "realtek,rtl9301-serdes-mdio",
|
|
.data = &rtsds_930x_cfg,
|
|
},
|
|
{
|
|
.compatible = "realtek,rtl9311-serdes-mdio",
|
|
.data = &rtsds_931x_cfg,
|
|
},
|
|
{ /* sentinel */ }
|
|
};
|
|
MODULE_DEVICE_TABLE(of, rtsds_of_match);
|
|
|
|
static struct platform_driver rtsds_mdio_driver = {
|
|
.driver = {
|
|
.name = "realtek-otto-serdes-mdio",
|
|
.of_match_table = rtsds_of_match
|
|
},
|
|
.probe = rtsds_probe,
|
|
};
|
|
module_platform_driver(rtsds_mdio_driver);
|
|
|
|
MODULE_AUTHOR("Markus Stockhausen <markus.stockhausen@gmx.de>");
|
|
MODULE_DESCRIPTION("Realtek Otto SerDes MDIO bus");
|
|
MODULE_LICENSE("GPL v2");
|