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" 251e264f9dSChristian Marangi #include "qca8k_leds.h" 26027152b8SChristian Marangi 27027152b8SChristian Marangi static void 28027152b8SChristian Marangi qca8k_split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) 29027152b8SChristian Marangi { 30027152b8SChristian Marangi regaddr >>= 1; 31027152b8SChristian Marangi *r1 = regaddr & 0x1e; 32027152b8SChristian Marangi 33027152b8SChristian Marangi regaddr >>= 5; 34027152b8SChristian Marangi *r2 = regaddr & 0x7; 35027152b8SChristian Marangi 36027152b8SChristian Marangi regaddr >>= 3; 37027152b8SChristian Marangi *page = regaddr & 0x3ff; 38027152b8SChristian Marangi } 39027152b8SChristian Marangi 40027152b8SChristian Marangi static int 41cfbd6de5SChristian Marangi qca8k_mii_write_lo(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) 42cfbd6de5SChristian Marangi { 43cfbd6de5SChristian Marangi int ret; 44cfbd6de5SChristian Marangi u16 lo; 45cfbd6de5SChristian Marangi 46cfbd6de5SChristian Marangi lo = val & 0xffff; 47cfbd6de5SChristian Marangi ret = bus->write(bus, phy_id, regnum, lo); 48cfbd6de5SChristian Marangi if (ret < 0) 49cfbd6de5SChristian Marangi dev_err_ratelimited(&bus->dev, 50cfbd6de5SChristian Marangi "failed to write qca8k 32bit lo register\n"); 51cfbd6de5SChristian Marangi 52cfbd6de5SChristian Marangi return ret; 53cfbd6de5SChristian Marangi } 54cfbd6de5SChristian Marangi 55cfbd6de5SChristian Marangi static int 56cfbd6de5SChristian Marangi qca8k_mii_write_hi(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) 57cfbd6de5SChristian Marangi { 58cfbd6de5SChristian Marangi int ret; 59cfbd6de5SChristian Marangi u16 hi; 60cfbd6de5SChristian Marangi 61cfbd6de5SChristian Marangi hi = (u16)(val >> 16); 62cfbd6de5SChristian Marangi ret = bus->write(bus, phy_id, regnum, hi); 63cfbd6de5SChristian Marangi if (ret < 0) 64cfbd6de5SChristian Marangi dev_err_ratelimited(&bus->dev, 65cfbd6de5SChristian Marangi "failed to write qca8k 32bit hi register\n"); 66cfbd6de5SChristian Marangi 67cfbd6de5SChristian Marangi return ret; 68cfbd6de5SChristian Marangi } 69cfbd6de5SChristian Marangi 70cfbd6de5SChristian Marangi static int 71cfbd6de5SChristian Marangi qca8k_mii_read_lo(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) 72027152b8SChristian Marangi { 73027152b8SChristian Marangi int ret; 74027152b8SChristian Marangi 75027152b8SChristian Marangi ret = bus->read(bus, phy_id, regnum); 76cfbd6de5SChristian Marangi if (ret < 0) 77cfbd6de5SChristian Marangi goto err; 78027152b8SChristian Marangi 79cfbd6de5SChristian Marangi *val = ret & 0xffff; 80cfbd6de5SChristian Marangi return 0; 81cfbd6de5SChristian Marangi 82cfbd6de5SChristian Marangi err: 83027152b8SChristian Marangi dev_err_ratelimited(&bus->dev, 84cfbd6de5SChristian Marangi "failed to read qca8k 32bit lo register\n"); 85027152b8SChristian Marangi *val = 0; 86cfbd6de5SChristian Marangi 87027152b8SChristian Marangi return ret; 88027152b8SChristian Marangi } 89027152b8SChristian Marangi 90cfbd6de5SChristian Marangi static int 91cfbd6de5SChristian Marangi qca8k_mii_read_hi(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) 92cfbd6de5SChristian Marangi { 93cfbd6de5SChristian Marangi int ret; 94cfbd6de5SChristian Marangi 95cfbd6de5SChristian Marangi ret = bus->read(bus, phy_id, regnum); 96cfbd6de5SChristian Marangi if (ret < 0) 97cfbd6de5SChristian Marangi goto err; 98cfbd6de5SChristian Marangi 99cfbd6de5SChristian Marangi *val = ret << 16; 100027152b8SChristian Marangi return 0; 101cfbd6de5SChristian Marangi 102cfbd6de5SChristian Marangi err: 103cfbd6de5SChristian Marangi dev_err_ratelimited(&bus->dev, 104cfbd6de5SChristian Marangi "failed to read qca8k 32bit hi register\n"); 105cfbd6de5SChristian Marangi *val = 0; 106cfbd6de5SChristian Marangi 107cfbd6de5SChristian Marangi return ret; 108cfbd6de5SChristian Marangi } 109cfbd6de5SChristian Marangi 110cfbd6de5SChristian Marangi static int 111cfbd6de5SChristian Marangi qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val) 112cfbd6de5SChristian Marangi { 113cfbd6de5SChristian Marangi u32 hi, lo; 114cfbd6de5SChristian Marangi int ret; 115cfbd6de5SChristian Marangi 116cfbd6de5SChristian Marangi *val = 0; 117cfbd6de5SChristian Marangi 118cfbd6de5SChristian Marangi ret = qca8k_mii_read_lo(bus, phy_id, regnum, &lo); 119cfbd6de5SChristian Marangi if (ret < 0) 120cfbd6de5SChristian Marangi goto err; 121cfbd6de5SChristian Marangi 122cfbd6de5SChristian Marangi ret = qca8k_mii_read_hi(bus, phy_id, regnum + 1, &hi); 123cfbd6de5SChristian Marangi if (ret < 0) 124cfbd6de5SChristian Marangi goto err; 125cfbd6de5SChristian Marangi 126cfbd6de5SChristian Marangi *val = lo | hi; 127cfbd6de5SChristian Marangi 128cfbd6de5SChristian Marangi err: 129cfbd6de5SChristian Marangi return ret; 130027152b8SChristian Marangi } 131027152b8SChristian Marangi 132027152b8SChristian Marangi static void 13303cb9e6dSChristian Marangi qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val) 134027152b8SChristian Marangi { 135cfbd6de5SChristian Marangi if (qca8k_mii_write_lo(bus, phy_id, regnum, val) < 0) 136cfbd6de5SChristian Marangi return; 137027152b8SChristian Marangi 138cfbd6de5SChristian Marangi qca8k_mii_write_hi(bus, phy_id, regnum + 1, val); 139027152b8SChristian Marangi } 140027152b8SChristian Marangi 141027152b8SChristian Marangi static int 142027152b8SChristian Marangi qca8k_set_page(struct qca8k_priv *priv, u16 page) 143027152b8SChristian Marangi { 144027152b8SChristian Marangi u16 *cached_page = &priv->mdio_cache.page; 145027152b8SChristian Marangi struct mii_bus *bus = priv->bus; 146027152b8SChristian Marangi int ret; 147027152b8SChristian Marangi 148027152b8SChristian Marangi if (page == *cached_page) 149027152b8SChristian Marangi return 0; 150027152b8SChristian Marangi 151027152b8SChristian Marangi ret = bus->write(bus, 0x18, 0, page); 152027152b8SChristian Marangi if (ret < 0) { 153027152b8SChristian Marangi dev_err_ratelimited(&bus->dev, 154027152b8SChristian Marangi "failed to set qca8k page\n"); 155027152b8SChristian Marangi return ret; 156027152b8SChristian Marangi } 157027152b8SChristian Marangi 158027152b8SChristian Marangi *cached_page = page; 159027152b8SChristian Marangi usleep_range(1000, 2000); 160027152b8SChristian Marangi return 0; 161027152b8SChristian Marangi } 162027152b8SChristian Marangi 163027152b8SChristian Marangi static void qca8k_rw_reg_ack_handler(struct dsa_switch *ds, struct sk_buff *skb) 164027152b8SChristian Marangi { 165027152b8SChristian Marangi struct qca8k_mgmt_eth_data *mgmt_eth_data; 166027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 167027152b8SChristian Marangi struct qca_mgmt_ethhdr *mgmt_ethhdr; 168a2550d3cSChristian Marangi u32 command; 169027152b8SChristian Marangi u8 len, cmd; 170a2550d3cSChristian Marangi int i; 171027152b8SChristian Marangi 172027152b8SChristian Marangi mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb_mac_header(skb); 173027152b8SChristian Marangi mgmt_eth_data = &priv->mgmt_eth_data; 174027152b8SChristian Marangi 175a2550d3cSChristian Marangi command = get_unaligned_le32(&mgmt_ethhdr->command); 176a2550d3cSChristian Marangi cmd = FIELD_GET(QCA_HDR_MGMT_CMD, command); 1779807ae69SChristian Marangi 178a2550d3cSChristian Marangi len = FIELD_GET(QCA_HDR_MGMT_LENGTH, command); 1799807ae69SChristian Marangi /* Special case for len of 15 as this is the max value for len and needs to 1809807ae69SChristian Marangi * be increased before converting it from word to dword. 1819807ae69SChristian Marangi */ 1829807ae69SChristian Marangi if (len == 15) 1839807ae69SChristian Marangi len++; 1849807ae69SChristian Marangi 1859807ae69SChristian Marangi /* We can ignore odd value, we always round up them in the alloc function. */ 1869807ae69SChristian Marangi len *= sizeof(u16); 187027152b8SChristian Marangi 188027152b8SChristian Marangi /* Make sure the seq match the requested packet */ 189a2550d3cSChristian Marangi if (get_unaligned_le32(&mgmt_ethhdr->seq) == mgmt_eth_data->seq) 190027152b8SChristian Marangi mgmt_eth_data->ack = true; 191027152b8SChristian Marangi 192027152b8SChristian Marangi if (cmd == MDIO_READ) { 193a2550d3cSChristian Marangi u32 *val = mgmt_eth_data->data; 194a2550d3cSChristian Marangi 195a2550d3cSChristian Marangi *val = get_unaligned_le32(&mgmt_ethhdr->mdio_data); 196027152b8SChristian Marangi 197027152b8SChristian Marangi /* Get the rest of the 12 byte of data. 198027152b8SChristian Marangi * The read/write function will extract the requested data. 199027152b8SChristian Marangi */ 200a2550d3cSChristian Marangi if (len > QCA_HDR_MGMT_DATA1_LEN) { 201a2550d3cSChristian Marangi __le32 *data2 = (__le32 *)skb->data; 202a2550d3cSChristian Marangi int data_len = min_t(int, QCA_HDR_MGMT_DATA2_LEN, 203a2550d3cSChristian Marangi len - QCA_HDR_MGMT_DATA1_LEN); 204a2550d3cSChristian Marangi 205a2550d3cSChristian Marangi val++; 206a2550d3cSChristian Marangi 207a2550d3cSChristian Marangi for (i = sizeof(u32); i <= data_len; i += sizeof(u32)) { 208a2550d3cSChristian Marangi *val = get_unaligned_le32(data2); 209a2550d3cSChristian Marangi val++; 210a2550d3cSChristian Marangi data2++; 211a2550d3cSChristian Marangi } 212a2550d3cSChristian Marangi } 213027152b8SChristian Marangi } 214027152b8SChristian Marangi 215027152b8SChristian Marangi complete(&mgmt_eth_data->rw_done); 216027152b8SChristian Marangi } 217027152b8SChristian Marangi 218027152b8SChristian Marangi static struct sk_buff *qca8k_alloc_mdio_header(enum mdio_cmd cmd, u32 reg, u32 *val, 219027152b8SChristian Marangi int priority, unsigned int len) 220027152b8SChristian Marangi { 221027152b8SChristian Marangi struct qca_mgmt_ethhdr *mgmt_ethhdr; 222027152b8SChristian Marangi unsigned int real_len; 223027152b8SChristian Marangi struct sk_buff *skb; 224a2550d3cSChristian Marangi __le32 *data2; 225a2550d3cSChristian Marangi u32 command; 226027152b8SChristian Marangi u16 hdr; 227a2550d3cSChristian Marangi int i; 228027152b8SChristian Marangi 229027152b8SChristian Marangi skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); 230027152b8SChristian Marangi if (!skb) 231027152b8SChristian Marangi return NULL; 232027152b8SChristian Marangi 2339807ae69SChristian Marangi /* Hdr mgmt length value is in step of word size. 2349807ae69SChristian Marangi * As an example to process 4 byte of data the correct length to set is 2. 2359807ae69SChristian Marangi * To process 8 byte 4, 12 byte 6, 16 byte 8... 2369807ae69SChristian Marangi * 2379807ae69SChristian Marangi * Odd values will always return the next size on the ack packet. 2389807ae69SChristian Marangi * (length of 3 (6 byte) will always return 8 bytes of data) 2399807ae69SChristian Marangi * 2409807ae69SChristian Marangi * This means that a value of 15 (0xf) actually means reading/writing 32 bytes 2419807ae69SChristian Marangi * of data. 2429807ae69SChristian Marangi * 2439807ae69SChristian Marangi * To correctly calculate the length we devide the requested len by word and 2449807ae69SChristian Marangi * round up. 2459807ae69SChristian Marangi * On the ack function we can skip the odd check as we already handle the 2469807ae69SChristian Marangi * case here. 247027152b8SChristian Marangi */ 2489807ae69SChristian Marangi real_len = DIV_ROUND_UP(len, sizeof(u16)); 2499807ae69SChristian Marangi 2509807ae69SChristian Marangi /* We check if the result len is odd and we round up another time to 2519807ae69SChristian Marangi * the next size. (length of 3 will be increased to 4 as switch will always 2529807ae69SChristian Marangi * return 8 bytes) 2539807ae69SChristian Marangi */ 2549807ae69SChristian Marangi if (real_len % sizeof(u16) != 0) 2559807ae69SChristian Marangi real_len++; 2569807ae69SChristian Marangi 2579807ae69SChristian Marangi /* Max reg value is 0xf(15) but switch will always return the next size (32 byte) */ 2589807ae69SChristian Marangi if (real_len == 16) 2599807ae69SChristian Marangi real_len--; 260027152b8SChristian Marangi 261027152b8SChristian Marangi skb_reset_mac_header(skb); 262027152b8SChristian Marangi skb_set_network_header(skb, skb->len); 263027152b8SChristian Marangi 264027152b8SChristian Marangi mgmt_ethhdr = skb_push(skb, QCA_HDR_MGMT_HEADER_LEN + QCA_HDR_LEN); 265027152b8SChristian Marangi 266027152b8SChristian Marangi hdr = FIELD_PREP(QCA_HDR_XMIT_VERSION, QCA_HDR_VERSION); 267027152b8SChristian Marangi hdr |= FIELD_PREP(QCA_HDR_XMIT_PRIORITY, priority); 268027152b8SChristian Marangi hdr |= QCA_HDR_XMIT_FROM_CPU; 269027152b8SChristian Marangi hdr |= FIELD_PREP(QCA_HDR_XMIT_DP_BIT, BIT(0)); 270027152b8SChristian Marangi hdr |= FIELD_PREP(QCA_HDR_XMIT_CONTROL, QCA_HDR_XMIT_TYPE_RW_REG); 271027152b8SChristian Marangi 272a2550d3cSChristian Marangi command = FIELD_PREP(QCA_HDR_MGMT_ADDR, reg); 273a2550d3cSChristian Marangi command |= FIELD_PREP(QCA_HDR_MGMT_LENGTH, real_len); 274a2550d3cSChristian Marangi command |= FIELD_PREP(QCA_HDR_MGMT_CMD, cmd); 275a2550d3cSChristian Marangi command |= FIELD_PREP(QCA_HDR_MGMT_CHECK_CODE, 276027152b8SChristian Marangi QCA_HDR_MGMT_CHECK_CODE_VAL); 277027152b8SChristian Marangi 278a2550d3cSChristian Marangi put_unaligned_le32(command, &mgmt_ethhdr->command); 279a2550d3cSChristian Marangi 280027152b8SChristian Marangi if (cmd == MDIO_WRITE) 281a2550d3cSChristian Marangi put_unaligned_le32(*val, &mgmt_ethhdr->mdio_data); 282027152b8SChristian Marangi 283027152b8SChristian Marangi mgmt_ethhdr->hdr = htons(hdr); 284027152b8SChristian Marangi 285027152b8SChristian Marangi data2 = skb_put_zero(skb, QCA_HDR_MGMT_DATA2_LEN + QCA_HDR_MGMT_PADDING_LEN); 286a2550d3cSChristian Marangi if (cmd == MDIO_WRITE && len > QCA_HDR_MGMT_DATA1_LEN) { 287a2550d3cSChristian Marangi int data_len = min_t(int, QCA_HDR_MGMT_DATA2_LEN, 288a2550d3cSChristian Marangi len - QCA_HDR_MGMT_DATA1_LEN); 289a2550d3cSChristian Marangi 290a2550d3cSChristian Marangi val++; 291a2550d3cSChristian Marangi 292a2550d3cSChristian Marangi for (i = sizeof(u32); i <= data_len; i += sizeof(u32)) { 293a2550d3cSChristian Marangi put_unaligned_le32(*val, data2); 294a2550d3cSChristian Marangi data2++; 295a2550d3cSChristian Marangi val++; 296a2550d3cSChristian Marangi } 297a2550d3cSChristian Marangi } 298027152b8SChristian Marangi 299027152b8SChristian Marangi return skb; 300027152b8SChristian Marangi } 301027152b8SChristian Marangi 302027152b8SChristian Marangi static void qca8k_mdio_header_fill_seq_num(struct sk_buff *skb, u32 seq_num) 303027152b8SChristian Marangi { 304027152b8SChristian Marangi struct qca_mgmt_ethhdr *mgmt_ethhdr; 305a2550d3cSChristian Marangi u32 seq; 306027152b8SChristian Marangi 307a2550d3cSChristian Marangi seq = FIELD_PREP(QCA_HDR_MGMT_SEQ_NUM, seq_num); 308027152b8SChristian Marangi mgmt_ethhdr = (struct qca_mgmt_ethhdr *)skb->data; 309a2550d3cSChristian Marangi put_unaligned_le32(seq, &mgmt_ethhdr->seq); 310027152b8SChristian Marangi } 311027152b8SChristian Marangi 312027152b8SChristian Marangi static int qca8k_read_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) 313027152b8SChristian Marangi { 314027152b8SChristian Marangi struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; 315027152b8SChristian Marangi struct sk_buff *skb; 316027152b8SChristian Marangi bool ack; 317027152b8SChristian Marangi int ret; 318027152b8SChristian Marangi 319027152b8SChristian Marangi skb = qca8k_alloc_mdio_header(MDIO_READ, reg, NULL, 320027152b8SChristian Marangi QCA8K_ETHERNET_MDIO_PRIORITY, len); 321027152b8SChristian Marangi if (!skb) 322027152b8SChristian Marangi return -ENOMEM; 323027152b8SChristian Marangi 324027152b8SChristian Marangi mutex_lock(&mgmt_eth_data->mutex); 325027152b8SChristian Marangi 326027152b8SChristian Marangi /* Check mgmt_master if is operational */ 327027152b8SChristian Marangi if (!priv->mgmt_master) { 328027152b8SChristian Marangi kfree_skb(skb); 329027152b8SChristian Marangi mutex_unlock(&mgmt_eth_data->mutex); 330027152b8SChristian Marangi return -EINVAL; 331027152b8SChristian Marangi } 332027152b8SChristian Marangi 333027152b8SChristian Marangi skb->dev = priv->mgmt_master; 334027152b8SChristian Marangi 335027152b8SChristian Marangi reinit_completion(&mgmt_eth_data->rw_done); 336027152b8SChristian Marangi 337027152b8SChristian Marangi /* Increment seq_num and set it in the mdio pkt */ 338027152b8SChristian Marangi mgmt_eth_data->seq++; 339027152b8SChristian Marangi qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); 340027152b8SChristian Marangi mgmt_eth_data->ack = false; 341027152b8SChristian Marangi 342027152b8SChristian Marangi dev_queue_xmit(skb); 343027152b8SChristian Marangi 344027152b8SChristian Marangi ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, 345027152b8SChristian Marangi msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); 346027152b8SChristian Marangi 347027152b8SChristian Marangi *val = mgmt_eth_data->data[0]; 348027152b8SChristian Marangi if (len > QCA_HDR_MGMT_DATA1_LEN) 349027152b8SChristian Marangi memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN); 350027152b8SChristian Marangi 351027152b8SChristian Marangi ack = mgmt_eth_data->ack; 352027152b8SChristian Marangi 353027152b8SChristian Marangi mutex_unlock(&mgmt_eth_data->mutex); 354027152b8SChristian Marangi 355027152b8SChristian Marangi if (ret <= 0) 356027152b8SChristian Marangi return -ETIMEDOUT; 357027152b8SChristian Marangi 358027152b8SChristian Marangi if (!ack) 359027152b8SChristian Marangi return -EINVAL; 360027152b8SChristian Marangi 361027152b8SChristian Marangi return 0; 362027152b8SChristian Marangi } 363027152b8SChristian Marangi 364027152b8SChristian Marangi static int qca8k_write_eth(struct qca8k_priv *priv, u32 reg, u32 *val, int len) 365027152b8SChristian Marangi { 366027152b8SChristian Marangi struct qca8k_mgmt_eth_data *mgmt_eth_data = &priv->mgmt_eth_data; 367027152b8SChristian Marangi struct sk_buff *skb; 368027152b8SChristian Marangi bool ack; 369027152b8SChristian Marangi int ret; 370027152b8SChristian Marangi 371027152b8SChristian Marangi skb = qca8k_alloc_mdio_header(MDIO_WRITE, reg, val, 372027152b8SChristian Marangi QCA8K_ETHERNET_MDIO_PRIORITY, len); 373027152b8SChristian Marangi if (!skb) 374027152b8SChristian Marangi return -ENOMEM; 375027152b8SChristian Marangi 376027152b8SChristian Marangi mutex_lock(&mgmt_eth_data->mutex); 377027152b8SChristian Marangi 378027152b8SChristian Marangi /* Check mgmt_master if is operational */ 379027152b8SChristian Marangi if (!priv->mgmt_master) { 380027152b8SChristian Marangi kfree_skb(skb); 381027152b8SChristian Marangi mutex_unlock(&mgmt_eth_data->mutex); 382027152b8SChristian Marangi return -EINVAL; 383027152b8SChristian Marangi } 384027152b8SChristian Marangi 385027152b8SChristian Marangi skb->dev = priv->mgmt_master; 386027152b8SChristian Marangi 387027152b8SChristian Marangi reinit_completion(&mgmt_eth_data->rw_done); 388027152b8SChristian Marangi 389027152b8SChristian Marangi /* Increment seq_num and set it in the mdio pkt */ 390027152b8SChristian Marangi mgmt_eth_data->seq++; 391027152b8SChristian Marangi qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); 392027152b8SChristian Marangi mgmt_eth_data->ack = false; 393027152b8SChristian Marangi 394027152b8SChristian Marangi dev_queue_xmit(skb); 395027152b8SChristian Marangi 396027152b8SChristian Marangi ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, 397027152b8SChristian Marangi msecs_to_jiffies(QCA8K_ETHERNET_TIMEOUT)); 398027152b8SChristian Marangi 399027152b8SChristian Marangi ack = mgmt_eth_data->ack; 400027152b8SChristian Marangi 401027152b8SChristian Marangi mutex_unlock(&mgmt_eth_data->mutex); 402027152b8SChristian Marangi 403027152b8SChristian Marangi if (ret <= 0) 404027152b8SChristian Marangi return -ETIMEDOUT; 405027152b8SChristian Marangi 406027152b8SChristian Marangi if (!ack) 407027152b8SChristian Marangi return -EINVAL; 408027152b8SChristian Marangi 409027152b8SChristian Marangi return 0; 410027152b8SChristian Marangi } 411027152b8SChristian Marangi 412027152b8SChristian Marangi static int 413027152b8SChristian Marangi qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val) 414027152b8SChristian Marangi { 415027152b8SChristian Marangi u32 val = 0; 416027152b8SChristian Marangi int ret; 417027152b8SChristian Marangi 418027152b8SChristian Marangi ret = qca8k_read_eth(priv, reg, &val, sizeof(val)); 419027152b8SChristian Marangi if (ret) 420027152b8SChristian Marangi return ret; 421027152b8SChristian Marangi 422027152b8SChristian Marangi val &= ~mask; 423027152b8SChristian Marangi val |= write_val; 424027152b8SChristian Marangi 425027152b8SChristian Marangi return qca8k_write_eth(priv, reg, &val, sizeof(val)); 426027152b8SChristian Marangi } 427027152b8SChristian Marangi 428027152b8SChristian Marangi static int 429c766e077SChristian Marangi qca8k_read_mii(struct qca8k_priv *priv, uint32_t reg, uint32_t *val) 430027152b8SChristian Marangi { 431027152b8SChristian Marangi struct mii_bus *bus = priv->bus; 432027152b8SChristian Marangi u16 r1, r2, page; 433027152b8SChristian Marangi int ret; 434027152b8SChristian Marangi 435027152b8SChristian Marangi qca8k_split_addr(reg, &r1, &r2, &page); 436027152b8SChristian Marangi 437027152b8SChristian Marangi mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); 438027152b8SChristian Marangi 439027152b8SChristian Marangi ret = qca8k_set_page(priv, page); 440027152b8SChristian Marangi if (ret < 0) 441027152b8SChristian Marangi goto exit; 442027152b8SChristian Marangi 443027152b8SChristian Marangi ret = qca8k_mii_read32(bus, 0x10 | r2, r1, val); 444027152b8SChristian Marangi 445027152b8SChristian Marangi exit: 446027152b8SChristian Marangi mutex_unlock(&bus->mdio_lock); 447027152b8SChristian Marangi return ret; 448027152b8SChristian Marangi } 449027152b8SChristian Marangi 450027152b8SChristian Marangi static int 451c766e077SChristian Marangi qca8k_write_mii(struct qca8k_priv *priv, uint32_t reg, uint32_t val) 452027152b8SChristian Marangi { 453027152b8SChristian Marangi struct mii_bus *bus = priv->bus; 454027152b8SChristian Marangi u16 r1, r2, page; 455027152b8SChristian Marangi int ret; 456027152b8SChristian Marangi 457027152b8SChristian Marangi qca8k_split_addr(reg, &r1, &r2, &page); 458027152b8SChristian Marangi 459027152b8SChristian Marangi mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); 460027152b8SChristian Marangi 461027152b8SChristian Marangi ret = qca8k_set_page(priv, page); 462027152b8SChristian Marangi if (ret < 0) 463027152b8SChristian Marangi goto exit; 464027152b8SChristian Marangi 46503cb9e6dSChristian Marangi qca8k_mii_write32(bus, 0x10 | r2, r1, val); 466027152b8SChristian Marangi 467027152b8SChristian Marangi exit: 468027152b8SChristian Marangi mutex_unlock(&bus->mdio_lock); 469027152b8SChristian Marangi return ret; 470027152b8SChristian Marangi } 471027152b8SChristian Marangi 472027152b8SChristian Marangi static int 473c766e077SChristian Marangi qca8k_regmap_update_bits_mii(struct qca8k_priv *priv, uint32_t reg, 474c766e077SChristian Marangi uint32_t mask, uint32_t write_val) 475027152b8SChristian Marangi { 476027152b8SChristian Marangi struct mii_bus *bus = priv->bus; 477027152b8SChristian Marangi u16 r1, r2, page; 478027152b8SChristian Marangi u32 val; 479027152b8SChristian Marangi int ret; 480027152b8SChristian Marangi 481027152b8SChristian Marangi qca8k_split_addr(reg, &r1, &r2, &page); 482027152b8SChristian Marangi 483027152b8SChristian Marangi mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); 484027152b8SChristian Marangi 485027152b8SChristian Marangi ret = qca8k_set_page(priv, page); 486027152b8SChristian Marangi if (ret < 0) 487027152b8SChristian Marangi goto exit; 488027152b8SChristian Marangi 489027152b8SChristian Marangi ret = qca8k_mii_read32(bus, 0x10 | r2, r1, &val); 490027152b8SChristian Marangi if (ret < 0) 491027152b8SChristian Marangi goto exit; 492027152b8SChristian Marangi 493027152b8SChristian Marangi val &= ~mask; 494027152b8SChristian Marangi val |= write_val; 49503cb9e6dSChristian Marangi qca8k_mii_write32(bus, 0x10 | r2, r1, val); 496027152b8SChristian Marangi 497027152b8SChristian Marangi exit: 498027152b8SChristian Marangi mutex_unlock(&bus->mdio_lock); 499027152b8SChristian Marangi 500027152b8SChristian Marangi return ret; 501027152b8SChristian Marangi } 502027152b8SChristian Marangi 503c766e077SChristian Marangi static int 504c766e077SChristian Marangi qca8k_bulk_read(void *ctx, const void *reg_buf, size_t reg_len, 505c766e077SChristian Marangi void *val_buf, size_t val_len) 506c766e077SChristian Marangi { 507c766e077SChristian Marangi int i, count = val_len / sizeof(u32), ret; 508c766e077SChristian Marangi u32 reg = *(u32 *)reg_buf & U16_MAX; 509c766e077SChristian Marangi struct qca8k_priv *priv = ctx; 510c766e077SChristian Marangi 511c766e077SChristian Marangi if (priv->mgmt_master && 512c766e077SChristian Marangi !qca8k_read_eth(priv, reg, val_buf, val_len)) 513c766e077SChristian Marangi return 0; 514c766e077SChristian Marangi 515c766e077SChristian Marangi /* loop count times and increment reg of 4 */ 516c766e077SChristian Marangi for (i = 0; i < count; i++, reg += sizeof(u32)) { 517c766e077SChristian Marangi ret = qca8k_read_mii(priv, reg, val_buf + i); 518c766e077SChristian Marangi if (ret < 0) 519c766e077SChristian Marangi return ret; 520c766e077SChristian Marangi } 521c766e077SChristian Marangi 522c766e077SChristian Marangi return 0; 523c766e077SChristian Marangi } 524c766e077SChristian Marangi 525c766e077SChristian Marangi static int 526c766e077SChristian Marangi qca8k_bulk_gather_write(void *ctx, const void *reg_buf, size_t reg_len, 527c766e077SChristian Marangi const void *val_buf, size_t val_len) 528c766e077SChristian Marangi { 529c766e077SChristian Marangi int i, count = val_len / sizeof(u32), ret; 530c766e077SChristian Marangi u32 reg = *(u32 *)reg_buf & U16_MAX; 531c766e077SChristian Marangi struct qca8k_priv *priv = ctx; 532c766e077SChristian Marangi u32 *val = (u32 *)val_buf; 533c766e077SChristian Marangi 534c766e077SChristian Marangi if (priv->mgmt_master && 535c766e077SChristian Marangi !qca8k_write_eth(priv, reg, val, val_len)) 536c766e077SChristian Marangi return 0; 537c766e077SChristian Marangi 538c766e077SChristian Marangi /* loop count times, increment reg of 4 and increment val ptr to 539c766e077SChristian Marangi * the next value 540c766e077SChristian Marangi */ 541c766e077SChristian Marangi for (i = 0; i < count; i++, reg += sizeof(u32), val++) { 542c766e077SChristian Marangi ret = qca8k_write_mii(priv, reg, *val); 543c766e077SChristian Marangi if (ret < 0) 544c766e077SChristian Marangi return ret; 545c766e077SChristian Marangi } 546c766e077SChristian Marangi 547c766e077SChristian Marangi return 0; 548c766e077SChristian Marangi } 549c766e077SChristian Marangi 550c766e077SChristian Marangi static int 551c766e077SChristian Marangi qca8k_bulk_write(void *ctx, const void *data, size_t bytes) 552c766e077SChristian Marangi { 553c766e077SChristian Marangi return qca8k_bulk_gather_write(ctx, data, sizeof(u16), data + sizeof(u16), 554c766e077SChristian Marangi bytes - sizeof(u16)); 555c766e077SChristian Marangi } 556c766e077SChristian Marangi 557c766e077SChristian Marangi static int 558c766e077SChristian Marangi qca8k_regmap_update_bits(void *ctx, uint32_t reg, uint32_t mask, uint32_t write_val) 559c766e077SChristian Marangi { 560c766e077SChristian Marangi struct qca8k_priv *priv = ctx; 561c766e077SChristian Marangi 562c766e077SChristian Marangi if (!qca8k_regmap_update_bits_eth(priv, reg, mask, write_val)) 563c766e077SChristian Marangi return 0; 564c766e077SChristian Marangi 565c766e077SChristian Marangi return qca8k_regmap_update_bits_mii(priv, reg, mask, write_val); 566c766e077SChristian Marangi } 567c766e077SChristian Marangi 568027152b8SChristian Marangi static struct regmap_config qca8k_regmap_config = { 569027152b8SChristian Marangi .reg_bits = 16, 570027152b8SChristian Marangi .val_bits = 32, 571027152b8SChristian Marangi .reg_stride = 4, 572027152b8SChristian Marangi .max_register = 0x16ac, /* end MIB - Port6 range */ 573c766e077SChristian Marangi .read = qca8k_bulk_read, 574c766e077SChristian Marangi .write = qca8k_bulk_write, 575027152b8SChristian Marangi .reg_update_bits = qca8k_regmap_update_bits, 576027152b8SChristian Marangi .rd_table = &qca8k_readable_table, 577027152b8SChristian Marangi .disable_locking = true, /* Locking is handled by qca8k read/write */ 578027152b8SChristian Marangi .cache_type = REGCACHE_NONE, /* Explicitly disable CACHE */ 579c766e077SChristian Marangi .max_raw_read = 32, /* mgmt eth can read/write up to 8 registers at time */ 580c766e077SChristian Marangi .max_raw_write = 32, 581027152b8SChristian Marangi }; 582027152b8SChristian Marangi 583027152b8SChristian Marangi static int 584027152b8SChristian Marangi qca8k_phy_eth_busy_wait(struct qca8k_mgmt_eth_data *mgmt_eth_data, 585027152b8SChristian Marangi struct sk_buff *read_skb, u32 *val) 586027152b8SChristian Marangi { 587027152b8SChristian Marangi struct sk_buff *skb = skb_copy(read_skb, GFP_KERNEL); 588027152b8SChristian Marangi bool ack; 589027152b8SChristian Marangi int ret; 590027152b8SChristian Marangi 591027152b8SChristian Marangi reinit_completion(&mgmt_eth_data->rw_done); 592027152b8SChristian Marangi 593027152b8SChristian Marangi /* Increment seq_num and set it in the copy pkt */ 594027152b8SChristian Marangi mgmt_eth_data->seq++; 595027152b8SChristian Marangi qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq); 596027152b8SChristian Marangi mgmt_eth_data->ack = false; 597027152b8SChristian Marangi 598027152b8SChristian Marangi dev_queue_xmit(skb); 599027152b8SChristian Marangi 600027152b8SChristian Marangi ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, 601027152b8SChristian Marangi QCA8K_ETHERNET_TIMEOUT); 602027152b8SChristian Marangi 603027152b8SChristian Marangi ack = mgmt_eth_data->ack; 604027152b8SChristian Marangi 605027152b8SChristian Marangi if (ret <= 0) 606027152b8SChristian Marangi return -ETIMEDOUT; 607027152b8SChristian Marangi 608027152b8SChristian Marangi if (!ack) 609027152b8SChristian Marangi return -EINVAL; 610027152b8SChristian Marangi 611027152b8SChristian Marangi *val = mgmt_eth_data->data[0]; 612027152b8SChristian Marangi 613027152b8SChristian Marangi return 0; 614027152b8SChristian Marangi } 615027152b8SChristian Marangi 616027152b8SChristian Marangi static int 617027152b8SChristian Marangi qca8k_phy_eth_command(struct qca8k_priv *priv, bool read, int phy, 618027152b8SChristian Marangi int regnum, u16 data) 619027152b8SChristian Marangi { 620027152b8SChristian Marangi struct sk_buff *write_skb, *clear_skb, *read_skb; 621027152b8SChristian Marangi struct qca8k_mgmt_eth_data *mgmt_eth_data; 622027152b8SChristian Marangi u32 write_val, clear_val = 0, val; 623027152b8SChristian Marangi struct net_device *mgmt_master; 624027152b8SChristian Marangi int ret, ret1; 625027152b8SChristian Marangi bool ack; 626027152b8SChristian Marangi 627027152b8SChristian Marangi if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) 628027152b8SChristian Marangi return -EINVAL; 629027152b8SChristian Marangi 630027152b8SChristian Marangi mgmt_eth_data = &priv->mgmt_eth_data; 631027152b8SChristian Marangi 632027152b8SChristian Marangi write_val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | 633027152b8SChristian Marangi QCA8K_MDIO_MASTER_PHY_ADDR(phy) | 634027152b8SChristian Marangi QCA8K_MDIO_MASTER_REG_ADDR(regnum); 635027152b8SChristian Marangi 636027152b8SChristian Marangi if (read) { 637027152b8SChristian Marangi write_val |= QCA8K_MDIO_MASTER_READ; 638027152b8SChristian Marangi } else { 639027152b8SChristian Marangi write_val |= QCA8K_MDIO_MASTER_WRITE; 640027152b8SChristian Marangi write_val |= QCA8K_MDIO_MASTER_DATA(data); 641027152b8SChristian Marangi } 642027152b8SChristian Marangi 643027152b8SChristian Marangi /* Prealloc all the needed skb before the lock */ 644027152b8SChristian Marangi write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val, 645027152b8SChristian Marangi QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val)); 646027152b8SChristian Marangi if (!write_skb) 647027152b8SChristian Marangi return -ENOMEM; 648027152b8SChristian Marangi 649027152b8SChristian Marangi clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val, 650027152b8SChristian Marangi QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); 651027152b8SChristian Marangi if (!clear_skb) { 652027152b8SChristian Marangi ret = -ENOMEM; 653027152b8SChristian Marangi goto err_clear_skb; 654027152b8SChristian Marangi } 655027152b8SChristian Marangi 656027152b8SChristian Marangi read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val, 657027152b8SChristian Marangi QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); 658027152b8SChristian Marangi if (!read_skb) { 659027152b8SChristian Marangi ret = -ENOMEM; 660027152b8SChristian Marangi goto err_read_skb; 661027152b8SChristian Marangi } 662027152b8SChristian Marangi 663027152b8SChristian Marangi /* Actually start the request: 664027152b8SChristian Marangi * 1. Send mdio master packet 665027152b8SChristian Marangi * 2. Busy Wait for mdio master command 666027152b8SChristian Marangi * 3. Get the data if we are reading 667027152b8SChristian Marangi * 4. Reset the mdio master (even with error) 668027152b8SChristian Marangi */ 669027152b8SChristian Marangi mutex_lock(&mgmt_eth_data->mutex); 670027152b8SChristian Marangi 671027152b8SChristian Marangi /* Check if mgmt_master is operational */ 672027152b8SChristian Marangi mgmt_master = priv->mgmt_master; 673027152b8SChristian Marangi if (!mgmt_master) { 674027152b8SChristian Marangi mutex_unlock(&mgmt_eth_data->mutex); 675027152b8SChristian Marangi ret = -EINVAL; 676027152b8SChristian Marangi goto err_mgmt_master; 677027152b8SChristian Marangi } 678027152b8SChristian Marangi 679027152b8SChristian Marangi read_skb->dev = mgmt_master; 680027152b8SChristian Marangi clear_skb->dev = mgmt_master; 681027152b8SChristian Marangi write_skb->dev = mgmt_master; 682027152b8SChristian Marangi 683027152b8SChristian Marangi reinit_completion(&mgmt_eth_data->rw_done); 684027152b8SChristian Marangi 685027152b8SChristian Marangi /* Increment seq_num and set it in the write pkt */ 686027152b8SChristian Marangi mgmt_eth_data->seq++; 687027152b8SChristian Marangi qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq); 688027152b8SChristian Marangi mgmt_eth_data->ack = false; 689027152b8SChristian Marangi 690027152b8SChristian Marangi dev_queue_xmit(write_skb); 691027152b8SChristian Marangi 692027152b8SChristian Marangi ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, 693027152b8SChristian Marangi QCA8K_ETHERNET_TIMEOUT); 694027152b8SChristian Marangi 695027152b8SChristian Marangi ack = mgmt_eth_data->ack; 696027152b8SChristian Marangi 697027152b8SChristian Marangi if (ret <= 0) { 698027152b8SChristian Marangi ret = -ETIMEDOUT; 699027152b8SChristian Marangi kfree_skb(read_skb); 700027152b8SChristian Marangi goto exit; 701027152b8SChristian Marangi } 702027152b8SChristian Marangi 703027152b8SChristian Marangi if (!ack) { 704027152b8SChristian Marangi ret = -EINVAL; 705027152b8SChristian Marangi kfree_skb(read_skb); 706027152b8SChristian Marangi goto exit; 707027152b8SChristian Marangi } 708027152b8SChristian Marangi 709027152b8SChristian Marangi ret = read_poll_timeout(qca8k_phy_eth_busy_wait, ret1, 710027152b8SChristian Marangi !(val & QCA8K_MDIO_MASTER_BUSY), 0, 711027152b8SChristian Marangi QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, 712027152b8SChristian Marangi mgmt_eth_data, read_skb, &val); 713027152b8SChristian Marangi 714027152b8SChristian Marangi if (ret < 0 && ret1 < 0) { 715027152b8SChristian Marangi ret = ret1; 716027152b8SChristian Marangi goto exit; 717027152b8SChristian Marangi } 718027152b8SChristian Marangi 719027152b8SChristian Marangi if (read) { 720027152b8SChristian Marangi reinit_completion(&mgmt_eth_data->rw_done); 721027152b8SChristian Marangi 722027152b8SChristian Marangi /* Increment seq_num and set it in the read pkt */ 723027152b8SChristian Marangi mgmt_eth_data->seq++; 724027152b8SChristian Marangi qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq); 725027152b8SChristian Marangi mgmt_eth_data->ack = false; 726027152b8SChristian Marangi 727027152b8SChristian Marangi dev_queue_xmit(read_skb); 728027152b8SChristian Marangi 729027152b8SChristian Marangi ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done, 730027152b8SChristian Marangi QCA8K_ETHERNET_TIMEOUT); 731027152b8SChristian Marangi 732027152b8SChristian Marangi ack = mgmt_eth_data->ack; 733027152b8SChristian Marangi 734027152b8SChristian Marangi if (ret <= 0) { 735027152b8SChristian Marangi ret = -ETIMEDOUT; 736027152b8SChristian Marangi goto exit; 737027152b8SChristian Marangi } 738027152b8SChristian Marangi 739027152b8SChristian Marangi if (!ack) { 740027152b8SChristian Marangi ret = -EINVAL; 741027152b8SChristian Marangi goto exit; 742027152b8SChristian Marangi } 743027152b8SChristian Marangi 744027152b8SChristian Marangi ret = mgmt_eth_data->data[0] & QCA8K_MDIO_MASTER_DATA_MASK; 745027152b8SChristian Marangi } else { 746027152b8SChristian Marangi kfree_skb(read_skb); 747027152b8SChristian Marangi } 748027152b8SChristian Marangi exit: 749027152b8SChristian Marangi reinit_completion(&mgmt_eth_data->rw_done); 750027152b8SChristian Marangi 751027152b8SChristian Marangi /* Increment seq_num and set it in the clear pkt */ 752027152b8SChristian Marangi mgmt_eth_data->seq++; 753027152b8SChristian Marangi qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq); 754027152b8SChristian Marangi mgmt_eth_data->ack = false; 755027152b8SChristian Marangi 756027152b8SChristian Marangi dev_queue_xmit(clear_skb); 757027152b8SChristian Marangi 758027152b8SChristian Marangi wait_for_completion_timeout(&mgmt_eth_data->rw_done, 759027152b8SChristian Marangi QCA8K_ETHERNET_TIMEOUT); 760027152b8SChristian Marangi 761027152b8SChristian Marangi mutex_unlock(&mgmt_eth_data->mutex); 762027152b8SChristian Marangi 763027152b8SChristian Marangi return ret; 764027152b8SChristian Marangi 765027152b8SChristian Marangi /* Error handling before lock */ 766027152b8SChristian Marangi err_mgmt_master: 767027152b8SChristian Marangi kfree_skb(read_skb); 768027152b8SChristian Marangi err_read_skb: 769027152b8SChristian Marangi kfree_skb(clear_skb); 770027152b8SChristian Marangi err_clear_skb: 771027152b8SChristian Marangi kfree_skb(write_skb); 772027152b8SChristian Marangi 773027152b8SChristian Marangi return ret; 774027152b8SChristian Marangi } 775027152b8SChristian Marangi 776027152b8SChristian Marangi static int 777027152b8SChristian Marangi qca8k_mdio_busy_wait(struct mii_bus *bus, u32 reg, u32 mask) 778027152b8SChristian Marangi { 779027152b8SChristian Marangi u16 r1, r2, page; 780027152b8SChristian Marangi u32 val; 781027152b8SChristian Marangi int ret, ret1; 782027152b8SChristian Marangi 783027152b8SChristian Marangi qca8k_split_addr(reg, &r1, &r2, &page); 784027152b8SChristian Marangi 785a4165830SChristian Marangi ret = read_poll_timeout(qca8k_mii_read_hi, ret1, !(val & mask), 0, 786027152b8SChristian Marangi QCA8K_BUSY_WAIT_TIMEOUT * USEC_PER_MSEC, false, 787a4165830SChristian Marangi bus, 0x10 | r2, r1 + 1, &val); 788027152b8SChristian Marangi 789027152b8SChristian Marangi /* Check if qca8k_read has failed for a different reason 790027152b8SChristian Marangi * before returnting -ETIMEDOUT 791027152b8SChristian Marangi */ 792027152b8SChristian Marangi if (ret < 0 && ret1 < 0) 793027152b8SChristian Marangi return ret1; 794027152b8SChristian Marangi 795027152b8SChristian Marangi return ret; 796027152b8SChristian Marangi } 797027152b8SChristian Marangi 798027152b8SChristian Marangi static int 799027152b8SChristian Marangi qca8k_mdio_write(struct qca8k_priv *priv, int phy, int regnum, u16 data) 800027152b8SChristian Marangi { 801027152b8SChristian Marangi struct mii_bus *bus = priv->bus; 802027152b8SChristian Marangi u16 r1, r2, page; 803027152b8SChristian Marangi u32 val; 804027152b8SChristian Marangi int ret; 805027152b8SChristian Marangi 806027152b8SChristian Marangi if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) 807027152b8SChristian Marangi return -EINVAL; 808027152b8SChristian Marangi 809027152b8SChristian Marangi val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | 810027152b8SChristian Marangi QCA8K_MDIO_MASTER_WRITE | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | 811027152b8SChristian Marangi QCA8K_MDIO_MASTER_REG_ADDR(regnum) | 812027152b8SChristian Marangi QCA8K_MDIO_MASTER_DATA(data); 813027152b8SChristian Marangi 814027152b8SChristian Marangi qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); 815027152b8SChristian Marangi 816027152b8SChristian Marangi mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); 817027152b8SChristian Marangi 818027152b8SChristian Marangi ret = qca8k_set_page(priv, page); 819027152b8SChristian Marangi if (ret) 820027152b8SChristian Marangi goto exit; 821027152b8SChristian Marangi 82203cb9e6dSChristian Marangi qca8k_mii_write32(bus, 0x10 | r2, r1, val); 823027152b8SChristian Marangi 824027152b8SChristian Marangi ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, 825027152b8SChristian Marangi QCA8K_MDIO_MASTER_BUSY); 826027152b8SChristian Marangi 827027152b8SChristian Marangi exit: 828027152b8SChristian Marangi /* even if the busy_wait timeouts try to clear the MASTER_EN */ 829a4165830SChristian Marangi qca8k_mii_write_hi(bus, 0x10 | r2, r1 + 1, 0); 830027152b8SChristian Marangi 831027152b8SChristian Marangi mutex_unlock(&bus->mdio_lock); 832027152b8SChristian Marangi 833027152b8SChristian Marangi return ret; 834027152b8SChristian Marangi } 835027152b8SChristian Marangi 836027152b8SChristian Marangi static int 837027152b8SChristian Marangi qca8k_mdio_read(struct qca8k_priv *priv, int phy, int regnum) 838027152b8SChristian Marangi { 839027152b8SChristian Marangi struct mii_bus *bus = priv->bus; 840027152b8SChristian Marangi u16 r1, r2, page; 841027152b8SChristian Marangi u32 val; 842027152b8SChristian Marangi int ret; 843027152b8SChristian Marangi 844027152b8SChristian Marangi if (regnum >= QCA8K_MDIO_MASTER_MAX_REG) 845027152b8SChristian Marangi return -EINVAL; 846027152b8SChristian Marangi 847027152b8SChristian Marangi val = QCA8K_MDIO_MASTER_BUSY | QCA8K_MDIO_MASTER_EN | 848027152b8SChristian Marangi QCA8K_MDIO_MASTER_READ | QCA8K_MDIO_MASTER_PHY_ADDR(phy) | 849027152b8SChristian Marangi QCA8K_MDIO_MASTER_REG_ADDR(regnum); 850027152b8SChristian Marangi 851027152b8SChristian Marangi qca8k_split_addr(QCA8K_MDIO_MASTER_CTRL, &r1, &r2, &page); 852027152b8SChristian Marangi 853027152b8SChristian Marangi mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); 854027152b8SChristian Marangi 855027152b8SChristian Marangi ret = qca8k_set_page(priv, page); 856027152b8SChristian Marangi if (ret) 857027152b8SChristian Marangi goto exit; 858027152b8SChristian Marangi 859a4165830SChristian Marangi qca8k_mii_write_hi(bus, 0x10 | r2, r1 + 1, val); 860027152b8SChristian Marangi 861027152b8SChristian Marangi ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL, 862027152b8SChristian Marangi QCA8K_MDIO_MASTER_BUSY); 863027152b8SChristian Marangi if (ret) 864027152b8SChristian Marangi goto exit; 865027152b8SChristian Marangi 866a4165830SChristian Marangi ret = qca8k_mii_read_lo(bus, 0x10 | r2, r1, &val); 867027152b8SChristian Marangi 868027152b8SChristian Marangi exit: 869027152b8SChristian Marangi /* even if the busy_wait timeouts try to clear the MASTER_EN */ 870a4165830SChristian Marangi qca8k_mii_write_hi(bus, 0x10 | r2, r1 + 1, 0); 871027152b8SChristian Marangi 872027152b8SChristian Marangi mutex_unlock(&bus->mdio_lock); 873027152b8SChristian Marangi 874027152b8SChristian Marangi if (ret >= 0) 875027152b8SChristian Marangi ret = val & QCA8K_MDIO_MASTER_DATA_MASK; 876027152b8SChristian Marangi 877027152b8SChristian Marangi return ret; 878027152b8SChristian Marangi } 879027152b8SChristian Marangi 880027152b8SChristian Marangi static int 881027152b8SChristian Marangi qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data) 882027152b8SChristian Marangi { 883027152b8SChristian Marangi struct qca8k_priv *priv = slave_bus->priv; 884027152b8SChristian Marangi int ret; 885027152b8SChristian Marangi 886027152b8SChristian Marangi /* Use mdio Ethernet when available, fallback to legacy one on error */ 887027152b8SChristian Marangi ret = qca8k_phy_eth_command(priv, false, phy, regnum, data); 888027152b8SChristian Marangi if (!ret) 889027152b8SChristian Marangi return 0; 890027152b8SChristian Marangi 891027152b8SChristian Marangi return qca8k_mdio_write(priv, phy, regnum, data); 892027152b8SChristian Marangi } 893027152b8SChristian Marangi 894027152b8SChristian Marangi static int 895027152b8SChristian Marangi qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum) 896027152b8SChristian Marangi { 897027152b8SChristian Marangi struct qca8k_priv *priv = slave_bus->priv; 898027152b8SChristian Marangi int ret; 899027152b8SChristian Marangi 900027152b8SChristian Marangi /* Use mdio Ethernet when available, fallback to legacy one on error */ 901027152b8SChristian Marangi ret = qca8k_phy_eth_command(priv, true, phy, regnum, 0); 902027152b8SChristian Marangi if (ret >= 0) 903027152b8SChristian Marangi return ret; 904027152b8SChristian Marangi 905027152b8SChristian Marangi ret = qca8k_mdio_read(priv, phy, regnum); 906027152b8SChristian Marangi 907027152b8SChristian Marangi if (ret < 0) 908027152b8SChristian Marangi return 0xffff; 909027152b8SChristian Marangi 910027152b8SChristian Marangi return ret; 911027152b8SChristian Marangi } 912027152b8SChristian Marangi 913027152b8SChristian Marangi static int 914027152b8SChristian Marangi qca8k_legacy_mdio_write(struct mii_bus *slave_bus, int port, int regnum, u16 data) 915027152b8SChristian Marangi { 916027152b8SChristian Marangi port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; 917027152b8SChristian Marangi 918027152b8SChristian Marangi return qca8k_internal_mdio_write(slave_bus, port, regnum, data); 919027152b8SChristian Marangi } 920027152b8SChristian Marangi 921027152b8SChristian Marangi static int 922027152b8SChristian Marangi qca8k_legacy_mdio_read(struct mii_bus *slave_bus, int port, int regnum) 923027152b8SChristian Marangi { 924027152b8SChristian Marangi port = qca8k_port_to_phy(port) % PHY_MAX_ADDR; 925027152b8SChristian Marangi 926027152b8SChristian Marangi return qca8k_internal_mdio_read(slave_bus, port, regnum); 927027152b8SChristian Marangi } 928027152b8SChristian Marangi 929027152b8SChristian Marangi static int 930027152b8SChristian Marangi qca8k_mdio_register(struct qca8k_priv *priv) 931027152b8SChristian Marangi { 932027152b8SChristian Marangi struct dsa_switch *ds = priv->ds; 933027152b8SChristian Marangi struct device_node *mdio; 934027152b8SChristian Marangi struct mii_bus *bus; 935027152b8SChristian Marangi 936027152b8SChristian Marangi bus = devm_mdiobus_alloc(ds->dev); 937027152b8SChristian Marangi if (!bus) 938027152b8SChristian Marangi return -ENOMEM; 939027152b8SChristian Marangi 940027152b8SChristian Marangi bus->priv = (void *)priv; 941027152b8SChristian Marangi snprintf(bus->id, MII_BUS_ID_SIZE, "qca8k-%d.%d", 942027152b8SChristian Marangi ds->dst->index, ds->index); 943027152b8SChristian Marangi bus->parent = ds->dev; 944027152b8SChristian Marangi bus->phy_mask = ~ds->phys_mii_mask; 945027152b8SChristian Marangi ds->slave_mii_bus = bus; 946027152b8SChristian Marangi 947027152b8SChristian Marangi /* Check if the devicetree declare the port:phy mapping */ 948027152b8SChristian Marangi mdio = of_get_child_by_name(priv->dev->of_node, "mdio"); 949027152b8SChristian Marangi if (of_device_is_available(mdio)) { 950027152b8SChristian Marangi bus->name = "qca8k slave mii"; 951027152b8SChristian Marangi bus->read = qca8k_internal_mdio_read; 952027152b8SChristian Marangi bus->write = qca8k_internal_mdio_write; 953027152b8SChristian Marangi return devm_of_mdiobus_register(priv->dev, bus, mdio); 954027152b8SChristian Marangi } 955027152b8SChristian Marangi 956027152b8SChristian Marangi /* If a mapping can't be found the legacy mapping is used, 957027152b8SChristian Marangi * using the qca8k_port_to_phy function 958027152b8SChristian Marangi */ 959027152b8SChristian Marangi bus->name = "qca8k-legacy slave mii"; 960027152b8SChristian Marangi bus->read = qca8k_legacy_mdio_read; 961027152b8SChristian Marangi bus->write = qca8k_legacy_mdio_write; 962027152b8SChristian Marangi return devm_mdiobus_register(priv->dev, bus); 963027152b8SChristian Marangi } 964027152b8SChristian Marangi 965027152b8SChristian Marangi static int 966027152b8SChristian Marangi qca8k_setup_mdio_bus(struct qca8k_priv *priv) 967027152b8SChristian Marangi { 968027152b8SChristian Marangi u32 internal_mdio_mask = 0, external_mdio_mask = 0, reg; 969027152b8SChristian Marangi struct device_node *ports, *port; 970027152b8SChristian Marangi phy_interface_t mode; 971027152b8SChristian Marangi int err; 972027152b8SChristian Marangi 973027152b8SChristian Marangi ports = of_get_child_by_name(priv->dev->of_node, "ports"); 974027152b8SChristian Marangi if (!ports) 975027152b8SChristian Marangi ports = of_get_child_by_name(priv->dev->of_node, "ethernet-ports"); 976027152b8SChristian Marangi 977027152b8SChristian Marangi if (!ports) 978027152b8SChristian Marangi return -EINVAL; 979027152b8SChristian Marangi 980027152b8SChristian Marangi for_each_available_child_of_node(ports, port) { 981027152b8SChristian Marangi err = of_property_read_u32(port, "reg", ®); 982027152b8SChristian Marangi if (err) { 983027152b8SChristian Marangi of_node_put(port); 984027152b8SChristian Marangi of_node_put(ports); 985027152b8SChristian Marangi return err; 986027152b8SChristian Marangi } 987027152b8SChristian Marangi 988027152b8SChristian Marangi if (!dsa_is_user_port(priv->ds, reg)) 989027152b8SChristian Marangi continue; 990027152b8SChristian Marangi 991027152b8SChristian Marangi of_get_phy_mode(port, &mode); 992027152b8SChristian Marangi 993027152b8SChristian Marangi if (of_property_read_bool(port, "phy-handle") && 994027152b8SChristian Marangi mode != PHY_INTERFACE_MODE_INTERNAL) 995027152b8SChristian Marangi external_mdio_mask |= BIT(reg); 996027152b8SChristian Marangi else 997027152b8SChristian Marangi internal_mdio_mask |= BIT(reg); 998027152b8SChristian Marangi } 999027152b8SChristian Marangi 1000027152b8SChristian Marangi of_node_put(ports); 1001027152b8SChristian Marangi if (!external_mdio_mask && !internal_mdio_mask) { 1002027152b8SChristian Marangi dev_err(priv->dev, "no PHYs are defined.\n"); 1003027152b8SChristian Marangi return -EINVAL; 1004027152b8SChristian Marangi } 1005027152b8SChristian Marangi 1006027152b8SChristian Marangi /* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through 1007027152b8SChristian Marangi * the MDIO_MASTER register also _disconnects_ the external MDC 1008027152b8SChristian Marangi * passthrough to the internal PHYs. It's not possible to use both 1009027152b8SChristian Marangi * configurations at the same time! 1010027152b8SChristian Marangi * 1011027152b8SChristian Marangi * Because this came up during the review process: 1012027152b8SChristian Marangi * If the external mdio-bus driver is capable magically disabling 1013027152b8SChristian Marangi * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's 1014027152b8SChristian Marangi * accessors for the time being, it would be possible to pull this 1015027152b8SChristian Marangi * off. 1016027152b8SChristian Marangi */ 1017027152b8SChristian Marangi if (!!external_mdio_mask && !!internal_mdio_mask) { 1018027152b8SChristian Marangi dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); 1019027152b8SChristian Marangi return -EINVAL; 1020027152b8SChristian Marangi } 1021027152b8SChristian Marangi 1022027152b8SChristian Marangi if (external_mdio_mask) { 1023027152b8SChristian Marangi /* Make sure to disable the internal mdio bus in cases 1024027152b8SChristian Marangi * a dt-overlay and driver reload changed the configuration 1025027152b8SChristian Marangi */ 1026027152b8SChristian Marangi 1027027152b8SChristian Marangi return regmap_clear_bits(priv->regmap, QCA8K_MDIO_MASTER_CTRL, 1028027152b8SChristian Marangi QCA8K_MDIO_MASTER_EN); 1029027152b8SChristian Marangi } 1030027152b8SChristian Marangi 1031027152b8SChristian Marangi return qca8k_mdio_register(priv); 1032027152b8SChristian Marangi } 1033027152b8SChristian Marangi 1034027152b8SChristian Marangi static int 1035027152b8SChristian Marangi qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv) 1036027152b8SChristian Marangi { 1037027152b8SChristian Marangi u32 mask = 0; 1038027152b8SChristian Marangi int ret = 0; 1039027152b8SChristian Marangi 1040027152b8SChristian Marangi /* SoC specific settings for ipq8064. 1041027152b8SChristian Marangi * If more device require this consider adding 1042027152b8SChristian Marangi * a dedicated binding. 1043027152b8SChristian Marangi */ 1044027152b8SChristian Marangi if (of_machine_is_compatible("qcom,ipq8064")) 1045027152b8SChristian Marangi mask |= QCA8K_MAC_PWR_RGMII0_1_8V; 1046027152b8SChristian Marangi 1047027152b8SChristian Marangi /* SoC specific settings for ipq8065 */ 1048027152b8SChristian Marangi if (of_machine_is_compatible("qcom,ipq8065")) 1049027152b8SChristian Marangi mask |= QCA8K_MAC_PWR_RGMII1_1_8V; 1050027152b8SChristian Marangi 1051027152b8SChristian Marangi if (mask) { 1052027152b8SChristian Marangi ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL, 1053027152b8SChristian Marangi QCA8K_MAC_PWR_RGMII0_1_8V | 1054027152b8SChristian Marangi QCA8K_MAC_PWR_RGMII1_1_8V, 1055027152b8SChristian Marangi mask); 1056027152b8SChristian Marangi } 1057027152b8SChristian Marangi 1058027152b8SChristian Marangi return ret; 1059027152b8SChristian Marangi } 1060027152b8SChristian Marangi 1061027152b8SChristian Marangi static int qca8k_find_cpu_port(struct dsa_switch *ds) 1062027152b8SChristian Marangi { 1063027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1064027152b8SChristian Marangi 1065027152b8SChristian Marangi /* Find the connected cpu port. Valid port are 0 or 6 */ 1066027152b8SChristian Marangi if (dsa_is_cpu_port(ds, 0)) 1067027152b8SChristian Marangi return 0; 1068027152b8SChristian Marangi 1069027152b8SChristian Marangi dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6"); 1070027152b8SChristian Marangi 1071027152b8SChristian Marangi if (dsa_is_cpu_port(ds, 6)) 1072027152b8SChristian Marangi return 6; 1073027152b8SChristian Marangi 1074027152b8SChristian Marangi return -EINVAL; 1075027152b8SChristian Marangi } 1076027152b8SChristian Marangi 1077027152b8SChristian Marangi static int 1078027152b8SChristian Marangi qca8k_setup_of_pws_reg(struct qca8k_priv *priv) 1079027152b8SChristian Marangi { 1080027152b8SChristian Marangi const struct qca8k_match_data *data = priv->info; 1081027152b8SChristian Marangi struct device_node *node = priv->dev->of_node; 1082027152b8SChristian Marangi u32 val = 0; 1083027152b8SChristian Marangi int ret; 1084027152b8SChristian Marangi 1085027152b8SChristian Marangi /* QCA8327 require to set to the correct mode. 1086027152b8SChristian Marangi * His bigger brother QCA8328 have the 172 pin layout. 1087027152b8SChristian Marangi * Should be applied by default but we set this just to make sure. 1088027152b8SChristian Marangi */ 1089027152b8SChristian Marangi if (priv->switch_id == QCA8K_ID_QCA8327) { 1090027152b8SChristian Marangi /* Set the correct package of 148 pin for QCA8327 */ 1091027152b8SChristian Marangi if (data->reduced_package) 1092027152b8SChristian Marangi val |= QCA8327_PWS_PACKAGE148_EN; 1093027152b8SChristian Marangi 1094027152b8SChristian Marangi ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN, 1095027152b8SChristian Marangi val); 1096027152b8SChristian Marangi if (ret) 1097027152b8SChristian Marangi return ret; 1098027152b8SChristian Marangi } 1099027152b8SChristian Marangi 1100027152b8SChristian Marangi if (of_property_read_bool(node, "qca,ignore-power-on-sel")) 1101027152b8SChristian Marangi val |= QCA8K_PWS_POWER_ON_SEL; 1102027152b8SChristian Marangi 1103027152b8SChristian Marangi if (of_property_read_bool(node, "qca,led-open-drain")) { 1104027152b8SChristian Marangi if (!(val & QCA8K_PWS_POWER_ON_SEL)) { 1105027152b8SChristian Marangi dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); 1106027152b8SChristian Marangi return -EINVAL; 1107027152b8SChristian Marangi } 1108027152b8SChristian Marangi 1109027152b8SChristian Marangi val |= QCA8K_PWS_LED_OPEN_EN_CSR; 1110027152b8SChristian Marangi } 1111027152b8SChristian Marangi 1112027152b8SChristian Marangi return qca8k_rmw(priv, QCA8K_REG_PWS, 1113027152b8SChristian Marangi QCA8K_PWS_LED_OPEN_EN_CSR | QCA8K_PWS_POWER_ON_SEL, 1114027152b8SChristian Marangi val); 1115027152b8SChristian Marangi } 1116027152b8SChristian Marangi 1117027152b8SChristian Marangi static int 1118027152b8SChristian Marangi qca8k_parse_port_config(struct qca8k_priv *priv) 1119027152b8SChristian Marangi { 1120027152b8SChristian Marangi int port, cpu_port_index = -1, ret; 1121027152b8SChristian Marangi struct device_node *port_dn; 1122027152b8SChristian Marangi phy_interface_t mode; 1123027152b8SChristian Marangi struct dsa_port *dp; 1124027152b8SChristian Marangi u32 delay; 1125027152b8SChristian Marangi 1126027152b8SChristian Marangi /* We have 2 CPU port. Check them */ 1127027152b8SChristian Marangi for (port = 0; port < QCA8K_NUM_PORTS; port++) { 1128027152b8SChristian Marangi /* Skip every other port */ 1129027152b8SChristian Marangi if (port != 0 && port != 6) 1130027152b8SChristian Marangi continue; 1131027152b8SChristian Marangi 1132027152b8SChristian Marangi dp = dsa_to_port(priv->ds, port); 1133027152b8SChristian Marangi port_dn = dp->dn; 1134027152b8SChristian Marangi cpu_port_index++; 1135027152b8SChristian Marangi 1136027152b8SChristian Marangi if (!of_device_is_available(port_dn)) 1137027152b8SChristian Marangi continue; 1138027152b8SChristian Marangi 1139027152b8SChristian Marangi ret = of_get_phy_mode(port_dn, &mode); 1140027152b8SChristian Marangi if (ret) 1141027152b8SChristian Marangi continue; 1142027152b8SChristian Marangi 1143027152b8SChristian Marangi switch (mode) { 1144027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII: 1145027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII_ID: 1146027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII_TXID: 1147027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII_RXID: 1148027152b8SChristian Marangi case PHY_INTERFACE_MODE_SGMII: 1149027152b8SChristian Marangi delay = 0; 1150027152b8SChristian Marangi 1151027152b8SChristian Marangi if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) 1152027152b8SChristian Marangi /* Switch regs accept value in ns, convert ps to ns */ 1153027152b8SChristian Marangi delay = delay / 1000; 1154027152b8SChristian Marangi else if (mode == PHY_INTERFACE_MODE_RGMII_ID || 1155027152b8SChristian Marangi mode == PHY_INTERFACE_MODE_RGMII_TXID) 1156027152b8SChristian Marangi delay = 1; 1157027152b8SChristian Marangi 1158027152b8SChristian Marangi if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) { 1159027152b8SChristian Marangi dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value"); 1160027152b8SChristian Marangi delay = 3; 1161027152b8SChristian Marangi } 1162027152b8SChristian Marangi 1163027152b8SChristian Marangi priv->ports_config.rgmii_tx_delay[cpu_port_index] = delay; 1164027152b8SChristian Marangi 1165027152b8SChristian Marangi delay = 0; 1166027152b8SChristian Marangi 1167027152b8SChristian Marangi if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) 1168027152b8SChristian Marangi /* Switch regs accept value in ns, convert ps to ns */ 1169027152b8SChristian Marangi delay = delay / 1000; 1170027152b8SChristian Marangi else if (mode == PHY_INTERFACE_MODE_RGMII_ID || 1171027152b8SChristian Marangi mode == PHY_INTERFACE_MODE_RGMII_RXID) 1172027152b8SChristian Marangi delay = 2; 1173027152b8SChristian Marangi 1174027152b8SChristian Marangi if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) { 1175027152b8SChristian Marangi dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value"); 1176027152b8SChristian Marangi delay = 3; 1177027152b8SChristian Marangi } 1178027152b8SChristian Marangi 1179027152b8SChristian Marangi priv->ports_config.rgmii_rx_delay[cpu_port_index] = delay; 1180027152b8SChristian Marangi 1181027152b8SChristian Marangi /* Skip sgmii parsing for rgmii* mode */ 1182027152b8SChristian Marangi if (mode == PHY_INTERFACE_MODE_RGMII || 1183027152b8SChristian Marangi mode == PHY_INTERFACE_MODE_RGMII_ID || 1184027152b8SChristian Marangi mode == PHY_INTERFACE_MODE_RGMII_TXID || 1185027152b8SChristian Marangi mode == PHY_INTERFACE_MODE_RGMII_RXID) 1186027152b8SChristian Marangi break; 1187027152b8SChristian Marangi 1188027152b8SChristian Marangi if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge")) 1189027152b8SChristian Marangi priv->ports_config.sgmii_tx_clk_falling_edge = true; 1190027152b8SChristian Marangi 1191027152b8SChristian Marangi if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge")) 1192027152b8SChristian Marangi priv->ports_config.sgmii_rx_clk_falling_edge = true; 1193027152b8SChristian Marangi 1194027152b8SChristian Marangi if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) { 1195027152b8SChristian Marangi priv->ports_config.sgmii_enable_pll = true; 1196027152b8SChristian Marangi 1197027152b8SChristian Marangi if (priv->switch_id == QCA8K_ID_QCA8327) { 1198027152b8SChristian Marangi dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling"); 1199027152b8SChristian Marangi priv->ports_config.sgmii_enable_pll = false; 1200027152b8SChristian Marangi } 1201027152b8SChristian Marangi 1202027152b8SChristian Marangi if (priv->switch_revision < 2) 1203027152b8SChristian Marangi dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more."); 1204027152b8SChristian Marangi } 1205027152b8SChristian Marangi 1206027152b8SChristian Marangi break; 1207027152b8SChristian Marangi default: 1208027152b8SChristian Marangi continue; 1209027152b8SChristian Marangi } 1210027152b8SChristian Marangi } 1211027152b8SChristian Marangi 1212027152b8SChristian Marangi return 0; 1213027152b8SChristian Marangi } 1214027152b8SChristian Marangi 1215027152b8SChristian Marangi static void 1216027152b8SChristian Marangi qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index, 1217027152b8SChristian Marangi u32 reg) 1218027152b8SChristian Marangi { 1219027152b8SChristian Marangi u32 delay, val = 0; 1220027152b8SChristian Marangi int ret; 1221027152b8SChristian Marangi 1222027152b8SChristian Marangi /* Delay can be declared in 3 different way. 1223027152b8SChristian Marangi * Mode to rgmii and internal-delay standard binding defined 1224027152b8SChristian Marangi * rgmii-id or rgmii-tx/rx phy mode set. 1225027152b8SChristian Marangi * The parse logic set a delay different than 0 only when one 1226027152b8SChristian Marangi * of the 3 different way is used. In all other case delay is 1227027152b8SChristian Marangi * not enabled. With ID or TX/RXID delay is enabled and set 1228027152b8SChristian Marangi * to the default and recommended value. 1229027152b8SChristian Marangi */ 1230027152b8SChristian Marangi if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) { 1231027152b8SChristian Marangi delay = priv->ports_config.rgmii_tx_delay[cpu_port_index]; 1232027152b8SChristian Marangi 1233027152b8SChristian Marangi val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) | 1234027152b8SChristian Marangi QCA8K_PORT_PAD_RGMII_TX_DELAY_EN; 1235027152b8SChristian Marangi } 1236027152b8SChristian Marangi 1237027152b8SChristian Marangi if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) { 1238027152b8SChristian Marangi delay = priv->ports_config.rgmii_rx_delay[cpu_port_index]; 1239027152b8SChristian Marangi 1240027152b8SChristian Marangi val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) | 1241027152b8SChristian Marangi QCA8K_PORT_PAD_RGMII_RX_DELAY_EN; 1242027152b8SChristian Marangi } 1243027152b8SChristian Marangi 1244027152b8SChristian Marangi /* Set RGMII delay based on the selected values */ 1245027152b8SChristian Marangi ret = qca8k_rmw(priv, reg, 1246027152b8SChristian Marangi QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK | 1247027152b8SChristian Marangi QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK | 1248027152b8SChristian Marangi QCA8K_PORT_PAD_RGMII_TX_DELAY_EN | 1249027152b8SChristian Marangi QCA8K_PORT_PAD_RGMII_RX_DELAY_EN, 1250027152b8SChristian Marangi val); 1251027152b8SChristian Marangi if (ret) 1252027152b8SChristian Marangi dev_err(priv->dev, "Failed to set internal delay for CPU port%d", 1253027152b8SChristian Marangi cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6); 1254027152b8SChristian Marangi } 1255027152b8SChristian Marangi 1256027152b8SChristian Marangi static struct phylink_pcs * 1257027152b8SChristian Marangi qca8k_phylink_mac_select_pcs(struct dsa_switch *ds, int port, 1258027152b8SChristian Marangi phy_interface_t interface) 1259027152b8SChristian Marangi { 1260027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1261027152b8SChristian Marangi struct phylink_pcs *pcs = NULL; 1262027152b8SChristian Marangi 1263027152b8SChristian Marangi switch (interface) { 1264027152b8SChristian Marangi case PHY_INTERFACE_MODE_SGMII: 1265027152b8SChristian Marangi case PHY_INTERFACE_MODE_1000BASEX: 1266027152b8SChristian Marangi switch (port) { 1267027152b8SChristian Marangi case 0: 1268027152b8SChristian Marangi pcs = &priv->pcs_port_0.pcs; 1269027152b8SChristian Marangi break; 1270027152b8SChristian Marangi 1271027152b8SChristian Marangi case 6: 1272027152b8SChristian Marangi pcs = &priv->pcs_port_6.pcs; 1273027152b8SChristian Marangi break; 1274027152b8SChristian Marangi } 1275027152b8SChristian Marangi break; 1276027152b8SChristian Marangi 1277027152b8SChristian Marangi default: 1278027152b8SChristian Marangi break; 1279027152b8SChristian Marangi } 1280027152b8SChristian Marangi 1281027152b8SChristian Marangi return pcs; 1282027152b8SChristian Marangi } 1283027152b8SChristian Marangi 1284027152b8SChristian Marangi static void 1285027152b8SChristian Marangi qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, 1286027152b8SChristian Marangi const struct phylink_link_state *state) 1287027152b8SChristian Marangi { 1288027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1289027152b8SChristian Marangi int cpu_port_index; 1290027152b8SChristian Marangi u32 reg; 1291027152b8SChristian Marangi 1292027152b8SChristian Marangi switch (port) { 1293027152b8SChristian Marangi case 0: /* 1st CPU port */ 1294027152b8SChristian Marangi if (state->interface != PHY_INTERFACE_MODE_RGMII && 1295027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_RGMII_ID && 1296027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_RGMII_TXID && 1297027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_RGMII_RXID && 1298027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_SGMII) 1299027152b8SChristian Marangi return; 1300027152b8SChristian Marangi 1301027152b8SChristian Marangi reg = QCA8K_REG_PORT0_PAD_CTRL; 1302027152b8SChristian Marangi cpu_port_index = QCA8K_CPU_PORT0; 1303027152b8SChristian Marangi break; 1304027152b8SChristian Marangi case 1: 1305027152b8SChristian Marangi case 2: 1306027152b8SChristian Marangi case 3: 1307027152b8SChristian Marangi case 4: 1308027152b8SChristian Marangi case 5: 1309027152b8SChristian Marangi /* Internal PHY, nothing to do */ 1310027152b8SChristian Marangi return; 1311027152b8SChristian Marangi case 6: /* 2nd CPU port / external PHY */ 1312027152b8SChristian Marangi if (state->interface != PHY_INTERFACE_MODE_RGMII && 1313027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_RGMII_ID && 1314027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_RGMII_TXID && 1315027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_RGMII_RXID && 1316027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_SGMII && 1317027152b8SChristian Marangi state->interface != PHY_INTERFACE_MODE_1000BASEX) 1318027152b8SChristian Marangi return; 1319027152b8SChristian Marangi 1320027152b8SChristian Marangi reg = QCA8K_REG_PORT6_PAD_CTRL; 1321027152b8SChristian Marangi cpu_port_index = QCA8K_CPU_PORT6; 1322027152b8SChristian Marangi break; 1323027152b8SChristian Marangi default: 1324027152b8SChristian Marangi dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port); 1325027152b8SChristian Marangi return; 1326027152b8SChristian Marangi } 1327027152b8SChristian Marangi 1328027152b8SChristian Marangi if (port != 6 && phylink_autoneg_inband(mode)) { 1329027152b8SChristian Marangi dev_err(ds->dev, "%s: in-band negotiation unsupported\n", 1330027152b8SChristian Marangi __func__); 1331027152b8SChristian Marangi return; 1332027152b8SChristian Marangi } 1333027152b8SChristian Marangi 1334027152b8SChristian Marangi switch (state->interface) { 1335027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII: 1336027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII_ID: 1337027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII_TXID: 1338027152b8SChristian Marangi case PHY_INTERFACE_MODE_RGMII_RXID: 1339027152b8SChristian Marangi qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN); 1340027152b8SChristian Marangi 1341027152b8SChristian Marangi /* Configure rgmii delay */ 1342027152b8SChristian Marangi qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); 1343027152b8SChristian Marangi 1344027152b8SChristian Marangi /* QCA8337 requires to set rgmii rx delay for all ports. 1345027152b8SChristian Marangi * This is enabled through PORT5_PAD_CTRL for all ports, 1346027152b8SChristian Marangi * rather than individual port registers. 1347027152b8SChristian Marangi */ 1348027152b8SChristian Marangi if (priv->switch_id == QCA8K_ID_QCA8337) 1349027152b8SChristian Marangi qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL, 1350027152b8SChristian Marangi QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); 1351027152b8SChristian Marangi break; 1352027152b8SChristian Marangi case PHY_INTERFACE_MODE_SGMII: 1353027152b8SChristian Marangi case PHY_INTERFACE_MODE_1000BASEX: 1354027152b8SChristian Marangi /* Enable SGMII on the port */ 1355027152b8SChristian Marangi qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); 1356027152b8SChristian Marangi break; 1357027152b8SChristian Marangi default: 1358027152b8SChristian Marangi dev_err(ds->dev, "xMII mode %s not supported for port %d\n", 1359027152b8SChristian Marangi phy_modes(state->interface), port); 1360027152b8SChristian Marangi return; 1361027152b8SChristian Marangi } 1362027152b8SChristian Marangi } 1363027152b8SChristian Marangi 1364027152b8SChristian Marangi static void qca8k_phylink_get_caps(struct dsa_switch *ds, int port, 1365027152b8SChristian Marangi struct phylink_config *config) 1366027152b8SChristian Marangi { 1367027152b8SChristian Marangi switch (port) { 1368027152b8SChristian Marangi case 0: /* 1st CPU port */ 1369027152b8SChristian Marangi phy_interface_set_rgmii(config->supported_interfaces); 1370027152b8SChristian Marangi __set_bit(PHY_INTERFACE_MODE_SGMII, 1371027152b8SChristian Marangi config->supported_interfaces); 1372027152b8SChristian Marangi break; 1373027152b8SChristian Marangi 1374027152b8SChristian Marangi case 1: 1375027152b8SChristian Marangi case 2: 1376027152b8SChristian Marangi case 3: 1377027152b8SChristian Marangi case 4: 1378027152b8SChristian Marangi case 5: 1379027152b8SChristian Marangi /* Internal PHY */ 1380027152b8SChristian Marangi __set_bit(PHY_INTERFACE_MODE_GMII, 1381027152b8SChristian Marangi config->supported_interfaces); 1382027152b8SChristian Marangi __set_bit(PHY_INTERFACE_MODE_INTERNAL, 1383027152b8SChristian Marangi config->supported_interfaces); 1384027152b8SChristian Marangi break; 1385027152b8SChristian Marangi 1386027152b8SChristian Marangi case 6: /* 2nd CPU port / external PHY */ 1387027152b8SChristian Marangi phy_interface_set_rgmii(config->supported_interfaces); 1388027152b8SChristian Marangi __set_bit(PHY_INTERFACE_MODE_SGMII, 1389027152b8SChristian Marangi config->supported_interfaces); 1390027152b8SChristian Marangi __set_bit(PHY_INTERFACE_MODE_1000BASEX, 1391027152b8SChristian Marangi config->supported_interfaces); 1392027152b8SChristian Marangi break; 1393027152b8SChristian Marangi } 1394027152b8SChristian Marangi 1395027152b8SChristian Marangi config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | 1396027152b8SChristian Marangi MAC_10 | MAC_100 | MAC_1000FD; 1397027152b8SChristian Marangi 1398027152b8SChristian Marangi config->legacy_pre_march2020 = false; 1399027152b8SChristian Marangi } 1400027152b8SChristian Marangi 1401027152b8SChristian Marangi static void 1402027152b8SChristian Marangi qca8k_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, 1403027152b8SChristian Marangi phy_interface_t interface) 1404027152b8SChristian Marangi { 1405027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1406027152b8SChristian Marangi 1407027152b8SChristian Marangi qca8k_port_set_status(priv, port, 0); 1408027152b8SChristian Marangi } 1409027152b8SChristian Marangi 1410027152b8SChristian Marangi static void 1411027152b8SChristian Marangi qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode, 1412027152b8SChristian Marangi phy_interface_t interface, struct phy_device *phydev, 1413027152b8SChristian Marangi int speed, int duplex, bool tx_pause, bool rx_pause) 1414027152b8SChristian Marangi { 1415027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1416027152b8SChristian Marangi u32 reg; 1417027152b8SChristian Marangi 1418027152b8SChristian Marangi if (phylink_autoneg_inband(mode)) { 1419027152b8SChristian Marangi reg = QCA8K_PORT_STATUS_LINK_AUTO; 1420027152b8SChristian Marangi } else { 1421027152b8SChristian Marangi switch (speed) { 1422027152b8SChristian Marangi case SPEED_10: 1423027152b8SChristian Marangi reg = QCA8K_PORT_STATUS_SPEED_10; 1424027152b8SChristian Marangi break; 1425027152b8SChristian Marangi case SPEED_100: 1426027152b8SChristian Marangi reg = QCA8K_PORT_STATUS_SPEED_100; 1427027152b8SChristian Marangi break; 1428027152b8SChristian Marangi case SPEED_1000: 1429027152b8SChristian Marangi reg = QCA8K_PORT_STATUS_SPEED_1000; 1430027152b8SChristian Marangi break; 1431027152b8SChristian Marangi default: 1432027152b8SChristian Marangi reg = QCA8K_PORT_STATUS_LINK_AUTO; 1433027152b8SChristian Marangi break; 1434027152b8SChristian Marangi } 1435027152b8SChristian Marangi 1436027152b8SChristian Marangi if (duplex == DUPLEX_FULL) 1437027152b8SChristian Marangi reg |= QCA8K_PORT_STATUS_DUPLEX; 1438027152b8SChristian Marangi 1439027152b8SChristian Marangi if (rx_pause || dsa_is_cpu_port(ds, port)) 1440027152b8SChristian Marangi reg |= QCA8K_PORT_STATUS_RXFLOW; 1441027152b8SChristian Marangi 1442027152b8SChristian Marangi if (tx_pause || dsa_is_cpu_port(ds, port)) 1443027152b8SChristian Marangi reg |= QCA8K_PORT_STATUS_TXFLOW; 1444027152b8SChristian Marangi } 1445027152b8SChristian Marangi 1446027152b8SChristian Marangi reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC; 1447027152b8SChristian Marangi 1448027152b8SChristian Marangi qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg); 1449027152b8SChristian Marangi } 1450027152b8SChristian Marangi 1451027152b8SChristian Marangi static struct qca8k_pcs *pcs_to_qca8k_pcs(struct phylink_pcs *pcs) 1452027152b8SChristian Marangi { 1453027152b8SChristian Marangi return container_of(pcs, struct qca8k_pcs, pcs); 1454027152b8SChristian Marangi } 1455027152b8SChristian Marangi 1456027152b8SChristian Marangi static void qca8k_pcs_get_state(struct phylink_pcs *pcs, 1457027152b8SChristian Marangi struct phylink_link_state *state) 1458027152b8SChristian Marangi { 1459027152b8SChristian Marangi struct qca8k_priv *priv = pcs_to_qca8k_pcs(pcs)->priv; 1460027152b8SChristian Marangi int port = pcs_to_qca8k_pcs(pcs)->port; 1461027152b8SChristian Marangi u32 reg; 1462027152b8SChristian Marangi int ret; 1463027152b8SChristian Marangi 1464027152b8SChristian Marangi ret = qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), ®); 1465027152b8SChristian Marangi if (ret < 0) { 1466027152b8SChristian Marangi state->link = false; 1467027152b8SChristian Marangi return; 1468027152b8SChristian Marangi } 1469027152b8SChristian Marangi 1470027152b8SChristian Marangi state->link = !!(reg & QCA8K_PORT_STATUS_LINK_UP); 1471027152b8SChristian Marangi state->an_complete = state->link; 1472027152b8SChristian Marangi state->duplex = (reg & QCA8K_PORT_STATUS_DUPLEX) ? DUPLEX_FULL : 1473027152b8SChristian Marangi DUPLEX_HALF; 1474027152b8SChristian Marangi 1475027152b8SChristian Marangi switch (reg & QCA8K_PORT_STATUS_SPEED) { 1476027152b8SChristian Marangi case QCA8K_PORT_STATUS_SPEED_10: 1477027152b8SChristian Marangi state->speed = SPEED_10; 1478027152b8SChristian Marangi break; 1479027152b8SChristian Marangi case QCA8K_PORT_STATUS_SPEED_100: 1480027152b8SChristian Marangi state->speed = SPEED_100; 1481027152b8SChristian Marangi break; 1482027152b8SChristian Marangi case QCA8K_PORT_STATUS_SPEED_1000: 1483027152b8SChristian Marangi state->speed = SPEED_1000; 1484027152b8SChristian Marangi break; 1485027152b8SChristian Marangi default: 1486027152b8SChristian Marangi state->speed = SPEED_UNKNOWN; 1487027152b8SChristian Marangi break; 1488027152b8SChristian Marangi } 1489027152b8SChristian Marangi 1490027152b8SChristian Marangi if (reg & QCA8K_PORT_STATUS_RXFLOW) 1491027152b8SChristian Marangi state->pause |= MLO_PAUSE_RX; 1492027152b8SChristian Marangi if (reg & QCA8K_PORT_STATUS_TXFLOW) 1493027152b8SChristian Marangi state->pause |= MLO_PAUSE_TX; 1494027152b8SChristian Marangi } 1495027152b8SChristian Marangi 1496*bfa0a3acSRussell King (Oracle) static int qca8k_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode, 1497027152b8SChristian Marangi phy_interface_t interface, 1498027152b8SChristian Marangi const unsigned long *advertising, 1499027152b8SChristian Marangi bool permit_pause_to_mac) 1500027152b8SChristian Marangi { 1501027152b8SChristian Marangi struct qca8k_priv *priv = pcs_to_qca8k_pcs(pcs)->priv; 1502027152b8SChristian Marangi int cpu_port_index, ret, port; 1503027152b8SChristian Marangi u32 reg, val; 1504027152b8SChristian Marangi 1505027152b8SChristian Marangi port = pcs_to_qca8k_pcs(pcs)->port; 1506027152b8SChristian Marangi switch (port) { 1507027152b8SChristian Marangi case 0: 1508027152b8SChristian Marangi reg = QCA8K_REG_PORT0_PAD_CTRL; 1509027152b8SChristian Marangi cpu_port_index = QCA8K_CPU_PORT0; 1510027152b8SChristian Marangi break; 1511027152b8SChristian Marangi 1512027152b8SChristian Marangi case 6: 1513027152b8SChristian Marangi reg = QCA8K_REG_PORT6_PAD_CTRL; 1514027152b8SChristian Marangi cpu_port_index = QCA8K_CPU_PORT6; 1515027152b8SChristian Marangi break; 1516027152b8SChristian Marangi 1517027152b8SChristian Marangi default: 1518027152b8SChristian Marangi WARN_ON(1); 1519027152b8SChristian Marangi return -EINVAL; 1520027152b8SChristian Marangi } 1521027152b8SChristian Marangi 1522027152b8SChristian Marangi /* Enable/disable SerDes auto-negotiation as necessary */ 1523*bfa0a3acSRussell King (Oracle) val = neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED ? 1524*bfa0a3acSRussell King (Oracle) 0 : QCA8K_PWS_SERDES_AEN_DIS; 1525*bfa0a3acSRussell King (Oracle) 1526*bfa0a3acSRussell King (Oracle) ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8K_PWS_SERDES_AEN_DIS, val); 1527027152b8SChristian Marangi if (ret) 1528027152b8SChristian Marangi return ret; 1529027152b8SChristian Marangi 1530027152b8SChristian Marangi /* Configure the SGMII parameters */ 1531027152b8SChristian Marangi ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val); 1532027152b8SChristian Marangi if (ret) 1533027152b8SChristian Marangi return ret; 1534027152b8SChristian Marangi 1535027152b8SChristian Marangi val |= QCA8K_SGMII_EN_SD; 1536027152b8SChristian Marangi 1537027152b8SChristian Marangi if (priv->ports_config.sgmii_enable_pll) 1538027152b8SChristian Marangi val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX | 1539027152b8SChristian Marangi QCA8K_SGMII_EN_TX; 1540027152b8SChristian Marangi 1541027152b8SChristian Marangi if (dsa_is_cpu_port(priv->ds, port)) { 1542027152b8SChristian Marangi /* CPU port, we're talking to the CPU MAC, be a PHY */ 1543027152b8SChristian Marangi val &= ~QCA8K_SGMII_MODE_CTRL_MASK; 1544027152b8SChristian Marangi val |= QCA8K_SGMII_MODE_CTRL_PHY; 1545027152b8SChristian Marangi } else if (interface == PHY_INTERFACE_MODE_SGMII) { 1546027152b8SChristian Marangi val &= ~QCA8K_SGMII_MODE_CTRL_MASK; 1547027152b8SChristian Marangi val |= QCA8K_SGMII_MODE_CTRL_MAC; 1548027152b8SChristian Marangi } else if (interface == PHY_INTERFACE_MODE_1000BASEX) { 1549027152b8SChristian Marangi val &= ~QCA8K_SGMII_MODE_CTRL_MASK; 1550027152b8SChristian Marangi val |= QCA8K_SGMII_MODE_CTRL_BASEX; 1551027152b8SChristian Marangi } 1552027152b8SChristian Marangi 1553027152b8SChristian Marangi qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val); 1554027152b8SChristian Marangi 1555027152b8SChristian Marangi /* From original code is reported port instability as SGMII also 1556027152b8SChristian Marangi * require delay set. Apply advised values here or take them from DT. 1557027152b8SChristian Marangi */ 1558027152b8SChristian Marangi if (interface == PHY_INTERFACE_MODE_SGMII) 1559027152b8SChristian Marangi qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); 1560027152b8SChristian Marangi /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and 1561027152b8SChristian Marangi * falling edge is set writing in the PORT0 PAD reg 1562027152b8SChristian Marangi */ 1563027152b8SChristian Marangi if (priv->switch_id == QCA8K_ID_QCA8327 || 1564027152b8SChristian Marangi priv->switch_id == QCA8K_ID_QCA8337) 1565027152b8SChristian Marangi reg = QCA8K_REG_PORT0_PAD_CTRL; 1566027152b8SChristian Marangi 1567027152b8SChristian Marangi val = 0; 1568027152b8SChristian Marangi 1569027152b8SChristian Marangi /* SGMII Clock phase configuration */ 1570027152b8SChristian Marangi if (priv->ports_config.sgmii_rx_clk_falling_edge) 1571027152b8SChristian Marangi val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE; 1572027152b8SChristian Marangi 1573027152b8SChristian Marangi if (priv->ports_config.sgmii_tx_clk_falling_edge) 1574027152b8SChristian Marangi val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE; 1575027152b8SChristian Marangi 1576027152b8SChristian Marangi if (val) 1577027152b8SChristian Marangi ret = qca8k_rmw(priv, reg, 1578027152b8SChristian Marangi QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE | 1579027152b8SChristian Marangi QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE, 1580027152b8SChristian Marangi val); 1581027152b8SChristian Marangi 1582027152b8SChristian Marangi return 0; 1583027152b8SChristian Marangi } 1584027152b8SChristian Marangi 1585027152b8SChristian Marangi static void qca8k_pcs_an_restart(struct phylink_pcs *pcs) 1586027152b8SChristian Marangi { 1587027152b8SChristian Marangi } 1588027152b8SChristian Marangi 1589027152b8SChristian Marangi static const struct phylink_pcs_ops qca8k_pcs_ops = { 1590027152b8SChristian Marangi .pcs_get_state = qca8k_pcs_get_state, 1591027152b8SChristian Marangi .pcs_config = qca8k_pcs_config, 1592027152b8SChristian Marangi .pcs_an_restart = qca8k_pcs_an_restart, 1593027152b8SChristian Marangi }; 1594027152b8SChristian Marangi 1595027152b8SChristian Marangi static void qca8k_setup_pcs(struct qca8k_priv *priv, struct qca8k_pcs *qpcs, 1596027152b8SChristian Marangi int port) 1597027152b8SChristian Marangi { 1598027152b8SChristian Marangi qpcs->pcs.ops = &qca8k_pcs_ops; 1599*bfa0a3acSRussell King (Oracle) qpcs->pcs.neg_mode = true; 1600027152b8SChristian Marangi 1601027152b8SChristian Marangi /* We don't have interrupts for link changes, so we need to poll */ 1602027152b8SChristian Marangi qpcs->pcs.poll = true; 1603027152b8SChristian Marangi qpcs->priv = priv; 1604027152b8SChristian Marangi qpcs->port = port; 1605027152b8SChristian Marangi } 1606027152b8SChristian Marangi 1607027152b8SChristian Marangi static void qca8k_mib_autocast_handler(struct dsa_switch *ds, struct sk_buff *skb) 1608027152b8SChristian Marangi { 1609027152b8SChristian Marangi struct qca8k_mib_eth_data *mib_eth_data; 1610027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1611027152b8SChristian Marangi const struct qca8k_mib_desc *mib; 1612027152b8SChristian Marangi struct mib_ethhdr *mib_ethhdr; 16130d4636f7SChristian Marangi __le32 *data2; 1614027152b8SChristian Marangi u8 port; 16150d4636f7SChristian Marangi int i; 1616027152b8SChristian Marangi 1617027152b8SChristian Marangi mib_ethhdr = (struct mib_ethhdr *)skb_mac_header(skb); 1618027152b8SChristian Marangi mib_eth_data = &priv->mib_eth_data; 1619027152b8SChristian Marangi 1620027152b8SChristian Marangi /* The switch autocast every port. Ignore other packet and 1621027152b8SChristian Marangi * parse only the requested one. 1622027152b8SChristian Marangi */ 1623027152b8SChristian Marangi port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr)); 1624027152b8SChristian Marangi if (port != mib_eth_data->req_port) 1625027152b8SChristian Marangi goto exit; 1626027152b8SChristian Marangi 16270d4636f7SChristian Marangi data2 = (__le32 *)skb->data; 1628027152b8SChristian Marangi 1629027152b8SChristian Marangi for (i = 0; i < priv->info->mib_count; i++) { 1630027152b8SChristian Marangi mib = &ar8327_mib[i]; 1631027152b8SChristian Marangi 1632027152b8SChristian Marangi /* First 3 mib are present in the skb head */ 1633027152b8SChristian Marangi if (i < 3) { 16340d4636f7SChristian Marangi mib_eth_data->data[i] = get_unaligned_le32(mib_ethhdr->data + i); 1635027152b8SChristian Marangi continue; 1636027152b8SChristian Marangi } 1637027152b8SChristian Marangi 1638027152b8SChristian Marangi /* Some mib are 64 bit wide */ 1639027152b8SChristian Marangi if (mib->size == 2) 16400d4636f7SChristian Marangi mib_eth_data->data[i] = get_unaligned_le64((__le64 *)data2); 16410d4636f7SChristian Marangi else 16420d4636f7SChristian Marangi mib_eth_data->data[i] = get_unaligned_le32(data2); 1643027152b8SChristian Marangi 16440d4636f7SChristian Marangi data2 += mib->size; 1645027152b8SChristian Marangi } 1646027152b8SChristian Marangi 1647027152b8SChristian Marangi exit: 1648027152b8SChristian Marangi /* Complete on receiving all the mib packet */ 1649027152b8SChristian Marangi if (refcount_dec_and_test(&mib_eth_data->port_parsed)) 1650027152b8SChristian Marangi complete(&mib_eth_data->rw_done); 1651027152b8SChristian Marangi } 1652027152b8SChristian Marangi 1653027152b8SChristian Marangi static int 1654027152b8SChristian Marangi qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data) 1655027152b8SChristian Marangi { 1656027152b8SChristian Marangi struct dsa_port *dp = dsa_to_port(ds, port); 1657027152b8SChristian Marangi struct qca8k_mib_eth_data *mib_eth_data; 1658027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1659027152b8SChristian Marangi int ret; 1660027152b8SChristian Marangi 1661027152b8SChristian Marangi mib_eth_data = &priv->mib_eth_data; 1662027152b8SChristian Marangi 1663027152b8SChristian Marangi mutex_lock(&mib_eth_data->mutex); 1664027152b8SChristian Marangi 1665027152b8SChristian Marangi reinit_completion(&mib_eth_data->rw_done); 1666027152b8SChristian Marangi 1667027152b8SChristian Marangi mib_eth_data->req_port = dp->index; 1668027152b8SChristian Marangi mib_eth_data->data = data; 1669027152b8SChristian Marangi refcount_set(&mib_eth_data->port_parsed, QCA8K_NUM_PORTS); 1670027152b8SChristian Marangi 1671027152b8SChristian Marangi mutex_lock(&priv->reg_mutex); 1672027152b8SChristian Marangi 1673027152b8SChristian Marangi /* Send mib autocast request */ 1674027152b8SChristian Marangi ret = regmap_update_bits(priv->regmap, QCA8K_REG_MIB, 1675027152b8SChristian Marangi QCA8K_MIB_FUNC | QCA8K_MIB_BUSY, 1676027152b8SChristian Marangi FIELD_PREP(QCA8K_MIB_FUNC, QCA8K_MIB_CAST) | 1677027152b8SChristian Marangi QCA8K_MIB_BUSY); 1678027152b8SChristian Marangi 1679027152b8SChristian Marangi mutex_unlock(&priv->reg_mutex); 1680027152b8SChristian Marangi 1681027152b8SChristian Marangi if (ret) 1682027152b8SChristian Marangi goto exit; 1683027152b8SChristian Marangi 1684027152b8SChristian Marangi ret = wait_for_completion_timeout(&mib_eth_data->rw_done, QCA8K_ETHERNET_TIMEOUT); 1685027152b8SChristian Marangi 1686027152b8SChristian Marangi exit: 1687027152b8SChristian Marangi mutex_unlock(&mib_eth_data->mutex); 1688027152b8SChristian Marangi 1689027152b8SChristian Marangi return ret; 1690027152b8SChristian Marangi } 1691027152b8SChristian Marangi 1692027152b8SChristian Marangi static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port) 1693027152b8SChristian Marangi { 1694027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1695027152b8SChristian Marangi 1696027152b8SChristian Marangi /* Communicate to the phy internal driver the switch revision. 1697027152b8SChristian Marangi * Based on the switch revision different values needs to be 1698027152b8SChristian Marangi * set to the dbg and mmd reg on the phy. 1699027152b8SChristian Marangi * The first 2 bit are used to communicate the switch revision 1700027152b8SChristian Marangi * to the phy driver. 1701027152b8SChristian Marangi */ 1702027152b8SChristian Marangi if (port > 0 && port < 6) 1703027152b8SChristian Marangi return priv->switch_revision; 1704027152b8SChristian Marangi 1705027152b8SChristian Marangi return 0; 1706027152b8SChristian Marangi } 1707027152b8SChristian Marangi 1708027152b8SChristian Marangi static enum dsa_tag_protocol 1709027152b8SChristian Marangi qca8k_get_tag_protocol(struct dsa_switch *ds, int port, 1710027152b8SChristian Marangi enum dsa_tag_protocol mp) 1711027152b8SChristian Marangi { 1712027152b8SChristian Marangi return DSA_TAG_PROTO_QCA; 1713027152b8SChristian Marangi } 1714027152b8SChristian Marangi 1715027152b8SChristian Marangi static void 1716027152b8SChristian Marangi qca8k_master_change(struct dsa_switch *ds, const struct net_device *master, 1717027152b8SChristian Marangi bool operational) 1718027152b8SChristian Marangi { 1719027152b8SChristian Marangi struct dsa_port *dp = master->dsa_ptr; 1720027152b8SChristian Marangi struct qca8k_priv *priv = ds->priv; 1721027152b8SChristian Marangi 1722027152b8SChristian Marangi /* Ethernet MIB/MDIO is only supported for CPU port 0 */ 1723027152b8SChristian Marangi if (dp->index != 0) 1724027152b8SChristian Marangi return; 1725027152b8SChristian Marangi 1726027152b8SChristian Marangi mutex_lock(&priv->mgmt_eth_data.mutex); 1727027152b8SChristian Marangi mutex_lock(&priv->mib_eth_data.mutex); 1728027152b8SChristian Marangi 1729027152b8SChristian Marangi priv->mgmt_master = operational ? (struct net_device *)master : NULL; 1730027152b8SChristian Marangi 1731027152b8SChristian Marangi mutex_unlock(&priv->mib_eth_data.mutex); 1732027152b8SChristian Marangi mutex_unlock(&priv->mgmt_eth_data.mutex); 1733027152b8SChristian Marangi } 1734027152b8SChristian Marangi 1735027152b8SChristian Marangi static int qca8k_connect_tag_protocol(struct dsa_switch *ds, 1736027152b8SChristian Marangi enum dsa_tag_protocol proto) 1737027152b8SChristian Marangi { 1738027152b8SChristian Marangi struct qca_tagger_data *tagger_data; 1739027152b8SChristian Marangi 1740027152b8SChristian Marangi switch (proto) { 1741027152b8SChristian Marangi case DSA_TAG_PROTO_QCA: 1742027152b8SChristian Marangi tagger_data = ds->tagger_data; 1743027152b8SChristian Marangi 1744027152b8SChristian Marangi tagger_data->rw_reg_ack_handler = qca8k_rw_reg_ack_handler; 1745027152b8SChristian Marangi tagger_data->mib_autocast_handler = qca8k_mib_autocast_handler; 1746027152b8SChristian Marangi 1747027152b8SChristian Marangi break; 1748027152b8SChristian Marangi default: 1749027152b8SChristian Marangi return -EOPNOTSUPP; 1750027152b8SChristian Marangi } 1751027152b8SChristian Marangi 1752027152b8SChristian Marangi return 0; 1753027152b8SChristian Marangi } 1754027152b8SChristian Marangi 1755027152b8SChristian Marangi static int 1756027152b8SChristian Marangi qca8k_setup(struct dsa_switch *ds) 1757027152b8SChristian Marangi { 175892db9e2eSAtin Bainada struct qca8k_priv *priv = ds->priv; 1759027152b8SChristian Marangi int cpu_port, ret, i; 1760027152b8SChristian Marangi u32 mask; 1761027152b8SChristian Marangi 1762027152b8SChristian Marangi cpu_port = qca8k_find_cpu_port(ds); 1763027152b8SChristian Marangi if (cpu_port < 0) { 1764027152b8SChristian Marangi dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6"); 1765027152b8SChristian Marangi return cpu_port; 1766027152b8SChristian Marangi } 1767027152b8SChristian Marangi 1768027152b8SChristian Marangi /* Parse CPU port config to be later used in phy_link mac_config */ 1769027152b8SChristian Marangi ret = qca8k_parse_port_config(priv); 1770027152b8SChristian Marangi if (ret) 1771027152b8SChristian Marangi return ret; 1772027152b8SChristian Marangi 1773027152b8SChristian Marangi ret = qca8k_setup_mdio_bus(priv); 1774027152b8SChristian Marangi if (ret) 1775027152b8SChristian Marangi return ret; 1776027152b8SChristian Marangi 1777027152b8SChristian Marangi ret = qca8k_setup_of_pws_reg(priv); 1778027152b8SChristian Marangi if (ret) 1779027152b8SChristian Marangi return ret; 1780027152b8SChristian Marangi 1781027152b8SChristian Marangi ret = qca8k_setup_mac_pwr_sel(priv); 1782027152b8SChristian Marangi if (ret) 1783027152b8SChristian Marangi return ret; 1784027152b8SChristian Marangi 17851e264f9dSChristian Marangi ret = qca8k_setup_led_ctrl(priv); 17861e264f9dSChristian Marangi if (ret) 17871e264f9dSChristian Marangi return ret; 17881e264f9dSChristian Marangi 1789027152b8SChristian Marangi qca8k_setup_pcs(priv, &priv->pcs_port_0, 0); 1790027152b8SChristian Marangi qca8k_setup_pcs(priv, &priv->pcs_port_6, 6); 1791027152b8SChristian Marangi 1792027152b8SChristian Marangi /* Make sure MAC06 is disabled */ 1793027152b8SChristian Marangi ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL, 1794027152b8SChristian Marangi QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); 1795027152b8SChristian Marangi if (ret) { 1796027152b8SChristian Marangi dev_err(priv->dev, "failed disabling MAC06 exchange"); 1797027152b8SChristian Marangi return ret; 1798027152b8SChristian Marangi } 1799027152b8SChristian Marangi 1800027152b8SChristian Marangi /* Enable CPU Port */ 1801027152b8SChristian Marangi ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0, 1802027152b8SChristian Marangi QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); 1803027152b8SChristian Marangi if (ret) { 1804027152b8SChristian Marangi dev_err(priv->dev, "failed enabling CPU port"); 1805027152b8SChristian Marangi return ret; 1806027152b8SChristian Marangi } 1807027152b8SChristian Marangi 1808027152b8SChristian Marangi /* Enable MIB counters */ 1809027152b8SChristian Marangi ret = qca8k_mib_init(priv); 1810027152b8SChristian Marangi if (ret) 1811027152b8SChristian Marangi dev_warn(priv->dev, "mib init failed"); 1812027152b8SChristian Marangi 1813027152b8SChristian Marangi /* Initial setup of all ports */ 1814027152b8SChristian Marangi for (i = 0; i < QCA8K_NUM_PORTS; i++) { 1815027152b8SChristian Marangi /* Disable forwarding by default on all ports */ 1816027152b8SChristian Marangi ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), 1817027152b8SChristian Marangi QCA8K_PORT_LOOKUP_MEMBER, 0); 1818027152b8SChristian Marangi if (ret) 1819027152b8SChristian Marangi return ret; 1820027152b8SChristian Marangi 1821027152b8SChristian Marangi /* Enable QCA header mode on all cpu ports */ 1822027152b8SChristian Marangi if (dsa_is_cpu_port(ds, i)) { 1823027152b8SChristian Marangi ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(i), 1824027152b8SChristian Marangi FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) | 1825027152b8SChristian Marangi FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL)); 1826027152b8SChristian Marangi if (ret) { 1827027152b8SChristian Marangi dev_err(priv->dev, "failed enabling QCA header mode"); 1828027152b8SChristian Marangi return ret; 1829027152b8SChristian Marangi } 1830027152b8SChristian Marangi } 1831027152b8SChristian Marangi 1832027152b8SChristian Marangi /* Disable MAC by default on all user ports */ 1833027152b8SChristian Marangi if (dsa_is_user_port(ds, i)) 1834027152b8SChristian Marangi qca8k_port_set_status(priv, i, 0); 1835027152b8SChristian Marangi } 1836027152b8SChristian Marangi 1837027152b8SChristian Marangi /* Forward all unknown frames to CPU port for Linux processing 1838027152b8SChristian Marangi * Notice that in multi-cpu config only one port should be set 1839027152b8SChristian Marangi * for igmp, unknown, multicast and broadcast packet 1840027152b8SChristian Marangi */ 1841027152b8SChristian Marangi ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1, 1842027152b8SChristian Marangi FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) | 1843027152b8SChristian Marangi FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) | 1844027152b8SChristian Marangi FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) | 1845027152b8SChristian Marangi FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); 1846027152b8SChristian Marangi if (ret) 1847027152b8SChristian Marangi return ret; 1848027152b8SChristian Marangi 1849027152b8SChristian Marangi /* Setup connection between CPU port & user ports 1850027152b8SChristian Marangi * Configure specific switch configuration for ports 1851027152b8SChristian Marangi */ 1852027152b8SChristian Marangi for (i = 0; i < QCA8K_NUM_PORTS; i++) { 1853027152b8SChristian Marangi /* CPU port gets connected to all user ports of the switch */ 1854027152b8SChristian Marangi if (dsa_is_cpu_port(ds, i)) { 1855027152b8SChristian Marangi ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), 1856027152b8SChristian Marangi QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); 1857027152b8SChristian Marangi if (ret) 1858027152b8SChristian Marangi return ret; 1859027152b8SChristian Marangi } 1860027152b8SChristian Marangi 1861027152b8SChristian Marangi /* Individual user ports get connected to CPU port only */ 1862027152b8SChristian Marangi if (dsa_is_user_port(ds, i)) { 1863027152b8SChristian Marangi ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(i), 1864027152b8SChristian Marangi QCA8K_PORT_LOOKUP_MEMBER, 1865027152b8SChristian Marangi BIT(cpu_port)); 1866027152b8SChristian Marangi if (ret) 1867027152b8SChristian Marangi return ret; 1868027152b8SChristian Marangi 1869027152b8SChristian Marangi /* Enable ARP Auto-learning by default */ 1870027152b8SChristian Marangi ret = regmap_set_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(i), 1871027152b8SChristian Marangi QCA8K_PORT_LOOKUP_LEARN); 1872027152b8SChristian Marangi if (ret) 1873027152b8SChristian Marangi return ret; 1874027152b8SChristian Marangi 1875027152b8SChristian Marangi /* For port based vlans to work we need to set the 1876027152b8SChristian Marangi * default egress vid 1877027152b8SChristian Marangi */ 1878027152b8SChristian Marangi ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(i), 1879027152b8SChristian Marangi QCA8K_EGREES_VLAN_PORT_MASK(i), 1880027152b8SChristian Marangi QCA8K_EGREES_VLAN_PORT(i, QCA8K_PORT_VID_DEF)); 1881027152b8SChristian Marangi if (ret) 1882027152b8SChristian Marangi return ret; 1883027152b8SChristian Marangi 1884027152b8SChristian Marangi ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(i), 1885027152b8SChristian Marangi QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) | 1886027152b8SChristian Marangi QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); 1887027152b8SChristian Marangi if (ret) 1888027152b8SChristian Marangi return ret; 1889027152b8SChristian Marangi } 1890027152b8SChristian Marangi 1891027152b8SChristian Marangi /* The port 5 of the qca8337 have some problem in flood condition. The 1892027152b8SChristian Marangi * original legacy driver had some specific buffer and priority settings 1893027152b8SChristian Marangi * for the different port suggested by the QCA switch team. Add this 1894027152b8SChristian Marangi * missing settings to improve switch stability under load condition. 1895027152b8SChristian Marangi * This problem is limited to qca8337 and other qca8k switch are not affected. 1896027152b8SChristian Marangi */ 1897027152b8SChristian Marangi if (priv->switch_id == QCA8K_ID_QCA8337) { 1898027152b8SChristian Marangi switch (i) { 1899027152b8SChristian Marangi /* The 2 CPU port and port 5 requires some different 1900027152b8SChristian Marangi * priority than any other ports. 1901027152b8SChristian Marangi */ 1902027152b8SChristian Marangi case 0: 1903027152b8SChristian Marangi case 5: 1904027152b8SChristian Marangi case 6: 1905027152b8SChristian Marangi mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | 1906027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | 1907027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) | 1908027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) | 1909027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) | 1910027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) | 1911027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e); 1912027152b8SChristian Marangi break; 1913027152b8SChristian Marangi default: 1914027152b8SChristian Marangi mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) | 1915027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) | 1916027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) | 1917027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) | 1918027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19); 1919027152b8SChristian Marangi } 1920027152b8SChristian Marangi qca8k_write(priv, QCA8K_REG_PORT_HOL_CTRL0(i), mask); 1921027152b8SChristian Marangi 1922027152b8SChristian Marangi mask = QCA8K_PORT_HOL_CTRL1_ING(0x6) | 1923027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | 1924027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | 1925027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL1_WRED_EN; 1926027152b8SChristian Marangi qca8k_rmw(priv, QCA8K_REG_PORT_HOL_CTRL1(i), 1927027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL1_ING_BUF_MASK | 1928027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL1_EG_PRI_BUF_EN | 1929027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL1_EG_PORT_BUF_EN | 1930027152b8SChristian Marangi QCA8K_PORT_HOL_CTRL1_WRED_EN, 1931027152b8SChristian Marangi mask); 1932027152b8SChristian Marangi } 1933027152b8SChristian Marangi } 1934027152b8SChristian Marangi 1935027152b8SChristian Marangi /* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ 1936027152b8SChristian Marangi if (priv->switch_id == QCA8K_ID_QCA8327) { 1937027152b8SChristian Marangi mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) | 1938027152b8SChristian Marangi QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496); 1939027152b8SChristian Marangi qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH, 1940027152b8SChristian Marangi QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK | 1941027152b8SChristian Marangi QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK, 1942027152b8SChristian Marangi mask); 1943027152b8SChristian Marangi } 1944027152b8SChristian Marangi 1945027152b8SChristian Marangi /* Setup our port MTUs to match power on defaults */ 1946027152b8SChristian Marangi ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); 1947027152b8SChristian Marangi if (ret) 1948027152b8SChristian Marangi dev_warn(priv->dev, "failed setting MTU settings"); 1949027152b8SChristian Marangi 1950027152b8SChristian Marangi /* Flush the FDB table */ 1951027152b8SChristian Marangi qca8k_fdb_flush(priv); 1952027152b8SChristian Marangi 1953027152b8SChristian Marangi /* Set min a max ageing value supported */ 1954027152b8SChristian Marangi ds->ageing_time_min = 7000; 1955027152b8SChristian Marangi ds->ageing_time_max = 458745000; 1956027152b8SChristian Marangi 1957027152b8SChristian Marangi /* Set max number of LAGs supported */ 1958027152b8SChristian Marangi ds->num_lag_ids = QCA8K_NUM_LAGS; 1959027152b8SChristian Marangi 1960027152b8SChristian Marangi return 0; 1961027152b8SChristian Marangi } 1962027152b8SChristian Marangi 1963027152b8SChristian Marangi static const struct dsa_switch_ops qca8k_switch_ops = { 1964027152b8SChristian Marangi .get_tag_protocol = qca8k_get_tag_protocol, 1965027152b8SChristian Marangi .setup = qca8k_setup, 1966027152b8SChristian Marangi .get_strings = qca8k_get_strings, 1967027152b8SChristian Marangi .get_ethtool_stats = qca8k_get_ethtool_stats, 1968027152b8SChristian Marangi .get_sset_count = qca8k_get_sset_count, 1969027152b8SChristian Marangi .set_ageing_time = qca8k_set_ageing_time, 1970027152b8SChristian Marangi .get_mac_eee = qca8k_get_mac_eee, 1971027152b8SChristian Marangi .set_mac_eee = qca8k_set_mac_eee, 1972027152b8SChristian Marangi .port_enable = qca8k_port_enable, 1973027152b8SChristian Marangi .port_disable = qca8k_port_disable, 1974027152b8SChristian Marangi .port_change_mtu = qca8k_port_change_mtu, 1975027152b8SChristian Marangi .port_max_mtu = qca8k_port_max_mtu, 1976027152b8SChristian Marangi .port_stp_state_set = qca8k_port_stp_state_set, 1977027152b8SChristian Marangi .port_bridge_join = qca8k_port_bridge_join, 1978027152b8SChristian Marangi .port_bridge_leave = qca8k_port_bridge_leave, 1979027152b8SChristian Marangi .port_fast_age = qca8k_port_fast_age, 1980027152b8SChristian Marangi .port_fdb_add = qca8k_port_fdb_add, 1981027152b8SChristian Marangi .port_fdb_del = qca8k_port_fdb_del, 1982027152b8SChristian Marangi .port_fdb_dump = qca8k_port_fdb_dump, 1983027152b8SChristian Marangi .port_mdb_add = qca8k_port_mdb_add, 1984027152b8SChristian Marangi .port_mdb_del = qca8k_port_mdb_del, 1985027152b8SChristian Marangi .port_mirror_add = qca8k_port_mirror_add, 1986027152b8SChristian Marangi .port_mirror_del = qca8k_port_mirror_del, 1987027152b8SChristian Marangi .port_vlan_filtering = qca8k_port_vlan_filtering, 1988027152b8SChristian Marangi .port_vlan_add = qca8k_port_vlan_add, 1989027152b8SChristian Marangi .port_vlan_del = qca8k_port_vlan_del, 1990027152b8SChristian Marangi .phylink_get_caps = qca8k_phylink_get_caps, 1991027152b8SChristian Marangi .phylink_mac_select_pcs = qca8k_phylink_mac_select_pcs, 1992027152b8SChristian Marangi .phylink_mac_config = qca8k_phylink_mac_config, 1993027152b8SChristian Marangi .phylink_mac_link_down = qca8k_phylink_mac_link_down, 1994027152b8SChristian Marangi .phylink_mac_link_up = qca8k_phylink_mac_link_up, 1995027152b8SChristian Marangi .get_phy_flags = qca8k_get_phy_flags, 1996027152b8SChristian Marangi .port_lag_join = qca8k_port_lag_join, 1997027152b8SChristian Marangi .port_lag_leave = qca8k_port_lag_leave, 1998027152b8SChristian Marangi .master_state_change = qca8k_master_change, 1999027152b8SChristian Marangi .connect_tag_protocol = qca8k_connect_tag_protocol, 2000027152b8SChristian Marangi }; 2001027152b8SChristian Marangi 2002027152b8SChristian Marangi static int 2003027152b8SChristian Marangi qca8k_sw_probe(struct mdio_device *mdiodev) 2004027152b8SChristian Marangi { 2005027152b8SChristian Marangi struct qca8k_priv *priv; 2006027152b8SChristian Marangi int ret; 2007027152b8SChristian Marangi 2008027152b8SChristian Marangi /* allocate the private data struct so that we can probe the switches 2009027152b8SChristian Marangi * ID register 2010027152b8SChristian Marangi */ 2011027152b8SChristian Marangi priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); 2012027152b8SChristian Marangi if (!priv) 2013027152b8SChristian Marangi return -ENOMEM; 2014027152b8SChristian Marangi 2015027152b8SChristian Marangi priv->bus = mdiodev->bus; 2016027152b8SChristian Marangi priv->dev = &mdiodev->dev; 201742b998d4SChristian Marangi priv->info = of_device_get_match_data(priv->dev); 2018027152b8SChristian Marangi 2019027152b8SChristian Marangi priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", 2020027152b8SChristian Marangi GPIOD_ASIS); 2021027152b8SChristian Marangi if (IS_ERR(priv->reset_gpio)) 2022027152b8SChristian Marangi return PTR_ERR(priv->reset_gpio); 2023027152b8SChristian Marangi 2024027152b8SChristian Marangi if (priv->reset_gpio) { 2025027152b8SChristian Marangi gpiod_set_value_cansleep(priv->reset_gpio, 1); 2026027152b8SChristian Marangi /* The active low duration must be greater than 10 ms 2027027152b8SChristian Marangi * and checkpatch.pl wants 20 ms. 2028027152b8SChristian Marangi */ 2029027152b8SChristian Marangi msleep(20); 2030027152b8SChristian Marangi gpiod_set_value_cansleep(priv->reset_gpio, 0); 2031027152b8SChristian Marangi } 2032027152b8SChristian Marangi 2033027152b8SChristian Marangi /* Start by setting up the register mapping */ 2034027152b8SChristian Marangi priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv, 2035027152b8SChristian Marangi &qca8k_regmap_config); 2036027152b8SChristian Marangi if (IS_ERR(priv->regmap)) { 2037027152b8SChristian Marangi dev_err(priv->dev, "regmap initialization failed"); 2038027152b8SChristian Marangi return PTR_ERR(priv->regmap); 2039027152b8SChristian Marangi } 2040027152b8SChristian Marangi 2041027152b8SChristian Marangi priv->mdio_cache.page = 0xffff; 2042027152b8SChristian Marangi 2043027152b8SChristian Marangi /* Check the detected switch id */ 2044027152b8SChristian Marangi ret = qca8k_read_switch_id(priv); 2045027152b8SChristian Marangi if (ret) 2046027152b8SChristian Marangi return ret; 2047027152b8SChristian Marangi 2048027152b8SChristian Marangi priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); 2049027152b8SChristian Marangi if (!priv->ds) 2050027152b8SChristian Marangi return -ENOMEM; 2051027152b8SChristian Marangi 2052027152b8SChristian Marangi mutex_init(&priv->mgmt_eth_data.mutex); 2053027152b8SChristian Marangi init_completion(&priv->mgmt_eth_data.rw_done); 2054027152b8SChristian Marangi 2055027152b8SChristian Marangi mutex_init(&priv->mib_eth_data.mutex); 2056027152b8SChristian Marangi init_completion(&priv->mib_eth_data.rw_done); 2057027152b8SChristian Marangi 2058027152b8SChristian Marangi priv->ds->dev = &mdiodev->dev; 2059027152b8SChristian Marangi priv->ds->num_ports = QCA8K_NUM_PORTS; 2060027152b8SChristian Marangi priv->ds->priv = priv; 2061027152b8SChristian Marangi priv->ds->ops = &qca8k_switch_ops; 2062027152b8SChristian Marangi mutex_init(&priv->reg_mutex); 2063027152b8SChristian Marangi dev_set_drvdata(&mdiodev->dev, priv); 2064027152b8SChristian Marangi 2065027152b8SChristian Marangi return dsa_register_switch(priv->ds); 2066027152b8SChristian Marangi } 2067027152b8SChristian Marangi 2068027152b8SChristian Marangi static void 2069027152b8SChristian Marangi qca8k_sw_remove(struct mdio_device *mdiodev) 2070027152b8SChristian Marangi { 2071027152b8SChristian Marangi struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); 2072027152b8SChristian Marangi int i; 2073027152b8SChristian Marangi 2074027152b8SChristian Marangi if (!priv) 2075027152b8SChristian Marangi return; 2076027152b8SChristian Marangi 2077027152b8SChristian Marangi for (i = 0; i < QCA8K_NUM_PORTS; i++) 2078027152b8SChristian Marangi qca8k_port_set_status(priv, i, 0); 2079027152b8SChristian Marangi 2080027152b8SChristian Marangi dsa_unregister_switch(priv->ds); 2081027152b8SChristian Marangi } 2082027152b8SChristian Marangi 2083027152b8SChristian Marangi static void qca8k_sw_shutdown(struct mdio_device *mdiodev) 2084027152b8SChristian Marangi { 2085027152b8SChristian Marangi struct qca8k_priv *priv = dev_get_drvdata(&mdiodev->dev); 2086027152b8SChristian Marangi 2087027152b8SChristian Marangi if (!priv) 2088027152b8SChristian Marangi return; 2089027152b8SChristian Marangi 2090027152b8SChristian Marangi dsa_switch_shutdown(priv->ds); 2091027152b8SChristian Marangi 2092027152b8SChristian Marangi dev_set_drvdata(&mdiodev->dev, NULL); 2093027152b8SChristian Marangi } 2094027152b8SChristian Marangi 2095027152b8SChristian Marangi #ifdef CONFIG_PM_SLEEP 2096027152b8SChristian Marangi static void 2097027152b8SChristian Marangi qca8k_set_pm(struct qca8k_priv *priv, int enable) 2098027152b8SChristian Marangi { 2099027152b8SChristian Marangi int port; 2100027152b8SChristian Marangi 2101027152b8SChristian Marangi for (port = 0; port < QCA8K_NUM_PORTS; port++) { 2102027152b8SChristian Marangi /* Do not enable on resume if the port was 2103027152b8SChristian Marangi * disabled before. 2104027152b8SChristian Marangi */ 2105027152b8SChristian Marangi if (!(priv->port_enabled_map & BIT(port))) 2106027152b8SChristian Marangi continue; 2107027152b8SChristian Marangi 2108027152b8SChristian Marangi qca8k_port_set_status(priv, port, enable); 2109027152b8SChristian Marangi } 2110027152b8SChristian Marangi } 2111027152b8SChristian Marangi 2112027152b8SChristian Marangi static int qca8k_suspend(struct device *dev) 2113027152b8SChristian Marangi { 2114027152b8SChristian Marangi struct qca8k_priv *priv = dev_get_drvdata(dev); 2115027152b8SChristian Marangi 2116027152b8SChristian Marangi qca8k_set_pm(priv, 0); 2117027152b8SChristian Marangi 2118027152b8SChristian Marangi return dsa_switch_suspend(priv->ds); 2119027152b8SChristian Marangi } 2120027152b8SChristian Marangi 2121027152b8SChristian Marangi static int qca8k_resume(struct device *dev) 2122027152b8SChristian Marangi { 2123027152b8SChristian Marangi struct qca8k_priv *priv = dev_get_drvdata(dev); 2124027152b8SChristian Marangi 2125027152b8SChristian Marangi qca8k_set_pm(priv, 1); 2126027152b8SChristian Marangi 2127027152b8SChristian Marangi return dsa_switch_resume(priv->ds); 2128027152b8SChristian Marangi } 2129027152b8SChristian Marangi #endif /* CONFIG_PM_SLEEP */ 2130027152b8SChristian Marangi 2131027152b8SChristian Marangi static SIMPLE_DEV_PM_OPS(qca8k_pm_ops, 2132027152b8SChristian Marangi qca8k_suspend, qca8k_resume); 2133027152b8SChristian Marangi 2134027152b8SChristian Marangi static const struct qca8k_info_ops qca8xxx_ops = { 2135027152b8SChristian Marangi .autocast_mib = qca8k_get_ethtool_stats_eth, 2136027152b8SChristian Marangi }; 2137027152b8SChristian Marangi 2138027152b8SChristian Marangi static const struct qca8k_match_data qca8327 = { 2139027152b8SChristian Marangi .id = QCA8K_ID_QCA8327, 2140027152b8SChristian Marangi .reduced_package = true, 2141027152b8SChristian Marangi .mib_count = QCA8K_QCA832X_MIB_COUNT, 2142027152b8SChristian Marangi .ops = &qca8xxx_ops, 2143027152b8SChristian Marangi }; 2144027152b8SChristian Marangi 2145027152b8SChristian Marangi static const struct qca8k_match_data qca8328 = { 2146027152b8SChristian Marangi .id = QCA8K_ID_QCA8327, 2147027152b8SChristian Marangi .mib_count = QCA8K_QCA832X_MIB_COUNT, 2148027152b8SChristian Marangi .ops = &qca8xxx_ops, 2149027152b8SChristian Marangi }; 2150027152b8SChristian Marangi 2151027152b8SChristian Marangi static const struct qca8k_match_data qca833x = { 2152027152b8SChristian Marangi .id = QCA8K_ID_QCA8337, 2153027152b8SChristian Marangi .mib_count = QCA8K_QCA833X_MIB_COUNT, 2154027152b8SChristian Marangi .ops = &qca8xxx_ops, 2155027152b8SChristian Marangi }; 2156027152b8SChristian Marangi 2157027152b8SChristian Marangi static const struct of_device_id qca8k_of_match[] = { 2158027152b8SChristian Marangi { .compatible = "qca,qca8327", .data = &qca8327 }, 2159027152b8SChristian Marangi { .compatible = "qca,qca8328", .data = &qca8328 }, 2160027152b8SChristian Marangi { .compatible = "qca,qca8334", .data = &qca833x }, 2161027152b8SChristian Marangi { .compatible = "qca,qca8337", .data = &qca833x }, 2162027152b8SChristian Marangi { /* sentinel */ }, 2163027152b8SChristian Marangi }; 2164027152b8SChristian Marangi 2165027152b8SChristian Marangi static struct mdio_driver qca8kmdio_driver = { 2166027152b8SChristian Marangi .probe = qca8k_sw_probe, 2167027152b8SChristian Marangi .remove = qca8k_sw_remove, 2168027152b8SChristian Marangi .shutdown = qca8k_sw_shutdown, 2169027152b8SChristian Marangi .mdiodrv.driver = { 2170027152b8SChristian Marangi .name = "qca8k", 2171027152b8SChristian Marangi .of_match_table = qca8k_of_match, 2172027152b8SChristian Marangi .pm = &qca8k_pm_ops, 2173027152b8SChristian Marangi }, 2174027152b8SChristian Marangi }; 2175027152b8SChristian Marangi 2176027152b8SChristian Marangi mdio_module_driver(qca8kmdio_driver); 2177027152b8SChristian Marangi 2178027152b8SChristian Marangi MODULE_AUTHOR("Mathieu Olivari, John Crispin <john@phrozen.org>"); 2179027152b8SChristian Marangi MODULE_DESCRIPTION("Driver for QCA8K ethernet switch family"); 2180027152b8SChristian Marangi MODULE_LICENSE("GPL v2"); 2181027152b8SChristian Marangi MODULE_ALIAS("platform:qca8k"); 2182