1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2018 Marvell International Ltd. 4 */ 5 6#include <dm.h> 7#include <errno.h> 8#include <malloc.h> 9#include <misc.h> 10#include <net.h> 11#include <pci_ids.h> 12#include <linux/list.h> 13#include <asm/arch/board.h> 14#include <asm/arch/csrs/csrs-cgx.h> 15#include <asm/io.h> 16 17#include "cgx.h" 18 19char lmac_type_to_str[][8] = { 20 "SGMII", 21 "XAUI", 22 "RXAUI", 23 "10G_R", 24 "40G_R", 25 "RGMII", 26 "QSGMII", 27 "25G_R", 28 "50G_R", 29 "100G_R", 30 "USXGMII", 31}; 32 33char lmac_speed_to_str[][8] = { 34 "0", 35 "10M", 36 "100M", 37 "1G", 38 "2.5G", 39 "5G", 40 "10G", 41 "20G", 42 "25G", 43 "40G", 44 "50G", 45 "80G", 46 "100G", 47}; 48 49/** 50 * Given an LMAC/PF instance number, return the lmac 51 * Per design, each PF has only one LMAC mapped. 52 * 53 * @param instance instance to find 54 * 55 * Return: pointer to lmac data structure or NULL if not found 56 */ 57struct lmac *nix_get_cgx_lmac(int lmac_instance) 58{ 59 struct cgx *cgx; 60 struct udevice *dev; 61 int i, idx, err; 62 63 for (i = 0; i < CGX_PER_NODE; i++) { 64 err = dm_pci_find_device(PCI_VENDOR_ID_CAVIUM, 65 PCI_DEVICE_ID_OCTEONTX2_CGX, i, 66 &dev); 67 if (err) 68 continue; 69 70 cgx = dev_get_priv(dev); 71 debug("%s udev %p cgx %p instance %d\n", __func__, dev, cgx, 72 lmac_instance); 73 for (idx = 0; idx < cgx->lmac_count; idx++) { 74 if (cgx->lmac[idx]->instance == lmac_instance) 75 return cgx->lmac[idx]; 76 } 77 } 78 return NULL; 79} 80 81void cgx_lmac_mac_filter_clear(struct lmac *lmac) 82{ 83 union cgxx_cmrx_rx_dmac_ctl0 dmac_ctl0; 84 union cgxx_cmr_rx_dmacx_cam0 dmac_cam0; 85 void *reg_addr; 86 87 dmac_cam0.u = 0x0; 88 reg_addr = lmac->cgx->reg_base + 89 CGXX_CMR_RX_DMACX_CAM0(lmac->lmac_id * 8); 90 writeq(dmac_cam0.u, reg_addr); 91 debug("%s: reg %p dmac_cam0 %llx\n", __func__, reg_addr, dmac_cam0.u); 92 93 dmac_ctl0.u = 0x0; 94 dmac_ctl0.s.bcst_accept = 1; 95 dmac_ctl0.s.mcst_mode = 1; 96 dmac_ctl0.s.cam_accept = 0; 97 reg_addr = lmac->cgx->reg_base + 98 CGXX_CMRX_RX_DMAC_CTL0(lmac->lmac_id); 99 writeq(dmac_ctl0.u, reg_addr); 100 debug("%s: reg %p dmac_ctl0 %llx\n", __func__, reg_addr, dmac_ctl0.u); 101} 102 103void cgx_lmac_mac_filter_setup(struct lmac *lmac) 104{ 105 union cgxx_cmrx_rx_dmac_ctl0 dmac_ctl0; 106 union cgxx_cmr_rx_dmacx_cam0 dmac_cam0; 107 u64 mac, tmp; 108 void *reg_addr; 109 110 memcpy((void *)&tmp, lmac->mac_addr, 6); 111 debug("%s: tmp %llx\n", __func__, tmp); 112 debug("%s: swab tmp %llx\n", __func__, swab64(tmp)); 113 mac = swab64(tmp) >> 16; 114 debug("%s: mac %llx\n", __func__, mac); 115 dmac_cam0.u = 0x0; 116 dmac_cam0.s.id = lmac->lmac_id; 117 dmac_cam0.s.adr = mac; 118 dmac_cam0.s.en = 1; 119 reg_addr = lmac->cgx->reg_base + 120 CGXX_CMR_RX_DMACX_CAM0(lmac->lmac_id * 8); 121 writeq(dmac_cam0.u, reg_addr); 122 debug("%s: reg %p dmac_cam0 %llx\n", __func__, reg_addr, dmac_cam0.u); 123 dmac_ctl0.u = 0x0; 124 dmac_ctl0.s.bcst_accept = 1; 125 dmac_ctl0.s.mcst_mode = 0; 126 dmac_ctl0.s.cam_accept = 1; 127 reg_addr = lmac->cgx->reg_base + 128 CGXX_CMRX_RX_DMAC_CTL0(lmac->lmac_id); 129 writeq(dmac_ctl0.u, reg_addr); 130 debug("%s: reg %p dmac_ctl0 %llx\n", __func__, reg_addr, dmac_ctl0.u); 131} 132 133int cgx_lmac_set_pkind(struct lmac *lmac, u8 lmac_id, int pkind) 134{ 135 cgx_write(lmac->cgx, lmac_id, CGXX_CMRX_RX_ID_MAP(0), 136 (pkind & 0x3f)); 137 return 0; 138} 139 140int cgx_lmac_link_status(struct lmac *lmac, int lmac_id, u64 *status) 141{ 142 int ret = 0; 143 144 ret = cgx_intf_get_link_sts(lmac->cgx->cgx_id, lmac_id, status); 145 if (ret) { 146 debug("%s request failed for cgx%d lmac%d\n", 147 __func__, lmac->cgx->cgx_id, lmac->lmac_id); 148 ret = -1; 149 } 150 return ret; 151} 152 153int cgx_lmac_rx_tx_enable(struct lmac *lmac, int lmac_id, bool enable) 154{ 155 struct cgx *cgx = lmac->cgx; 156 union cgxx_cmrx_config cmrx_config; 157 158 if (!cgx || lmac_id >= cgx->lmac_count) 159 return -ENODEV; 160 161 cmrx_config.u = cgx_read(cgx, lmac_id, CGXX_CMRX_CONFIG(0)); 162 cmrx_config.s.data_pkt_rx_en = 163 cmrx_config.s.data_pkt_tx_en = enable ? 1 : 0; 164 cgx_write(cgx, lmac_id, CGXX_CMRX_CONFIG(0), cmrx_config.u); 165 return 0; 166} 167 168int cgx_lmac_link_enable(struct lmac *lmac, int lmac_id, bool enable, 169 u64 *status) 170{ 171 int ret = 0; 172 173 ret = cgx_intf_link_up_dwn(lmac->cgx->cgx_id, lmac_id, enable, 174 status); 175 if (ret) { 176 debug("%s request failed for cgx%d lmac%d\n", 177 __func__, lmac->cgx->cgx_id, lmac->lmac_id); 178 ret = -1; 179 } 180 return ret; 181} 182 183int cgx_lmac_internal_loopback(struct lmac *lmac, int lmac_id, bool enable) 184{ 185 struct cgx *cgx = lmac->cgx; 186 union cgxx_cmrx_config cmrx_cfg; 187 union cgxx_gmp_pcs_mrx_control mrx_control; 188 union cgxx_spux_control1 spux_control1; 189 enum lmac_type lmac_type; 190 191 if (!cgx || lmac_id >= cgx->lmac_count) 192 return -ENODEV; 193 194 cmrx_cfg.u = cgx_read(cgx, lmac_id, CGXX_CMRX_CONFIG(0)); 195 lmac_type = cmrx_cfg.s.lmac_type; 196 if (lmac_type == LMAC_MODE_SGMII || lmac_type == LMAC_MODE_QSGMII) { 197 mrx_control.u = cgx_read(cgx, lmac_id, 198 CGXX_GMP_PCS_MRX_CONTROL(0)); 199 mrx_control.s.loopbck1 = enable ? 1 : 0; 200 cgx_write(cgx, lmac_id, CGXX_GMP_PCS_MRX_CONTROL(0), 201 mrx_control.u); 202 } else { 203 spux_control1.u = cgx_read(cgx, lmac_id, 204 CGXX_SPUX_CONTROL1(0)); 205 spux_control1.s.loopbck = enable ? 1 : 0; 206 cgx_write(cgx, lmac_id, CGXX_SPUX_CONTROL1(0), 207 spux_control1.u); 208 } 209 return 0; 210} 211 212static int cgx_lmac_init(struct cgx *cgx) 213{ 214 struct lmac *lmac; 215 union cgxx_cmrx_config cmrx_cfg; 216 static int instance = 1; 217 int i; 218 219 cgx->lmac_count = cgx_read(cgx, 0, CGXX_CMR_RX_LMACS()); 220 debug("%s: Found %d lmacs for cgx %d@%p\n", __func__, cgx->lmac_count, 221 cgx->cgx_id, cgx->reg_base); 222 223 for (i = 0; i < cgx->lmac_count; i++) { 224 lmac = calloc(1, sizeof(*lmac)); 225 if (!lmac) 226 return -ENOMEM; 227 lmac->instance = instance++; 228 snprintf(lmac->name, sizeof(lmac->name), "cgx_fwi_%d_%d", 229 cgx->cgx_id, i); 230 /* Get LMAC type */ 231 cmrx_cfg.u = cgx_read(cgx, i, CGXX_CMRX_CONFIG(0)); 232 lmac->lmac_type = cmrx_cfg.s.lmac_type; 233 234 lmac->lmac_id = i; 235 lmac->cgx = cgx; 236 cgx->lmac[i] = lmac; 237 debug("%s: map id %d to lmac %p (%s), type:%d instance %d\n", 238 __func__, i, lmac, lmac->name, lmac->lmac_type, 239 lmac->instance); 240 lmac->init_pend = 1; 241 printf("CGX%d LMAC%d [%s]\n", lmac->cgx->cgx_id, 242 lmac->lmac_id, lmac_type_to_str[lmac->lmac_type]); 243 octeontx2_board_get_mac_addr((lmac->instance - 1), 244 lmac->mac_addr); 245 debug("%s: MAC %pM\n", __func__, lmac->mac_addr); 246 cgx_lmac_mac_filter_setup(lmac); 247 } 248 return 0; 249} 250 251int cgx_probe(struct udevice *dev) 252{ 253 struct cgx *cgx = dev_get_priv(dev); 254 int err; 255 256 cgx->reg_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, 257 PCI_REGION_MEM); 258 cgx->dev = dev; 259 cgx->cgx_id = ((u64)(cgx->reg_base) >> 24) & 0x7; 260 261 debug("%s CGX BAR %p, id: %d\n", __func__, cgx->reg_base, 262 cgx->cgx_id); 263 debug("%s CGX %p, udev: %p\n", __func__, cgx, dev); 264 265 err = cgx_lmac_init(cgx); 266 267 return err; 268} 269 270int cgx_remove(struct udevice *dev) 271{ 272 struct cgx *cgx = dev_get_priv(dev); 273 int i; 274 275 debug("%s: cgx remove reg_base %p cgx_id %d", 276 __func__, cgx->reg_base, cgx->cgx_id); 277 for (i = 0; i < cgx->lmac_count; i++) 278 cgx_lmac_mac_filter_clear(cgx->lmac[i]); 279 280 return 0; 281} 282 283U_BOOT_DRIVER(cgx) = { 284 .name = "cgx", 285 .id = UCLASS_MISC, 286 .probe = cgx_probe, 287 .remove = cgx_remove, 288 .priv_auto = sizeof(struct cgx), 289}; 290 291static struct pci_device_id cgx_supported[] = { 292 {PCI_VDEVICE(CAVIUM, PCI_DEVICE_ID_CAVIUM_CGX) }, 293 {} 294}; 295 296U_BOOT_PCI_DEVICE(cgx, cgx_supported); 297