.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)
{
const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
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 dsa_switch_ops *ops;
struct bcm_sf2_priv *priv;
if (!pdata)
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
* provide an indication of what kind of device we are for
* b53_common to work with
*/
- pdata->chip_id = BCM7445_DEVICE_ID;
+ pdata->chip_id = priv->type;
dev->pdata = pdata;
priv->dev = dev;
static SIMPLE_DEV_PM_OPS(bcm_sf2_pm_ops,
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 = {
.probe = bcm_sf2_sw_probe,
void __iomem *fcb;
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_t indir_lock;
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) \
static inline u32 name##_readl(struct bcm_sf2_priv *priv, u32 off) \
{ \
priv->irq##which##_mask |= (mask); \
} \
-SF2_IO_MACRO(core);
-SF2_IO_MACRO(reg);
+static inline u32 core_readl(struct bcm_sf2_priv *priv, u32 off)
+{
+ 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_IO_MACRO(intrl2_0);
SF2_IO_MACRO(intrl2_1);
#define __BCM_SF2_REGS_H
/* Register set relative to 'REG' */
-#define REG_SWITCH_CNTRL 0x00
-#define MDIO_MASTER_SEL (1 << 0)
-#define REG_SWITCH_STATUS 0x04
-#define REG_DIR_DATA_WRITE 0x08
-#define REG_DIR_DATA_READ 0x0C
+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 REG_SWITCH_REVISION 0x18
+/* Relative to REG_SWITCH_REVISION */
#define SF2_REV_MASK 0xffff
#define SWITCH_TOP_REV_SHIFT 16
#define SWITCH_TOP_REV_MASK 0xffff
-#define REG_PHY_REVISION 0x1C
+/* Relative to REG_PHY_REVISION */
#define PHY_REVISION_MASK 0xffff
-#define REG_SPHY_CNTRL 0x2C
+/* Relative to REG_SPHY_CNTRL */
#define IDDQ_BIAS (1 << 0)
#define EXT_PWR_DOWN (1 << 1)
#define FORCE_DLL_EN (1 << 2)
#define PHY_PHYAD_SHIFT 8
#define PHY_PHYAD_MASK 0x1F
-#define REG_RGMII_0_BASE 0x34
-#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))
+#define REG_RGMII_CNTRL_P(x) (REG_RGMII_0_CNTRL + (x))
+
/* Relative to REG_RGMII_CNTRL */
#define RGMII_MODE_EN (1 << 0)
#define ID_MODE_DIS (1 << 1)
#define LPI_COUNT_SHIFT 9
#define LPI_COUNT_MASK 0x3F
-#define REG_LED_CNTRL_BASE 0x90
-#define REG_LED_CNTRL(x) (REG_LED_CNTRL_BASE + (x) * 4)
+#define REG_LED_CNTRL(x) (REG_LED_0_CNTRL + (x))
+
#define SPDLNK_SRC_SEL (1 << 24)
/* Register set relative to 'INTRL2_0' and 'INTRL2_1' */