From patchwork Sat Dec 18 21:49:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Colin Foster X-Patchwork-Id: 526188 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 00361C433EF for ; Sat, 18 Dec 2021 21:50:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234709AbhLRVuT (ORCPT ); Sat, 18 Dec 2021 16:50:19 -0500 Received: from mail-mw2nam10on2118.outbound.protection.outlook.com ([40.107.94.118]:19424 "EHLO NAM10-MW2-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S234623AbhLRVuQ (ORCPT ); Sat, 18 Dec 2021 16:50:16 -0500 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=jV/PXIV1zDgbsd7eG2DG0ODK9Dj4mHbuHZDO2BMK8xCH02mAVAw5w8kq0Hv+m7n7Ec2kdDytYREjSvXUZc9hYkEpCUuOsKfmw/bZz0CKK9PkBYid5VwjWcZqc0kEbd+eeoTHShzsZpEC/5yxFgVZ0+tfekQjfgxM6ISPSBqzZx+PljNU7ely0HojGb2suOcw2siVbTmr77wStMBYj084oufEBs+DbNV2KMc0NNHrYqYbnIKirtFuljX23X6AZHbwKCHYZKlB3OgZMj3Yz6wQtGRcy44FY82KNfkYyBwN0emxrO9d9LdIcZJ30u1/mBQ6SdBypHKNrWopJRGIICh+ig== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=bUb9n1OMVkjY/1NG3XhlQOmAXBxCnkMlCNZ+SOpA2zY=; b=Easr0jxrQPI4L+aPPPEuFHKJKYqhjeimarJCrNqVOyQ3+0Y78O3ApTZCjEXHC7Vq8olyd2RSbBSyxQDchqDvaaMO6/I2D4ygU1RDks4ZkBIDS7ZW4ObGtASlDQu+e161GWrpIubsm1QOipvaR71QZkJs8cMgHxaejLAqimzXe1vFq8YFESDndU15KRcZnu0axk9gIXO7APJ/hYHkAj+5DUle+kQGBcvagk9v4A9lDRYfojJ3ydCrTW4yVzmHADC4ZEYRILrJzjFnfKDb5oxJVluLiC8WujnwH0qNye0otI/ZLtSzo/U0MyJlYNfc7cjsaWccBcTzjlYLN+wIH9K+AA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=in-advantage.com; dmarc=pass action=none header.from=in-advantage.com; dkim=pass header.d=in-advantage.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=inadvantage.onmicrosoft.com; s=selector2-inadvantage-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=bUb9n1OMVkjY/1NG3XhlQOmAXBxCnkMlCNZ+SOpA2zY=; b=b7HT2HB7qN3gO5hwhYUfRihzhzrl9N/ddM8elabOKQMnqJnWhAwSGbCkxvROxsrgcJfg5rrtYkdqTDBn8V2Wq0vIIXbTqabWw0RtIaUmVF2QUEkv+3xrhwNLGetXSPk472GzrMIyr0ozLiOB8zvet8jUrmaIJyKyLMmTzuqzd+0= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=in-advantage.com; Received: from MWHPR1001MB2351.namprd10.prod.outlook.com (2603:10b6:301:35::37) by CO6PR10MB5633.namprd10.prod.outlook.com (2603:10b6:303:148::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4801.17; Sat, 18 Dec 2021 21:50:10 +0000 Received: from MWHPR1001MB2351.namprd10.prod.outlook.com ([fe80::2d52:2a96:7e6c:460f]) by MWHPR1001MB2351.namprd10.prod.outlook.com ([fe80::2d52:2a96:7e6c:460f%4]) with mapi id 15.20.4801.017; Sat, 18 Dec 2021 21:50:10 +0000 From: Colin Foster To: linux-gpio@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Linus Walleij , Russell King , Heiner Kallweit , Jakub Kicinski , "David S. Miller" , Florian Fainelli , Vivien Didelot , Andrew Lunn , UNGLinuxDriver@microchip.com, Alexandre Belloni , Claudiu Manoil , Vladimir Oltean , Lee Jones Subject: [RFC v5 net-next 06/13] net: dsa: ocelot: add external ocelot switch control Date: Sat, 18 Dec 2021 13:49:47 -0800 Message-Id: <20211218214954.109755-7-colin.foster@in-advantage.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211218214954.109755-1-colin.foster@in-advantage.com> References: <20211218214954.109755-1-colin.foster@in-advantage.com> X-ClientProxiedBy: MWHPR02CA0011.namprd02.prod.outlook.com (2603:10b6:300:4b::21) To MWHPR1001MB2351.namprd10.prod.outlook.com (2603:10b6:301:35::37) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: fbec9c59-db4f-4a27-a1d1-08d9c2705cef X-MS-TrafficTypeDiagnostic: CO6PR10MB5633:EE_ X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:4941; X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: uHNW8I77dB/WTh7Wc1T5Rj2wIoYCXUXIZE/+DCqPnFQtCyLzWGPeHIHfEaMCw5Ut0PXkKzWfNFa3oIXLQn8RVXA1o1uQgLcjVnZd4Fbr30FwIN3/MbrQMPJ5qvSHV867fos7wSos2M+fulwU/TBk3Xwlv2oDMKNOQkHsZ7pYB9XTKQEBqjKh03/S8nyQOXyssa9VHRkAMwF8rMfco/V+kC31xQIc7yubfJHK8j7FJ+tlzTRHN9SigoZ8GpKmrtOWfGqQ3wMYCLAY5YeVC0vj6GW40VRncgmxudxwt5aTfU1K6Y6AdQJYQzan4V37bPjHTijk7BJoqKrT+ijSinio7aqUDGy1MWWcy0m/ZvRmaii8AtatJMgPbuSqSsav4bFF2daEXOfNKTdw+jM+NpSLz7JF9t2mgtR3AYLjQrV1coWXT2gKcE/K930YLBAXWB/BCGjkFi/khImtKdR8Kg4MRhOBVlHwRv2YEPo4VcyVyYjyC7AtXMN0gf1ckG7+Tz6HttimgRFn3lkpIZS62VAC6fdlg6TxW/w9p8pOjJurrYk1F3Jh2+Zo5ETt5ABpEK1wBryVCtnJj53xpE1va8btD6aypyNSm31SJY/tDYdGiI+gn0RLclfccuGkihLojpxonomimCc6UnPCNxEnlWwNw8mHkt1pVX14TOcgWY5pJJIYM19Dy07hZK3SZfrBPIQjUpXnTD40eVUHsvwYzypj4w== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:MWHPR1001MB2351.namprd10.prod.outlook.com; PTR:; CAT:NONE; SFS:(39830400003)(396003)(366004)(346002)(376002)(136003)(6486002)(6506007)(7416002)(2906002)(36756003)(6512007)(26005)(86362001)(66556008)(66476007)(186003)(1076003)(6666004)(4326008)(83380400001)(30864003)(66946007)(2616005)(44832011)(8936002)(8676002)(316002)(54906003)(38100700002)(5660300002)(508600001)(52116002)(38350700002); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: tBQ2/a78qhngMF0Q6pxlXB0QvlAVa0QQIvudKJzGaSy2I1Cww8+VujzNgI9UAR+HB0b8niZXeCwivWUSzO6RVNbm6Sh1U5UPHGapOVkn+q/mIpPEWnWyv0l5sTF4j7AHgoLLQzAZQoyxQI49Kz/pbn9gooMwOGfQafM/6b+of0P2k6vXmyEBqRmdpZBEOswwR+WgZF9r98rDu3cxF8e2ktYJ7ZOY5cEGzRV18TG5Lst7s9iLTnoX53SLYILd9iz5cJNrmb46E5OVmB+gi6e1P1s9OZ/S3JWWMWFaXyPoJY4kgolMRrdmqsiqsu+CUU6p/8BonzbjmyiFa5TYaEffKrGaYV9S2xvN99ZiH2Fwk5UXC/9vzulpSX3RL/IJvXtWzFEsWMOIj3maVZyhg4AQIvquSsj+HIfK3GyTUNgK/EYL4+1EZi+1Xt5HVtSS6R+t3JvOAhMpjHNIJGkLmvo6MkIjvyNb/gYB5dXpc3i+4eTEz2lgvaakXaEYkfUs7XPTuyqsFZBbBvZ1GqO8y930LKNPp4aaTX2jON9d6uwBrYRUQjUL+ZrwM1x8llDoRm56nwGgzw5pL1JtOyqRtEVCKyCLlTCBtTh/aXF8bS19+NDRD++nA9NMlaQDCWKArdFQsr9yYwjRaKDytIoCIrDaKOZmfvvfFlUEXiS46VnlIIwJTtBl9VkKiTBTonM7GEbXSxZ3fExJksRbypfqH0USMuJVOpFcxawAZemVwAfc17g4eg85NhjMEUk6H4DT2zZqb+HZnu+F1i29jgbj0zB8mPIO4rZ9difJtdpOn+iluOX71orBeJ+9CQGRyQgwm1dtYU6UBzhZy7RzRsku39JLnBkpOFY5+2t4d35r556mvvqbDR1gytOa5QOR/pUa9QzxJbcT00WyJrdjj6JnMQdEllDtVvsQk2swNld8oqPDhMJ9ounk2+24YA7rdfrBcXUZQDbThdlo7vxX9WcQsYcrzRD7FgtsSBvvF+Cn6OC68n/r6HykJOpeXKdptqKB5EFRqr9lJPBXmbABfqhrlwFuFDDWEXymUpH+H3JZvUOM7OTajNpclqvRDRLDxfGb6KxaERNoM0nk23lo5zh035i7BZTNlHr4+U37B70VzXNxzzi7GE01imYiFF01/7VZdXsPGLPowE5zWF9nCPCnk+Q5FeT9dwHlxPoWUbbvHhQnWE0M4veEP/LYUuLmJ5KfX+MaHT5dtfAYE0h8Z5Q2RP5ELX06toWlHm6virZVYuybzA39t78VB//xeHBiPguPezQqV82JWo/cHKBpZxDCi+JcD90fa3rV0VVJuAEkkNTLUNmV1oYlHBSk2FTfBAGcGwWFGtYYXty7Ic/cf/hLNmf9NTcx9MDXW0Bkj9za27Q0mqMKXHmLxphr7GMffyLTKfUo/6NcragZnbKSXd8/85fcXHyGYc4/cXz8j07Xh8kJEFrh4IHRWHL6Otry1vdkfhQtIv8ln/Dnkml4De1zaqPD8nLcdnaaaPItGMhFu/U3Ju3EjoGQD26jnoD2fkgg90NttSfNH3ZyLJ5vDNmUh770Tw9s+hIrqdY6H8B+D1dqfD2rVc/C9CNIuFju90v9aISx8mJgZVhIiZNXfVtggTdpSTEqtfNjlB8r8RAo21jQucA9PXyau0U7WHeewJ0SOXA9gdARsdqF7dr6C99rBZIf5g== X-OriginatorOrg: in-advantage.com X-MS-Exchange-CrossTenant-Network-Message-Id: fbec9c59-db4f-4a27-a1d1-08d9c2705cef X-MS-Exchange-CrossTenant-AuthSource: MWHPR1001MB2351.namprd10.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Dec 2021 21:50:10.4407 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 48e842ca-fbd8-4633-a79d-0c955a7d3aae X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 5s6G7n+j19VtHvM8+YuOt7B0TVliSHE2Z5N1mHQshVFDNk2AmhOnTlskOJoXu4gWdPCf317u6Ay4amYdqDD8G611olEFaaZBoKCiPxiKCLk= X-MS-Exchange-Transport-CrossTenantHeadersStamped: CO6PR10MB5633 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org Add control of an external VSC7512 chip by way of the ocelot-mfd interface. Signed-off-by: Colin Foster --- drivers/net/dsa/ocelot/Kconfig | 15 + drivers/net/dsa/ocelot/Makefile | 5 + drivers/net/dsa/ocelot/ocelot_ext.c | 644 ++++++++++++++++++++++++++++ include/soc/mscc/ocelot.h | 2 + 4 files changed, 666 insertions(+) create mode 100644 drivers/net/dsa/ocelot/ocelot_ext.c diff --git a/drivers/net/dsa/ocelot/Kconfig b/drivers/net/dsa/ocelot/Kconfig index 220b0b027b55..60a930f48014 100644 --- a/drivers/net/dsa/ocelot/Kconfig +++ b/drivers/net/dsa/ocelot/Kconfig @@ -1,4 +1,19 @@ # SPDX-License-Identifier: GPL-2.0-only +config NET_DSA_MSCC_OCELOT_EXT + tristate "Ocelot External Ethernet switch support" + depends on NET_DSA && SPI + depends on NET_VENDOR_MICROSEMI + select MDIO_MSCC_MIIM + select MFD_OCELOT_CORE + select MFD_OCELOT_SPI + select MSCC_OCELOT_SWITCH_LIB + select NET_DSA_TAG_OCELOT_8021Q + select NET_DSA_TAG_OCELOT + help + This driver supports the VSC7511, VSC7512, VSC7513 and VSC7514 chips + when controlled through SPI. It can be used with the Microsemi dev + boards and an external CPU or custom hardware. + config NET_DSA_MSCC_FELIX tristate "Ocelot / Felix Ethernet switch support" depends on NET_DSA && PCI diff --git a/drivers/net/dsa/ocelot/Makefile b/drivers/net/dsa/ocelot/Makefile index f6dd131e7491..d7f3f5a4461c 100644 --- a/drivers/net/dsa/ocelot/Makefile +++ b/drivers/net/dsa/ocelot/Makefile @@ -1,11 +1,16 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_NET_DSA_MSCC_FELIX) += mscc_felix.o +obj-$(CONFIG_NET_DSA_MSCC_OCELOT_EXT) += mscc_ocelot_ext.o obj-$(CONFIG_NET_DSA_MSCC_SEVILLE) += mscc_seville.o mscc_felix-objs := \ felix.o \ felix_vsc9959.o +mscc_ocelot_ext-objs := \ + felix.o \ + ocelot_ext.o + mscc_seville-objs := \ felix.o \ seville_vsc9953.o diff --git a/drivers/net/dsa/ocelot/ocelot_ext.c b/drivers/net/dsa/ocelot/ocelot_ext.c new file mode 100644 index 000000000000..e35f21ba5dc3 --- /dev/null +++ b/drivers/net/dsa/ocelot/ocelot_ext.c @@ -0,0 +1,644 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Copyright 2021 Innovative Advantage Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "felix.h" + +struct ocelot_ext_data { + struct felix felix; +}; + +static const u32 vsc7512_gcb_regmap[] = { + REG(GCB_SOFT_RST, 0x0008), + REG(GCB_MIIM_MII_STATUS, 0x009c), + REG(GCB_PHY_PHY_CFG, 0x00f0), + REG(GCB_PHY_PHY_STAT, 0x00f4), +}; + +static const u32 *vsc7512_regmap[TARGET_MAX] = { + [ANA] = vsc7514_ana_regmap, + [QS] = vsc7514_qs_regmap, + [QSYS] = vsc7514_qsys_regmap, + [REW] = vsc7514_rew_regmap, + [SYS] = vsc7514_sys_regmap, + [S0] = vsc7514_vcap_regmap, + [S1] = vsc7514_vcap_regmap, + [S2] = vsc7514_vcap_regmap, + [PTP] = vsc7514_ptp_regmap, + [GCB] = vsc7512_gcb_regmap, + [DEV_GMII] = vsc7514_dev_gmii_regmap, +}; + +#define VSC7512_BYTE_ORDER_LE 0x00000000 +#define VSC7512_BYTE_ORDER_BE 0x81818181 +#define VSC7512_BIT_ORDER_MSB 0x00000000 +#define VSC7512_BIT_ORDER_LSB 0x42424242 + +static void ocelot_ext_reset_phys(struct ocelot *ocelot) +{ + ocelot_write(ocelot, 0, GCB_PHY_PHY_CFG); + ocelot_write(ocelot, 0x1ff, GCB_PHY_PHY_CFG); + mdelay(500); +} + +static int ocelot_ext_reset(struct ocelot *ocelot) +{ + struct felix *felix = ocelot_to_felix(ocelot); + struct device *dev = ocelot->dev; + struct device_node *mdio_node; + int retries = 100; + int err, val; + + ocelot_ext_reset_phys(ocelot); + + mdio_node = of_get_child_by_name(dev->of_node, "mdio"); + if (!mdio_node) + dev_info(ocelot->dev, + "mdio children not found in device tree\n"); + + err = of_mdiobus_register(felix->imdio, mdio_node); + if (err) { + dev_err(ocelot->dev, "error registering MDIO bus\n"); + return err; + } + + felix->ds->slave_mii_bus = felix->imdio; + + /* We might need to reset the switch core here, if that is possible */ + err = regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], 1); + if (err) + return err; + + err = regmap_field_write(ocelot->regfields[SYS_RESET_CFG_MEM_ENA], 1); + if (err) + return err; + + do { + msleep(1); + regmap_field_read(ocelot->regfields[SYS_RESET_CFG_MEM_INIT], + &val); + } while (val && --retries); + + if (!retries) + return -ETIMEDOUT; + + err = regmap_field_write(ocelot->regfields[SYS_RESET_CFG_CORE_ENA], 1); + + return err; +} + +static u32 ocelot_offset_from_reg_base(struct ocelot *ocelot, u32 target, + u32 reg) +{ + return ocelot->map[target][reg & REG_MASK]; +} + +static const struct ocelot_ops vsc7512_ops = { + .reset = ocelot_ext_reset, + .wm_enc = ocelot_wm_enc, + .wm_dec = ocelot_wm_dec, + .wm_stat = ocelot_wm_stat, + .port_to_netdev = felix_port_to_netdev, + .netdev_to_port = felix_netdev_to_port, +}; + +static const struct resource vsc7512_target_io_res[TARGET_MAX] = { + [ANA] = { + .start = 0x71880000, + .end = 0x7188ffff, + .name = "ana", + }, + [QS] = { + .start = 0x71080000, + .end = 0x710800ff, + .name = "qs", + }, + [QSYS] = { + .start = 0x71800000, + .end = 0x719fffff, + .name = "qsys", + }, + [REW] = { + .start = 0x71030000, + .end = 0x7103ffff, + .name = "rew", + }, + [SYS] = { + .start = 0x71010000, + .end = 0x7101ffff, + .name = "sys", + }, + [S0] = { + .start = 0x71040000, + .end = 0x710403ff, + .name = "s0", + }, + [S1] = { + .start = 0x71050000, + .end = 0x710503ff, + .name = "s1", + }, + [S2] = { + .start = 0x71060000, + .end = 0x710603ff, + .name = "s2", + }, + [GCB] = { + .start = 0x71070000, + .end = 0x7107022b, + .name = "devcpu_gcb", + }, +}; + +static const struct resource vsc7512_port_io_res[] = { + { + .start = 0x711e0000, + .end = 0x711effff, + .name = "port0", + }, + { + .start = 0x711f0000, + .end = 0x711fffff, + .name = "port1", + }, + { + .start = 0x71200000, + .end = 0x7120ffff, + .name = "port2", + }, + { + .start = 0x71210000, + .end = 0x7121ffff, + .name = "port3", + }, + { + .start = 0x71220000, + .end = 0x7122ffff, + .name = "port4", + }, + { + .start = 0x71230000, + .end = 0x7123ffff, + .name = "port5", + }, + { + .start = 0x71240000, + .end = 0x7124ffff, + .name = "port6", + }, + { + .start = 0x71250000, + .end = 0x7125ffff, + .name = "port7", + }, + { + .start = 0x71260000, + .end = 0x7126ffff, + .name = "port8", + }, + { + .start = 0x71270000, + .end = 0x7127ffff, + .name = "port9", + }, + { + .start = 0x71280000, + .end = 0x7128ffff, + .name = "port10", + }, +}; + +static const struct reg_field vsc7512_regfields[REGFIELD_MAX] = { + [ANA_ADVLEARN_VLAN_CHK] = REG_FIELD(ANA_ADVLEARN, 11, 11), + [ANA_ADVLEARN_LEARN_MIRROR] = REG_FIELD(ANA_ADVLEARN, 0, 10), + [ANA_ANEVENTS_MSTI_DROP] = REG_FIELD(ANA_ANEVENTS, 27, 27), + [ANA_ANEVENTS_ACLKILL] = REG_FIELD(ANA_ANEVENTS, 26, 26), + [ANA_ANEVENTS_ACLUSED] = REG_FIELD(ANA_ANEVENTS, 25, 25), + [ANA_ANEVENTS_AUTOAGE] = REG_FIELD(ANA_ANEVENTS, 24, 24), + [ANA_ANEVENTS_VS2TTL1] = REG_FIELD(ANA_ANEVENTS, 23, 23), + [ANA_ANEVENTS_STORM_DROP] = REG_FIELD(ANA_ANEVENTS, 22, 22), + [ANA_ANEVENTS_LEARN_DROP] = REG_FIELD(ANA_ANEVENTS, 21, 21), + [ANA_ANEVENTS_AGED_ENTRY] = REG_FIELD(ANA_ANEVENTS, 20, 20), + [ANA_ANEVENTS_CPU_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 19, 19), + [ANA_ANEVENTS_AUTO_LEARN_FAILED] = REG_FIELD(ANA_ANEVENTS, 18, 18), + [ANA_ANEVENTS_LEARN_REMOVE] = REG_FIELD(ANA_ANEVENTS, 17, 17), + [ANA_ANEVENTS_AUTO_LEARNED] = REG_FIELD(ANA_ANEVENTS, 16, 16), + [ANA_ANEVENTS_AUTO_MOVED] = REG_FIELD(ANA_ANEVENTS, 15, 15), + [ANA_ANEVENTS_DROPPED] = REG_FIELD(ANA_ANEVENTS, 14, 14), + [ANA_ANEVENTS_CLASSIFIED_DROP] = REG_FIELD(ANA_ANEVENTS, 13, 13), + [ANA_ANEVENTS_CLASSIFIED_COPY] = REG_FIELD(ANA_ANEVENTS, 12, 12), + [ANA_ANEVENTS_VLAN_DISCARD] = REG_FIELD(ANA_ANEVENTS, 11, 11), + [ANA_ANEVENTS_FWD_DISCARD] = REG_FIELD(ANA_ANEVENTS, 10, 10), + [ANA_ANEVENTS_MULTICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 9, 9), + [ANA_ANEVENTS_UNICAST_FLOOD] = REG_FIELD(ANA_ANEVENTS, 8, 8), + [ANA_ANEVENTS_DEST_KNOWN] = REG_FIELD(ANA_ANEVENTS, 7, 7), + [ANA_ANEVENTS_BUCKET3_MATCH] = REG_FIELD(ANA_ANEVENTS, 6, 6), + [ANA_ANEVENTS_BUCKET2_MATCH] = REG_FIELD(ANA_ANEVENTS, 5, 5), + [ANA_ANEVENTS_BUCKET1_MATCH] = REG_FIELD(ANA_ANEVENTS, 4, 4), + [ANA_ANEVENTS_BUCKET0_MATCH] = REG_FIELD(ANA_ANEVENTS, 3, 3), + [ANA_ANEVENTS_CPU_OPERATION] = REG_FIELD(ANA_ANEVENTS, 2, 2), + [ANA_ANEVENTS_DMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 1, 1), + [ANA_ANEVENTS_SMAC_LOOKUP] = REG_FIELD(ANA_ANEVENTS, 0, 0), + [ANA_TABLES_MACACCESS_B_DOM] = REG_FIELD(ANA_TABLES_MACACCESS, 18, 18), + [ANA_TABLES_MACTINDX_BUCKET] = REG_FIELD(ANA_TABLES_MACTINDX, 10, 11), + [ANA_TABLES_MACTINDX_M_INDEX] = REG_FIELD(ANA_TABLES_MACTINDX, 0, 9), + [GCB_SOFT_RST_SWC_RST] = REG_FIELD(GCB_SOFT_RST, 1, 1), + [QSYS_TIMED_FRAME_ENTRY_TFRM_VLD] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 20, 20), + [QSYS_TIMED_FRAME_ENTRY_TFRM_FP] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 8, 19), + [QSYS_TIMED_FRAME_ENTRY_TFRM_PORTNO] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 4, 7), + [QSYS_TIMED_FRAME_ENTRY_TFRM_TM_SEL] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 1, 3), + [QSYS_TIMED_FRAME_ENTRY_TFRM_TM_T] = REG_FIELD(QSYS_TIMED_FRAME_ENTRY, 0, 0), + [SYS_RESET_CFG_CORE_ENA] = REG_FIELD(SYS_RESET_CFG, 2, 2), + [SYS_RESET_CFG_MEM_ENA] = REG_FIELD(SYS_RESET_CFG, 1, 1), + [SYS_RESET_CFG_MEM_INIT] = REG_FIELD(SYS_RESET_CFG, 0, 0), + /* Replicated per number of ports (12), register size 4 per port */ + [QSYS_SWITCH_PORT_MODE_PORT_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 14, 14, 12, 4), + [QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 11, 13, 12, 4), + [QSYS_SWITCH_PORT_MODE_YEL_RSRVD] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 10, 10, 12, 4), + [QSYS_SWITCH_PORT_MODE_INGRESS_DROP_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 9, 9, 12, 4), + [QSYS_SWITCH_PORT_MODE_TX_PFC_ENA] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 1, 8, 12, 4), + [QSYS_SWITCH_PORT_MODE_TX_PFC_MODE] = REG_FIELD_ID(QSYS_SWITCH_PORT_MODE, 0, 0, 12, 4), + [SYS_PORT_MODE_DATA_WO_TS] = REG_FIELD_ID(SYS_PORT_MODE, 5, 6, 12, 4), + [SYS_PORT_MODE_INCL_INJ_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 3, 4, 12, 4), + [SYS_PORT_MODE_INCL_XTR_HDR] = REG_FIELD_ID(SYS_PORT_MODE, 1, 2, 12, 4), + [SYS_PORT_MODE_INCL_HDR_ERR] = REG_FIELD_ID(SYS_PORT_MODE, 0, 0, 12, 4), + [SYS_PAUSE_CFG_PAUSE_START] = REG_FIELD_ID(SYS_PAUSE_CFG, 10, 18, 12, 4), + [SYS_PAUSE_CFG_PAUSE_STOP] = REG_FIELD_ID(SYS_PAUSE_CFG, 1, 9, 12, 4), + [SYS_PAUSE_CFG_PAUSE_ENA] = REG_FIELD_ID(SYS_PAUSE_CFG, 0, 1, 12, 4), +}; + +static const struct ocelot_stat_layout vsc7512_stats_layout[] = { + { .offset = 0x00, .name = "rx_octets", }, + { .offset = 0x01, .name = "rx_unicast", }, + { .offset = 0x02, .name = "rx_multicast", }, + { .offset = 0x03, .name = "rx_broadcast", }, + { .offset = 0x04, .name = "rx_shorts", }, + { .offset = 0x05, .name = "rx_fragments", }, + { .offset = 0x06, .name = "rx_jabbers", }, + { .offset = 0x07, .name = "rx_crc_align_errs", }, + { .offset = 0x08, .name = "rx_sym_errs", }, + { .offset = 0x09, .name = "rx_frames_below_65_octets", }, + { .offset = 0x0A, .name = "rx_frames_65_to_127_octets", }, + { .offset = 0x0B, .name = "rx_frames_128_to_255_octets", }, + { .offset = 0x0C, .name = "rx_frames_256_to_511_octets", }, + { .offset = 0x0D, .name = "rx_frames_512_to_1023_octets", }, + { .offset = 0x0E, .name = "rx_frames_1024_to_1526_octets", }, + { .offset = 0x0F, .name = "rx_frames_over_1526_octets", }, + { .offset = 0x10, .name = "rx_pause", }, + { .offset = 0x11, .name = "rx_control", }, + { .offset = 0x12, .name = "rx_longs", }, + { .offset = 0x13, .name = "rx_classified_drops", }, + { .offset = 0x14, .name = "rx_red_prio_0", }, + { .offset = 0x15, .name = "rx_red_prio_1", }, + { .offset = 0x16, .name = "rx_red_prio_2", }, + { .offset = 0x17, .name = "rx_red_prio_3", }, + { .offset = 0x18, .name = "rx_red_prio_4", }, + { .offset = 0x19, .name = "rx_red_prio_5", }, + { .offset = 0x1A, .name = "rx_red_prio_6", }, + { .offset = 0x1B, .name = "rx_red_prio_7", }, + { .offset = 0x1C, .name = "rx_yellow_prio_0", }, + { .offset = 0x1D, .name = "rx_yellow_prio_1", }, + { .offset = 0x1E, .name = "rx_yellow_prio_2", }, + { .offset = 0x1F, .name = "rx_yellow_prio_3", }, + { .offset = 0x20, .name = "rx_yellow_prio_4", }, + { .offset = 0x21, .name = "rx_yellow_prio_5", }, + { .offset = 0x22, .name = "rx_yellow_prio_6", }, + { .offset = 0x23, .name = "rx_yellow_prio_7", }, + { .offset = 0x24, .name = "rx_green_prio_0", }, + { .offset = 0x25, .name = "rx_green_prio_1", }, + { .offset = 0x26, .name = "rx_green_prio_2", }, + { .offset = 0x27, .name = "rx_green_prio_3", }, + { .offset = 0x28, .name = "rx_green_prio_4", }, + { .offset = 0x29, .name = "rx_green_prio_5", }, + { .offset = 0x2A, .name = "rx_green_prio_6", }, + { .offset = 0x2B, .name = "rx_green_prio_7", }, + { .offset = 0x40, .name = "tx_octets", }, + { .offset = 0x41, .name = "tx_unicast", }, + { .offset = 0x42, .name = "tx_multicast", }, + { .offset = 0x43, .name = "tx_broadcast", }, + { .offset = 0x44, .name = "tx_collision", }, + { .offset = 0x45, .name = "tx_drops", }, + { .offset = 0x46, .name = "tx_pause", }, + { .offset = 0x47, .name = "tx_frames_below_65_octets", }, + { .offset = 0x48, .name = "tx_frames_65_to_127_octets", }, + { .offset = 0x49, .name = "tx_frames_128_255_octets", }, + { .offset = 0x4A, .name = "tx_frames_256_511_octets", }, + { .offset = 0x4B, .name = "tx_frames_512_1023_octets", }, + { .offset = 0x4C, .name = "tx_frames_1024_1526_octets", }, + { .offset = 0x4D, .name = "tx_frames_over_1526_octets", }, + { .offset = 0x4E, .name = "tx_yellow_prio_0", }, + { .offset = 0x4F, .name = "tx_yellow_prio_1", }, + { .offset = 0x50, .name = "tx_yellow_prio_2", }, + { .offset = 0x51, .name = "tx_yellow_prio_3", }, + { .offset = 0x52, .name = "tx_yellow_prio_4", }, + { .offset = 0x53, .name = "tx_yellow_prio_5", }, + { .offset = 0x54, .name = "tx_yellow_prio_6", }, + { .offset = 0x55, .name = "tx_yellow_prio_7", }, + { .offset = 0x56, .name = "tx_green_prio_0", }, + { .offset = 0x57, .name = "tx_green_prio_1", }, + { .offset = 0x58, .name = "tx_green_prio_2", }, + { .offset = 0x59, .name = "tx_green_prio_3", }, + { .offset = 0x5A, .name = "tx_green_prio_4", }, + { .offset = 0x5B, .name = "tx_green_prio_5", }, + { .offset = 0x5C, .name = "tx_green_prio_6", }, + { .offset = 0x5D, .name = "tx_green_prio_7", }, + { .offset = 0x5E, .name = "tx_aged", }, + { .offset = 0x80, .name = "drop_local", }, + { .offset = 0x81, .name = "drop_tail", }, + { .offset = 0x82, .name = "drop_yellow_prio_0", }, + { .offset = 0x83, .name = "drop_yellow_prio_1", }, + { .offset = 0x84, .name = "drop_yellow_prio_2", }, + { .offset = 0x85, .name = "drop_yellow_prio_3", }, + { .offset = 0x86, .name = "drop_yellow_prio_4", }, + { .offset = 0x87, .name = "drop_yellow_prio_5", }, + { .offset = 0x88, .name = "drop_yellow_prio_6", }, + { .offset = 0x89, .name = "drop_yellow_prio_7", }, + { .offset = 0x8A, .name = "drop_green_prio_0", }, + { .offset = 0x8B, .name = "drop_green_prio_1", }, + { .offset = 0x8C, .name = "drop_green_prio_2", }, + { .offset = 0x8D, .name = "drop_green_prio_3", }, + { .offset = 0x8E, .name = "drop_green_prio_4", }, + { .offset = 0x8F, .name = "drop_green_prio_5", }, + { .offset = 0x90, .name = "drop_green_prio_6", }, + { .offset = 0x91, .name = "drop_green_prio_7", }, +}; + +static void vsc7512_phylink_validate(struct ocelot *ocelot, int port, + unsigned long *supported, + struct phylink_link_state *state) +{ + struct ocelot_port *ocelot_port = ocelot->ports[port]; + + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; + + if (state->interface != PHY_INTERFACE_MODE_NA && + state->interface != ocelot_port->phy_mode) { + bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); + return; + } + + phylink_set_port_modes(mask); + + phylink_set(mask, Pause); + phylink_set(mask, Autoneg); + phylink_set(mask, Asym_Pause); + phylink_set(mask, 10baseT_Half); + phylink_set(mask, 10baseT_Full); + phylink_set(mask, 100baseT_Half); + phylink_set(mask, 100baseT_Full); + phylink_set(mask, 1000baseT_Half); + phylink_set(mask, 1000baseT_Full); + + bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); + bitmap_and(state->advertising, state->advertising, mask, + __ETHTOOL_LINK_MODE_MASK_NBITS); +} + +static int vsc7512_prevalidate_phy_mode(struct ocelot *ocelot, int port, + phy_interface_t phy_mode) +{ + switch (phy_mode) { + case PHY_INTERFACE_MODE_INTERNAL: + if (port < 4) + return 0; + return -EOPNOTSUPP; + case PHY_INTERFACE_MODE_SGMII: + if (port < 8) + return 0; + return -EOPNOTSUPP; + case PHY_INTERFACE_MODE_QSGMII: + if (port == 7 || port == 8 || port == 10) + return 0; + return -EOPNOTSUPP; + default: + return -EOPNOTSUPP; + } +} + +static int vsc7512_port_setup_tc(struct dsa_switch *ds, int port, + enum tc_setup_type type, void *type_data) +{ + return -EOPNOTSUPP; +} + +static struct vcap_props vsc7512_vcap_props[] = { + [VCAP_ES0] = { + .action_type_width = 0, + .action_table = { + [ES0_ACTION_TYPE_NORMAL] = { + .width = 73, + .count = 1, + }, + }, + .target = S0, + .keys = vsc7514_vcap_es0_keys, + .actions = vsc7514_vcap_es0_actions, + }, + [VCAP_IS1] = { + .action_type_width = 0, + .action_table = { + [IS1_ACTION_TYPE_NORMAL] = { + .width = 78, + .count = 4, + }, + }, + .target = S1, + .keys = vsc7514_vcap_is1_keys, + .actions = vsc7514_vcap_is1_actions, + }, + [VCAP_IS2] = { + .action_type_width = 1, + .action_table = { + [IS2_ACTION_TYPE_NORMAL] = { + .width = 49, + .count = 2, + }, + [IS2_ACTION_TYPE_SMAC_SIP] = { + .width = 6, + .count = 4, + }, + }, + .target = S2, + .keys = vsc7514_vcap_is2_keys, + .actions = vsc7514_vcap_is2_actions, + }, +}; + +static struct regmap *vsc7512_regmap_init(struct ocelot *ocelot, + struct resource *res) +{ + struct device *dev = ocelot->dev; + struct regmap *regmap; + + regmap = ocelot_mfd_get_regmap_from_resource(dev->parent, res); + if (IS_ERR(regmap)) + return ERR_CAST(regmap); + + return regmap; +} + +static int vsc7512_mdio_bus_alloc(struct ocelot *ocelot) +{ + struct felix *felix = ocelot_to_felix(ocelot); + struct device *dev = ocelot->dev; + u32 mii_offset, phy_offset; + struct mii_bus *bus; + int err; + + mii_offset = ocelot_offset_from_reg_base(ocelot, GCB, + GCB_MIIM_MII_STATUS); + + phy_offset = ocelot_offset_from_reg_base(ocelot, GCB, GCB_PHY_PHY_CFG); + + err = mscc_miim_setup(dev, &bus, "ocelot_ext MDIO bus", + ocelot->targets[GCB], mii_offset, + ocelot->targets[GCB], phy_offset); + if (err) { + dev_err(dev, "failed to setup MDIO bus\n"); + return err; + } + + felix->imdio = bus; + + return err; +} + + +static void vsc7512_mdio_bus_free(struct ocelot *ocelot) +{ + struct felix *felix = ocelot_to_felix(ocelot); + + if (felix->imdio) + mdiobus_unregister(felix->imdio); +} + +static const struct felix_info ocelot_ext_info = { + .target_io_res = vsc7512_target_io_res, + .port_io_res = vsc7512_port_io_res, + .regfields = vsc7512_regfields, + .map = vsc7512_regmap, + .ops = &vsc7512_ops, + .stats_layout = vsc7512_stats_layout, + .num_stats = ARRAY_SIZE(vsc7512_stats_layout), + .vcap = vsc7512_vcap_props, + .num_mact_rows = 1024, + .num_ports = 11, + .num_tx_queues = OCELOT_NUM_TC, + .mdio_bus_alloc = vsc7512_mdio_bus_alloc, + .mdio_bus_free = vsc7512_mdio_bus_free, + .phylink_validate = vsc7512_phylink_validate, + .prevalidate_phy_mode = vsc7512_prevalidate_phy_mode, + .port_setup_tc = vsc7512_port_setup_tc, + .init_regmap = vsc7512_regmap_init, +}; + +static int ocelot_ext_probe(struct platform_device *pdev) +{ + struct ocelot_ext_data *ocelot_ext; + struct dsa_switch *ds; + struct ocelot *ocelot; + struct felix *felix; + struct device *dev; + int err; + + dev = &pdev->dev; + + ocelot_ext = devm_kzalloc(dev, sizeof(struct ocelot_ext_data), + GFP_KERNEL); + + if (!ocelot_ext) + return -ENOMEM; + + dev_set_drvdata(dev, ocelot_ext); + + felix = &ocelot_ext->felix; + + ocelot = &felix->ocelot; + ocelot->dev = dev; + + ocelot->num_flooding_pgids = 1; + + felix->info = &ocelot_ext_info; + + ds = kzalloc(sizeof(*ds), GFP_KERNEL); + if (!ds) { + err = -ENOMEM; + dev_err(dev, "Failed to allocate DSA switch\n"); + return err; + } + + ds->dev = dev; + ds->num_ports = felix->info->num_ports; + ds->num_tx_queues = felix->info->num_tx_queues; + + ds->ops = &felix_switch_ops; + ds->priv = ocelot; + felix->ds = ds; + felix->tag_proto = DSA_TAG_PROTO_OCELOT; + + err = dsa_register_switch(ds); + + if (err) { + dev_err(dev, "Failed to register DSA switch: %d\n", err); + goto err_register_ds; + } + + return 0; + +err_register_ds: + kfree(ds); + return err; +} + +static int ocelot_ext_remove(struct platform_device *pdev) +{ + struct ocelot_ext_data *ocelot_ext; + struct felix *felix; + + ocelot_ext = dev_get_drvdata(&pdev->dev); + felix = &ocelot_ext->felix; + + dsa_unregister_switch(felix->ds); + + kfree(felix->ds); + + devm_kfree(&pdev->dev, ocelot_ext); + + return 0; +} + +const struct of_device_id ocelot_ext_switch_of_match[] = { + { .compatible = "mscc,vsc7512-ext-switch" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ocelot_ext_switch_of_match); + +static struct platform_driver ocelot_ext_switch_driver = { + .driver = { + .name = "ocelot-ext-switch", + .of_match_table = of_match_ptr(ocelot_ext_switch_of_match), + }, + .probe = ocelot_ext_probe, + .remove = ocelot_ext_remove, +}; +module_platform_driver(ocelot_ext_switch_driver); + +MODULE_DESCRIPTION("External Ocelot Switch driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index 37bc9d647bc2..c56eaedc5e58 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -399,6 +399,8 @@ enum ocelot_reg { GCB_MIIM_MII_STATUS, GCB_MIIM_MII_CMD, GCB_MIIM_MII_DATA, + GCB_PHY_PHY_CFG, + GCB_PHY_PHY_STAT, DEV_CLOCK_CFG = DEV_GMII << TARGET_OFFSET, DEV_PORT_MISC, DEV_EVENTS,