+static void
+ar8216_init_port(struct ar8xxx_priv *priv, int port)
+{
+ __ar8216_init_port(priv, port, ar8xxx_has_gige(priv),
+ chip_is_ar8316(priv));
+}
+
+static void
+ar8216_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1)
+{
+ int timeout = 20;
+
+ while (ar8xxx_mii_read32(priv, r2, r1) & AR8216_ATU_ACTIVE && --timeout) {
+ udelay(10);
+ cond_resched();
+ }
+
+ if (!timeout)
+ pr_err("ar8216: timeout waiting for atu to become ready\n");
+}
+
+static void ar8216_get_arl_entry(struct ar8xxx_priv *priv,
+ struct arl_entry *a, u32 *status, enum arl_op op)
+{
+ struct mii_bus *bus = priv->mii_bus;
+ u16 r2, page;
+ u16 r1_func0, r1_func1, r1_func2;
+ u32 t, val0, val1, val2;
+
+ split_addr(AR8216_REG_ATU_FUNC0, &r1_func0, &r2, &page);
+ r2 |= 0x10;
+
+ r1_func1 = (AR8216_REG_ATU_FUNC1 >> 1) & 0x1e;
+ r1_func2 = (AR8216_REG_ATU_FUNC2 >> 1) & 0x1e;
+
+ switch (op) {
+ case AR8XXX_ARL_INITIALIZE:
+ /* all ATU registers are on the same page
+ * therefore set page only once
+ */
+ bus->write(bus, 0x18, 0, page);
+ wait_for_page_switch();
+
+ ar8216_wait_atu_ready(priv, r2, r1_func0);
+
+ ar8xxx_mii_write32(priv, r2, r1_func0, AR8216_ATU_OP_GET_NEXT);
+ ar8xxx_mii_write32(priv, r2, r1_func1, 0);
+ ar8xxx_mii_write32(priv, r2, r1_func2, 0);
+ break;
+ case AR8XXX_ARL_GET_NEXT:
+ t = ar8xxx_mii_read32(priv, r2, r1_func0);
+ t |= AR8216_ATU_ACTIVE;
+ ar8xxx_mii_write32(priv, r2, r1_func0, t);
+ ar8216_wait_atu_ready(priv, r2, r1_func0);
+
+ val0 = ar8xxx_mii_read32(priv, r2, r1_func0);
+ val1 = ar8xxx_mii_read32(priv, r2, r1_func1);
+ val2 = ar8xxx_mii_read32(priv, r2, r1_func2);
+
+ *status = (val2 & AR8216_ATU_STATUS) >> AR8216_ATU_STATUS_S;
+ if (!*status)
+ break;
+
+ a->portmap = (val2 & AR8216_ATU_PORTS) >> AR8216_ATU_PORTS_S;
+ a->mac[0] = (val0 & AR8216_ATU_ADDR5) >> AR8216_ATU_ADDR5_S;
+ a->mac[1] = (val0 & AR8216_ATU_ADDR4) >> AR8216_ATU_ADDR4_S;
+ a->mac[2] = (val1 & AR8216_ATU_ADDR3) >> AR8216_ATU_ADDR3_S;
+ a->mac[3] = (val1 & AR8216_ATU_ADDR2) >> AR8216_ATU_ADDR2_S;
+ a->mac[4] = (val1 & AR8216_ATU_ADDR1) >> AR8216_ATU_ADDR1_S;
+ a->mac[5] = (val1 & AR8216_ATU_ADDR0) >> AR8216_ATU_ADDR0_S;
+ break;
+ }
+}
+
+static int
+ar8229_hw_init(struct ar8xxx_priv *priv)
+{
+ int phy_if_mode;
+
+ if (priv->initialized)
+ return 0;
+
+ ar8xxx_write(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET);
+ ar8xxx_reg_wait(priv, AR8216_REG_CTRL, AR8216_CTRL_RESET, 0, 1000);
+
+ phy_if_mode = of_get_phy_mode(priv->pdev->of_node);
+
+ if (phy_if_mode == PHY_INTERFACE_MODE_GMII) {
+ ar8xxx_write(priv, AR8229_REG_OPER_MODE0,
+ AR8229_OPER_MODE0_MAC_GMII_EN);
+ } else if (phy_if_mode == PHY_INTERFACE_MODE_MII) {
+ ar8xxx_write(priv, AR8229_REG_OPER_MODE0,
+ AR8229_OPER_MODE0_PHY_MII_EN);
+ } else {
+ pr_err("ar8229: unsupported mii mode\n");
+ return -EINVAL;
+ }
+
+ if (priv->port4_phy)
+ ar8xxx_write(priv, AR8229_REG_OPER_MODE1,
+ AR8229_REG_OPER_MODE1_PHY4_MII_EN);
+
+ ar8xxx_phy_init(priv);
+
+ priv->initialized = true;
+ return 0;
+}
+
+static void
+ar8229_init_globals(struct ar8xxx_priv *priv)
+{
+
+ /* Enable CPU port, and disable mirror port */
+ ar8xxx_write(priv, AR8216_REG_GLOBAL_CPUPORT,
+ AR8216_GLOBAL_CPUPORT_EN |
+ (15 << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
+
+ /* Setup TAG priority mapping */
+ ar8xxx_write(priv, AR8216_REG_TAG_PRIORITY, 0xfa50);
+
+ /* Enable aging, MAC replacing */
+ ar8xxx_write(priv, AR8216_REG_ATU_CTRL,
+ 0x2b /* 5 min age time */ |
+ AR8216_ATU_CTRL_AGE_EN |
+ AR8216_ATU_CTRL_LEARN_CHANGE);
+
+ /* Enable ARP frame acknowledge */
+ ar8xxx_reg_set(priv, AR8229_REG_QM_CTRL,
+ AR8229_QM_CTRL_ARP_EN);
+
+ /* Enable Broadcast/Multicast frames transmitted to the CPU */
+ ar8xxx_reg_set(priv, AR8216_REG_FLOOD_MASK,
+ AR8229_FLOOD_MASK_BC_DP(0) |
+ AR8229_FLOOD_MASK_MC_DP(0));
+
+ /* setup MTU */
+ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+ AR8236_GCTRL_MTU, AR8236_GCTRL_MTU);
+
+ /* Enable MIB counters */
+ ar8xxx_reg_set(priv, AR8216_REG_MIB_FUNC,
+ AR8236_MIB_EN);
+
+ /* setup Service TAG */
+ ar8xxx_rmw(priv, AR8216_REG_SERVICE_TAG, AR8216_SERVICE_TAG_M, 0);
+}
+
+static void
+ar8229_init_port(struct ar8xxx_priv *priv, int port)
+{
+ __ar8216_init_port(priv, port, true, true);
+}
+