1027152b8SChristian Marangi // SPDX-License-Identifier: GPL-2.0 2027152b8SChristian Marangi /* 3027152b8SChristian Marangi * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name> 4027152b8SChristian Marangi * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org> 5027152b8SChristian Marangi * Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved. 6027152b8SChristian Marangi * Copyright (c) 2016 John Crispin <john@phrozen.org> 7027152b8SChristian Marangi */ 8027152b8SChristian Marangi 9027152b8SChristian Marangi #include <linux/module.h> 10027152b8SChristian Marangi #include <linux/phy.h> 11027152b8SChristian Marangi #include <linux/netdevice.h> 12027152b8SChristian Marangi #include <linux/bitfield.h> 13027152b8SChristian Marangi #include <linux/regmap.h> 14027152b8SChristian Marangi #include <net/dsa.h> 15027152b8SChristian Marangi #include <linux/of_net.h> 16027152b8SChristian Marangi #include <linux/of_mdio.h> 17027152b8SChristian Marangi #include <linux/of_platform.h> 18027152b8SChristian Marangi #include <linux/mdio.h> 19027152b8SChristian Marangi #include <linux/phylink.h> 20027152b8SChristian Marangi #include <linux/gpio/consumer.h> 21027152b8SChristian Marangi #include <linux/etherdevice.h> 22027152b8SChristian Marangi #include <linux/dsa/tag_qca.h> 23027152b8SChristian Marangi 24027152b8SChristian Marangi #include "qca8k.h" 25027152b8SChristian Marangi 26027152b8SChristian Marangi static void 27027152b8SChristian Marangi qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) 28027152b8SChristian Marangi { 29027152b8SChristian Marangi regaddr >>= 1; 30027152b8SChristian Marangi *r1 = regaddr & 0x1e; 31027152b8SChristian Marangi 32027152b8SChristian Marangi regaddr >>= 5; 33027152b8SChristian Marangi *r2 = regaddr & 0x7; 34027152b8SChristian Marangi 35027152b8SChristian Marangi regaddr >>= 3; 36027152b8SChristian Marangi *page = regaddr & 0x3ff; 37027152b8SChristian Marangi } 38027152b8SChristian Marangi 39027152b8SChristian Marangi static int 40027152b8SChristian Marangi qca8k_set_lo(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 lo) 41027152b8SChristian Marangi { 42027152b8SChristian Marangi u16 *cached_lo = &priv->mdio_cache.lo; 43027152b8SChristian Marangi struct mii_bus *bus = priv->bus; 44027152b8SChristian Marangi int ret; 45027152b8SChristian Marangi 46027152b8SChristian Marangi if (lo == *cached_lo) 47027152b8SChristian Marangi return 0; 48027152b8SChristian Marangi 49027152b8SChristian Marangi ret = bus->write(bus, phy_id, regnum, lo); 50027152b8SChristian Marangi if (ret < 0) 51027152b8SChristian Marangi dev_err_ratelimited(&bus->dev, 52027152b8SChristian Marangi "failed to write qca8k 32bit lo register\n"); 53027152b8SChristian Marangi 54027152b8SChristian Marangi *cached_lo = lo; 55027152b8SChristian Marangi return 0; 56027152b8SChristian Marangi } 57027152b8SChristian Marangi 58027152b8SChristian Marangi static int 59027152b8SChristian Marangi qca8k_set_hi(struct qca8k_priv *priv, int phy_id, u32 regnum, u16 hi) 60027152b8SChristian Marangi { 61027152b8SChristian Marangi u16 *cached_hi = &priv->mdio_cache.hi; 62027152b8SChristian Marangi struct mii_bus *bus = priv->bus; 63027152b8SChristian Marangi int ret; 64027152b8SChristian Marangi 65027152b8SChristian Marangi if (hi == *cached_hi) 66027152b8SChristian Marangi return 0; 67027152b8SChristian Marangi 68027152b8SChristian Marangi ret = bus->write(bus, phy_id, regnum, hi); 69027152b8SChristian Marangi if (ret < 0) 70027152b8SChristian Marangi dev_err_ratelimited(&bus->dev, 71027152b8SChristian Marangi "failed to write qca8k 32bit hi register\n"); 72027152b8SChristian Marangi 73027152b8SChristian Marangi *cached_hi = hi; 74027152b8SChristian Marangi return 0; 75027152b8SChristian Marangi } 76027152b8SChristian Marangi 77027152b8SChristian Marangi static int 78027152b8SChristian Marangi qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) 79027152b8SChristian Marangi { 80027152b8SChristian Marangi int ret; 81027152b8SChristian Marangi 82027152b8SChristian Marangi ret = bus->read(bus, phy_id, regnum); 83027152b8SChristian Marangi if (ret >= 0) { 84027152b8SChristian Marangi *val = ret; 85027152b8SChristian Marangi ret = bus->read(bus, phy_id, regnum + 1); 86027152b8SChristian Marangi *val |= ret << 16; 87027152b8SChristian Marangi } 88027152b8SChristian Marangi 89027152b8SChristian Marangi if (ret < 0) { 90027152b8SChristian Marangi dev_err_ratelimited(&bus->dev, 91027152b8SChristian Marangi "failed to read qca8k 32bit register\n"); 92027152b8SChristian Marangi *val = 0; 93027152b8SChristian Marangi return ret; 94027152b8SChristian Marangi } 95027152b8SChristian Marangi 96027152b8SChristian Marangi return 0; 97027152b8SChristian Marangi } 98027152b8SChristian Marangi 99027152b8SChristian Marangi static void 100027152b8SChristian Marangi qca8k_mii_write32(struct qca8k_priv *priv, int phy_id, u32 regnum, u32 val) 101027152b8SChristian Marangi { 102027152b8SChristian Marangi u16 lo, hi; 103027152b8SChristian Marangi int ret; 104027152b8SChristian Marangi 105027152b8SChristian Marangi lo = val & 0xffff; 106027152b8SChristian Marangi hi = (u16)(val >> 16); 107027152b8SChristian Marangi 108027152b8SChristian Marangi ret = qca8k_set_lo(priv, phy_id, regnum, lo); 109027152b8SChristian Marangi if (ret >= 0) 110027152b8SChristian Marangi ret = qca8k_set_hi(priv, phy_id, regnum + 1, hi); 111027152b8SChristian Marangi } 112027152b8SChristian Marangi 113027152b8SChristian Marangi static int 114027152b8SChristian Marangi qca8k_set_page(struct qca8k_priv *priv, u16 page) 115027152b8SChristian Marangi { 116027152b8SChristian Marangi u16 *cached_page = &priv->mdio_cache.page; 117027152b8SChristian Marangi struct mii_bus *bus = priv->bus; 118027152b8SChristian Marangi int ret; 119027152b8SChristian Marangi 120027152b8SChristian Marangi if (page == *cached_page) 121027152b8SChristian Marangi return 0; 122027152b8SChristian Marangi 123027152b8SChristian Marangi ret = bus->write(bus, 0x18, 0, page); 124027152b8SChristian Marangi if (ret < 0) { 125027152b8SChristian Marangi dev_err_ratelimited(&bus->dev, 126027152b8SChristian Marangi "failed to set qca8k page\n"); 127027152b8SChristian Marangi return ret; 128027152b8SChristian Marangi } 129027152b8SChristian Marangi 130027152b8SChristian Marangi *cached_page = page; 131027152b8SChristian Marangi usleep_range(1000, 2000); 132027152b8SChristian Marangi return 0; 133027152b8SChristian Marangi } 134027152b8SChristian Marangi 135027152b8SChristian Marangi static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) 136027152b8SChristian Marangi { 137027152b8SChristian Marangi struct qca8k_mgmt_eth_data *mgmt_eth_data; 138027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 139027152b8SChristian Marangi struct qca_mgmt_ethhdr *mgmt_ethhdr; 140a2550d3cSChristian Marangi u32 command; 141027152b8SChristian Marangi u8 len, cmd; 142a2550d3cSChristian Marangi int i; 143027152b8SChristian Marangi 144027152b8SChristian Marangi mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb); 145027152b8SChristian Marangi mgmt_eth_data = &priv->mgmt_eth_data; 146027152b8SChristian Marangi 147a2550d3cSChristian Marangi command = get_unaligned_le32(&mgmt_ethhdr->command); 148a2550d3cSChristian Marangi cmd = FIELD_GET(QCA_HDR_MGMT_CMD, command); 149a2550d3cSChristian Marangi len = FIELD_GET(QCA_HDR_MGMT_LENGTH, command); 150027152b8SChristian Marangi 151027152b8SChristian Marangi /* Make sure the seq match the requested packet */ 152a2550d3cSChristian Marangi if (get_unaligned_le32(&mgmt_ethhdr->seq) == mgmt_eth_data->seq) 153027152b8SChristian Marangi mgmt_eth_data->ack = true; 154027152b8SChristian Marangi 155027152b8SChristian Marangi if (cmd == MDIO_READ) { 156a2550d3cSChristian Marangi u32 *val = mgmt_eth_data->data; 157a2550d3cSChristian Marangi 158a2550d3cSChristian Marangi *val = get_unaligned_le32(&mgmt_ethhdr->mdio_data); 159027152b8SChristian Marangi 160027152b8SChristian Marangi /* Get the rest of the 12 byte of data. 161027152b8SChristian Marangi * The read/write function will extract the requested data. 162027152b8SChristian Marangi */ 163a2550d3cSChristian Marangi if (len > QCA_HDR_MGMT_DATA1_LEN) { 164a2550d3cSChristian Marangi __le32 *data2 = (__le32 *)skb->data; 165a2550d3cSChristian Marangi int data_len = min_t(int, QCA_HDR_MGMT_DATA2_LEN, 166a2550d3cSChristian Marangi len - QCA_HDR_MGMT_DATA1_LEN); 167a2550d3cSChristian Marangi 168a2550d3cSChristian Marangi val++; 169a2550d3cSChristian Marangi 170a2550d3cSChristian Marangi for (i = sizeof(u32); i <= data_len; i += sizeof(u32)) { 171a2550d3cSChristian Marangi *val = get_unaligned_le32(data2); 172a2550d3cSChristian Marangi val++; 173a2550d3cSChristian Marangi data2++; 174a2550d3cSChristian Marangi } 175a2550d3cSChristian Marangi } 176027152b8SChristian Marangi } 177027152b8SChristian Marangi 178027152b8SChristian Marangi complete(&mgmt_eth_data->rw_done); 179027152b8SChristian Marangi } 180027152b8SChristian Marangi 181027152b8SChristian Marangi static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val, 182027152b8SChristian Marangi int priority, unsigned int len) 183027152b8SChristian Marangi { 184027152b8SChristian Marangi struct qca_mgmt_ethhdr *mgmt_ethhdr; 185027152b8SChristian Marangi unsigned int real_len; 186027152b8SChristian Marangi struct sk_buff *skb; 187a2550d3cSChristian Marangi __le32 *data2; 188a2550d3cSChristian Marangi u32 command; 189027152b8SChristian Marangi u16 hdr; 190a2550d3cSChristian Marangi int i; 191027152b8SChristian Marangi 192027152b8SChristian Marangi skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); 193027152b8SChristian Marangi if (!skb) 194027152b8SChristian Marangi return NULL; 195027152b8SChristian Marangi 196027152b8SChristian Marangi /* Max value for len reg is 15 (0xf) but the switch actually return 16 byte 197027152b8SChristian Marangi * Actually for some reason the steps are: 198027152b8SChristian Marangi * 0: nothing 199027152b8SChristian Marangi * 1-4: first 4 byte 200027152b8SChristian Marangi * 5-6: first 12 byte 201027152b8SChristian Marangi * 7-15: all 16 byte 202027152b8SChristian Marangi */ 203027152b8SChristian Marangi if (len == 16) 204027152b8SChristian Marangi real_len = 15; 205027152b8SChristian Marangi else 206027152b8SChristian Marangi real_len = len; 207027152b8SChristian Marangi 208027152b8SChristian Marangi skb_reset_mac_header(skb); 209027152b8SChristian Marangi skb_set_network_header(skb, skb->len); 210027152b8SChristian Marangi 211027152b8SChristian Marangi mgmt_ethhdr = skb_push(skb, QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); 212027152b8SChristian Marangi 213027152b8SChristian Marangi hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); 214027152b8SChristian Marangi hdr |= FIELD_PREP(QCA_HDR_XMIT_PRIORITY, priority); 215027152b8SChristian Marangi hdr |= QCA_HDR_XMIT_FROM_CPU; 216027152b8SChristian Marangi hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0)); 217027152b8SChristian Marangi hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); 218027152b8SChristian Marangi 219a2550d3cSChristian Marangi command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); 220a2550d3cSChristian Marangi command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); 221a2550d3cSChristian Marangi command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); 222a2550d3cSChristian Marangi command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, 223027152b8SChristian Marangi QCA_HDR_MGMT_CHECK_CODE_VAL); 224027152b8SChristian Marangi 225a2550d3cSChristian Marangi put_unaligned_le32(command, &mgmt_ethhdr->command); 226a2550d3cSChristian Marangi 227027152b8SChristian Marangi if (cmd == MDIO_WRITE) 228a2550d3cSChristian Marangi put_unaligned_le32(*val, &mgmt_ethhdr->mdio_data); 229027152b8SChristian Marangi 230027152b8SChristian Marangi mgmt_ethhdr->hdr = htons(hdr); 231027152b8SChristian Marangi 232027152b8SChristian Marangi data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); 233a2550d3cSChristian Marangi if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) { 234a2550d3cSChristian Marangi int data_len = min_t(int, QCA_HDR_MGMT_DATA2_LEN, 235a2550d3cSChristian Marangi len - QCA_HDR_MGMT_DATA1_LEN); 236a2550d3cSChristian Marangi 237a2550d3cSChristian Marangi val++; 238a2550d3cSChristian Marangi 239a2550d3cSChristian Marangi for (i = sizeof(u32); i <= data_len; i += sizeof(u32)) { 240a2550d3cSChristian Marangi put_unaligned_le32(*val, data2); 241a2550d3cSChristian Marangi data2++; 242a2550d3cSChristian Marangi val++; 243a2550d3cSChristian Marangi } 244a2550d3cSChristian Marangi } 245027152b8SChristian Marangi 246027152b8SChristian Marangi return skb; 247027152b8SChristian Marangi } 248027152b8SChristian Marangi 249027152b8SChristian Marangi static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num) 250027152b8SChristian Marangi { 251027152b8SChristian Marangi struct qca_mgmt_ethhdr *mgmt_ethhdr; 252a2550d3cSChristian Marangi u32 seq; 253027152b8SChristian Marangi 254a2550d3cSChristian Marangi seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); 255027152b8SChristian Marangi mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data; 256a2550d3cSChristian Marangi put_unaligned_le32(seq, &mgmt_ethhdr->seq); 257027152b8SChristian Marangi } 258027152b8SChristian Marangi 259027152b8SChristian Marangi static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) 260027152b8SChristian Marangi { 261027152b8SChristian Marangi struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; 262027152b8SChristian Marangi struct sk_buff *skb; 263027152b8SChristian Marangi bool ack; 264027152b8SChristian Marangi int ret; 265027152b8SChristian Marangi 266027152b8SChristian Marangi skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, 267027152b8SChristian Marangi QCA8K_ETHERNET_MDIO_PRIORITY, len); 268027152b8SChristian Marangi if (!skb) 269027152b8SChristian Marangi return -ENOMEM; 270027152b8SChristian Marangi 271027152b8SChristian Marangi mutex_lock(&mgmt_eth_data->mutex); 272027152b8SChristian Marangi 273027152b8SChristian Marangi /* Check mgmt_master if is operational */ 274027152b8SChristian Marangi if (!priv->mgmt_master) { 275027152b8SChristian Marangi kfree_skb(skb); 276027152b8SChristian Marangi mutex_unlock(&mgmt_eth_data->mutex); 277027152b8SChristian Marangi return -EINVAL; 278027152b8SChristian Marangi } 279027152b8SChristian Marangi 280027152b8SChristian Marangi skb->dev = priv->mgmt_master; 281027152b8SChristian Marangi 282027152b8SChristian Marangi reinit_completion(&mgmt_eth_data->rw_done); 283027152b8SChristian Marangi 284027152b8SChristian Marangi /* Increment seq_num and set it in the mdio pkt */ 285027152b8SChristian Marangi mgmt_eth_data->seq++; 286027152b8SChristian Marangi qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); 287027152b8SChristian Marangi mgmt_eth_data->ack = false; 288027152b8SChristian Marangi 289027152b8SChristian Marangi dev_queue_xmit(skb); 290027152b8SChristian Marangi 291027152b8SChristian Marangi ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, 292027152b8SChristian Marangi msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); 293027152b8SChristian Marangi 294027152b8SChristian Marangi *val = mgmt_eth_data->data[0]; 295027152b8SChristian Marangi if (len > QCA_HDR_MGMT_DATA1_LEN) 296027152b8SChristian Marangi memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN); 297027152b8SChristian Marangi 298027152b8SChristian Marangi ack = mgmt_eth_data->ack; 299027152b8SChristian Marangi 300027152b8SChristian Marangi mutex_unlock(&mgmt_eth_data->mutex); 301027152b8SChristian Marangi 302027152b8SChristian Marangi if (ret <= 0) 303027152b8SChristian Marangi return -ETIMEDOUT; 304027152b8SChristian Marangi 305027152b8SChristian Marangi if (!ack) 306027152b8SChristian Marangi return -EINVAL; 307027152b8SChristian Marangi 308027152b8SChristian Marangi return 0; 309027152b8SChristian Marangi } 310027152b8SChristian Marangi 311027152b8SChristian Marangi static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) 312027152b8SChristian Marangi { 313027152b8SChristian Marangi struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; 314027152b8SChristian Marangi struct sk_buff *skb; 315027152b8SChristian Marangi bool ack; 316027152b8SChristian Marangi int ret; 317027152b8SChristian Marangi 318027152b8SChristian Marangi skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val, 319027152b8SChristian Marangi QCA8K_ETHERNET_MDIO_PRIORITY, len); 320027152b8SChristian Marangi if (!skb) 321027152b8SChristian Marangi return -ENOMEM; 322027152b8SChristian Marangi 323027152b8SChristian Marangi mutex_lock(&mgmt_eth_data->mutex); 324027152b8SChristian Marangi 325027152b8SChristian Marangi /* Check mgmt_master if is operational */ 326027152b8SChristian Marangi if (!priv->mgmt_master) { 327027152b8SChristian Marangi kfree_skb(skb); 328027152b8SChristian Marangi mutex_unlock(&mgmt_eth_data->mutex); 329027152b8SChristian Marangi return -EINVAL; 330027152b8SChristian Marangi } 331027152b8SChristian Marangi 332027152b8SChristian Marangi skb->dev = priv->mgmt_master; 333027152b8SChristian Marangi 334027152b8SChristian Marangi reinit_completion(&mgmt_eth_data->rw_done); 335027152b8SChristian Marangi 336027152b8SChristian Marangi /* Increment seq_num and set it in the mdio pkt */ 337027152b8SChristian Marangi mgmt_eth_data->seq++; 338027152b8SChristian Marangi qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); 339027152b8SChristian Marangi mgmt_eth_data->ack = false; 340027152b8SChristian Marangi 341027152b8SChristian Marangi dev_queue_xmit(skb); 342027152b8SChristian Marangi 343027152b8SChristian Marangi ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, 344027152b8SChristian Marangi msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); 345027152b8SChristian Marangi 346027152b8SChristian Marangi ack = mgmt_eth_data->ack; 347027152b8SChristian Marangi 348027152b8SChristian Marangi mutex_unlock(&mgmt_eth_data->mutex); 349027152b8SChristian Marangi 350027152b8SChristian Marangi if (ret <= 0) 351027152b8SChristian Marangi return -ETIMEDOUT; 352027152b8SChristian Marangi 353027152b8SChristian Marangi if (!ack) 354027152b8SChristian Marangi return -EINVAL; 355027152b8SChristian Marangi 356027152b8SChristian Marangi return 0; 357027152b8SChristian Marangi } 358027152b8SChristian Marangi 359027152b8SChristian Marangi static int 360027152b8SChristian Marangi qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) 361027152b8SChristian Marangi { 362027152b8SChristian Marangi u32 val = 0; 363027152b8SChristian Marangi int ret; 364027152b8SChristian Marangi 365027152b8SChristian Marangi ret = qca8k_read_eth(priv, reg, &val, sizeof(val)); 366027152b8SChristian Marangi if (ret) 367027152b8SChristian Marangi return ret; 368027152b8SChristian Marangi 369027152b8SChristian Marangi val &= ~mask; 370027152b8SChristian Marangi val |= write_val; 371027152b8SChristian Marangi 372027152b8SChristian Marangi return qca8k_write_eth(priv, reg, &val, sizeof(val)); 373027152b8SChristian Marangi } 374027152b8SChristian Marangi 375027152b8SChristian Marangi static int 376027152b8SChristian Marangi qca8k_regmap_read(void *ctx, uint32_t reg, uint32_t *val) 377027152b8SChristian Marangi { 378027152b8SChristian Marangi struct qca8k_priv *priv = (struct qca8k_priv *)ctx; 379027152b8SChristian Marangi struct mii_bus *bus = priv->bus; 380027152b8SChristian Marangi u16 r1, r2, page; 381027152b8SChristian Marangi int ret; 382027152b8SChristian Marangi 383027152b8SChristian Marangi if (!qca8k_read_eth(priv, reg, val, sizeof(*val))) 384027152b8SChristian Marangi return 0; 385027152b8SChristian Marangi 386027152b8SChristian Marangi qca8k_split_addr(reg, &r1, &r2, &page); 387027152b8SChristian Marangi 388027152b8SChristian Marangi mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); 389027152b8SChristian Marangi 390027152b8SChristian Marangi ret = qca8k_set_page(priv, page); 391027152b8SChristian Marangi if (ret < 0) 392027152b8SChristian Marangi goto exit; 393027152b8SChristian Marangi 394027152b8SChristian Marangi ret = qca8k_mii_read32(bus, 0x10 | r2, r1, val); 395027152b8SChristian Marangi 396027152b8SChristian Marangi exit: 397027152b8SChristian Marangi mutex_unlock(&bus->mdio_lock); 398027152b8SChristian Marangi return ret; 399027152b8SChristian Marangi } 400027152b8SChristian Marangi 401027152b8SChristian Marangi static int 402027152b8SChristian Marangi qca8k_regmap_write(void *ctx, uint32_t reg, uint32_t val) 403027152b8SChristian Marangi { 404027152b8SChristian Marangi struct qca8k_priv *priv = (struct qca8k_priv *)ctx; 405027152b8SChristian Marangi struct mii_bus *bus = priv->bus; 406027152b8SChristian Marangi u16 r1, r2, page; 407027152b8SChristian Marangi int ret; 408027152b8SChristian Marangi 409027152b8SChristian Marangi if (!qca8k_write_eth(priv, reg, &val, sizeof(val))) 410027152b8SChristian Marangi return 0; 411027152b8SChristian Marangi 412027152b8SChristian Marangi qca8k_split_addr(reg, &r1, &r2, &page); 413027152b8SChristian Marangi 414027152b8SChristian Marangi mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); 415027152b8SChristian Marangi 416027152b8SChristian Marangi ret = qca8k_set_page(priv, page); 417027152b8SChristian Marangi if (ret < 0) 418027152b8SChristian Marangi goto exit; 419027152b8SChristian Marangi 420027152b8SChristian Marangi qca8k_mii_write32(priv, 0x10 | r2, r1, val); 421027152b8SChristian Marangi 422027152b8SChristian Marangi exit: 423027152b8SChristian Marangi mutex_unlock(&bus->mdio_lock); 424027152b8SChristian Marangi return ret; 425027152b8SChristian Marangi } 426027152b8SChristian Marangi 427027152b8SChristian Marangi static int 428027152b8SChristian Marangi qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val) 429027152b8SChristian Marangi { 430027152b8SChristian Marangi struct qca8k_priv *priv = (struct qca8k_priv *)ctx; 431027152b8SChristian Marangi struct mii_bus *bus = priv->bus; 432027152b8SChristian Marangi u16 r1, r2, page; 433027152b8SChristian Marangi u32 val; 434027152b8SChristian Marangi int ret; 435027152b8SChristian Marangi 436027152b8SChristian Marangi if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val)) 437027152b8SChristian Marangi return 0; 438027152b8SChristian Marangi 439027152b8SChristian Marangi qca8k_split_addr(reg, &r1, &r2, &page); 440027152b8SChristian Marangi 441027152b8SChristian Marangi mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); 442027152b8SChristian Marangi 443027152b8SChristian Marangi ret = qca8k_set_page(priv, page); 444027152b8SChristian Marangi if (ret < 0) 445027152b8SChristian Marangi goto exit; 446027152b8SChristian Marangi 447027152b8SChristian Marangi ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); 448027152b8SChristian Marangi if (ret < 0) 449027152b8SChristian Marangi goto exit; 450027152b8SChristian Marangi 451027152b8SChristian Marangi val &= ~mask; 452027152b8SChristian Marangi val |= write_val; 453027152b8SChristian Marangi qca8k_mii_write32(priv, 0x10 | r2, r1, val); 454027152b8SChristian Marangi 455027152b8SChristian Marangi exit: 456027152b8SChristian Marangi mutex_unlock(&bus->mdio_lock); 457027152b8SChristian Marangi 458027152b8SChristian Marangi return ret; 459027152b8SChristian Marangi } 460027152b8SChristian Marangi 461027152b8SChristian Marangi static struct regmap_config qca8k_regmap_config = { 462027152b8SChristian Marangi .reg_bits = 16, 463027152b8SChristian Marangi .val_bits = 32, 464027152b8SChristian Marangi .reg_stride = 4, 465027152b8SChristian Marangi .max_register = 0x16ac, /* end MIB - Port6 range */ 466027152b8SChristian Marangi .reg_read = qca8k_regmap_read, 467027152b8SChristian Marangi .reg_write = qca8k_regmap_write, 468027152b8SChristian Marangi .reg_update_bits = qca8k_regmap_update_bits, 469027152b8SChristian Marangi .rd_table = &qca8k_readable_table, 470027152b8SChristian Marangi .disable_locking = true, /* Locking is handled by qca8k read/write */ 471027152b8SChristian Marangi .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */ 472027152b8SChristian Marangi }; 473027152b8SChristian Marangi 474027152b8SChristian Marangi static int 475027152b8SChristian Marangi qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, 476027152b8SChristian Marangi struct sk_buff *read_skb, u32 *val) 477027152b8SChristian Marangi { 478027152b8SChristian Marangi struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL); 479027152b8SChristian Marangi bool ack; 480027152b8SChristian Marangi int ret; 481027152b8SChristian Marangi 482027152b8SChristian Marangi reinit_completion(&mgmt_eth_data->rw_done); 483027152b8SChristian Marangi 484027152b8SChristian Marangi /* Increment seq_num and set it in the copy pkt */ 485027152b8SChristian Marangi mgmt_eth_data->seq++; 486027152b8SChristian Marangi qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); 487027152b8SChristian Marangi mgmt_eth_data->ack = false; 488027152b8SChristian Marangi 489027152b8SChristian Marangi dev_queue_xmit(skb); 490027152b8SChristian Marangi 491027152b8SChristian Marangi ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, 492027152b8SChristian Marangi QCA8K_ETHERNET_TIMEOUT); 493027152b8SChristian Marangi 494027152b8SChristian Marangi ack = mgmt_eth_data->ack; 495027152b8SChristian Marangi 496027152b8SChristian Marangi if (ret <= 0) 497027152b8SChristian Marangi return -ETIMEDOUT; 498027152b8SChristian Marangi 499027152b8SChristian Marangi if (!ack) 500027152b8SChristian Marangi return -EINVAL; 501027152b8SChristian Marangi 502027152b8SChristian Marangi *val = mgmt_eth_data->data[0]; 503027152b8SChristian Marangi 504027152b8SChristian Marangi return 0; 505027152b8SChristian Marangi } 506027152b8SChristian Marangi 507027152b8SChristian Marangi static int 508027152b8SChristian Marangi qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, 509027152b8SChristian Marangi int regnum, u16 data) 510027152b8SChristian Marangi { 511027152b8SChristian Marangi struct sk_buff *write_skb, *clear_skb, *read_skb; 512027152b8SChristian Marangi struct qca8k_mgmt_eth_data *mgmt_eth_data; 513027152b8SChristian Marangi u32 write_val, clear_val = 0, val; 514027152b8SChristian Marangi struct net_device *mgmt_master; 515027152b8SChristian Marangi int ret, ret1; 516027152b8SChristian Marangi bool ack; 517027152b8SChristian Marangi 518027152b8SChristian Marangi if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) 519027152b8SChristian Marangi return -EINVAL; 520027152b8SChristian Marangi 521027152b8SChristian Marangi mgmt_eth_data = &priv->mgmt_eth_data; 522027152b8SChristian Marangi 523027152b8SChristian Marangi write_val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | 524027152b8SChristian Marangi QCA8K_MDIO_MASTER_PHY_ADDR(phy) | 525027152b8SChristian Marangi QCA8K_MDIO_MASTER_REG_ADDR(regnum); 526027152b8SChristian Marangi 527027152b8SChristian Marangi if (read) { 528027152b8SChristian Marangi write_val |= QCA8K_MDIO_MASTER_READ; 529027152b8SChristian Marangi } else { 530027152b8SChristian Marangi write_val |= QCA8K_MDIO_MASTER_WRITE; 531027152b8SChristian Marangi write_val |= QCA8K_MDIO_MASTER_DATA(data); 532027152b8SChristian Marangi } 533027152b8SChristian Marangi 534027152b8SChristian Marangi /* Prealloc all the needed skb before the lock */ 535027152b8SChristian Marangi write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val, 536027152b8SChristian Marangi QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val)); 537027152b8SChristian Marangi if (!write_skb) 538027152b8SChristian Marangi return -ENOMEM; 539027152b8SChristian Marangi 540027152b8SChristian Marangi clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val, 541027152b8SChristian Marangi QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); 542027152b8SChristian Marangi if (!clear_skb) { 543027152b8SChristian Marangi ret = -ENOMEM; 544027152b8SChristian Marangi goto err_clear_skb; 545027152b8SChristian Marangi } 546027152b8SChristian Marangi 547027152b8SChristian Marangi read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val, 548027152b8SChristian Marangi QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); 549027152b8SChristian Marangi if (!read_skb) { 550027152b8SChristian Marangi ret = -ENOMEM; 551027152b8SChristian Marangi goto err_read_skb; 552027152b8SChristian Marangi } 553027152b8SChristian Marangi 554027152b8SChristian Marangi /* Actually start the request: 555027152b8SChristian Marangi * 1. Send mdio master packet 556027152b8SChristian Marangi * 2. Busy Wait for mdio master command 557027152b8SChristian Marangi * 3. Get the data if we are reading 558027152b8SChristian Marangi * 4. Reset the mdio master (even with error) 559027152b8SChristian Marangi */ 560027152b8SChristian Marangi mutex_lock(&mgmt_eth_data->mutex); 561027152b8SChristian Marangi 562027152b8SChristian Marangi /* Check if mgmt_master is operational */ 563027152b8SChristian Marangi mgmt_master = priv->mgmt_master; 564027152b8SChristian Marangi if (!mgmt_master) { 565027152b8SChristian Marangi mutex_unlock(&mgmt_eth_data->mutex); 566027152b8SChristian Marangi ret = -EINVAL; 567027152b8SChristian Marangi goto err_mgmt_master; 568027152b8SChristian Marangi } 569027152b8SChristian Marangi 570027152b8SChristian Marangi read_skb->dev = mgmt_master; 571027152b8SChristian Marangi clear_skb->dev = mgmt_master; 572027152b8SChristian Marangi write_skb->dev = mgmt_master; 573027152b8SChristian Marangi 574027152b8SChristian Marangi reinit_completion(&mgmt_eth_data->rw_done); 575027152b8SChristian Marangi 576027152b8SChristian Marangi /* Increment seq_num and set it in the write pkt */ 577027152b8SChristian Marangi mgmt_eth_data->seq++; 578027152b8SChristian Marangi qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq); 579027152b8SChristian Marangi mgmt_eth_data->ack = false; 580027152b8SChristian Marangi 581027152b8SChristian Marangi dev_queue_xmit(write_skb); 582027152b8SChristian Marangi 583027152b8SChristian Marangi ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, 584027152b8SChristian Marangi QCA8K_ETHERNET_TIMEOUT); 585027152b8SChristian Marangi 586027152b8SChristian Marangi ack = mgmt_eth_data->ack; 587027152b8SChristian Marangi 588027152b8SChristian Marangi if (ret <= 0) { 589027152b8SChristian Marangi ret = -ETIMEDOUT; 590027152b8SChristian Marangi kfree_skb(read_skb); 591027152b8SChristian Marangi goto exit; 592027152b8SChristian Marangi } 593027152b8SChristian Marangi 594027152b8SChristian Marangi if (!ack) { 595027152b8SChristian Marangi ret = -EINVAL; 596027152b8SChristian Marangi kfree_skb(read_skb); 597027152b8SChristian Marangi goto exit; 598027152b8SChristian Marangi } 599027152b8SChristian Marangi 600027152b8SChristian Marangi ret = read_poll_timeout(qca8k_phy_eth_busy_wait, ret1, 601027152b8SChristian Marangi !(val & QCA8K_MDIO_MASTER_BUSY), 0, 602027152b8SChristian Marangi QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, 603027152b8SChristian Marangi mgmt_eth_data, read_skb, &val); 604027152b8SChristian Marangi 605027152b8SChristian Marangi if (ret < 0 && ret1 < 0) { 606027152b8SChristian Marangi ret = ret1; 607027152b8SChristian Marangi goto exit; 608027152b8SChristian Marangi } 609027152b8SChristian Marangi 610027152b8SChristian Marangi if (read) { 611027152b8SChristian Marangi reinit_completion(&mgmt_eth_data->rw_done); 612027152b8SChristian Marangi 613027152b8SChristian Marangi /* Increment seq_num and set it in the read pkt */ 614027152b8SChristian Marangi mgmt_eth_data->seq++; 615027152b8SChristian Marangi qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq); 616027152b8SChristian Marangi mgmt_eth_data->ack = false; 617027152b8SChristian Marangi 618027152b8SChristian Marangi dev_queue_xmit(read_skb); 619027152b8SChristian Marangi 620027152b8SChristian Marangi ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, 621027152b8SChristian Marangi QCA8K_ETHERNET_TIMEOUT); 622027152b8SChristian Marangi 623027152b8SChristian Marangi ack = mgmt_eth_data->ack; 624027152b8SChristian Marangi 625027152b8SChristian Marangi if (ret <= 0) { 626027152b8SChristian Marangi ret = -ETIMEDOUT; 627027152b8SChristian Marangi goto exit; 628027152b8SChristian Marangi } 629027152b8SChristian Marangi 630027152b8SChristian Marangi if (!ack) { 631027152b8SChristian Marangi ret = -EINVAL; 632027152b8SChristian Marangi goto exit; 633027152b8SChristian Marangi } 634027152b8SChristian Marangi 635027152b8SChristian Marangi ret = mgmt_eth_data->data[0] & QCA8K_MDIO_MASTER_DATA_MASK; 636027152b8SChristian Marangi } else { 637027152b8SChristian Marangi kfree_skb(read_skb); 638027152b8SChristian Marangi } 639027152b8SChristian Marangi exit: 640027152b8SChristian Marangi reinit_completion(&mgmt_eth_data->rw_done); 641027152b8SChristian Marangi 642027152b8SChristian Marangi /* Increment seq_num and set it in the clear pkt */ 643027152b8SChristian Marangi mgmt_eth_data->seq++; 644027152b8SChristian Marangi qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq); 645027152b8SChristian Marangi mgmt_eth_data->ack = false; 646027152b8SChristian Marangi 647027152b8SChristian Marangi dev_queue_xmit(clear_skb); 648027152b8SChristian Marangi 649027152b8SChristian Marangi wait_for_completion_timeout(&mgmt_eth_data->rw_done, 650027152b8SChristian Marangi QCA8K_ETHERNET_TIMEOUT); 651027152b8SChristian Marangi 652027152b8SChristian Marangi mutex_unlock(&mgmt_eth_data->mutex); 653027152b8SChristian Marangi 654027152b8SChristian Marangi return ret; 655027152b8SChristian Marangi 656027152b8SChristian Marangi /* Error handling before lock */ 657027152b8SChristian Marangi err_mgmt_master: 658027152b8SChristian Marangi kfree_skb(read_skb); 659027152b8SChristian Marangi err_read_skb: 660027152b8SChristian Marangi kfree_skb(clear_skb); 661027152b8SChristian Marangi err_clear_skb: 662027152b8SChristian Marangi kfree_skb(write_skb); 663027152b8SChristian Marangi 664027152b8SChristian Marangi return ret; 665027152b8SChristian Marangi } 666027152b8SChristian Marangi 667027152b8SChristian Marangi static u32 668027152b8SChristian Marangi qca8k_port_to_phy(int port) 669027152b8SChristian Marangi { 670027152b8SChristian Marangi /* From Andrew Lunn: 671027152b8SChristian Marangi * Port 0 has no internal phy. 672027152b8SChristian Marangi * Port 1 has an internal PHY at MDIO address 0. 673027152b8SChristian Marangi * Port 2 has an internal PHY at MDIO address 1. 674027152b8SChristian Marangi * ... 675027152b8SChristian Marangi * Port 5 has an internal PHY at MDIO address 4. 676027152b8SChristian Marangi * Port 6 has no internal PHY. 677027152b8SChristian Marangi */ 678027152b8SChristian Marangi 679027152b8SChristian Marangi return port - 1; 680027152b8SChristian Marangi } 681027152b8SChristian Marangi 682027152b8SChristian Marangi static int 683027152b8SChristian Marangi qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask) 684027152b8SChristian Marangi { 685027152b8SChristian Marangi u16 r1, r2, page; 686027152b8SChristian Marangi u32 val; 687027152b8SChristian Marangi int ret, ret1; 688027152b8SChristian Marangi 689027152b8SChristian Marangi qca8k_split_addr(reg, &r1, &r2, &page); 690027152b8SChristian Marangi 691027152b8SChristian Marangi ret = read_poll_timeout(qca8k_mii_read32, ret1, !(val & mask), 0, 692027152b8SChristian Marangi QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, 693027152b8SChristian Marangi bus, 0x10 | r2, r1, &val); 694027152b8SChristian Marangi 695027152b8SChristian Marangi /* Check if qca8k_read has failed for a different reason 696027152b8SChristian Marangi * before returnting -ETIMEDOUT 697027152b8SChristian Marangi */ 698027152b8SChristian Marangi if (ret < 0 && ret1 < 0) 699027152b8SChristian Marangi return ret1; 700027152b8SChristian Marangi 701027152b8SChristian Marangi return ret; 702027152b8SChristian Marangi } 703027152b8SChristian Marangi 704027152b8SChristian Marangi static int 705027152b8SChristian Marangi qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data) 706027152b8SChristian Marangi { 707027152b8SChristian Marangi struct mii_bus *bus = priv->bus; 708027152b8SChristian Marangi u16 r1, r2, page; 709027152b8SChristian Marangi u32 val; 710027152b8SChristian Marangi int ret; 711027152b8SChristian Marangi 712027152b8SChristian Marangi if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) 713027152b8SChristian Marangi return -EINVAL; 714027152b8SChristian Marangi 715027152b8SChristian Marangi val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | 716027152b8SChristian Marangi QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | 717027152b8SChristian Marangi QCA8K_MDIO_MASTER_REG_ADDR(regnum) | 718027152b8SChristian Marangi QCA8K_MDIO_MASTER_DATA(data); 719027152b8SChristian Marangi 720027152b8SChristian Marangi qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); 721027152b8SChristian Marangi 722027152b8SChristian Marangi mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); 723027152b8SChristian Marangi 724027152b8SChristian Marangi ret = qca8k_set_page(priv, page); 725027152b8SChristian Marangi if (ret) 726027152b8SChristian Marangi goto exit; 727027152b8SChristian Marangi 728027152b8SChristian Marangi qca8k_mii_write32(priv, 0x10 | r2, r1, val); 729027152b8SChristian Marangi 730027152b8SChristian Marangi ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, 731027152b8SChristian Marangi QCA8K_MDIO_MASTER_BUSY); 732027152b8SChristian Marangi 733027152b8SChristian Marangi exit: 734027152b8SChristian Marangi /* even if the busy_wait timeouts try to clear the MASTER_EN */ 735027152b8SChristian Marangi qca8k_mii_write32(priv, 0x10 | r2, r1, 0); 736027152b8SChristian Marangi 737027152b8SChristian Marangi mutex_unlock(&bus->mdio_lock); 738027152b8SChristian Marangi 739027152b8SChristian Marangi return ret; 740027152b8SChristian Marangi } 741027152b8SChristian Marangi 742027152b8SChristian Marangi static int 743027152b8SChristian Marangi qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum) 744027152b8SChristian Marangi { 745027152b8SChristian Marangi struct mii_bus *bus = priv->bus; 746027152b8SChristian Marangi u16 r1, r2, page; 747027152b8SChristian Marangi u32 val; 748027152b8SChristian Marangi int ret; 749027152b8SChristian Marangi 750027152b8SChristian Marangi if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) 751027152b8SChristian Marangi return -EINVAL; 752027152b8SChristian Marangi 753027152b8SChristian Marangi val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | 754027152b8SChristian Marangi QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | 755027152b8SChristian Marangi QCA8K_MDIO_MASTER_REG_ADDR(regnum); 756027152b8SChristian Marangi 757027152b8SChristian Marangi qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); 758027152b8SChristian Marangi 759027152b8SChristian Marangi mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); 760027152b8SChristian Marangi 761027152b8SChristian Marangi ret = qca8k_set_page(priv, page); 762027152b8SChristian Marangi if (ret) 763027152b8SChristian Marangi goto exit; 764027152b8SChristian Marangi 765027152b8SChristian Marangi qca8k_mii_write32(priv, 0x10 | r2, r1, val); 766027152b8SChristian Marangi 767027152b8SChristian Marangi ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, 768027152b8SChristian Marangi QCA8K_MDIO_MASTER_BUSY); 769027152b8SChristian Marangi if (ret) 770027152b8SChristian Marangi goto exit; 771027152b8SChristian Marangi 772027152b8SChristian Marangi ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); 773027152b8SChristian Marangi 774027152b8SChristian Marangi exit: 775027152b8SChristian Marangi /* even if the busy_wait timeouts try to clear the MASTER_EN */ 776027152b8SChristian Marangi qca8k_mii_write32(priv, 0x10 | r2, r1, 0); 777027152b8SChristian Marangi 778027152b8SChristian Marangi mutex_unlock(&bus->mdio_lock); 779027152b8SChristian Marangi 780027152b8SChristian Marangi if (ret >= 0) 781027152b8SChristian Marangi ret = val & QCA8K_MDIO_MASTER_DATA_MASK; 782027152b8SChristian Marangi 783027152b8SChristian Marangi return ret; 784027152b8SChristian Marangi } 785027152b8SChristian Marangi 786027152b8SChristian Marangi static int 787027152b8SChristian Marangi qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data) 788027152b8SChristian Marangi { 789027152b8SChristian Marangi struct qca8k_priv *priv = slave_bus->priv; 790027152b8SChristian Marangi int ret; 791027152b8SChristian Marangi 792027152b8SChristian Marangi /* Use mdio Ethernet when available, fallback to legacy one on error */ 793027152b8SChristian Marangi ret = qca8k_phy_eth_command(priv, false, phy, regnum, data); 794027152b8SChristian Marangi if (!ret) 795027152b8SChristian Marangi return 0; 796027152b8SChristian Marangi 797027152b8SChristian Marangi return qca8k_mdio_write(priv, phy, regnum, data); 798027152b8SChristian Marangi } 799027152b8SChristian Marangi 800027152b8SChristian Marangi static int 801027152b8SChristian Marangi qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum) 802027152b8SChristian Marangi { 803027152b8SChristian Marangi struct qca8k_priv *priv = slave_bus->priv; 804027152b8SChristian Marangi int ret; 805027152b8SChristian Marangi 806027152b8SChristian Marangi /* Use mdio Ethernet when available, fallback to legacy one on error */ 807027152b8SChristian Marangi ret = qca8k_phy_eth_command(priv, true, phy, regnum, 0); 808027152b8SChristian Marangi if (ret >= 0) 809027152b8SChristian Marangi return ret; 810027152b8SChristian Marangi 811027152b8SChristian Marangi ret = qca8k_mdio_read(priv, phy, regnum); 812027152b8SChristian Marangi 813027152b8SChristian Marangi if (ret < 0) 814027152b8SChristian Marangi return 0xffff; 815027152b8SChristian Marangi 816027152b8SChristian Marangi return ret; 817027152b8SChristian Marangi } 818027152b8SChristian Marangi 819027152b8SChristian Marangi static int 820027152b8SChristian Marangi qca8k_legacy_mdio_write(struct mii_bus *slave_bus, int port, int regnum, u16 data) 821027152b8SChristian Marangi { 822027152b8SChristian Marangi port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; 823027152b8SChristian Marangi 824027152b8SChristian Marangi return qca8k_internal_mdio_write(slave_bus, port, regnum, data); 825027152b8SChristian Marangi } 826027152b8SChristian Marangi 827027152b8SChristian Marangi static int 828027152b8SChristian Marangi qca8k_legacy_mdio_read(struct mii_bus *slave_bus, int port, int regnum) 829027152b8SChristian Marangi { 830027152b8SChristian Marangi port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; 831027152b8SChristian Marangi 832027152b8SChristian Marangi return qca8k_internal_mdio_read(slave_bus, port, regnum); 833027152b8SChristian Marangi } 834027152b8SChristian Marangi 835027152b8SChristian Marangi static int 836027152b8SChristian Marangi qca8k_mdio_register(struct qca8k_priv *priv) 837027152b8SChristian Marangi { 838027152b8SChristian Marangi struct dsa_switch *ds = priv->ds; 839027152b8SChristian Marangi struct device_node *mdio; 840027152b8SChristian Marangi struct mii_bus *bus; 841027152b8SChristian Marangi 842027152b8SChristian Marangi bus = devm_mdiobus_alloc(ds->dev); 843027152b8SChristian Marangi if (!bus) 844027152b8SChristian Marangi return -ENOMEM; 845027152b8SChristian Marangi 846027152b8SChristian Marangi bus->priv = (void *)priv; 847027152b8SChristian Marangi snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", 848027152b8SChristian Marangi ds->dst->index, ds->index); 849027152b8SChristian Marangi bus->parent = ds->dev; 850027152b8SChristian Marangi bus->phy_mask = ~ds->phys_mii_mask; 851027152b8SChristian Marangi ds->slave_mii_bus = bus; 852027152b8SChristian Marangi 853027152b8SChristian Marangi /* Check if the devicetree declare the port:phy mapping */ 854027152b8SChristian Marangi mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); 855027152b8SChristian Marangi if (of_device_is_available(mdio)) { 856027152b8SChristian Marangi bus->name = "qca8k slave mii"; 857027152b8SChristian Marangi bus->read = qca8k_internal_mdio_read; 858027152b8SChristian Marangi bus->write = qca8k_internal_mdio_write; 859027152b8SChristian Marangi return devm_of_mdiobus_register(priv->dev, bus, mdio); 860027152b8SChristian Marangi } 861027152b8SChristian Marangi 862027152b8SChristian Marangi /* If a mapping can't be found the legacy mapping is used, 863027152b8SChristian Marangi * using the qca8k_port_to_phy function 864027152b8SChristian Marangi */ 865027152b8SChristian Marangi bus->name = "qca8k-legacy slave mii"; 866027152b8SChristian Marangi bus->read = qca8k_legacy_mdio_read; 867027152b8SChristian Marangi bus->write = qca8k_legacy_mdio_write; 868027152b8SChristian Marangi return devm_mdiobus_register(priv->dev, bus); 869027152b8SChristian Marangi } 870027152b8SChristian Marangi 871027152b8SChristian Marangi static int 872027152b8SChristian Marangi qca8k_setup_mdio_bus(struct qca8k_priv *priv) 873027152b8SChristian Marangi { 874027152b8SChristian Marangi u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; 875027152b8SChristian Marangi struct device_node *ports, *port; 876027152b8SChristian Marangi phy_interface_t mode; 877027152b8SChristian Marangi int err; 878027152b8SChristian Marangi 879027152b8SChristian Marangi ports = of_get_child_by_name(priv->dev->of_node, "ports"); 880027152b8SChristian Marangi if (!ports) 881027152b8SChristian Marangi ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports"); 882027152b8SChristian Marangi 883027152b8SChristian Marangi if (!ports) 884027152b8SChristian Marangi return -EINVAL; 885027152b8SChristian Marangi 886027152b8SChristian Marangi for_each_available_child_of_node(ports, port) { 887027152b8SChristian Marangi err = of_property_read_u32(port, "reg", ®); 888027152b8SChristian Marangi if (err) { 889027152b8SChristian Marangi of_node_put(port); 890027152b8SChristian Marangi of_node_put(ports); 891027152b8SChristian Marangi return err; 892027152b8SChristian Marangi } 893027152b8SChristian Marangi 894027152b8SChristian Marangi if (!dsa_is_user_port(priv->ds, reg)) 895027152b8SChristian Marangi continue; 896027152b8SChristian Marangi 897027152b8SChristian Marangi of_get_phy_mode(port, &mode); 898027152b8SChristian Marangi 899027152b8SChristian Marangi if (of_property_read_bool(port, "phy-handle") && 900027152b8SChristian Marangi mode != PHY_INTERFACE_MODE_INTERNAL) 901027152b8SChristian Marangi external_mdio_mask |= BIT(reg); 902027152b8SChristian Marangi else 903027152b8SChristian Marangi internal_mdio_mask |= BIT(reg); 904027152b8SChristian Marangi } 905027152b8SChristian Marangi 906027152b8SChristian Marangi of_node_put(ports); 907027152b8SChristian Marangi if (!external_mdio_mask && !internal_mdio_mask) { 908027152b8SChristian Marangi dev_err(priv->dev, "no PHYs are defined.\n"); 909027152b8SChristian Marangi return -EINVAL; 910027152b8SChristian Marangi } 911027152b8SChristian Marangi 912027152b8SChristian Marangi /* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through 913027152b8SChristian Marangi * the MDIO_MASTER register also _disconnects_ the external MDC 914027152b8SChristian Marangi * passthrough to the internal PHYs. It's not possible to use both 915027152b8SChristian Marangi * configurations at the same time! 916027152b8SChristian Marangi * 917027152b8SChristian Marangi * Because this came up during the review process: 918027152b8SChristian Marangi * If the external mdio-bus driver is capable magically disabling 919027152b8SChristian Marangi * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's 920027152b8SChristian Marangi * accessors for the time being, it would be possible to pull this 921027152b8SChristian Marangi * off. 922027152b8SChristian Marangi */ 923027152b8SChristian Marangi if (!!external_mdio_mask && !!internal_mdio_mask) { 924027152b8SChristian Marangi dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); 925027152b8SChristian Marangi return -EINVAL; 926027152b8SChristian Marangi } 927027152b8SChristian Marangi 928027152b8SChristian Marangi if (external_mdio_mask) { 929027152b8SChristian Marangi /* Make sure to disable the internal mdio bus in cases 930027152b8SChristian Marangi * a dt-overlay and driver reload changed the configuration 931027152b8SChristian Marangi */ 932027152b8SChristian Marangi 933027152b8SChristian Marangi return regmap_clear_bits(priv->regmap, QCA8K_MDIO_MASTER_CTRL, 934027152b8SChristian Marangi QCA8K_MDIO_MASTER_EN); 935027152b8SChristian Marangi } 936027152b8SChristian Marangi 937027152b8SChristian Marangi return qca8k_mdio_register(priv); 938027152b8SChristian Marangi } 939027152b8SChristian Marangi 940027152b8SChristian Marangi static int 941027152b8SChristian Marangi qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) 942027152b8SChristian Marangi { 943027152b8SChristian Marangi u32 mask = 0; 944027152b8SChristian Marangi int ret = 0; 945027152b8SChristian Marangi 946027152b8SChristian Marangi /* SoC specific settings for ipq8064. 947027152b8SChristian Marangi * If more device require this consider adding 948027152b8SChristian Marangi * a dedicated binding. 949027152b8SChristian Marangi */ 950027152b8SChristian Marangi if (of_machine_is_compatible("qcom,ipq8064")) 951027152b8SChristian Marangi mask |= QCA8K_MAC_PWR_RGMII0_1_8V; 952027152b8SChristian Marangi 953027152b8SChristian Marangi /* SoC specific settings for ipq8065 */ 954027152b8SChristian Marangi if (of_machine_is_compatible("qcom,ipq8065")) 955027152b8SChristian Marangi mask |= QCA8K_MAC_PWR_RGMII1_1_8V; 956027152b8SChristian Marangi 957027152b8SChristian Marangi if (mask) { 958027152b8SChristian Marangi ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, 959027152b8SChristian Marangi QCA8K_MAC_PWR_RGMII0_1_8V | 960027152b8SChristian Marangi QCA8K_MAC_PWR_RGMII1_1_8V, 961027152b8SChristian Marangi mask); 962027152b8SChristian Marangi } 963027152b8SChristian Marangi 964027152b8SChristian Marangi return ret; 965027152b8SChristian Marangi } 966027152b8SChristian Marangi 967027152b8SChristian Marangi static int qca8k_find_cpu_port(struct dsa_switch *ds) 968027152b8SChristian Marangi { 969027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 970027152b8SChristian Marangi 971027152b8SChristian Marangi /* Find the connected cpu port. Valid port are 0 or 6 */ 972027152b8SChristian Marangi if (dsa_is_cpu_port(ds, 0)) 973027152b8SChristian Marangi return 0; 974027152b8SChristian Marangi 975027152b8SChristian Marangi dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); 976027152b8SChristian Marangi 977027152b8SChristian Marangi if (dsa_is_cpu_port(ds, 6)) 978027152b8SChristian Marangi return 6; 979027152b8SChristian Marangi 980027152b8SChristian Marangi return -EINVAL; 981027152b8SChristian Marangi } 982027152b8SChristian Marangi 983027152b8SChristian Marangi static int 984027152b8SChristian Marangi qca8k_setup_of_pws_reg(struct qca8k_priv *priv) 985027152b8SChristian Marangi { 986027152b8SChristian Marangi const struct qca8k_match_data *data = priv->info; 987027152b8SChristian Marangi struct device_node *node = priv->dev->of_node; 988027152b8SChristian Marangi u32 val = 0; 989027152b8SChristian Marangi int ret; 990027152b8SChristian Marangi 991027152b8SChristian Marangi /* QCA8327 require to set to the correct mode. 992027152b8SChristian Marangi * His bigger brother QCA8328 have the 172 pin layout. 993027152b8SChristian Marangi * Should be applied by default but we set this just to make sure. 994027152b8SChristian Marangi */ 995027152b8SChristian Marangi if (priv->switch_id == QCA8K_ID_QCA8327) { 996027152b8SChristian Marangi /* Set the correct package of 148 pin for QCA8327 */ 997027152b8SChristian Marangi if (data->reduced_package) 998027152b8SChristian Marangi val |= QCA8327_PWS_PACKAGE148_EN; 999027152b8SChristian Marangi 1000027152b8SChristian Marangi ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, 1001027152b8SChristian Marangi val); 1002027152b8SChristian Marangi if (ret) 1003027152b8SChristian Marangi return ret; 1004027152b8SChristian Marangi } 1005027152b8SChristian Marangi 1006027152b8SChristian Marangi if (of_property_read_bool(node, "qca,ignore-power-on-sel")) 1007027152b8SChristian Marangi val |= QCA8K_PWS_POWER_ON_SEL; 1008027152b8SChristian Marangi 1009027152b8SChristian Marangi if (of_property_read_bool(node, "qca,led-open-drain")) { 1010027152b8SChristian Marangi if (!(val & QCA8K_PWS_POWER_ON_SEL)) { 1011027152b8SChristian Marangi dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); 1012027152b8SChristian Marangi return -EINVAL; 1013027152b8SChristian Marangi } 1014027152b8SChristian Marangi 1015027152b8SChristian Marangi val |= QCA8K_PWS_LED_OPEN_EN_CSR; 1016027152b8SChristian Marangi } 1017027152b8SChristian Marangi 1018027152b8SChristian Marangi return qca8k_rmw(priv, QCA8K_REG_PWS, 1019027152b8SChristian Marangi QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, 1020027152b8SChristian Marangi val); 1021027152b8SChristian Marangi } 1022027152b8SChristian Marangi 1023027152b8SChristian Marangi static int 1024027152b8SChristian Marangi qca8k_parse_port_config(struct qca8k_priv *priv) 1025027152b8SChristian Marangi { 1026027152b8SChristian Marangi int port, cpu_port_index = -1, ret; 1027027152b8SChristian Marangi struct device_node *port_dn; 1028027152b8SChristian Marangi phy_interface_t mode; 1029027152b8SChristian Marangi struct dsa_port *dp; 1030027152b8SChristian Marangi u32 delay; 1031027152b8SChristian Marangi 1032027152b8SChristian Marangi /* We have 2 CPU port. Check them */ 1033027152b8SChristian Marangi for (port = 0; port < QCA8K_NUM_PORTS; port++) { 1034027152b8SChristian Marangi /* Skip every other port */ 1035027152b8SChristian Marangi if (port != 0 && port != 6) 1036027152b8SChristian Marangi continue; 1037027152b8SChristian Marangi 1038027152b8SChristian Marangi dp = dsa_to_port(priv->ds, port); 1039027152b8SChristian Marangi port_dn = dp->dn; 1040027152b8SChristian Marangi cpu_port_index++; 1041027152b8SChristian Marangi 1042027152b8SChristian Marangi if (!of_device_is_available(port_dn)) 1043027152b8SChristian Marangi continue; 1044027152b8SChristian Marangi 1045027152b8SChristian Marangi ret = of_get_phy_mode(port_dn, &mode); 1046027152b8SChristian Marangi if (ret) 1047027152b8SChristian Marangi continue; 1048027152b8SChristian Marangi 1049027152b8SChristian Marangi switch (mode) { 1050027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII: 1051027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII_ID: 1052027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII_TXID: 1053027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII_RXID: 1054027152b8SChristian Marangi case PHY_INTERFACE_MODE_SGMII: 1055027152b8SChristian Marangi delay = 0; 1056027152b8SChristian Marangi 1057027152b8SChristian Marangi if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) 1058027152b8SChristian Marangi /* Switch regs accept value in ns, convert ps to ns */ 1059027152b8SChristian Marangi delay = delay / 1000; 1060027152b8SChristian Marangi else if (mode == PHY_INTERFACE_MODE_RGMII_ID || 1061027152b8SChristian Marangi mode == PHY_INTERFACE_MODE_RGMII_TXID) 1062027152b8SChristian Marangi delay = 1; 1063027152b8SChristian Marangi 1064027152b8SChristian Marangi if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) { 1065027152b8SChristian Marangi dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); 1066027152b8SChristian Marangi delay = 3; 1067027152b8SChristian Marangi } 1068027152b8SChristian Marangi 1069027152b8SChristian Marangi priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; 1070027152b8SChristian Marangi 1071027152b8SChristian Marangi delay = 0; 1072027152b8SChristian Marangi 1073027152b8SChristian Marangi if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) 1074027152b8SChristian Marangi /* Switch regs accept value in ns, convert ps to ns */ 1075027152b8SChristian Marangi delay = delay / 1000; 1076027152b8SChristian Marangi else if (mode == PHY_INTERFACE_MODE_RGMII_ID || 1077027152b8SChristian Marangi mode == PHY_INTERFACE_MODE_RGMII_RXID) 1078027152b8SChristian Marangi delay = 2; 1079027152b8SChristian Marangi 1080027152b8SChristian Marangi if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) { 1081027152b8SChristian Marangi dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); 1082027152b8SChristian Marangi delay = 3; 1083027152b8SChristian Marangi } 1084027152b8SChristian Marangi 1085027152b8SChristian Marangi priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; 1086027152b8SChristian Marangi 1087027152b8SChristian Marangi /* Skip sgmii parsing for rgmii* mode */ 1088027152b8SChristian Marangi if (mode == PHY_INTERFACE_MODE_RGMII || 1089027152b8SChristian Marangi mode == PHY_INTERFACE_MODE_RGMII_ID || 1090027152b8SChristian Marangi mode == PHY_INTERFACE_MODE_RGMII_TXID || 1091027152b8SChristian Marangi mode == PHY_INTERFACE_MODE_RGMII_RXID) 1092027152b8SChristian Marangi break; 1093027152b8SChristian Marangi 1094027152b8SChristian Marangi if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) 1095027152b8SChristian Marangi priv->ports_config.sgmii_tx_clk_falling_edge = true; 1096027152b8SChristian Marangi 1097027152b8SChristian Marangi if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) 1098027152b8SChristian Marangi priv->ports_config.sgmii_rx_clk_falling_edge = true; 1099027152b8SChristian Marangi 1100027152b8SChristian Marangi if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { 1101027152b8SChristian Marangi priv->ports_config.sgmii_enable_pll = true; 1102027152b8SChristian Marangi 1103027152b8SChristian Marangi if (priv->switch_id == QCA8K_ID_QCA8327) { 1104027152b8SChristian Marangi dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); 1105027152b8SChristian Marangi priv->ports_config.sgmii_enable_pll = false; 1106027152b8SChristian Marangi } 1107027152b8SChristian Marangi 1108027152b8SChristian Marangi if (priv->switch_revision < 2) 1109027152b8SChristian Marangi dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); 1110027152b8SChristian Marangi } 1111027152b8SChristian Marangi 1112027152b8SChristian Marangi break; 1113027152b8SChristian Marangi default: 1114027152b8SChristian Marangi continue; 1115027152b8SChristian Marangi } 1116027152b8SChristian Marangi } 1117027152b8SChristian Marangi 1118027152b8SChristian Marangi return 0; 1119027152b8SChristian Marangi } 1120027152b8SChristian Marangi 1121027152b8SChristian Marangi static void 1122027152b8SChristian Marangi qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, 1123027152b8SChristian Marangi u32 reg) 1124027152b8SChristian Marangi { 1125027152b8SChristian Marangi u32 delay, val = 0; 1126027152b8SChristian Marangi int ret; 1127027152b8SChristian Marangi 1128027152b8SChristian Marangi /* Delay can be declared in 3 different way. 1129027152b8SChristian Marangi * Mode to rgmii and internal-delay standard binding defined 1130027152b8SChristian Marangi * rgmii-id or rgmii-tx/rx phy mode set. 1131027152b8SChristian Marangi * The parse logic set a delay different than 0 only when one 1132027152b8SChristian Marangi * of the 3 different way is used. In all other case delay is 1133027152b8SChristian Marangi * not enabled. With ID or TX/RXID delay is enabled and set 1134027152b8SChristian Marangi * to the default and recommended value. 1135027152b8SChristian Marangi */ 1136027152b8SChristian Marangi if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { 1137027152b8SChristian Marangi delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; 1138027152b8SChristian Marangi 1139027152b8SChristian Marangi val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | 1140027152b8SChristian Marangi QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; 1141027152b8SChristian Marangi } 1142027152b8SChristian Marangi 1143027152b8SChristian Marangi if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { 1144027152b8SChristian Marangi delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; 1145027152b8SChristian Marangi 1146027152b8SChristian Marangi val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | 1147027152b8SChristian Marangi QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; 1148027152b8SChristian Marangi } 1149027152b8SChristian Marangi 1150027152b8SChristian Marangi /* Set RGMII delay based on the selected values */ 1151027152b8SChristian Marangi ret = qca8k_rmw(priv, reg, 1152027152b8SChristian Marangi QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | 1153027152b8SChristian Marangi QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | 1154027152b8SChristian Marangi QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | 1155027152b8SChristian Marangi QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, 1156027152b8SChristian Marangi val); 1157027152b8SChristian Marangi if (ret) 1158027152b8SChristian Marangi dev_err(priv->dev, "Failed to set internal delay for CPU port%d", 1159027152b8SChristian Marangi cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); 1160027152b8SChristian Marangi } 1161027152b8SChristian Marangi 1162027152b8SChristian Marangi static struct phylink_pcs * 1163027152b8SChristian Marangi qca8k_phylink_mac_select_pcs(struct dsa_switch *ds, int port, 1164027152b8SChristian Marangi phy_interface_t interface) 1165027152b8SChristian Marangi { 1166027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1167027152b8SChristian Marangi struct phylink_pcs *pcs = NULL; 1168027152b8SChristian Marangi 1169027152b8SChristian Marangi switch (interface) { 1170027152b8SChristian Marangi case PHY_INTERFACE_MODE_SGMII: 1171027152b8SChristian Marangi case PHY_INTERFACE_MODE_1000BASEX: 1172027152b8SChristian Marangi switch (port) { 1173027152b8SChristian Marangi case 0: 1174027152b8SChristian Marangi pcs = &priv->pcs_port_0.pcs; 1175027152b8SChristian Marangi break; 1176027152b8SChristian Marangi 1177027152b8SChristian Marangi case 6: 1178027152b8SChristian Marangi pcs = &priv->pcs_port_6.pcs; 1179027152b8SChristian Marangi break; 1180027152b8SChristian Marangi } 1181027152b8SChristian Marangi break; 1182027152b8SChristian Marangi 1183027152b8SChristian Marangi default: 1184027152b8SChristian Marangi break; 1185027152b8SChristian Marangi } 1186027152b8SChristian Marangi 1187027152b8SChristian Marangi return pcs; 1188027152b8SChristian Marangi } 1189027152b8SChristian Marangi 1190027152b8SChristian Marangi static void 1191027152b8SChristian Marangi qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, 1192027152b8SChristian Marangi const struct phylink_link_state *state) 1193027152b8SChristian Marangi { 1194027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1195027152b8SChristian Marangi int cpu_port_index; 1196027152b8SChristian Marangi u32 reg; 1197027152b8SChristian Marangi 1198027152b8SChristian Marangi switch (port) { 1199027152b8SChristian Marangi case 0: /* 1st CPU port */ 1200027152b8SChristian Marangi if (state->interface != PHY_INTERFACE_MODE_RGMII && 1201027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_RGMII_ID && 1202027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_RGMII_TXID && 1203027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_RGMII_RXID && 1204027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_SGMII) 1205027152b8SChristian Marangi return; 1206027152b8SChristian Marangi 1207027152b8SChristian Marangi reg = QCA8K_REG_PORT0_PAD_CTRL; 1208027152b8SChristian Marangi cpu_port_index = QCA8K_CPU_PORT0; 1209027152b8SChristian Marangi break; 1210027152b8SChristian Marangi case 1: 1211027152b8SChristian Marangi case 2: 1212027152b8SChristian Marangi case 3: 1213027152b8SChristian Marangi case 4: 1214027152b8SChristian Marangi case 5: 1215027152b8SChristian Marangi /* Internal PHY, nothing to do */ 1216027152b8SChristian Marangi return; 1217027152b8SChristian Marangi case 6: /* 2nd CPU port / external PHY */ 1218027152b8SChristian Marangi if (state->interface != PHY_INTERFACE_MODE_RGMII && 1219027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_RGMII_ID && 1220027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_RGMII_TXID && 1221027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_RGMII_RXID && 1222027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_SGMII && 1223027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_1000BASEX) 1224027152b8SChristian Marangi return; 1225027152b8SChristian Marangi 1226027152b8SChristian Marangi reg = QCA8K_REG_PORT6_PAD_CTRL; 1227027152b8SChristian Marangi cpu_port_index = QCA8K_CPU_PORT6; 1228027152b8SChristian Marangi break; 1229027152b8SChristian Marangi default: 1230027152b8SChristian Marangi dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); 1231027152b8SChristian Marangi return; 1232027152b8SChristian Marangi } 1233027152b8SChristian Marangi 1234027152b8SChristian Marangi if (port != 6 && phylink_autoneg_inband(mode)) { 1235027152b8SChristian Marangi dev_err(ds->dev, "%s: in-band negotiation unsupported\n", 1236027152b8SChristian Marangi __func__); 1237027152b8SChristian Marangi return; 1238027152b8SChristian Marangi } 1239027152b8SChristian Marangi 1240027152b8SChristian Marangi switch (state->interface) { 1241027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII: 1242027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII_ID: 1243027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII_TXID: 1244027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII_RXID: 1245027152b8SChristian Marangi qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); 1246027152b8SChristian Marangi 1247027152b8SChristian Marangi /* Configure rgmii delay */ 1248027152b8SChristian Marangi qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); 1249027152b8SChristian Marangi 1250027152b8SChristian Marangi /* QCA8337 requires to set rgmii rx delay for all ports. 1251027152b8SChristian Marangi * This is enabled through PORT5_PAD_CTRL for all ports, 1252027152b8SChristian Marangi * rather than individual port registers. 1253027152b8SChristian Marangi */ 1254027152b8SChristian Marangi if (priv->switch_id == QCA8K_ID_QCA8337) 1255027152b8SChristian Marangi qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, 1256027152b8SChristian Marangi QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); 1257027152b8SChristian Marangi break; 1258027152b8SChristian Marangi case PHY_INTERFACE_MODE_SGMII: 1259027152b8SChristian Marangi case PHY_INTERFACE_MODE_1000BASEX: 1260027152b8SChristian Marangi /* Enable SGMII on the port */ 1261027152b8SChristian Marangi qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); 1262027152b8SChristian Marangi break; 1263027152b8SChristian Marangi default: 1264027152b8SChristian Marangi dev_err(ds->dev, "xMII mode %s not supported for port %d\n", 1265027152b8SChristian Marangi phy_modes(state->interface), port); 1266027152b8SChristian Marangi return; 1267027152b8SChristian Marangi } 1268027152b8SChristian Marangi } 1269027152b8SChristian Marangi 1270027152b8SChristian Marangi static void qca8k_phylink_get_caps(struct dsa_switch *ds, int port, 1271027152b8SChristian Marangi struct phylink_config *config) 1272027152b8SChristian Marangi { 1273027152b8SChristian Marangi switch (port) { 1274027152b8SChristian Marangi case 0: /* 1st CPU port */ 1275027152b8SChristian Marangi phy_interface_set_rgmii(config->supported_interfaces); 1276027152b8SChristian Marangi __set_bit(PHY_INTERFACE_MODE_SGMII, 1277027152b8SChristian Marangi config->supported_interfaces); 1278027152b8SChristian Marangi break; 1279027152b8SChristian Marangi 1280027152b8SChristian Marangi case 1: 1281027152b8SChristian Marangi case 2: 1282027152b8SChristian Marangi case 3: 1283027152b8SChristian Marangi case 4: 1284027152b8SChristian Marangi case 5: 1285027152b8SChristian Marangi /* Internal PHY */ 1286027152b8SChristian Marangi __set_bit(PHY_INTERFACE_MODE_GMII, 1287027152b8SChristian Marangi config->supported_interfaces); 1288027152b8SChristian Marangi __set_bit(PHY_INTERFACE_MODE_INTERNAL, 1289027152b8SChristian Marangi config->supported_interfaces); 1290027152b8SChristian Marangi break; 1291027152b8SChristian Marangi 1292027152b8SChristian Marangi case 6: /* 2nd CPU port / external PHY */ 1293027152b8SChristian Marangi phy_interface_set_rgmii(config->supported_interfaces); 1294027152b8SChristian Marangi __set_bit(PHY_INTERFACE_MODE_SGMII, 1295027152b8SChristian Marangi config->supported_interfaces); 1296027152b8SChristian Marangi __set_bit(PHY_INTERFACE_MODE_1000BASEX, 1297027152b8SChristian Marangi config->supported_interfaces); 1298027152b8SChristian Marangi break; 1299027152b8SChristian Marangi } 1300027152b8SChristian Marangi 1301027152b8SChristian Marangi config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | 1302027152b8SChristian Marangi MAC_10 | MAC_100 | MAC_1000FD; 1303027152b8SChristian Marangi 1304027152b8SChristian Marangi config->legacy_pre_march2020 = false; 1305027152b8SChristian Marangi } 1306027152b8SChristian Marangi 1307027152b8SChristian Marangi static void 1308027152b8SChristian Marangi qca8k_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, 1309027152b8SChristian Marangi phy_interface_t interface) 1310027152b8SChristian Marangi { 1311027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1312027152b8SChristian Marangi 1313027152b8SChristian Marangi qca8k_port_set_status(priv, port, 0); 1314027152b8SChristian Marangi } 1315027152b8SChristian Marangi 1316027152b8SChristian Marangi static void 1317027152b8SChristian Marangi qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, 1318027152b8SChristian Marangi phy_interface_t interface, struct phy_device *phydev, 1319027152b8SChristian Marangi int speed, int duplex, bool tx_pause, bool rx_pause) 1320027152b8SChristian Marangi { 1321027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1322027152b8SChristian Marangi u32 reg; 1323027152b8SChristian Marangi 1324027152b8SChristian Marangi if (phylink_autoneg_inband(mode)) { 1325027152b8SChristian Marangi reg = QCA8K_PORT_STATUS_LINK_AUTO; 1326027152b8SChristian Marangi } else { 1327027152b8SChristian Marangi switch (speed) { 1328027152b8SChristian Marangi case SPEED_10: 1329027152b8SChristian Marangi reg = QCA8K_PORT_STATUS_SPEED_10; 1330027152b8SChristian Marangi break; 1331027152b8SChristian Marangi case SPEED_100: 1332027152b8SChristian Marangi reg = QCA8K_PORT_STATUS_SPEED_100; 1333027152b8SChristian Marangi break; 1334027152b8SChristian Marangi case SPEED_1000: 1335027152b8SChristian Marangi reg = QCA8K_PORT_STATUS_SPEED_1000; 1336027152b8SChristian Marangi break; 1337027152b8SChristian Marangi default: 1338027152b8SChristian Marangi reg = QCA8K_PORT_STATUS_LINK_AUTO; 1339027152b8SChristian Marangi break; 1340027152b8SChristian Marangi } 1341027152b8SChristian Marangi 1342027152b8SChristian Marangi if (duplex == DUPLEX_FULL) 1343027152b8SChristian Marangi reg |= QCA8K_PORT_STATUS_DUPLEX; 1344027152b8SChristian Marangi 1345027152b8SChristian Marangi if (rx_pause || dsa_is_cpu_port(ds, port)) 1346027152b8SChristian Marangi reg |= QCA8K_PORT_STATUS_RXFLOW; 1347027152b8SChristian Marangi 1348027152b8SChristian Marangi if (tx_pause || dsa_is_cpu_port(ds, port)) 1349027152b8SChristian Marangi reg |= QCA8K_PORT_STATUS_TXFLOW; 1350027152b8SChristian Marangi } 1351027152b8SChristian Marangi 1352027152b8SChristian Marangi reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; 1353027152b8SChristian Marangi 1354027152b8SChristian Marangi qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); 1355027152b8SChristian Marangi } 1356027152b8SChristian Marangi 1357027152b8SChristian Marangi static struct qca8k_pcs *pcs_to_qca8k_pcs(struct phylink_pcs *pcs) 1358027152b8SChristian Marangi { 1359027152b8SChristian Marangi return container_of(pcs, struct qca8k_pcs, pcs); 1360027152b8SChristian Marangi } 1361027152b8SChristian Marangi 1362027152b8SChristian Marangi static void qca8k_pcs_get_state(struct phylink_pcs *pcs, 1363027152b8SChristian Marangi struct phylink_link_state *state) 1364027152b8SChristian Marangi { 1365027152b8SChristian Marangi struct qca8k_priv *priv = pcs_to_qca8k_pcs(pcs)->priv; 1366027152b8SChristian Marangi int port = pcs_to_qca8k_pcs(pcs)->port; 1367027152b8SChristian Marangi u32 reg; 1368027152b8SChristian Marangi int ret; 1369027152b8SChristian Marangi 1370027152b8SChristian Marangi ret = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), ®); 1371027152b8SChristian Marangi if (ret < 0) { 1372027152b8SChristian Marangi state->link = false; 1373027152b8SChristian Marangi return; 1374027152b8SChristian Marangi } 1375027152b8SChristian Marangi 1376027152b8SChristian Marangi state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP); 1377027152b8SChristian Marangi state->an_complete = state->link; 1378027152b8SChristian Marangi state->an_enabled = !!(reg & QCA8K_PORT_STATUS_LINK_AUTO); 1379027152b8SChristian Marangi state->duplex = (reg & QCA8K_PORT_STATUS_DUPLEX) ? DUPLEX_FULL : 1380027152b8SChristian Marangi DUPLEX_HALF; 1381027152b8SChristian Marangi 1382027152b8SChristian Marangi switch (reg & QCA8K_PORT_STATUS_SPEED) { 1383027152b8SChristian Marangi case QCA8K_PORT_STATUS_SPEED_10: 1384027152b8SChristian Marangi state->speed = SPEED_10; 1385027152b8SChristian Marangi break; 1386027152b8SChristian Marangi case QCA8K_PORT_STATUS_SPEED_100: 1387027152b8SChristian Marangi state->speed = SPEED_100; 1388027152b8SChristian Marangi break; 1389027152b8SChristian Marangi case QCA8K_PORT_STATUS_SPEED_1000: 1390027152b8SChristian Marangi state->speed = SPEED_1000; 1391027152b8SChristian Marangi break; 1392027152b8SChristian Marangi default: 1393027152b8SChristian Marangi state->speed = SPEED_UNKNOWN; 1394027152b8SChristian Marangi break; 1395027152b8SChristian Marangi } 1396027152b8SChristian Marangi 1397027152b8SChristian Marangi if (reg & QCA8K_PORT_STATUS_RXFLOW) 1398027152b8SChristian Marangi state->pause |= MLO_PAUSE_RX; 1399027152b8SChristian Marangi if (reg & QCA8K_PORT_STATUS_TXFLOW) 1400027152b8SChristian Marangi state->pause |= MLO_PAUSE_TX; 1401027152b8SChristian Marangi } 1402027152b8SChristian Marangi 1403027152b8SChristian Marangi static int qca8k_pcs_config(struct phylink_pcs *pcs, unsigned int mode, 1404027152b8SChristian Marangi phy_interface_t interface, 1405027152b8SChristian Marangi const unsigned long *advertising, 1406027152b8SChristian Marangi bool permit_pause_to_mac) 1407027152b8SChristian Marangi { 1408027152b8SChristian Marangi struct qca8k_priv *priv = pcs_to_qca8k_pcs(pcs)->priv; 1409027152b8SChristian Marangi int cpu_port_index, ret, port; 1410027152b8SChristian Marangi u32 reg, val; 1411027152b8SChristian Marangi 1412027152b8SChristian Marangi port = pcs_to_qca8k_pcs(pcs)->port; 1413027152b8SChristian Marangi switch (port) { 1414027152b8SChristian Marangi case 0: 1415027152b8SChristian Marangi reg = QCA8K_REG_PORT0_PAD_CTRL; 1416027152b8SChristian Marangi cpu_port_index = QCA8K_CPU_PORT0; 1417027152b8SChristian Marangi break; 1418027152b8SChristian Marangi 1419027152b8SChristian Marangi case 6: 1420027152b8SChristian Marangi reg = QCA8K_REG_PORT6_PAD_CTRL; 1421027152b8SChristian Marangi cpu_port_index = QCA8K_CPU_PORT6; 1422027152b8SChristian Marangi break; 1423027152b8SChristian Marangi 1424027152b8SChristian Marangi default: 1425027152b8SChristian Marangi WARN_ON(1); 1426027152b8SChristian Marangi return -EINVAL; 1427027152b8SChristian Marangi } 1428027152b8SChristian Marangi 1429027152b8SChristian Marangi /* Enable/disable SerDes auto-negotiation as necessary */ 1430027152b8SChristian Marangi ret = qca8k_read(priv, QCA8K_REG_PWS, &val); 1431027152b8SChristian Marangi if (ret) 1432027152b8SChristian Marangi return ret; 1433027152b8SChristian Marangi if (phylink_autoneg_inband(mode)) 1434027152b8SChristian Marangi val &= ~QCA8K_PWS_SERDES_AEN_DIS; 1435027152b8SChristian Marangi else 1436027152b8SChristian Marangi val |= QCA8K_PWS_SERDES_AEN_DIS; 1437027152b8SChristian Marangi qca8k_write(priv, QCA8K_REG_PWS, val); 1438027152b8SChristian Marangi 1439027152b8SChristian Marangi /* Configure the SGMII parameters */ 1440027152b8SChristian Marangi ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val); 1441027152b8SChristian Marangi if (ret) 1442027152b8SChristian Marangi return ret; 1443027152b8SChristian Marangi 1444027152b8SChristian Marangi val |= QCA8K_SGMII_EN_SD; 1445027152b8SChristian Marangi 1446027152b8SChristian Marangi if (priv->ports_config.sgmii_enable_pll) 1447027152b8SChristian Marangi val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | 1448027152b8SChristian Marangi QCA8K_SGMII_EN_TX; 1449027152b8SChristian Marangi 1450027152b8SChristian Marangi if (dsa_is_cpu_port(priv->ds, port)) { 1451027152b8SChristian Marangi /* CPU port, we're talking to the CPU MAC, be a PHY */ 1452027152b8SChristian Marangi val &= ~QCA8K_SGMII_MODE_CTRL_MASK; 1453027152b8SChristian Marangi val |= QCA8K_SGMII_MODE_CTRL_PHY; 1454027152b8SChristian Marangi } else if (interface == PHY_INTERFACE_MODE_SGMII) { 1455027152b8SChristian Marangi val &= ~QCA8K_SGMII_MODE_CTRL_MASK; 1456027152b8SChristian Marangi val |= QCA8K_SGMII_MODE_CTRL_MAC; 1457027152b8SChristian Marangi } else if (interface == PHY_INTERFACE_MODE_1000BASEX) { 1458027152b8SChristian Marangi val &= ~QCA8K_SGMII_MODE_CTRL_MASK; 1459027152b8SChristian Marangi val |= QCA8K_SGMII_MODE_CTRL_BASEX; 1460027152b8SChristian Marangi } 1461027152b8SChristian Marangi 1462027152b8SChristian Marangi qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); 1463027152b8SChristian Marangi 1464027152b8SChristian Marangi /* From original code is reported port instability as SGMII also 1465027152b8SChristian Marangi * require delay set. Apply advised values here or take them from DT. 1466027152b8SChristian Marangi */ 1467027152b8SChristian Marangi if (interface == PHY_INTERFACE_MODE_SGMII) 1468027152b8SChristian Marangi qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); 1469027152b8SChristian Marangi /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and 1470027152b8SChristian Marangi * falling edge is set writing in the PORT0 PAD reg 1471027152b8SChristian Marangi */ 1472027152b8SChristian Marangi if (priv->switch_id == QCA8K_ID_QCA8327 || 1473027152b8SChristian Marangi priv->switch_id == QCA8K_ID_QCA8337) 1474027152b8SChristian Marangi reg = QCA8K_REG_PORT0_PAD_CTRL; 1475027152b8SChristian Marangi 1476027152b8SChristian Marangi val = 0; 1477027152b8SChristian Marangi 1478027152b8SChristian Marangi /* SGMII Clock phase configuration */ 1479027152b8SChristian Marangi if (priv->ports_config.sgmii_rx_clk_falling_edge) 1480027152b8SChristian Marangi val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; 1481027152b8SChristian Marangi 1482027152b8SChristian Marangi if (priv->ports_config.sgmii_tx_clk_falling_edge) 1483027152b8SChristian Marangi val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; 1484027152b8SChristian Marangi 1485027152b8SChristian Marangi if (val) 1486027152b8SChristian Marangi ret = qca8k_rmw(priv, reg, 1487027152b8SChristian Marangi QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | 1488027152b8SChristian Marangi QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, 1489027152b8SChristian Marangi val); 1490027152b8SChristian Marangi 1491027152b8SChristian Marangi return 0; 1492027152b8SChristian Marangi } 1493027152b8SChristian Marangi 1494027152b8SChristian Marangi static void qca8k_pcs_an_restart(struct phylink_pcs *pcs) 1495027152b8SChristian Marangi { 1496027152b8SChristian Marangi } 1497027152b8SChristian Marangi 1498027152b8SChristian Marangi static const struct phylink_pcs_ops qca8k_pcs_ops = { 1499027152b8SChristian Marangi .pcs_get_state = qca8k_pcs_get_state, 1500027152b8SChristian Marangi .pcs_config = qca8k_pcs_config, 1501027152b8SChristian Marangi .pcs_an_restart = qca8k_pcs_an_restart, 1502027152b8SChristian Marangi }; 1503027152b8SChristian Marangi 1504027152b8SChristian Marangi static void qca8k_setup_pcs(struct qca8k_priv *priv, struct qca8k_pcs *qpcs, 1505027152b8SChristian Marangi int port) 1506027152b8SChristian Marangi { 1507027152b8SChristian Marangi qpcs->pcs.ops = &qca8k_pcs_ops; 1508027152b8SChristian Marangi 1509027152b8SChristian Marangi /* We don't have interrupts for link changes, so we need to poll */ 1510027152b8SChristian Marangi qpcs->pcs.poll = true; 1511027152b8SChristian Marangi qpcs->priv = priv; 1512027152b8SChristian Marangi qpcs->port = port; 1513027152b8SChristian Marangi } 1514027152b8SChristian Marangi 1515027152b8SChristian Marangi static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) 1516027152b8SChristian Marangi { 1517027152b8SChristian Marangi struct qca8k_mib_eth_data *mib_eth_data; 1518027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1519027152b8SChristian Marangi const struct qca8k_mib_desc *mib; 1520027152b8SChristian Marangi struct mib_ethhdr *mib_ethhdr; 1521*0d4636f7SChristian Marangi __le32 *data2; 1522027152b8SChristian Marangi u8 port; 1523*0d4636f7SChristian Marangi int i; 1524027152b8SChristian Marangi 1525027152b8SChristian Marangi mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); 1526027152b8SChristian Marangi mib_eth_data = &priv->mib_eth_data; 1527027152b8SChristian Marangi 1528027152b8SChristian Marangi /* The switch autocast every port. Ignore other packet and 1529027152b8SChristian Marangi * parse only the requested one. 1530027152b8SChristian Marangi */ 1531027152b8SChristian Marangi port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr)); 1532027152b8SChristian Marangi if (port != mib_eth_data->req_port) 1533027152b8SChristian Marangi goto exit; 1534027152b8SChristian Marangi 1535*0d4636f7SChristian Marangi data2 = (__le32 *)skb->data; 1536027152b8SChristian Marangi 1537027152b8SChristian Marangi for (i = 0; i < priv->info->mib_count; i++) { 1538027152b8SChristian Marangi mib = &ar8327_mib[i]; 1539027152b8SChristian Marangi 1540027152b8SChristian Marangi /* First 3 mib are present in the skb head */ 1541027152b8SChristian Marangi if (i < 3) { 1542*0d4636f7SChristian Marangi mib_eth_data->data[i] = get_unaligned_le32(mib_ethhdr->data + i); 1543027152b8SChristian Marangi continue; 1544027152b8SChristian Marangi } 1545027152b8SChristian Marangi 1546027152b8SChristian Marangi /* Some mib are 64 bit wide */ 1547027152b8SChristian Marangi if (mib->size == 2) 1548*0d4636f7SChristian Marangi mib_eth_data->data[i] = get_unaligned_le64((__le64 *)data2); 1549*0d4636f7SChristian Marangi else 1550*0d4636f7SChristian Marangi mib_eth_data->data[i] = get_unaligned_le32(data2); 1551027152b8SChristian Marangi 1552*0d4636f7SChristian Marangi data2 += mib->size; 1553027152b8SChristian Marangi } 1554027152b8SChristian Marangi 1555027152b8SChristian Marangi exit: 1556027152b8SChristian Marangi /* Complete on receiving all the mib packet */ 1557027152b8SChristian Marangi if (refcount_dec_and_test(&mib_eth_data->port_parsed)) 1558027152b8SChristian Marangi complete(&mib_eth_data->rw_done); 1559027152b8SChristian Marangi } 1560027152b8SChristian Marangi 1561027152b8SChristian Marangi static int 1562027152b8SChristian Marangi qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) 1563027152b8SChristian Marangi { 1564027152b8SChristian Marangi struct dsa_port *dp = dsa_to_port(ds, port); 1565027152b8SChristian Marangi struct qca8k_mib_eth_data *mib_eth_data; 1566027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1567027152b8SChristian Marangi int ret; 1568027152b8SChristian Marangi 1569027152b8SChristian Marangi mib_eth_data = &priv->mib_eth_data; 1570027152b8SChristian Marangi 1571027152b8SChristian Marangi mutex_lock(&mib_eth_data->mutex); 1572027152b8SChristian Marangi 1573027152b8SChristian Marangi reinit_completion(&mib_eth_data->rw_done); 1574027152b8SChristian Marangi 1575027152b8SChristian Marangi mib_eth_data->req_port = dp->index; 1576027152b8SChristian Marangi mib_eth_data->data = data; 1577027152b8SChristian Marangi refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS); 1578027152b8SChristian Marangi 1579027152b8SChristian Marangi mutex_lock(&priv->reg_mutex); 1580027152b8SChristian Marangi 1581027152b8SChristian Marangi /* Send mib autocast request */ 1582027152b8SChristian Marangi ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, 1583027152b8SChristian Marangi QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, 1584027152b8SChristian Marangi FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) | 1585027152b8SChristian Marangi QCA8K_MIB_BUSY); 1586027152b8SChristian Marangi 1587027152b8SChristian Marangi mutex_unlock(&priv->reg_mutex); 1588027152b8SChristian Marangi 1589027152b8SChristian Marangi if (ret) 1590027152b8SChristian Marangi goto exit; 1591027152b8SChristian Marangi 1592027152b8SChristian Marangi ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT); 1593027152b8SChristian Marangi 1594027152b8SChristian Marangi exit: 1595027152b8SChristian Marangi mutex_unlock(&mib_eth_data->mutex); 1596027152b8SChristian Marangi 1597027152b8SChristian Marangi return ret; 1598027152b8SChristian Marangi } 1599027152b8SChristian Marangi 1600027152b8SChristian Marangi static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port) 1601027152b8SChristian Marangi { 1602027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1603027152b8SChristian Marangi 1604027152b8SChristian Marangi /* Communicate to the phy internal driver the switch revision. 1605027152b8SChristian Marangi * Based on the switch revision different values needs to be 1606027152b8SChristian Marangi * set to the dbg and mmd reg on the phy. 1607027152b8SChristian Marangi * The first 2 bit are used to communicate the switch revision 1608027152b8SChristian Marangi * to the phy driver. 1609027152b8SChristian Marangi */ 1610027152b8SChristian Marangi if (port > 0 && port < 6) 1611027152b8SChristian Marangi return priv->switch_revision; 1612027152b8SChristian Marangi 1613027152b8SChristian Marangi return 0; 1614027152b8SChristian Marangi } 1615027152b8SChristian Marangi 1616027152b8SChristian Marangi static enum dsa_tag_protocol 1617027152b8SChristian Marangi qca8k_get_tag_protocol(struct dsa_switch *ds, int port, 1618027152b8SChristian Marangi enum dsa_tag_protocol mp) 1619027152b8SChristian Marangi { 1620027152b8SChristian Marangi return DSA_TAG_PROTO_QCA; 1621027152b8SChristian Marangi } 1622027152b8SChristian Marangi 1623027152b8SChristian Marangi static void 1624027152b8SChristian Marangi qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, 1625027152b8SChristian Marangi bool operational) 1626027152b8SChristian Marangi { 1627027152b8SChristian Marangi struct dsa_port *dp = master->dsa_ptr; 1628027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1629027152b8SChristian Marangi 1630027152b8SChristian Marangi /* Ethernet MIB/MDIO is only supported for CPU port 0 */ 1631027152b8SChristian Marangi if (dp->index != 0) 1632027152b8SChristian Marangi return; 1633027152b8SChristian Marangi 1634027152b8SChristian Marangi mutex_lock(&priv->mgmt_eth_data.mutex); 1635027152b8SChristian Marangi mutex_lock(&priv->mib_eth_data.mutex); 1636027152b8SChristian Marangi 1637027152b8SChristian Marangi priv->mgmt_master = operational ? (struct net_device *)master : NULL; 1638027152b8SChristian Marangi 1639027152b8SChristian Marangi mutex_unlock(&priv->mib_eth_data.mutex); 1640027152b8SChristian Marangi mutex_unlock(&priv->mgmt_eth_data.mutex); 1641027152b8SChristian Marangi } 1642027152b8SChristian Marangi 1643027152b8SChristian Marangi static int qca8k_connect_tag_protocol(struct dsa_switch *ds, 1644027152b8SChristian Marangi enum dsa_tag_protocol proto) 1645027152b8SChristian Marangi { 1646027152b8SChristian Marangi struct qca_tagger_data *tagger_data; 1647027152b8SChristian Marangi 1648027152b8SChristian Marangi switch (proto) { 1649027152b8SChristian Marangi case DSA_TAG_PROTO_QCA: 1650027152b8SChristian Marangi tagger_data = ds->tagger_data; 1651027152b8SChristian Marangi 1652027152b8SChristian Marangi tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; 1653027152b8SChristian Marangi tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler; 1654027152b8SChristian Marangi 1655027152b8SChristian Marangi break; 1656027152b8SChristian Marangi default: 1657027152b8SChristian Marangi return -EOPNOTSUPP; 1658027152b8SChristian Marangi } 1659027152b8SChristian Marangi 1660027152b8SChristian Marangi return 0; 1661027152b8SChristian Marangi } 1662027152b8SChristian Marangi 1663027152b8SChristian Marangi static int 1664027152b8SChristian Marangi qca8k_setup(struct dsa_switch *ds) 1665027152b8SChristian Marangi { 1666027152b8SChristian Marangi struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv; 1667027152b8SChristian Marangi int cpu_port, ret, i; 1668027152b8SChristian Marangi u32 mask; 1669027152b8SChristian Marangi 1670027152b8SChristian Marangi cpu_port = qca8k_find_cpu_port(ds); 1671027152b8SChristian Marangi if (cpu_port < 0) { 1672027152b8SChristian Marangi dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); 1673027152b8SChristian Marangi return cpu_port; 1674027152b8SChristian Marangi } 1675027152b8SChristian Marangi 1676027152b8SChristian Marangi /* Parse CPU port config to be later used in phy_link mac_config */ 1677027152b8SChristian Marangi ret = qca8k_parse_port_config(priv); 1678027152b8SChristian Marangi if (ret) 1679027152b8SChristian Marangi return ret; 1680027152b8SChristian Marangi 1681027152b8SChristian Marangi ret = qca8k_setup_mdio_bus(priv); 1682027152b8SChristian Marangi if (ret) 1683027152b8SChristian Marangi return ret; 1684027152b8SChristian Marangi 1685027152b8SChristian Marangi ret = qca8k_setup_of_pws_reg(priv); 1686027152b8SChristian Marangi if (ret) 1687027152b8SChristian Marangi return ret; 1688027152b8SChristian Marangi 1689027152b8SChristian Marangi ret = qca8k_setup_mac_pwr_sel(priv); 1690027152b8SChristian Marangi if (ret) 1691027152b8SChristian Marangi return ret; 1692027152b8SChristian Marangi 1693027152b8SChristian Marangi qca8k_setup_pcs(priv, &priv->pcs_port_0, 0); 1694027152b8SChristian Marangi qca8k_setup_pcs(priv, &priv->pcs_port_6, 6); 1695027152b8SChristian Marangi 1696027152b8SChristian Marangi /* Make sure MAC06 is disabled */ 1697027152b8SChristian Marangi ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL, 1698027152b8SChristian Marangi QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); 1699027152b8SChristian Marangi if (ret) { 1700027152b8SChristian Marangi dev_err(priv->dev, "failed disabling MAC06 exchange"); 1701027152b8SChristian Marangi return ret; 1702027152b8SChristian Marangi } 1703027152b8SChristian Marangi 1704027152b8SChristian Marangi /* Enable CPU Port */ 1705027152b8SChristian Marangi ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, 1706027152b8SChristian Marangi QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); 1707027152b8SChristian Marangi if (ret) { 1708027152b8SChristian Marangi dev_err(priv->dev, "failed enabling CPU port"); 1709027152b8SChristian Marangi return ret; 1710027152b8SChristian Marangi } 1711027152b8SChristian Marangi 1712027152b8SChristian Marangi /* Enable MIB counters */ 1713027152b8SChristian Marangi ret = qca8k_mib_init(priv); 1714027152b8SChristian Marangi if (ret) 1715027152b8SChristian Marangi dev_warn(priv->dev, "mib init failed"); 1716027152b8SChristian Marangi 1717027152b8SChristian Marangi /* Initial setup of all ports */ 1718027152b8SChristian Marangi for (i = 0; i < QCA8K_NUM_PORTS; i++) { 1719027152b8SChristian Marangi /* Disable forwarding by default on all ports */ 1720027152b8SChristian Marangi ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), 1721027152b8SChristian Marangi QCA8K_PORT_LOOKUP_MEMBER, 0); 1722027152b8SChristian Marangi if (ret) 1723027152b8SChristian Marangi return ret; 1724027152b8SChristian Marangi 1725027152b8SChristian Marangi /* Enable QCA header mode on all cpu ports */ 1726027152b8SChristian Marangi if (dsa_is_cpu_port(ds, i)) { 1727027152b8SChristian Marangi ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), 1728027152b8SChristian Marangi FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) | 1729027152b8SChristian Marangi FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL)); 1730027152b8SChristian Marangi if (ret) { 1731027152b8SChristian Marangi dev_err(priv->dev, "failed enabling QCA header mode"); 1732027152b8SChristian Marangi return ret; 1733027152b8SChristian Marangi } 1734027152b8SChristian Marangi } 1735027152b8SChristian Marangi 1736027152b8SChristian Marangi /* Disable MAC by default on all user ports */ 1737027152b8SChristian Marangi if (dsa_is_user_port(ds, i)) 1738027152b8SChristian Marangi qca8k_port_set_status(priv, i, 0); 1739027152b8SChristian Marangi } 1740027152b8SChristian Marangi 1741027152b8SChristian Marangi /* Forward all unknown frames to CPU port for Linux processing 1742027152b8SChristian Marangi * Notice that in multi-cpu config only one port should be set 1743027152b8SChristian Marangi * for igmp, unknown, multicast and broadcast packet 1744027152b8SChristian Marangi */ 1745027152b8SChristian Marangi ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, 1746027152b8SChristian Marangi FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | 1747027152b8SChristian Marangi FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | 1748027152b8SChristian Marangi FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | 1749027152b8SChristian Marangi FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); 1750027152b8SChristian Marangi if (ret) 1751027152b8SChristian Marangi return ret; 1752027152b8SChristian Marangi 1753027152b8SChristian Marangi /* Setup connection between CPU port & user ports 1754027152b8SChristian Marangi * Configure specific switch configuration for ports 1755027152b8SChristian Marangi */ 1756027152b8SChristian Marangi for (i = 0; i < QCA8K_NUM_PORTS; i++) { 1757027152b8SChristian Marangi /* CPU port gets connected to all user ports of the switch */ 1758027152b8SChristian Marangi if (dsa_is_cpu_port(ds, i)) { 1759027152b8SChristian Marangi ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), 1760027152b8SChristian Marangi QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); 1761027152b8SChristian Marangi if (ret) 1762027152b8SChristian Marangi return ret; 1763027152b8SChristian Marangi } 1764027152b8SChristian Marangi 1765027152b8SChristian Marangi /* Individual user ports get connected to CPU port only */ 1766027152b8SChristian Marangi if (dsa_is_user_port(ds, i)) { 1767027152b8SChristian Marangi ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), 1768027152b8SChristian Marangi QCA8K_PORT_LOOKUP_MEMBER, 1769027152b8SChristian Marangi BIT(cpu_port)); 1770027152b8SChristian Marangi if (ret) 1771027152b8SChristian Marangi return ret; 1772027152b8SChristian Marangi 1773027152b8SChristian Marangi /* Enable ARP Auto-learning by default */ 1774027152b8SChristian Marangi ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i), 1775027152b8SChristian Marangi QCA8K_PORT_LOOKUP_LEARN); 1776027152b8SChristian Marangi if (ret) 1777027152b8SChristian Marangi return ret; 1778027152b8SChristian Marangi 1779027152b8SChristian Marangi /* For port based vlans to work we need to set the 1780027152b8SChristian Marangi * default egress vid 1781027152b8SChristian Marangi */ 1782027152b8SChristian Marangi ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), 1783027152b8SChristian Marangi QCA8K_EGREES_VLAN_PORT_MASK(i), 1784027152b8SChristian Marangi QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF)); 1785027152b8SChristian Marangi if (ret) 1786027152b8SChristian Marangi return ret; 1787027152b8SChristian Marangi 1788027152b8SChristian Marangi ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i), 1789027152b8SChristian Marangi QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) | 1790027152b8SChristian Marangi QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); 1791027152b8SChristian Marangi if (ret) 1792027152b8SChristian Marangi return ret; 1793027152b8SChristian Marangi } 1794027152b8SChristian Marangi 1795027152b8SChristian Marangi /* The port 5 of the qca8337 have some problem in flood condition. The 1796027152b8SChristian Marangi * original legacy driver had some specific buffer and priority settings 1797027152b8SChristian Marangi * for the different port suggested by the QCA switch team. Add this 1798027152b8SChristian Marangi * missing settings to improve switch stability under load condition. 1799027152b8SChristian Marangi * This problem is limited to qca8337 and other qca8k switch are not affected. 1800027152b8SChristian Marangi */ 1801027152b8SChristian Marangi if (priv->switch_id == QCA8K_ID_QCA8337) { 1802027152b8SChristian Marangi switch (i) { 1803027152b8SChristian Marangi /* The 2 CPU port and port 5 requires some different 1804027152b8SChristian Marangi * priority than any other ports. 1805027152b8SChristian Marangi */ 1806027152b8SChristian Marangi case 0: 1807027152b8SChristian Marangi case 5: 1808027152b8SChristian Marangi case 6: 1809027152b8SChristian Marangi mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | 1810027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | 1811027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) | 1812027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) | 1813027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) | 1814027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) | 1815027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e); 1816027152b8SChristian Marangi break; 1817027152b8SChristian Marangi default: 1818027152b8SChristian Marangi mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | 1819027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | 1820027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) | 1821027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) | 1822027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19); 1823027152b8SChristian Marangi } 1824027152b8SChristian Marangi qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask); 1825027152b8SChristian Marangi 1826027152b8SChristian Marangi mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) | 1827027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | 1828027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | 1829027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL1_WRED_EN; 1830027152b8SChristian Marangi qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), 1831027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK | 1832027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | 1833027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | 1834027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL1_WRED_EN, 1835027152b8SChristian Marangi mask); 1836027152b8SChristian Marangi } 1837027152b8SChristian Marangi } 1838027152b8SChristian Marangi 1839027152b8SChristian Marangi /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ 1840027152b8SChristian Marangi if (priv->switch_id == QCA8K_ID_QCA8327) { 1841027152b8SChristian Marangi mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | 1842027152b8SChristian Marangi QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); 1843027152b8SChristian Marangi qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, 1844027152b8SChristian Marangi QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK | 1845027152b8SChristian Marangi QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, 1846027152b8SChristian Marangi mask); 1847027152b8SChristian Marangi } 1848027152b8SChristian Marangi 1849027152b8SChristian Marangi /* Setup our port MTUs to match power on defaults */ 1850027152b8SChristian Marangi ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); 1851027152b8SChristian Marangi if (ret) 1852027152b8SChristian Marangi dev_warn(priv->dev, "failed setting MTU settings"); 1853027152b8SChristian Marangi 1854027152b8SChristian Marangi /* Flush the FDB table */ 1855027152b8SChristian Marangi qca8k_fdb_flush(priv); 1856027152b8SChristian Marangi 1857027152b8SChristian Marangi /* Set min a max ageing value supported */ 1858027152b8SChristian Marangi ds->ageing_time_min = 7000; 1859027152b8SChristian Marangi ds->ageing_time_max = 458745000; 1860027152b8SChristian Marangi 1861027152b8SChristian Marangi /* Set max number of LAGs supported */ 1862027152b8SChristian Marangi ds->num_lag_ids = QCA8K_NUM_LAGS; 1863027152b8SChristian Marangi 1864027152b8SChristian Marangi return 0; 1865027152b8SChristian Marangi } 1866027152b8SChristian Marangi 1867027152b8SChristian Marangi static const struct dsa_switch_ops qca8k_switch_ops = { 1868027152b8SChristian Marangi .get_tag_protocol = qca8k_get_tag_protocol, 1869027152b8SChristian Marangi .setup = qca8k_setup, 1870027152b8SChristian Marangi .get_strings = qca8k_get_strings, 1871027152b8SChristian Marangi .get_ethtool_stats = qca8k_get_ethtool_stats, 1872027152b8SChristian Marangi .get_sset_count = qca8k_get_sset_count, 1873027152b8SChristian Marangi .set_ageing_time = qca8k_set_ageing_time, 1874027152b8SChristian Marangi .get_mac_eee = qca8k_get_mac_eee, 1875027152b8SChristian Marangi .set_mac_eee = qca8k_set_mac_eee, 1876027152b8SChristian Marangi .port_enable = qca8k_port_enable, 1877027152b8SChristian Marangi .port_disable = qca8k_port_disable, 1878027152b8SChristian Marangi .port_change_mtu = qca8k_port_change_mtu, 1879027152b8SChristian Marangi .port_max_mtu = qca8k_port_max_mtu, 1880027152b8SChristian Marangi .port_stp_state_set = qca8k_port_stp_state_set, 1881027152b8SChristian Marangi .port_bridge_join = qca8k_port_bridge_join, 1882027152b8SChristian Marangi .port_bridge_leave = qca8k_port_bridge_leave, 1883027152b8SChristian Marangi .port_fast_age = qca8k_port_fast_age, 1884027152b8SChristian Marangi .port_fdb_add = qca8k_port_fdb_add, 1885027152b8SChristian Marangi .port_fdb_del = qca8k_port_fdb_del, 1886027152b8SChristian Marangi .port_fdb_dump = qca8k_port_fdb_dump, 1887027152b8SChristian Marangi .port_mdb_add = qca8k_port_mdb_add, 1888027152b8SChristian Marangi .port_mdb_del = qca8k_port_mdb_del, 1889027152b8SChristian Marangi .port_mirror_add = qca8k_port_mirror_add, 1890027152b8SChristian Marangi .port_mirror_del = qca8k_port_mirror_del, 1891027152b8SChristian Marangi .port_vlan_filtering = qca8k_port_vlan_filtering, 1892027152b8SChristian Marangi .port_vlan_add = qca8k_port_vlan_add, 1893027152b8SChristian Marangi .port_vlan_del = qca8k_port_vlan_del, 1894027152b8SChristian Marangi .phylink_get_caps = qca8k_phylink_get_caps, 1895027152b8SChristian Marangi .phylink_mac_select_pcs = qca8k_phylink_mac_select_pcs, 1896027152b8SChristian Marangi .phylink_mac_config = qca8k_phylink_mac_config, 1897027152b8SChristian Marangi .phylink_mac_link_down = qca8k_phylink_mac_link_down, 1898027152b8SChristian Marangi .phylink_mac_link_up = qca8k_phylink_mac_link_up, 1899027152b8SChristian Marangi .get_phy_flags = qca8k_get_phy_flags, 1900027152b8SChristian Marangi .port_lag_join = qca8k_port_lag_join, 1901027152b8SChristian Marangi .port_lag_leave = qca8k_port_lag_leave, 1902027152b8SChristian Marangi .master_state_change = qca8k_master_change, 1903027152b8SChristian Marangi .connect_tag_protocol = qca8k_connect_tag_protocol, 1904027152b8SChristian Marangi }; 1905027152b8SChristian Marangi 1906027152b8SChristian Marangi static int 1907027152b8SChristian Marangi qca8k_sw_probe(struct mdio_device *mdiodev) 1908027152b8SChristian Marangi { 1909027152b8SChristian Marangi struct qca8k_priv *priv; 1910027152b8SChristian Marangi int ret; 1911027152b8SChristian Marangi 1912027152b8SChristian Marangi /* allocate the private data struct so that we can probe the switches 1913027152b8SChristian Marangi * ID register 1914027152b8SChristian Marangi */ 1915027152b8SChristian Marangi priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); 1916027152b8SChristian Marangi if (!priv) 1917027152b8SChristian Marangi return -ENOMEM; 1918027152b8SChristian Marangi 1919027152b8SChristian Marangi priv->bus = mdiodev->bus; 1920027152b8SChristian Marangi priv->dev = &mdiodev->dev; 192142b998d4SChristian Marangi priv->info = of_device_get_match_data(priv->dev); 1922027152b8SChristian Marangi 1923027152b8SChristian Marangi priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", 1924027152b8SChristian Marangi GPIOD_ASIS); 1925027152b8SChristian Marangi if (IS_ERR(priv->reset_gpio)) 1926027152b8SChristian Marangi return PTR_ERR(priv->reset_gpio); 1927027152b8SChristian Marangi 1928027152b8SChristian Marangi if (priv->reset_gpio) { 1929027152b8SChristian Marangi gpiod_set_value_cansleep(priv->reset_gpio, 1); 1930027152b8SChristian Marangi /* The active low duration must be greater than 10 ms 1931027152b8SChristian Marangi * and checkpatch.pl wants 20 ms. 1932027152b8SChristian Marangi */ 1933027152b8SChristian Marangi msleep(20); 1934027152b8SChristian Marangi gpiod_set_value_cansleep(priv->reset_gpio, 0); 1935027152b8SChristian Marangi } 1936027152b8SChristian Marangi 1937027152b8SChristian Marangi /* Start by setting up the register mapping */ 1938027152b8SChristian Marangi priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv, 1939027152b8SChristian Marangi &qca8k_regmap_config); 1940027152b8SChristian Marangi if (IS_ERR(priv->regmap)) { 1941027152b8SChristian Marangi dev_err(priv->dev, "regmap initialization failed"); 1942027152b8SChristian Marangi return PTR_ERR(priv->regmap); 1943027152b8SChristian Marangi } 1944027152b8SChristian Marangi 1945027152b8SChristian Marangi priv->mdio_cache.page = 0xffff; 1946027152b8SChristian Marangi priv->mdio_cache.lo = 0xffff; 1947027152b8SChristian Marangi priv->mdio_cache.hi = 0xffff; 1948027152b8SChristian Marangi 1949027152b8SChristian Marangi /* Check the detected switch id */ 1950027152b8SChristian Marangi ret = qca8k_read_switch_id(priv); 1951027152b8SChristian Marangi if (ret) 1952027152b8SChristian Marangi return ret; 1953027152b8SChristian Marangi 1954027152b8SChristian Marangi priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); 1955027152b8SChristian Marangi if (!priv->ds) 1956027152b8SChristian Marangi return -ENOMEM; 1957027152b8SChristian Marangi 1958027152b8SChristian Marangi mutex_init(&priv->mgmt_eth_data.mutex); 1959027152b8SChristian Marangi init_completion(&priv->mgmt_eth_data.rw_done); 1960027152b8SChristian Marangi 1961027152b8SChristian Marangi mutex_init(&priv->mib_eth_data.mutex); 1962027152b8SChristian Marangi init_completion(&priv->mib_eth_data.rw_done); 1963027152b8SChristian Marangi 1964027152b8SChristian Marangi priv->ds->dev = &mdiodev->dev; 1965027152b8SChristian Marangi priv->ds->num_ports = QCA8K_NUM_PORTS; 1966027152b8SChristian Marangi priv->ds->priv = priv; 1967027152b8SChristian Marangi priv->ds->ops = &qca8k_switch_ops; 1968027152b8SChristian Marangi mutex_init(&priv->reg_mutex); 1969027152b8SChristian Marangi dev_set_drvdata(&mdiodev->dev, priv); 1970027152b8SChristian Marangi 1971027152b8SChristian Marangi return dsa_register_switch(priv->ds); 1972027152b8SChristian Marangi } 1973027152b8SChristian Marangi 1974027152b8SChristian Marangi static void 1975027152b8SChristian Marangi qca8k_sw_remove(struct mdio_device *mdiodev) 1976027152b8SChristian Marangi { 1977027152b8SChristian Marangi struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); 1978027152b8SChristian Marangi int i; 1979027152b8SChristian Marangi 1980027152b8SChristian Marangi if (!priv) 1981027152b8SChristian Marangi return; 1982027152b8SChristian Marangi 1983027152b8SChristian Marangi for (i = 0; i < QCA8K_NUM_PORTS; i++) 1984027152b8SChristian Marangi qca8k_port_set_status(priv, i, 0); 1985027152b8SChristian Marangi 1986027152b8SChristian Marangi dsa_unregister_switch(priv->ds); 1987027152b8SChristian Marangi } 1988027152b8SChristian Marangi 1989027152b8SChristian Marangi static void qca8k_sw_shutdown(struct mdio_device *mdiodev) 1990027152b8SChristian Marangi { 1991027152b8SChristian Marangi struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); 1992027152b8SChristian Marangi 1993027152b8SChristian Marangi if (!priv) 1994027152b8SChristian Marangi return; 1995027152b8SChristian Marangi 1996027152b8SChristian Marangi dsa_switch_shutdown(priv->ds); 1997027152b8SChristian Marangi 1998027152b8SChristian Marangi dev_set_drvdata(&mdiodev->dev, NULL); 1999027152b8SChristian Marangi } 2000027152b8SChristian Marangi 2001027152b8SChristian Marangi #ifdef CONFIG_PM_SLEEP 2002027152b8SChristian Marangi static void 2003027152b8SChristian Marangi qca8k_set_pm(struct qca8k_priv *priv, int enable) 2004027152b8SChristian Marangi { 2005027152b8SChristian Marangi int port; 2006027152b8SChristian Marangi 2007027152b8SChristian Marangi for (port = 0; port < QCA8K_NUM_PORTS; port++) { 2008027152b8SChristian Marangi /* Do not enable on resume if the port was 2009027152b8SChristian Marangi * disabled before. 2010027152b8SChristian Marangi */ 2011027152b8SChristian Marangi if (!(priv->port_enabled_map & BIT(port))) 2012027152b8SChristian Marangi continue; 2013027152b8SChristian Marangi 2014027152b8SChristian Marangi qca8k_port_set_status(priv, port, enable); 2015027152b8SChristian Marangi } 2016027152b8SChristian Marangi } 2017027152b8SChristian Marangi 2018027152b8SChristian Marangi static int qca8k_suspend(struct device *dev) 2019027152b8SChristian Marangi { 2020027152b8SChristian Marangi struct qca8k_priv *priv = dev_get_drvdata(dev); 2021027152b8SChristian Marangi 2022027152b8SChristian Marangi qca8k_set_pm(priv, 0); 2023027152b8SChristian Marangi 2024027152b8SChristian Marangi return dsa_switch_suspend(priv->ds); 2025027152b8SChristian Marangi } 2026027152b8SChristian Marangi 2027027152b8SChristian Marangi static int qca8k_resume(struct device *dev) 2028027152b8SChristian Marangi { 2029027152b8SChristian Marangi struct qca8k_priv *priv = dev_get_drvdata(dev); 2030027152b8SChristian Marangi 2031027152b8SChristian Marangi qca8k_set_pm(priv, 1); 2032027152b8SChristian Marangi 2033027152b8SChristian Marangi return dsa_switch_resume(priv->ds); 2034027152b8SChristian Marangi } 2035027152b8SChristian Marangi #endif /* CONFIG_PM_SLEEP */ 2036027152b8SChristian Marangi 2037027152b8SChristian Marangi static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, 2038027152b8SChristian Marangi qca8k_suspend, qca8k_resume); 2039027152b8SChristian Marangi 2040027152b8SChristian Marangi static const struct qca8k_info_ops qca8xxx_ops = { 2041027152b8SChristian Marangi .autocast_mib = qca8k_get_ethtool_stats_eth, 204291074644SChristian Marangi .read_eth = qca8k_read_eth, 204391074644SChristian Marangi .write_eth = qca8k_write_eth, 2044027152b8SChristian Marangi }; 2045027152b8SChristian Marangi 2046027152b8SChristian Marangi static const struct qca8k_match_data qca8327 = { 2047027152b8SChristian Marangi .id = QCA8K_ID_QCA8327, 2048027152b8SChristian Marangi .reduced_package = true, 2049027152b8SChristian Marangi .mib_count = QCA8K_QCA832X_MIB_COUNT, 2050027152b8SChristian Marangi .ops = &qca8xxx_ops, 2051027152b8SChristian Marangi }; 2052027152b8SChristian Marangi 2053027152b8SChristian Marangi static const struct qca8k_match_data qca8328 = { 2054027152b8SChristian Marangi .id = QCA8K_ID_QCA8327, 2055027152b8SChristian Marangi .mib_count = QCA8K_QCA832X_MIB_COUNT, 2056027152b8SChristian Marangi .ops = &qca8xxx_ops, 2057027152b8SChristian Marangi }; 2058027152b8SChristian Marangi 2059027152b8SChristian Marangi static const struct qca8k_match_data qca833x = { 2060027152b8SChristian Marangi .id = QCA8K_ID_QCA8337, 2061027152b8SChristian Marangi .mib_count = QCA8K_QCA833X_MIB_COUNT, 2062027152b8SChristian Marangi .ops = &qca8xxx_ops, 2063027152b8SChristian Marangi }; 2064027152b8SChristian Marangi 2065027152b8SChristian Marangi static const struct of_device_id qca8k_of_match[] = { 2066027152b8SChristian Marangi { .compatible = "qca,qca8327", .data = &qca8327 }, 2067027152b8SChristian Marangi { .compatible = "qca,qca8328", .data = &qca8328 }, 2068027152b8SChristian Marangi { .compatible = "qca,qca8334", .data = &qca833x }, 2069027152b8SChristian Marangi { .compatible = "qca,qca8337", .data = &qca833x }, 2070027152b8SChristian Marangi { /* sentinel */ }, 2071027152b8SChristian Marangi }; 2072027152b8SChristian Marangi 2073027152b8SChristian Marangi static struct mdio_driver qca8kmdio_driver = { 2074027152b8SChristian Marangi .probe = qca8k_sw_probe, 2075027152b8SChristian Marangi .remove = qca8k_sw_remove, 2076027152b8SChristian Marangi .shutdown = qca8k_sw_shutdown, 2077027152b8SChristian Marangi .mdiodrv.driver = { 2078027152b8SChristian Marangi .name = "qca8k", 2079027152b8SChristian Marangi .of_match_table = qca8k_of_match, 2080027152b8SChristian Marangi .pm = &qca8k_pm_ops, 2081027152b8SChristian Marangi }, 2082027152b8SChristian Marangi }; 2083027152b8SChristian Marangi 2084027152b8SChristian Marangi mdio_module_driver(qca8kmdio_driver); 2085027152b8SChristian Marangi 2086027152b8SChristian Marangi MODULE_AUTHOR("Mathieu Olivari, John Crispin <john@phrozen.org>"); 2087027152b8SChristian Marangi MODULE_DESCRIPTION("Driver for QCA8K ethernet switch family"); 2088027152b8SChristian Marangi MODULE_LICENSE("GPL v2"); 2089027152b8SChristian Marangi MODULE_ALIAS("platform:qca8k"); 2090