net: dsa: bcm_sf2: Prepare for different register layouts
In preparation for supporting a new device with a slightly different register layout, affecting the SWITCH_REG and SWITCH_CORE address spaces, perform a few preparatory steps: - allow matching the compatible string against a data description - convert the SWITCH_REG register accesses into an indirection table - prepare for supporting a SWITCH_CORE register alignment requirement Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
329b5c58f8
commit
a78e86ed58
@ -1009,10 +1009,49 @@ static const struct dsa_switch_ops bcm_sf2_ops = {
|
|||||||
.port_fdb_del = b53_fdb_del,
|
.port_fdb_del = b53_fdb_del,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct bcm_sf2_of_data {
|
||||||
|
u32 type;
|
||||||
|
const u16 *reg_offsets;
|
||||||
|
unsigned int core_reg_align;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Register offsets for the SWITCH_REG_* block */
|
||||||
|
static const u16 bcm_sf2_7445_reg_offsets[] = {
|
||||||
|
[REG_SWITCH_CNTRL] = 0x00,
|
||||||
|
[REG_SWITCH_STATUS] = 0x04,
|
||||||
|
[REG_DIR_DATA_WRITE] = 0x08,
|
||||||
|
[REG_DIR_DATA_READ] = 0x0C,
|
||||||
|
[REG_SWITCH_REVISION] = 0x18,
|
||||||
|
[REG_PHY_REVISION] = 0x1C,
|
||||||
|
[REG_SPHY_CNTRL] = 0x2C,
|
||||||
|
[REG_RGMII_0_CNTRL] = 0x34,
|
||||||
|
[REG_RGMII_1_CNTRL] = 0x40,
|
||||||
|
[REG_RGMII_2_CNTRL] = 0x4c,
|
||||||
|
[REG_LED_0_CNTRL] = 0x90,
|
||||||
|
[REG_LED_1_CNTRL] = 0x94,
|
||||||
|
[REG_LED_2_CNTRL] = 0x98,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct bcm_sf2_of_data bcm_sf2_7445_data = {
|
||||||
|
.type = BCM7445_DEVICE_ID,
|
||||||
|
.core_reg_align = 0,
|
||||||
|
.reg_offsets = bcm_sf2_7445_reg_offsets,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id bcm_sf2_of_match[] = {
|
||||||
|
{ .compatible = "brcm,bcm7445-switch-v4.0",
|
||||||
|
.data = &bcm_sf2_7445_data
|
||||||
|
},
|
||||||
|
{ /* sentinel */ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, bcm_sf2_of_match);
|
||||||
|
|
||||||
static int bcm_sf2_sw_probe(struct platform_device *pdev)
|
static int bcm_sf2_sw_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
|
const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
|
||||||
struct device_node *dn = pdev->dev.of_node;
|
struct device_node *dn = pdev->dev.of_node;
|
||||||
|
const struct of_device_id *of_id = NULL;
|
||||||
|
const struct bcm_sf2_of_data *data;
|
||||||
struct b53_platform_data *pdata;
|
struct b53_platform_data *pdata;
|
||||||
struct dsa_switch_ops *ops;
|
struct dsa_switch_ops *ops;
|
||||||
struct bcm_sf2_priv *priv;
|
struct bcm_sf2_priv *priv;
|
||||||
@ -1040,11 +1079,22 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev)
|
|||||||
if (!pdata)
|
if (!pdata)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
of_id = of_match_node(bcm_sf2_of_match, dn);
|
||||||
|
if (!of_id || !of_id->data)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
data = of_id->data;
|
||||||
|
|
||||||
|
/* Set SWITCH_REG register offsets and SWITCH_CORE align factor */
|
||||||
|
priv->type = data->type;
|
||||||
|
priv->reg_offsets = data->reg_offsets;
|
||||||
|
priv->core_reg_align = data->core_reg_align;
|
||||||
|
|
||||||
/* Auto-detection using standard registers will not work, so
|
/* Auto-detection using standard registers will not work, so
|
||||||
* provide an indication of what kind of device we are for
|
* provide an indication of what kind of device we are for
|
||||||
* b53_common to work with
|
* b53_common to work with
|
||||||
*/
|
*/
|
||||||
pdata->chip_id = BCM7445_DEVICE_ID;
|
pdata->chip_id = priv->type;
|
||||||
dev->pdata = pdata;
|
dev->pdata = pdata;
|
||||||
|
|
||||||
priv->dev = dev;
|
priv->dev = dev;
|
||||||
@ -1190,11 +1240,6 @@ static int bcm_sf2_resume(struct device *dev)
|
|||||||
static SIMPLE_DEV_PM_OPS(bcm_sf2_pm_ops,
|
static SIMPLE_DEV_PM_OPS(bcm_sf2_pm_ops,
|
||||||
bcm_sf2_suspend, bcm_sf2_resume);
|
bcm_sf2_suspend, bcm_sf2_resume);
|
||||||
|
|
||||||
static const struct of_device_id bcm_sf2_of_match[] = {
|
|
||||||
{ .compatible = "brcm,bcm7445-switch-v4.0" },
|
|
||||||
{ /* sentinel */ },
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(of, bcm_sf2_of_match);
|
|
||||||
|
|
||||||
static struct platform_driver bcm_sf2_driver = {
|
static struct platform_driver bcm_sf2_driver = {
|
||||||
.probe = bcm_sf2_sw_probe,
|
.probe = bcm_sf2_sw_probe,
|
||||||
|
@ -61,6 +61,11 @@ struct bcm_sf2_priv {
|
|||||||
void __iomem *fcb;
|
void __iomem *fcb;
|
||||||
void __iomem *acb;
|
void __iomem *acb;
|
||||||
|
|
||||||
|
/* Register offsets indirection tables */
|
||||||
|
u32 type;
|
||||||
|
const u16 *reg_offsets;
|
||||||
|
unsigned int core_reg_align;
|
||||||
|
|
||||||
/* spinlock protecting access to the indirect registers */
|
/* spinlock protecting access to the indirect registers */
|
||||||
spinlock_t indir_lock;
|
spinlock_t indir_lock;
|
||||||
|
|
||||||
@ -104,6 +109,11 @@ static inline struct bcm_sf2_priv *bcm_sf2_to_priv(struct dsa_switch *ds)
|
|||||||
return dev->priv;
|
return dev->priv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline u32 bcm_sf2_mangle_addr(struct bcm_sf2_priv *priv, u32 off)
|
||||||
|
{
|
||||||
|
return off << priv->core_reg_align;
|
||||||
|
}
|
||||||
|
|
||||||
#define SF2_IO_MACRO(name) \
|
#define SF2_IO_MACRO(name) \
|
||||||
static inline u32 name##_readl(struct bcm_sf2_priv *priv, u32 off) \
|
static inline u32 name##_readl(struct bcm_sf2_priv *priv, u32 off) \
|
||||||
{ \
|
{ \
|
||||||
@ -153,8 +163,28 @@ static inline void intrl2_##which##_mask_set(struct bcm_sf2_priv *priv, \
|
|||||||
priv->irq##which##_mask |= (mask); \
|
priv->irq##which##_mask |= (mask); \
|
||||||
} \
|
} \
|
||||||
|
|
||||||
SF2_IO_MACRO(core);
|
static inline u32 core_readl(struct bcm_sf2_priv *priv, u32 off)
|
||||||
SF2_IO_MACRO(reg);
|
{
|
||||||
|
u32 tmp = bcm_sf2_mangle_addr(priv, off);
|
||||||
|
return __raw_readl(priv->core + tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void core_writel(struct bcm_sf2_priv *priv, u32 val, u32 off)
|
||||||
|
{
|
||||||
|
u32 tmp = bcm_sf2_mangle_addr(priv, off);
|
||||||
|
__raw_writel(val, priv->core + tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u32 reg_readl(struct bcm_sf2_priv *priv, u16 off)
|
||||||
|
{
|
||||||
|
return __raw_readl(priv->reg + priv->reg_offsets[off]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void reg_writel(struct bcm_sf2_priv *priv, u32 val, u16 off)
|
||||||
|
{
|
||||||
|
__raw_writel(val, priv->reg + priv->reg_offsets[off]);
|
||||||
|
}
|
||||||
|
|
||||||
SF2_IO64_MACRO(core);
|
SF2_IO64_MACRO(core);
|
||||||
SF2_IO_MACRO(intrl2_0);
|
SF2_IO_MACRO(intrl2_0);
|
||||||
SF2_IO_MACRO(intrl2_1);
|
SF2_IO_MACRO(intrl2_1);
|
||||||
|
@ -12,22 +12,36 @@
|
|||||||
#define __BCM_SF2_REGS_H
|
#define __BCM_SF2_REGS_H
|
||||||
|
|
||||||
/* Register set relative to 'REG' */
|
/* Register set relative to 'REG' */
|
||||||
#define REG_SWITCH_CNTRL 0x00
|
|
||||||
|
enum bcm_sf2_reg_offs {
|
||||||
|
REG_SWITCH_CNTRL = 0,
|
||||||
|
REG_SWITCH_STATUS,
|
||||||
|
REG_DIR_DATA_WRITE,
|
||||||
|
REG_DIR_DATA_READ,
|
||||||
|
REG_SWITCH_REVISION,
|
||||||
|
REG_PHY_REVISION,
|
||||||
|
REG_SPHY_CNTRL,
|
||||||
|
REG_RGMII_0_CNTRL,
|
||||||
|
REG_RGMII_1_CNTRL,
|
||||||
|
REG_RGMII_2_CNTRL,
|
||||||
|
REG_LED_0_CNTRL,
|
||||||
|
REG_LED_1_CNTRL,
|
||||||
|
REG_LED_2_CNTRL,
|
||||||
|
REG_SWITCH_REG_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Relative to REG_SWITCH_CNTRL */
|
||||||
#define MDIO_MASTER_SEL (1 << 0)
|
#define MDIO_MASTER_SEL (1 << 0)
|
||||||
|
|
||||||
#define REG_SWITCH_STATUS 0x04
|
/* Relative to REG_SWITCH_REVISION */
|
||||||
#define REG_DIR_DATA_WRITE 0x08
|
|
||||||
#define REG_DIR_DATA_READ 0x0C
|
|
||||||
|
|
||||||
#define REG_SWITCH_REVISION 0x18
|
|
||||||
#define SF2_REV_MASK 0xffff
|
#define SF2_REV_MASK 0xffff
|
||||||
#define SWITCH_TOP_REV_SHIFT 16
|
#define SWITCH_TOP_REV_SHIFT 16
|
||||||
#define SWITCH_TOP_REV_MASK 0xffff
|
#define SWITCH_TOP_REV_MASK 0xffff
|
||||||
|
|
||||||
#define REG_PHY_REVISION 0x1C
|
/* Relative to REG_PHY_REVISION */
|
||||||
#define PHY_REVISION_MASK 0xffff
|
#define PHY_REVISION_MASK 0xffff
|
||||||
|
|
||||||
#define REG_SPHY_CNTRL 0x2C
|
/* Relative to REG_SPHY_CNTRL */
|
||||||
#define IDDQ_BIAS (1 << 0)
|
#define IDDQ_BIAS (1 << 0)
|
||||||
#define EXT_PWR_DOWN (1 << 1)
|
#define EXT_PWR_DOWN (1 << 1)
|
||||||
#define FORCE_DLL_EN (1 << 2)
|
#define FORCE_DLL_EN (1 << 2)
|
||||||
@ -37,13 +51,8 @@
|
|||||||
#define PHY_PHYAD_SHIFT 8
|
#define PHY_PHYAD_SHIFT 8
|
||||||
#define PHY_PHYAD_MASK 0x1F
|
#define PHY_PHYAD_MASK 0x1F
|
||||||
|
|
||||||
#define REG_RGMII_0_BASE 0x34
|
#define REG_RGMII_CNTRL_P(x) (REG_RGMII_0_CNTRL + (x))
|
||||||
#define REG_RGMII_CNTRL 0x00
|
|
||||||
#define REG_RGMII_IB_STATUS 0x04
|
|
||||||
#define REG_RGMII_RX_CLOCK_DELAY_CNTRL 0x08
|
|
||||||
#define REG_RGMII_CNTRL_SIZE 0x0C
|
|
||||||
#define REG_RGMII_CNTRL_P(x) (REG_RGMII_0_BASE + \
|
|
||||||
((x) * REG_RGMII_CNTRL_SIZE))
|
|
||||||
/* Relative to REG_RGMII_CNTRL */
|
/* Relative to REG_RGMII_CNTRL */
|
||||||
#define RGMII_MODE_EN (1 << 0)
|
#define RGMII_MODE_EN (1 << 0)
|
||||||
#define ID_MODE_DIS (1 << 1)
|
#define ID_MODE_DIS (1 << 1)
|
||||||
@ -61,8 +70,8 @@
|
|||||||
#define LPI_COUNT_SHIFT 9
|
#define LPI_COUNT_SHIFT 9
|
||||||
#define LPI_COUNT_MASK 0x3F
|
#define LPI_COUNT_MASK 0x3F
|
||||||
|
|
||||||
#define REG_LED_CNTRL_BASE 0x90
|
#define REG_LED_CNTRL(x) (REG_LED_0_CNTRL + (x))
|
||||||
#define REG_LED_CNTRL(x) (REG_LED_CNTRL_BASE + (x) * 4)
|
|
||||||
#define SPDLNK_SRC_SEL (1 << 24)
|
#define SPDLNK_SRC_SEL (1 << 24)
|
||||||
|
|
||||||
/* Register set relative to 'INTRL2_0' and 'INTRL2_1' */
|
/* Register set relative to 'INTRL2_0' and 'INTRL2_1' */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user