* [PATCH 05/15] PCI: mobiveil: Use pci_host_probe() to register host
From: Rob Herring @ 2020-05-22 23:48 UTC (permalink / raw)
To: Lorenzo Pieralisi
Cc: Bjorn Helgaas, linux-pci, Hou Zhiqiang, Karthikeyan Mitran,
linux-arm-kernel
In-Reply-To: <20200522234832.954484-1-robh@kernel.org>
The mobiveil host driver does the same host registration and bus scanning
calls as pci_host_probe, so let's use it instead.
Cc: Karthikeyan Mitran <m.karthikeyan@mobiveil.co.in>
Cc: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
Signed-off-by: Rob Herring <robh@kernel.org>
---
.../pci/controller/mobiveil/pcie-mobiveil-host.c | 16 +---------------
1 file changed, 1 insertion(+), 15 deletions(-)
diff --git a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
index 5907baa9b1f2..5974619811ec 100644
--- a/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
+++ b/drivers/pci/controller/mobiveil/pcie-mobiveil-host.c
@@ -569,8 +569,6 @@ int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie)
struct mobiveil_root_port *rp = &pcie->rp;
struct pci_host_bridge *bridge = rp->bridge;
struct device *dev = &pcie->pdev->dev;
- struct pci_bus *bus;
- struct pci_bus *child;
int ret;
ret = mobiveil_pcie_parse_dt(pcie);
@@ -620,17 +618,5 @@ int mobiveil_pcie_host_probe(struct mobiveil_pcie *pcie)
return ret;
}
- /* setup the kernel resources for the newly added PCIe root bus */
- ret = pci_scan_root_bus_bridge(bridge);
- if (ret)
- return ret;
-
- bus = bridge->bus;
-
- pci_assign_unassigned_bus_resources(bus);
- list_for_each_entry(child, &bus->children, node)
- pcie_bus_configure_settings(child);
- pci_bus_add_devices(bus);
-
- return 0;
+ return pci_host_probe(bridge);
}
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 06/15] PCI: tegra: Use pci_host_probe() to register host
From: Rob Herring @ 2020-05-22 23:48 UTC (permalink / raw)
To: Lorenzo Pieralisi
Cc: linux-pci, Jonathan Hunter, linux-tegra, Thierry Reding,
Bjorn Helgaas, linux-arm-kernel
In-Reply-To: <20200522234832.954484-1-robh@kernel.org>
The tegra host driver does the same host registration and bus scanning
calls as pci_host_probe, so let's use it instead.
Cc: Thierry Reding <thierry.reding@gmail.com>
Cc: Jonathan Hunter <jonathanh@nvidia.com>
Cc: linux-tegra@vger.kernel.org
Signed-off-by: Rob Herring <robh@kernel.org>
---
drivers/pci/controller/pci-tegra.c | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c
index e3e917243e10..3cae96dfe75d 100644
--- a/drivers/pci/controller/pci-tegra.c
+++ b/drivers/pci/controller/pci-tegra.c
@@ -2670,7 +2670,6 @@ static int tegra_pcie_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct pci_host_bridge *host;
struct tegra_pcie *pcie;
- struct pci_bus *child;
struct resource *bus;
int err;
@@ -2721,20 +2720,12 @@ static int tegra_pcie_probe(struct platform_device *pdev)
host->map_irq = tegra_pcie_map_irq;
host->swizzle_irq = pci_common_swizzle;
- err = pci_scan_root_bus_bridge(host);
+ err = pci_host_probe(host);
if (err < 0) {
dev_err(dev, "failed to register host: %d\n", err);
goto pm_runtime_put;
}
- pci_bus_size_bridges(host->bus);
- pci_bus_assign_resources(host->bus);
-
- list_for_each_entry(child, &host->bus->children, node)
- pcie_bus_configure_settings(child);
-
- pci_bus_add_devices(host->bus);
-
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
err = tegra_pcie_debugfs_init(pcie);
if (err < 0)
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 04/15] PCI: brcmstb: Use pci_host_probe() to register host
From: Rob Herring @ 2020-05-22 23:48 UTC (permalink / raw)
To: Lorenzo Pieralisi
Cc: linux-pci, bcm-kernel-feedback-list, linux-arm-kernel,
Bjorn Helgaas, Nicolas Saenz Julienne, linux-rpi-kernel
In-Reply-To: <20200522234832.954484-1-robh@kernel.org>
The brcmstb host driver does the same host registration and bus scanning
calls as pci_host_probe, so let's use it instead.
Cc: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
Cc: bcm-kernel-feedback-list@broadcom.com
Cc: linux-rpi-kernel@lists.infradead.org
Signed-off-by: Rob Herring <robh@kernel.org>
---
drivers/pci/controller/pcie-brcmstb.c | 20 ++++----------------
1 file changed, 4 insertions(+), 16 deletions(-)
diff --git a/drivers/pci/controller/pcie-brcmstb.c b/drivers/pci/controller/pcie-brcmstb.c
index 7730ea845ff2..15c747c1390a 100644
--- a/drivers/pci/controller/pcie-brcmstb.c
+++ b/drivers/pci/controller/pcie-brcmstb.c
@@ -172,7 +172,6 @@ struct brcm_pcie {
struct device *dev;
void __iomem *base;
struct clk *clk;
- struct pci_bus *root_bus;
struct device_node *np;
bool ssc;
int gen;
@@ -919,9 +918,10 @@ static void __brcm_pcie_remove(struct brcm_pcie *pcie)
static int brcm_pcie_remove(struct platform_device *pdev)
{
struct brcm_pcie *pcie = platform_get_drvdata(pdev);
+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
- pci_stop_root_bus(pcie->root_bus);
- pci_remove_root_bus(pcie->root_bus);
+ pci_stop_root_bus(bridge->bus);
+ pci_remove_root_bus(bridge->bus);
__brcm_pcie_remove(pcie);
return 0;
@@ -933,7 +933,6 @@ static int brcm_pcie_probe(struct platform_device *pdev)
struct pci_host_bridge *bridge;
struct device_node *fw_np;
struct brcm_pcie *pcie;
- struct pci_bus *child;
struct resource *res;
int ret;
@@ -1004,20 +1003,9 @@ static int brcm_pcie_probe(struct platform_device *pdev)
bridge->map_irq = of_irq_parse_and_map_pci;
bridge->swizzle_irq = pci_common_swizzle;
- ret = pci_scan_root_bus_bridge(bridge);
- if (ret < 0) {
- dev_err(pcie->dev, "Scanning root bridge failed\n");
- goto fail;
- }
-
- pci_assign_unassigned_bus_resources(bridge->bus);
- list_for_each_entry(child, &bridge->bus->children, node)
- pcie_bus_configure_settings(child);
- pci_bus_add_devices(bridge->bus);
platform_set_drvdata(pdev, pcie);
- pcie->root_bus = bridge->bus;
- return 0;
+ return pci_host_probe(bridge);
fail:
__brcm_pcie_remove(pcie);
return ret;
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 03/15] PCI: host-common: Use struct pci_host_bridge.windows list directly
From: Rob Herring @ 2020-05-22 23:48 UTC (permalink / raw)
To: Lorenzo Pieralisi; +Cc: Bjorn Helgaas, linux-pci, Will Deacon, linux-arm-kernel
In-Reply-To: <20200522234832.954484-1-robh@kernel.org>
There's no need to create a temporary resource list and then splice it to
struct pci_host_bridge.windows list. Just use pci_host_bridge.windows
directly. The necessary clean-up is already handled by the PCI core.
Cc: Will Deacon <will@kernel.org>
Signed-off-by: Rob Herring <robh@kernel.org>
---
drivers/pci/controller/pci-host-common.c | 36 ++++++++----------------
1 file changed, 11 insertions(+), 25 deletions(-)
diff --git a/drivers/pci/controller/pci-host-common.c b/drivers/pci/controller/pci-host-common.c
index 953de57f6c57..f8f71d99e427 100644
--- a/drivers/pci/controller/pci-host-common.c
+++ b/drivers/pci/controller/pci-host-common.c
@@ -21,7 +21,7 @@ static void gen_pci_unmap_cfg(void *ptr)
}
static struct pci_config_window *gen_pci_init(struct device *dev,
- struct list_head *resources, const struct pci_ecam_ops *ops)
+ struct pci_host_bridge *bridge, const struct pci_ecam_ops *ops)
{
int err;
struct resource cfgres;
@@ -29,31 +29,25 @@ static struct pci_config_window *gen_pci_init(struct device *dev,
struct pci_config_window *cfg;
/* Parse our PCI ranges and request their resources */
- err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range);
+ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, NULL, &bus_range);
if (err)
return ERR_PTR(err);
err = of_address_to_resource(dev->of_node, 0, &cfgres);
if (err) {
dev_err(dev, "missing \"reg\" property\n");
- goto err_out;
+ return ERR_PTR(err);
}
cfg = pci_ecam_create(dev, &cfgres, bus_range, ops);
- if (IS_ERR(cfg)) {
- err = PTR_ERR(cfg);
- goto err_out;
- }
+ if (IS_ERR(cfg))
+ return cfg;
err = devm_add_action_or_reset(dev, gen_pci_unmap_cfg, cfg);
- if (err) {
- goto err_out;
- }
- return cfg;
+ if (err)
+ return ERR_PTR(err);
-err_out:
- pci_free_resource_list(resources);
- return ERR_PTR(err);
+ return cfg;
}
int pci_host_common_probe(struct platform_device *pdev)
@@ -61,9 +55,7 @@ int pci_host_common_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct pci_host_bridge *bridge;
struct pci_config_window *cfg;
- struct list_head resources;
const struct pci_ecam_ops *ops;
- int ret;
ops = of_device_get_match_data(&pdev->dev);
if (!ops)
@@ -76,7 +68,7 @@ int pci_host_common_probe(struct platform_device *pdev)
of_pci_check_probe_only();
/* Parse and map our Configuration Space windows */
- cfg = gen_pci_init(dev, &resources, ops);
+ cfg = gen_pci_init(dev, bridge, ops);
if (IS_ERR(cfg))
return PTR_ERR(cfg);
@@ -84,7 +76,6 @@ int pci_host_common_probe(struct platform_device *pdev)
if (!pci_has_flag(PCI_PROBE_ONLY))
pci_add_flags(PCI_REASSIGN_ALL_BUS);
- list_splice_init(&resources, &bridge->windows);
bridge->dev.parent = dev;
bridge->sysdata = cfg;
bridge->busnr = cfg->busr.start;
@@ -92,14 +83,9 @@ int pci_host_common_probe(struct platform_device *pdev)
bridge->map_irq = of_irq_parse_and_map_pci;
bridge->swizzle_irq = pci_common_swizzle;
- ret = pci_host_probe(bridge);
- if (ret < 0) {
- pci_free_resource_list(&resources);
- return ret;
- }
-
platform_set_drvdata(pdev, bridge->bus);
- return 0;
+
+ return pci_host_probe(bridge);
}
EXPORT_SYMBOL_GPL(pci_host_common_probe);
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 02/15] PCI: mvebu: Use struct pci_host_bridge.windows list directly
From: Rob Herring @ 2020-05-22 23:48 UTC (permalink / raw)
To: Lorenzo Pieralisi
Cc: Bjorn Helgaas, linux-pci, Thomas Petazzoni, linux-arm-kernel,
Jason Cooper
In-Reply-To: <20200522234832.954484-1-robh@kernel.org>
There's no need to create a temporary resource list and then splice it to
struct pci_host_bridge.windows list. Just use pci_host_bridge.windows
directly. The necessary clean-up is already handled by the PCI core.
Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
Cc: Jason Cooper <jason@lakedaemon.net>
Signed-off-by: Rob Herring <robh@kernel.org>
---
drivers/pci/controller/pci-mvebu.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c
index 153a64676bc9..801044523a3d 100644
--- a/drivers/pci/controller/pci-mvebu.c
+++ b/drivers/pci/controller/pci-mvebu.c
@@ -71,7 +71,6 @@ struct mvebu_pcie {
struct platform_device *pdev;
struct mvebu_pcie_port *ports;
struct msi_controller *msi;
- struct list_head resources;
struct resource io;
struct resource realio;
struct resource mem;
@@ -961,17 +960,16 @@ static int mvebu_pcie_parse_request_resources(struct mvebu_pcie *pcie)
{
struct device *dev = &pcie->pdev->dev;
struct device_node *np = dev->of_node;
+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(pcie);
int ret;
- INIT_LIST_HEAD(&pcie->resources);
-
/* Get the bus range */
ret = of_pci_parse_bus_range(np, &pcie->busn);
if (ret) {
dev_err(dev, "failed to parse bus-range property: %d\n", ret);
return ret;
}
- pci_add_resource(&pcie->resources, &pcie->busn);
+ pci_add_resource(&bridge->windows, &pcie->busn);
/* Get the PCIe memory aperture */
mvebu_mbus_get_pcie_mem_aperture(&pcie->mem);
@@ -981,7 +979,7 @@ static int mvebu_pcie_parse_request_resources(struct mvebu_pcie *pcie)
}
pcie->mem.name = "PCI MEM";
- pci_add_resource(&pcie->resources, &pcie->mem);
+ pci_add_resource(&bridge->windows, &pcie->mem);
/* Get the PCIe IO aperture */
mvebu_mbus_get_pcie_io_aperture(&pcie->io);
@@ -994,10 +992,10 @@ static int mvebu_pcie_parse_request_resources(struct mvebu_pcie *pcie)
resource_size(&pcie->io) - 1);
pcie->realio.name = "PCI I/O";
- pci_add_resource(&pcie->resources, &pcie->realio);
+ pci_add_resource(&bridge->windows, &pcie->realio);
}
- return devm_request_pci_bus_resources(dev, &pcie->resources);
+ return devm_request_pci_bus_resources(dev, &bridge->windows);
}
/*
@@ -1118,7 +1116,6 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
pcie->nports = i;
- list_splice_init(&pcie->resources, &bridge->windows);
bridge->dev.parent = dev;
bridge->sysdata = pcie;
bridge->busnr = 0;
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 01/15] PCI: cadence: Use struct pci_host_bridge.windows list directly
From: Rob Herring @ 2020-05-22 23:48 UTC (permalink / raw)
To: Lorenzo Pieralisi; +Cc: Bjorn Helgaas, linux-pci, Tom Joseph, linux-arm-kernel
In-Reply-To: <20200522234832.954484-1-robh@kernel.org>
There's no need to create a temporary resource list and then splice it to
struct pci_host_bridge.windows list. Just use pci_host_bridge.windows
directly. The necessary clean-up is already handled by the PCI core.
Cc: Tom Joseph <tjoseph@cadence.com>
Signed-off-by: Rob Herring <robh@kernel.org>
---
.../controller/cadence/pcie-cadence-host.c | 26 +++++--------------
1 file changed, 7 insertions(+), 19 deletions(-)
diff --git a/drivers/pci/controller/cadence/pcie-cadence-host.c b/drivers/pci/controller/cadence/pcie-cadence-host.c
index 8c2543f28ba0..9f77e47983c3 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host.c
@@ -169,14 +169,15 @@ static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
}
static int cdns_pcie_host_init(struct device *dev,
- struct list_head *resources,
struct cdns_pcie_rc *rc)
{
+ struct pci_host_bridge *bridge = pci_host_bridge_from_priv(rc);
struct resource *bus_range = NULL;
int err;
/* Parse our PCI ranges and request their resources */
- err = pci_parse_request_of_pci_ranges(dev, resources, NULL, &bus_range);
+ err = pci_parse_request_of_pci_ranges(dev, &bridge->windows, NULL,
+ &bus_range);
if (err)
return err;
@@ -185,17 +186,9 @@ static int cdns_pcie_host_init(struct device *dev,
err = cdns_pcie_host_init_root_port(rc);
if (err)
- goto err_out;
-
- err = cdns_pcie_host_init_address_translation(rc);
- if (err)
- goto err_out;
-
- return 0;
+ return err;
- err_out:
- pci_free_resource_list(resources);
- return err;
+ return cdns_pcie_host_init_address_translation(rc);
}
int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
@@ -204,7 +197,6 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
struct platform_device *pdev = to_platform_device(dev);
struct device_node *np = dev->of_node;
struct pci_host_bridge *bridge;
- struct list_head resources;
struct cdns_pcie *pcie;
struct resource *res;
int ret;
@@ -248,11 +240,10 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
pcie->mem_res = res;
- ret = cdns_pcie_host_init(dev, &resources, rc);
+ ret = cdns_pcie_host_init(dev, rc);
if (ret)
goto err_init;
- list_splice_init(&resources, &bridge->windows);
bridge->dev.parent = dev;
bridge->busnr = pcie->bus;
bridge->ops = &cdns_pcie_host_ops;
@@ -261,13 +252,10 @@ int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
ret = pci_host_probe(bridge);
if (ret < 0)
- goto err_host_probe;
+ goto err_init;
return 0;
- err_host_probe:
- pci_free_resource_list(&resources);
-
err_init:
pm_runtime_put_sync(dev);
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 00/15] PCI controller probe cleanups
From: Rob Herring @ 2020-05-22 23:48 UTC (permalink / raw)
To: Lorenzo Pieralisi; +Cc: Bjorn Helgaas, linux-pci, linux-arm-kernel
I started this on my last series of dma-ranges rework and am just
getting back to finishing it. This series simplifies the resource list
handling in a couple of drivers and converts almost all the remaining
drivers to use pci_host_probe().
The one holdout is Designware. This is due to the .scan_bus() hook
which is only used by TI Keystone. I think it could be a fixup instead
matching on the root bus id. I'm not sure though. See
ks_pcie_v3_65_scan_bus().
Rob
Rob Herring (15):
PCI: cadence: Use struct pci_host_bridge.windows list directly
PCI: mvebu: Use struct pci_host_bridge.windows list directly
PCI: host-common: Use struct pci_host_bridge.windows list directly
PCI: brcmstb: Use pci_host_probe() to register host
PCI: mobiveil: Use pci_host_probe() to register host
PCI: tegra: Use pci_host_probe() to register host
PCI: v3: Use pci_host_probe() to register host
PCI: versatile: Use pci_host_probe() to register host
PCI: xgene: Use pci_host_probe() to register host
PCI: altera: Use pci_host_probe() to register host
PCI: iproc: Use pci_host_probe() to register host
PCI: rcar: Use pci_host_probe() to register host
PCI: rockchip: Use pci_host_probe() to register host
PCI: xilinx-nwl: Use pci_host_probe() to register host
PCI: xilinx: Use pci_host_probe() to register host
.../controller/cadence/pcie-cadence-host.c | 26 ++++----------
.../controller/mobiveil/pcie-mobiveil-host.c | 16 +--------
drivers/pci/controller/pci-host-common.c | 36 ++++++-------------
drivers/pci/controller/pci-mvebu.c | 13 +++----
drivers/pci/controller/pci-tegra.c | 11 +-----
drivers/pci/controller/pci-v3-semi.c | 13 +------
drivers/pci/controller/pci-versatile.c | 14 +-------
drivers/pci/controller/pci-xgene.c | 13 +------
drivers/pci/controller/pcie-altera.c | 17 +--------
drivers/pci/controller/pcie-brcmstb.c | 20 +++--------
drivers/pci/controller/pcie-iproc.c | 18 +++-------
drivers/pci/controller/pcie-iproc.h | 2 --
drivers/pci/controller/pcie-rcar-host.c | 18 +---------
drivers/pci/controller/pcie-rockchip-host.c | 18 +++-------
drivers/pci/controller/pcie-rockchip.h | 1 -
drivers/pci/controller/pcie-xilinx-nwl.c | 14 +-------
drivers/pci/controller/pcie-xilinx.c | 13 +------
17 files changed, 45 insertions(+), 218 deletions(-)
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v5 06/11] net: ethernet: mtk-star-emac: new driver
From: Andrew Lunn @ 2020-05-22 23:36 UTC (permalink / raw)
To: Matthias Brugger
Cc: Edwin Peer, devicetree, Stephane Le Provost, Arnd Bergmann,
Bartosz Golaszewski, netdev, Bartosz Golaszewski, Sean Wang,
linux-kernel, Pedro Tsai, David S . Miller, Fabien Parent,
Rob Herring, linux-mediatek, Andrew Perepech, John Crispin,
Jakub Kicinski, Mark Lee, linux-arm-kernel, Heiner Kallweit
In-Reply-To: <5627e304-3463-9229-fa86-d7d31cad7a61@gmail.com>
On Fri, May 22, 2020 at 05:06:34PM +0200, Matthias Brugger wrote:
>
>
> On 22/05/2020 14:06, Bartosz Golaszewski wrote:
> > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> >
> > This adds the driver for the MediaTek STAR Ethernet MAC currently used
> > on the MT8* SoC family. For now we only support full-duplex.
>
> MT85** SoC family, AFAIU it's not used on MT81** devices. Correct?
>
> >
> > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> > ---
> > drivers/net/ethernet/mediatek/Kconfig | 7 +
> > drivers/net/ethernet/mediatek/Makefile | 1 +
> > drivers/net/ethernet/mediatek/mtk_star_emac.c | 1678 +++++++++++++++++
> > 3 files changed, 1686 insertions(+)
> > create mode 100644 drivers/net/ethernet/mediatek/mtk_star_emac.c
> >
> > diff --git a/drivers/net/ethernet/mediatek/Kconfig b/drivers/net/ethernet/mediatek/Kconfig
> > index 5079b8090f16..500c15e7ea4a 100644
> > --- a/drivers/net/ethernet/mediatek/Kconfig
> > +++ b/drivers/net/ethernet/mediatek/Kconfig
> > @@ -14,4 +14,11 @@ config NET_MEDIATEK_SOC
> > This driver supports the gigabit ethernet MACs in the
> > MediaTek SoC family.
> >
> > +config NET_MEDIATEK_STAR_EMAC
> > + tristate "MediaTek STAR Ethernet MAC support"
> > + select PHYLIB
> > + help
> > + This driver supports the ethernet MAC IP first used on
> > + MediaTek MT85** SoCs.
> > +
> > endif #NET_VENDOR_MEDIATEK
> > diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
> > index 3362fb7ef859..3a777b4a6cd3 100644
> > --- a/drivers/net/ethernet/mediatek/Makefile
> > +++ b/drivers/net/ethernet/mediatek/Makefile
> > @@ -5,3 +5,4 @@
> >
> > obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
> > mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o
> > +obj-$(CONFIG_NET_MEDIATEK_STAR_EMAC) += mtk_star_emac.o
> > diff --git a/drivers/net/ethernet/mediatek/mtk_star_emac.c b/drivers/net/ethernet/mediatek/mtk_star_emac.c
> > new file mode 100644
> > index 000000000000..789c77af501f
> > --- /dev/null
> > +++ b/drivers/net/ethernet/mediatek/mtk_star_emac.c
> > @@ -0,0 +1,1678 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright (c) 2020 MediaTek Corporation
> > + * Copyright (c) 2020 BayLibre SAS
> > + *
> > + * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> > + */
> > +
> > +#include <linux/bits.h>
> > +#include <linux/clk.h>
> > +#include <linux/compiler.h>
> > +#include <linux/dma-mapping.h>
> > +#include <linux/etherdevice.h>
> > +#include <linux/kernel.h>
> > +#include <linux/mfd/syscon.h>
> > +#include <linux/mii.h>
> > +#include <linux/module.h>
> > +#include <linux/netdevice.h>
> > +#include <linux/of.h>
> > +#include <linux/of_mdio.h>
> > +#include <linux/of_net.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/pm.h>
> > +#include <linux/regmap.h>
> > +#include <linux/skbuff.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/workqueue.h>
> > +
> > +#define MTK_STAR_DRVNAME "mtk_star_emac"
> > +
> > +#define MTK_STAR_WAIT_TIMEOUT 300
> > +#define MTK_STAR_MAX_FRAME_SIZE 1514
> > +#define MTK_STAR_SKB_ALIGNMENT 16
> > +#define MTK_STAR_NAPI_WEIGHT 64
> > +#define MTK_STAR_HASHTABLE_MC_LIMIT 256
> > +#define MTK_STAR_HASHTABLE_SIZE_MAX 512
> > +
> > +/* Normally we'd use NET_IP_ALIGN but on arm64 its value is 0 and it doesn't
> > + * work for this controller.
> > + */
> > +#define MTK_STAR_IP_ALIGN 2
> > +
> > +static const char *const mtk_star_clk_names[] = { "core", "reg", "trans" };
> > +#define MTK_STAR_NCLKS ARRAY_SIZE(mtk_star_clk_names)
> > +
> > +/* PHY Control Register 0 */
> > +#define MTK_STAR_REG_PHY_CTRL0 0x0000
> > +#define MTK_STAR_BIT_PHY_CTRL0_WTCMD BIT(13)
> > +#define MTK_STAR_BIT_PHY_CTRL0_RDCMD BIT(14)
> > +#define MTK_STAR_BIT_PHY_CTRL0_RWOK BIT(15)
> > +#define MTK_STAR_MSK_PHY_CTRL0_PREG GENMASK(12, 8)
> > +#define MTK_STAR_OFF_PHY_CTRL0_PREG 8
> > +#define MTK_STAR_MSK_PHY_CTRL0_RWDATA GENMASK(31, 16)
> > +#define MTK_STAR_OFF_PHY_CTRL0_RWDATA 16
> > +
> > +/* PHY Control Register 1 */
> > +#define MTK_STAR_REG_PHY_CTRL1 0x0004
> > +#define MTK_STAR_BIT_PHY_CTRL1_LINK_ST BIT(0)
> > +#define MTK_STAR_BIT_PHY_CTRL1_AN_EN BIT(8)
> > +#define MTK_STAR_OFF_PHY_CTRL1_FORCE_SPD 9
> > +#define MTK_STAR_VAL_PHY_CTRL1_FORCE_SPD_10M 0x00
> > +#define MTK_STAR_VAL_PHY_CTRL1_FORCE_SPD_100M 0x01
> > +#define MTK_STAR_VAL_PHY_CTRL1_FORCE_SPD_1000M 0x02
> > +#define MTK_STAR_BIT_PHY_CTRL1_FORCE_DPX BIT(11)
> > +#define MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_RX BIT(12)
> > +#define MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_TX BIT(13)
> > +
> > +/* MAC Configuration Register */
> > +#define MTK_STAR_REG_MAC_CFG 0x0008
> > +#define MTK_STAR_OFF_MAC_CFG_IPG 10
> > +#define MTK_STAR_VAL_MAC_CFG_IPG_96BIT GENMASK(4, 0)
> > +#define MTK_STAR_BIT_MAC_CFG_MAXLEN_1522 BIT(16)
> > +#define MTK_STAR_BIT_MAC_CFG_AUTO_PAD BIT(19)
> > +#define MTK_STAR_BIT_MAC_CFG_CRC_STRIP BIT(20)
> > +#define MTK_STAR_BIT_MAC_CFG_VLAN_STRIP BIT(22)
> > +#define MTK_STAR_BIT_MAC_CFG_NIC_PD BIT(31)
> > +
> > +/* Flow-Control Configuration Register */
> > +#define MTK_STAR_REG_FC_CFG 0x000c
> > +#define MTK_STAR_BIT_FC_CFG_BP_EN BIT(7)
> > +#define MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR BIT(8)
> > +#define MTK_STAR_OFF_FC_CFG_SEND_PAUSE_TH 16
> > +#define MTK_STAR_MSK_FC_CFG_SEND_PAUSE_TH GENMASK(27, 16)
> > +#define MTK_STAR_VAL_FC_CFG_SEND_PAUSE_TH_2K 0x800
> > +
> > +/* ARL Configuration Register */
> > +#define MTK_STAR_REG_ARL_CFG 0x0010
> > +#define MTK_STAR_BIT_ARL_CFG_HASH_ALG BIT(0)
> > +#define MTK_STAR_BIT_ARL_CFG_MISC_MODE BIT(4)
> > +
> > +/* MAC High and Low Bytes Registers */
> > +#define MTK_STAR_REG_MY_MAC_H 0x0014
> > +#define MTK_STAR_REG_MY_MAC_L 0x0018
> > +
> > +/* Hash Table Control Register */
> > +#define MTK_STAR_REG_HASH_CTRL 0x001c
> > +#define MTK_STAR_MSK_HASH_CTRL_HASH_BIT_ADDR GENMASK(8, 0)
> > +#define MTK_STAR_BIT_HASH_CTRL_HASH_BIT_DATA BIT(12)
> > +#define MTK_STAR_BIT_HASH_CTRL_ACC_CMD BIT(13)
> > +#define MTK_STAR_BIT_HASH_CTRL_CMD_START BIT(14)
> > +#define MTK_STAR_BIT_HASH_CTRL_BIST_OK BIT(16)
> > +#define MTK_STAR_BIT_HASH_CTRL_BIST_DONE BIT(17)
> > +#define MTK_STAR_BIT_HASH_CTRL_BIST_EN BIT(31)
> > +
> > +/* TX DMA Control Register */
> > +#define MTK_STAR_REG_TX_DMA_CTRL 0x0034
> > +#define MTK_STAR_BIT_TX_DMA_CTRL_START BIT(0)
> > +#define MTK_STAR_BIT_TX_DMA_CTRL_STOP BIT(1)
> > +#define MTK_STAR_BIT_TX_DMA_CTRL_RESUME BIT(2)
> > +
> > +/* RX DMA Control Register */
> > +#define MTK_STAR_REG_RX_DMA_CTRL 0x0038
> > +#define MTK_STAR_BIT_RX_DMA_CTRL_START BIT(0)
> > +#define MTK_STAR_BIT_RX_DMA_CTRL_STOP BIT(1)
> > +#define MTK_STAR_BIT_RX_DMA_CTRL_RESUME BIT(2)
> > +
> > +/* DMA Address Registers */
> > +#define MTK_STAR_REG_TX_DPTR 0x003c
> > +#define MTK_STAR_REG_RX_DPTR 0x0040
> > +#define MTK_STAR_REG_TX_BASE_ADDR 0x0044
> > +#define MTK_STAR_REG_RX_BASE_ADDR 0x0048
> > +
> > +/* Interrupt Status Register */
> > +#define MTK_STAR_REG_INT_STS 0x0050
> > +#define MTK_STAR_REG_INT_STS_PORT_STS_CHG BIT(2)
> > +#define MTK_STAR_REG_INT_STS_MIB_CNT_TH BIT(3)
> > +#define MTK_STAR_BIT_INT_STS_FNRC BIT(6)
> > +#define MTK_STAR_BIT_INT_STS_TNTC BIT(8)
> > +
> > +/* Interrupt Mask Register */
> > +#define MTK_STAR_REG_INT_MASK 0x0054
> > +#define MTK_STAR_BIT_INT_MASK_FNRC BIT(6)
> > +
> > +/* Misc. Config Register */
> > +#define MTK_STAR_REG_TEST1 0x005c
> > +#define MTK_STAR_BIT_TEST1_RST_HASH_MBIST BIT(31)
> > +
> > +/* Extended Configuration Register */
> > +#define MTK_STAR_REG_EXT_CFG 0x0060
> > +#define MTK_STAR_OFF_EXT_CFG_SND_PAUSE_RLS 16
> > +#define MTK_STAR_MSK_EXT_CFG_SND_PAUSE_RLS GENMASK(26, 16)
> > +#define MTK_STAR_VAL_EXT_CFG_SND_PAUSE_RLS_1K 0x400
> > +
> > +/* EthSys Configuration Register */
> > +#define MTK_STAR_REG_SYS_CONF 0x0094
> > +#define MTK_STAR_BIT_MII_PAD_OUT_ENABLE BIT(0)
> > +#define MTK_STAR_BIT_EXT_MDC_MODE BIT(1)
> > +#define MTK_STAR_BIT_SWC_MII_MODE BIT(2)
> > +
> > +/* MAC Clock Configuration Register */
> > +#define MTK_STAR_REG_MAC_CLK_CONF 0x00ac
> > +#define MTK_STAR_MSK_MAC_CLK_CONF GENMASK(7, 0)
> > +#define MTK_STAR_BIT_CLK_DIV_10 0x0a
> > +
> > +/* Counter registers. */
> > +#define MTK_STAR_REG_C_RXOKPKT 0x0100
> > +#define MTK_STAR_REG_C_RXOKBYTE 0x0104
> > +#define MTK_STAR_REG_C_RXRUNT 0x0108
> > +#define MTK_STAR_REG_C_RXLONG 0x010c
> > +#define MTK_STAR_REG_C_RXDROP 0x0110
> > +#define MTK_STAR_REG_C_RXCRC 0x0114
> > +#define MTK_STAR_REG_C_RXARLDROP 0x0118
> > +#define MTK_STAR_REG_C_RXVLANDROP 0x011c
> > +#define MTK_STAR_REG_C_RXCSERR 0x0120
> > +#define MTK_STAR_REG_C_RXPAUSE 0x0124
> > +#define MTK_STAR_REG_C_TXOKPKT 0x0128
> > +#define MTK_STAR_REG_C_TXOKBYTE 0x012c
> > +#define MTK_STAR_REG_C_TXPAUSECOL 0x0130
> > +#define MTK_STAR_REG_C_TXRTY 0x0134
> > +#define MTK_STAR_REG_C_TXSKIP 0x0138
> > +#define MTK_STAR_REG_C_TX_ARP 0x013c
> > +#define MTK_STAR_REG_C_RX_RERR 0x01d8
> > +#define MTK_STAR_REG_C_RX_UNI 0x01dc
> > +#define MTK_STAR_REG_C_RX_MULTI 0x01e0
> > +#define MTK_STAR_REG_C_RX_BROAD 0x01e4
> > +#define MTK_STAR_REG_C_RX_ALIGNERR 0x01e8
> > +#define MTK_STAR_REG_C_TX_UNI 0x01ec
> > +#define MTK_STAR_REG_C_TX_MULTI 0x01f0
> > +#define MTK_STAR_REG_C_TX_BROAD 0x01f4
> > +#define MTK_STAR_REG_C_TX_TIMEOUT 0x01f8
> > +#define MTK_STAR_REG_C_TX_LATECOL 0x01fc
> > +#define MTK_STAR_REG_C_RX_LENGTHERR 0x0214
> > +#define MTK_STAR_REG_C_RX_TWIST 0x0218
> > +
> > +/* Ethernet CFG Control */
> > +#define MTK_PERICFG_REG_NIC_CFG_CON 0x03c4
> > +#define MTK_PERICFG_MSK_NIC_CFG_CON_CFG_MII GENMASK(3, 0)
> > +#define MTK_PERICFG_BIT_NIC_CFG_CON_RMII BIT(0)
> > +
> > +/* Represents the actual structure of descriptors used by the MAC. We can
> > + * reuse the same structure for both TX and RX - the layout is the same, only
> > + * the flags differ slightly.
> > + */
> > +struct mtk_star_ring_desc {
> > + /* Contains both the status flags as well as packet length. */
> > + u32 status;
> > + u32 data_ptr;
> > + u32 vtag;
> > + u32 reserved;
> > +};
> > +
> > +#define MTK_STAR_DESC_MSK_LEN GENMASK(15, 0)
> > +#define MTK_STAR_DESC_BIT_RX_CRCE BIT(24)
> > +#define MTK_STAR_DESC_BIT_RX_OSIZE BIT(25)
> > +#define MTK_STAR_DESC_BIT_INT BIT(27)
> > +#define MTK_STAR_DESC_BIT_LS BIT(28)
> > +#define MTK_STAR_DESC_BIT_FS BIT(29)
> > +#define MTK_STAR_DESC_BIT_EOR BIT(30)
> > +#define MTK_STAR_DESC_BIT_COWN BIT(31)
> > +
> > +/* Helper structure for storing data read from/written to descriptors in order
> > + * to limit reads from/writes to DMA memory.
> > + */
> > +struct mtk_star_ring_desc_data {
> > + unsigned int len;
> > + unsigned int flags;
> > + dma_addr_t dma_addr;
> > + struct sk_buff *skb;
> > +};
> > +
> > +#define MTK_STAR_RING_NUM_DESCS 128
> > +#define MTK_STAR_NUM_TX_DESCS MTK_STAR_RING_NUM_DESCS
> > +#define MTK_STAR_NUM_RX_DESCS MTK_STAR_RING_NUM_DESCS
> > +#define MTK_STAR_NUM_DESCS_TOTAL (MTK_STAR_RING_NUM_DESCS * 2)
> > +#define MTK_STAR_DMA_SIZE \
> > + (MTK_STAR_NUM_DESCS_TOTAL * sizeof(struct mtk_star_ring_desc))
> > +
> > +struct mtk_star_ring {
> > + struct mtk_star_ring_desc *descs;
> > + struct sk_buff *skbs[MTK_STAR_RING_NUM_DESCS];
> > + dma_addr_t dma_addrs[MTK_STAR_RING_NUM_DESCS];
> > + unsigned int head;
> > + unsigned int tail;
> > +};
> > +
> > +struct mtk_star_priv {
> > + struct net_device *ndev;
> > +
> > + struct regmap *regs;
> > + struct regmap *pericfg;
> > +
> > + struct clk_bulk_data clks[MTK_STAR_NCLKS];
> > +
> > + void *ring_base;
> > + struct mtk_star_ring_desc *descs_base;
> > + dma_addr_t dma_addr;
> > + struct mtk_star_ring tx_ring;
> > + struct mtk_star_ring rx_ring;
> > +
> > + struct mii_bus *mii;
> > + struct napi_struct napi;
> > +
> > + struct device_node *phy_node;
> > + phy_interface_t phy_intf;
> > + struct phy_device *phydev;
> > + unsigned int link;
> > + int speed;
> > + int duplex;
> > + int pause;
> > +
> > + /* Protects against concurrent descriptor access. */
> > + spinlock_t lock;
> > +
> > + struct rtnl_link_stats64 stats;
> > + struct work_struct stats_work;
> > +};
> > +
> > +static struct device *mtk_star_get_dev(struct mtk_star_priv *priv)
> > +{
> > + return priv->ndev->dev.parent;
> > +}
> > +
> > +static const struct regmap_config mtk_star_regmap_config = {
> > + .reg_bits = 32,
> > + .val_bits = 32,
> > + .reg_stride = 4,
> > + .disable_locking = true,
> > +};
> > +
> > +static void mtk_star_ring_init(struct mtk_star_ring *ring,
> > + struct mtk_star_ring_desc *descs)
> > +{
> > + memset(ring, 0, sizeof(*ring));
> > + ring->descs = descs;
> > + ring->head = 0;
> > + ring->tail = 0;
> > +}
> > +
> > +static int mtk_star_ring_pop_tail(struct mtk_star_ring *ring,
> > + struct mtk_star_ring_desc_data *desc_data)
> > +{
> > + struct mtk_star_ring_desc *desc = &ring->descs[ring->tail];
> > + unsigned int status;
> > +
> > + status = READ_ONCE(desc->status);
> > + dma_rmb(); /* Make sure we read the status bits before checking it. */
> > +
> > + if (!(status & MTK_STAR_DESC_BIT_COWN))
> > + return -1;
> > +
> > + desc_data->len = status & MTK_STAR_DESC_MSK_LEN;
> > + desc_data->flags = status & ~MTK_STAR_DESC_MSK_LEN;
> > + desc_data->dma_addr = ring->dma_addrs[ring->tail];
> > + desc_data->skb = ring->skbs[ring->tail];
> > +
> > + ring->dma_addrs[ring->tail] = 0;
> > + ring->skbs[ring->tail] = NULL;
> > +
> > + status &= MTK_STAR_DESC_BIT_COWN | MTK_STAR_DESC_BIT_EOR;
> > +
> > + WRITE_ONCE(desc->data_ptr, 0);
> > + WRITE_ONCE(desc->status, status);
> > +
> > + ring->tail = (ring->tail + 1) % MTK_STAR_RING_NUM_DESCS;
> > +
> > + return 0;
> > +}
> > +
> > +static void mtk_star_ring_push_head(struct mtk_star_ring *ring,
> > + struct mtk_star_ring_desc_data *desc_data,
> > + unsigned int flags)
> > +{
> > + struct mtk_star_ring_desc *desc = &ring->descs[ring->head];
> > + unsigned int status;
> > +
> > + status = READ_ONCE(desc->status);
> > +
> > + ring->skbs[ring->head] = desc_data->skb;
> > + ring->dma_addrs[ring->head] = desc_data->dma_addr;
> > +
> > + status |= desc_data->len;
> > + if (flags)
> > + status |= flags;
> > +
> > + WRITE_ONCE(desc->data_ptr, desc_data->dma_addr);
> > + WRITE_ONCE(desc->status, status);
> > + status &= ~MTK_STAR_DESC_BIT_COWN;
> > + /* Flush previous modifications before ownership change. */
> > + dma_wmb();
> > + WRITE_ONCE(desc->status, status);
> > +
> > + ring->head = (ring->head + 1) % MTK_STAR_RING_NUM_DESCS;
> > +}
> > +
> > +static void
> > +mtk_star_ring_push_head_rx(struct mtk_star_ring *ring,
> > + struct mtk_star_ring_desc_data *desc_data)
> > +{
> > + mtk_star_ring_push_head(ring, desc_data, 0);
> > +}
> > +
> > +static void
> > +mtk_star_ring_push_head_tx(struct mtk_star_ring *ring,
> > + struct mtk_star_ring_desc_data *desc_data)
> > +{
> > + static const unsigned int flags = MTK_STAR_DESC_BIT_FS |
> > + MTK_STAR_DESC_BIT_LS |
> > + MTK_STAR_DESC_BIT_INT;
> > +
> > + mtk_star_ring_push_head(ring, desc_data, flags);
> > +}
> > +
> > +static unsigned int mtk_star_ring_num_used_descs(struct mtk_star_ring *ring)
> > +{
> > + return abs(ring->head - ring->tail);
> > +}
> > +
> > +static bool mtk_star_ring_full(struct mtk_star_ring *ring)
> > +{
> > + return mtk_star_ring_num_used_descs(ring) == MTK_STAR_RING_NUM_DESCS;
> > +}
> > +
> > +static bool mtk_star_ring_descs_available(struct mtk_star_ring *ring)
> > +{
> > + return mtk_star_ring_num_used_descs(ring) > 0;
> > +}
> > +
> > +static dma_addr_t mtk_star_dma_map_rx(struct mtk_star_priv *priv,
> > + struct sk_buff *skb)
> > +{
> > + struct device *dev = mtk_star_get_dev(priv);
> > +
> > + /* Data pointer for the RX DMA descriptor must be aligned to 4N + 2. */
> > + return dma_map_single(dev, skb_tail_pointer(skb) - 2,
> > + skb_tailroom(skb), DMA_FROM_DEVICE);
> > +}
> > +
> > +static void mtk_star_dma_unmap_rx(struct mtk_star_priv *priv,
> > + struct mtk_star_ring_desc_data *desc_data)
> > +{
> > + struct device *dev = mtk_star_get_dev(priv);
> > +
> > + dma_unmap_single(dev, desc_data->dma_addr,
> > + skb_tailroom(desc_data->skb), DMA_FROM_DEVICE);
> > +}
> > +
> > +static dma_addr_t mtk_star_dma_map_tx(struct mtk_star_priv *priv,
> > + struct sk_buff *skb)
> > +{
> > + struct device *dev = mtk_star_get_dev(priv);
> > +
> > + return dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
> > +}
> > +
> > +static void mtk_star_dma_unmap_tx(struct mtk_star_priv *priv,
> > + struct mtk_star_ring_desc_data *desc_data)
> > +{
> > + struct device *dev = mtk_star_get_dev(priv);
> > +
> > + return dma_unmap_single(dev, desc_data->dma_addr,
> > + skb_headlen(desc_data->skb), DMA_TO_DEVICE);
> > +}
> > +
> > +static void mtk_star_nic_disable_pd(struct mtk_star_priv *priv)
> > +{
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_MAC_CFG,
> > + MTK_STAR_BIT_MAC_CFG_NIC_PD, 0);
> > +}
> > +
> > +/* Unmask the three interrupts we care about, mask all others. */
> > +static void mtk_star_intr_enable(struct mtk_star_priv *priv)
> > +{
> > + unsigned int val = MTK_STAR_BIT_INT_STS_TNTC |
> > + MTK_STAR_BIT_INT_STS_FNRC |
> > + MTK_STAR_REG_INT_STS_MIB_CNT_TH;
> > +
> > + regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, ~val);
> > +}
> > +
> > +static void mtk_star_intr_disable(struct mtk_star_priv *priv)
> > +{
> > + regmap_write(priv->regs, MTK_STAR_REG_INT_MASK, ~0);
> > +}
> > +
> > +static void mtk_star_intr_enable_tx(struct mtk_star_priv *priv)
> > +{
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_INT_MASK,
> > + MTK_STAR_BIT_INT_STS_TNTC, 0);
> > +}
> > +
> > +static void mtk_star_intr_enable_rx(struct mtk_star_priv *priv)
> > +{
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_INT_MASK,
> > + MTK_STAR_BIT_INT_STS_FNRC, 0);
> > +}
> > +
> > +static void mtk_star_intr_enable_stats(struct mtk_star_priv *priv)
> > +{
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_INT_MASK,
> > + MTK_STAR_REG_INT_STS_MIB_CNT_TH, 0);
> > +}
> > +
> > +static void mtk_star_intr_disable_tx(struct mtk_star_priv *priv)
> > +{
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_INT_MASK,
> > + MTK_STAR_BIT_INT_STS_TNTC,
> > + MTK_STAR_BIT_INT_STS_TNTC);
> > +}
> > +
> > +static void mtk_star_intr_disable_rx(struct mtk_star_priv *priv)
> > +{
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_INT_MASK,
> > + MTK_STAR_BIT_INT_STS_FNRC,
> > + MTK_STAR_BIT_INT_STS_FNRC);
> > +}
> > +
> > +static void mtk_star_intr_disable_stats(struct mtk_star_priv *priv)
> > +{
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_INT_MASK,
> > + MTK_STAR_REG_INT_STS_MIB_CNT_TH,
> > + MTK_STAR_REG_INT_STS_MIB_CNT_TH);
> > +}
> > +
> > +static unsigned int mtk_star_intr_read(struct mtk_star_priv *priv)
> > +{
> > + unsigned int val;
> > +
> > + regmap_read(priv->regs, MTK_STAR_REG_INT_STS, &val);
> > +
> > + return val;
> > +}
> > +
> > +static unsigned int mtk_star_intr_ack_all(struct mtk_star_priv *priv)
> > +{
> > + unsigned int val;
> > +
> > + val = mtk_star_intr_read(priv);
> > + regmap_write(priv->regs, MTK_STAR_REG_INT_STS, val);
> > +
> > + return val;
> > +}
> > +
> > +static void mtk_star_dma_init(struct mtk_star_priv *priv)
> > +{
> > + struct mtk_star_ring_desc *desc;
> > + unsigned int val;
> > + int i;
> > +
> > + priv->descs_base = (struct mtk_star_ring_desc *)priv->ring_base;
> > +
> > + for (i = 0; i < MTK_STAR_NUM_DESCS_TOTAL; i++) {
> > + desc = &priv->descs_base[i];
> > +
> > + memset(desc, 0, sizeof(*desc));
> > + desc->status = MTK_STAR_DESC_BIT_COWN;
> > + if ((i == MTK_STAR_NUM_TX_DESCS - 1) ||
> > + (i == MTK_STAR_NUM_DESCS_TOTAL - 1))
> > + desc->status |= MTK_STAR_DESC_BIT_EOR;
> > + }
> > +
> > + mtk_star_ring_init(&priv->tx_ring, priv->descs_base);
> > + mtk_star_ring_init(&priv->rx_ring,
> > + priv->descs_base + MTK_STAR_NUM_TX_DESCS);
> > +
> > + /* Set DMA pointers. */
> > + val = (unsigned int)priv->dma_addr;
> > + regmap_write(priv->regs, MTK_STAR_REG_TX_BASE_ADDR, val);
> > + regmap_write(priv->regs, MTK_STAR_REG_TX_DPTR, val);
> > +
> > + val += sizeof(struct mtk_star_ring_desc) * MTK_STAR_NUM_TX_DESCS;
> > + regmap_write(priv->regs, MTK_STAR_REG_RX_BASE_ADDR, val);
> > + regmap_write(priv->regs, MTK_STAR_REG_RX_DPTR, val);
> > +}
> > +
> > +static void mtk_star_dma_start(struct mtk_star_priv *priv)
> > +{
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_TX_DMA_CTRL,
> > + MTK_STAR_BIT_TX_DMA_CTRL_START,
> > + MTK_STAR_BIT_TX_DMA_CTRL_START);
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_RX_DMA_CTRL,
> > + MTK_STAR_BIT_RX_DMA_CTRL_START,
> > + MTK_STAR_BIT_RX_DMA_CTRL_START);
> > +}
> > +
> > +static void mtk_star_dma_stop(struct mtk_star_priv *priv)
> > +{
> > + regmap_write(priv->regs, MTK_STAR_REG_TX_DMA_CTRL,
> > + MTK_STAR_BIT_TX_DMA_CTRL_STOP);
> > + regmap_write(priv->regs, MTK_STAR_REG_RX_DMA_CTRL,
> > + MTK_STAR_BIT_RX_DMA_CTRL_STOP);
> > +}
> > +
> > +static void mtk_star_dma_disable(struct mtk_star_priv *priv)
> > +{
> > + int i;
> > +
> > + mtk_star_dma_stop(priv);
> > +
> > + /* Take back all descriptors. */
> > + for (i = 0; i < MTK_STAR_NUM_DESCS_TOTAL; i++)
> > + priv->descs_base[i].status |= MTK_STAR_DESC_BIT_COWN;
> > +}
> > +
> > +static void mtk_star_dma_resume_rx(struct mtk_star_priv *priv)
> > +{
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_RX_DMA_CTRL,
> > + MTK_STAR_BIT_RX_DMA_CTRL_RESUME,
> > + MTK_STAR_BIT_RX_DMA_CTRL_RESUME);
> > +}
> > +
> > +static void mtk_star_dma_resume_tx(struct mtk_star_priv *priv)
> > +{
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_TX_DMA_CTRL,
> > + MTK_STAR_BIT_TX_DMA_CTRL_RESUME,
> > + MTK_STAR_BIT_TX_DMA_CTRL_RESUME);
> > +}
> > +
> > +static void mtk_star_set_mac_addr(struct net_device *ndev)
> > +{
> > + struct mtk_star_priv *priv = netdev_priv(ndev);
> > + u8 *mac_addr = ndev->dev_addr;
> > + unsigned int high, low;
> > +
> > + high = mac_addr[0] << 8 | mac_addr[1] << 0;
> > + low = mac_addr[2] << 24 | mac_addr[3] << 16 |
> > + mac_addr[4] << 8 | mac_addr[5];
> > +
> > + regmap_write(priv->regs, MTK_STAR_REG_MY_MAC_H, high);
> > + regmap_write(priv->regs, MTK_STAR_REG_MY_MAC_L, low);
> > +}
> > +
> > +static void mtk_star_reset_counters(struct mtk_star_priv *priv)
> > +{
> > + static const unsigned int counter_regs[] = {
> > + MTK_STAR_REG_C_RXOKPKT,
> > + MTK_STAR_REG_C_RXOKBYTE,
> > + MTK_STAR_REG_C_RXRUNT,
> > + MTK_STAR_REG_C_RXLONG,
> > + MTK_STAR_REG_C_RXDROP,
> > + MTK_STAR_REG_C_RXCRC,
> > + MTK_STAR_REG_C_RXARLDROP,
> > + MTK_STAR_REG_C_RXVLANDROP,
> > + MTK_STAR_REG_C_RXCSERR,
> > + MTK_STAR_REG_C_RXPAUSE,
> > + MTK_STAR_REG_C_TXOKPKT,
> > + MTK_STAR_REG_C_TXOKBYTE,
> > + MTK_STAR_REG_C_TXPAUSECOL,
> > + MTK_STAR_REG_C_TXRTY,
> > + MTK_STAR_REG_C_TXSKIP,
> > + MTK_STAR_REG_C_TX_ARP,
> > + MTK_STAR_REG_C_RX_RERR,
> > + MTK_STAR_REG_C_RX_UNI,
> > + MTK_STAR_REG_C_RX_MULTI,
> > + MTK_STAR_REG_C_RX_BROAD,
> > + MTK_STAR_REG_C_RX_ALIGNERR,
> > + MTK_STAR_REG_C_TX_UNI,
> > + MTK_STAR_REG_C_TX_MULTI,
> > + MTK_STAR_REG_C_TX_BROAD,
> > + MTK_STAR_REG_C_TX_TIMEOUT,
> > + MTK_STAR_REG_C_TX_LATECOL,
> > + MTK_STAR_REG_C_RX_LENGTHERR,
> > + MTK_STAR_REG_C_RX_TWIST,
> > + };
> > +
> > + unsigned int i, val;
> > +
> > + for (i = 0; i < ARRAY_SIZE(counter_regs); i++)
> > + regmap_read(priv->regs, counter_regs[i], &val);
> > +}
> > +
> > +static void mtk_star_update_stat(struct mtk_star_priv *priv,
> > + unsigned int reg, u64 *stat)
> > +{
> > + unsigned int val;
> > +
> > + regmap_read(priv->regs, reg, &val);
> > + *stat += val;
> > +}
> > +
> > +/* Try to get as many stats as possible from the internal registers instead
> > + * of tracking them ourselves.
> > + */
> > +static void mtk_star_update_stats(struct mtk_star_priv *priv)
> > +{
> > + struct rtnl_link_stats64 *stats = &priv->stats;
> > +
> > + /* OK packets and bytes. */
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_RXOKPKT, &stats->rx_packets);
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_TXOKPKT, &stats->tx_packets);
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_RXOKBYTE, &stats->rx_bytes);
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_TXOKBYTE, &stats->tx_bytes);
> > +
> > + /* RX & TX multicast. */
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_RX_MULTI, &stats->multicast);
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_TX_MULTI, &stats->multicast);
> > +
> > + /* Collisions. */
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_TXPAUSECOL,
> > + &stats->collisions);
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_TX_LATECOL,
> > + &stats->collisions);
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_RXRUNT, &stats->collisions);
> > +
> > + /* RX Errors. */
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_RX_LENGTHERR,
> > + &stats->rx_length_errors);
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_RXLONG,
> > + &stats->rx_over_errors);
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_RXCRC, &stats->rx_crc_errors);
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_RX_ALIGNERR,
> > + &stats->rx_frame_errors);
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_RXDROP,
> > + &stats->rx_fifo_errors);
> > + /* Sum of the general RX error counter + all of the above. */
> > + mtk_star_update_stat(priv, MTK_STAR_REG_C_RX_RERR, &stats->rx_errors);
> > + stats->rx_errors += stats->rx_length_errors;
> > + stats->rx_errors += stats->rx_over_errors;
> > + stats->rx_errors += stats->rx_crc_errors;
> > + stats->rx_errors += stats->rx_frame_errors;
> > + stats->rx_errors += stats->rx_fifo_errors;
> > +}
> > +
> > +/* This runs in process context and parallel TX and RX paths executing in
> > + * napi context may result in losing some stats data but this should happen
> > + * seldom enough to be acceptable.
> > + */
> > +static void mtk_star_update_stats_work(struct work_struct *work)
> > +{
> > + struct mtk_star_priv *priv = container_of(work, struct mtk_star_priv,
> > + stats_work);
> > +
> > + mtk_star_update_stats(priv);
> > + mtk_star_reset_counters(priv);
> > + mtk_star_intr_enable_stats(priv);
> > +}
> > +
> > +static struct sk_buff *mtk_star_alloc_skb(struct net_device *ndev)
> > +{
> > + uintptr_t tail, offset;
> > + struct sk_buff *skb;
> > +
> > + skb = dev_alloc_skb(MTK_STAR_MAX_FRAME_SIZE);
> > + if (!skb)
> > + return NULL;
> > +
> > + /* Align to 16 bytes. */
> > + tail = (uintptr_t)skb_tail_pointer(skb);
> > + if (tail & (MTK_STAR_SKB_ALIGNMENT - 1)) {
> > + offset = tail & (MTK_STAR_SKB_ALIGNMENT - 1);
> > + skb_reserve(skb, MTK_STAR_SKB_ALIGNMENT - offset);
> > + }
> > +
> > + /* Ensure 16-byte alignment of the skb pointer: eth_type_trans() will
> > + * extract the Ethernet header (14 bytes) so we need two more bytes.
> > + */
> > + skb_reserve(skb, MTK_STAR_IP_ALIGN);
> > +
> > + return skb;
> > +}
> > +
> > +static int mtk_star_prepare_rx_skbs(struct net_device *ndev)
> > +{
> > + struct mtk_star_priv *priv = netdev_priv(ndev);
> > + struct mtk_star_ring *ring = &priv->rx_ring;
> > + struct device *dev = mtk_star_get_dev(priv);
> > + struct mtk_star_ring_desc *desc;
> > + struct sk_buff *skb;
> > + dma_addr_t dma_addr;
> > + int i;
> > +
> > + for (i = 0; i < MTK_STAR_NUM_RX_DESCS; i++) {
> > + skb = mtk_star_alloc_skb(ndev);
> > + if (!skb)
> > + return -ENOMEM;
> > +
> > + dma_addr = mtk_star_dma_map_rx(priv, skb);
> > + if (dma_mapping_error(dev, dma_addr)) {
> > + dev_kfree_skb(skb);
> > + return -ENOMEM;
> > + }
> > +
> > + desc = &ring->descs[i];
> > + desc->data_ptr = dma_addr;
> > + desc->status |= skb_tailroom(skb) & MTK_STAR_DESC_MSK_LEN;
> > + desc->status &= ~MTK_STAR_DESC_BIT_COWN;
> > + ring->skbs[i] = skb;
> > + ring->dma_addrs[i] = dma_addr;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static void
> > +mtk_star_ring_free_skbs(struct mtk_star_priv *priv, struct mtk_star_ring *ring,
> > + void (*unmap_func)(struct mtk_star_priv *,
> > + struct mtk_star_ring_desc_data *))
> > +{
> > + struct mtk_star_ring_desc_data desc_data;
> > + struct mtk_star_ring_desc *desc;
> > + int i;
> > +
> > + for (i = 0; i < MTK_STAR_RING_NUM_DESCS; i++) {
> > + if (!ring->dma_addrs[i])
> > + continue;
> > +
> > + desc = &ring->descs[i];
> > +
> > + desc_data.dma_addr = ring->dma_addrs[i];
> > + desc_data.skb = ring->skbs[i];
> > +
> > + unmap_func(priv, &desc_data);
> > + dev_kfree_skb(desc_data.skb);
> > + }
> > +}
> > +
> > +static void mtk_star_free_rx_skbs(struct mtk_star_priv *priv)
> > +{
> > + struct mtk_star_ring *ring = &priv->rx_ring;
> > +
> > + mtk_star_ring_free_skbs(priv, ring, mtk_star_dma_unmap_rx);
> > +}
> > +
> > +static void mtk_star_free_tx_skbs(struct mtk_star_priv *priv)
> > +{
> > + struct mtk_star_ring *ring = &priv->tx_ring;
> > +
> > + mtk_star_ring_free_skbs(priv, ring, mtk_star_dma_unmap_tx);
> > +}
> > +
> > +/* All processing for TX and RX happens in the napi poll callback. */
> > +static irqreturn_t mtk_star_handle_irq(int irq, void *data)
> > +{
> > + struct mtk_star_priv *priv;
> > + struct net_device *ndev;
> > + bool need_napi = false;
> > + unsigned int status;
> > +
> > + ndev = data;
> > + priv = netdev_priv(ndev);
> > +
> > + if (netif_running(ndev)) {
> > + status = mtk_star_intr_read(priv);
> > +
> > + if (status & MTK_STAR_BIT_INT_STS_TNTC) {
> > + mtk_star_intr_disable_tx(priv);
> > + need_napi = true;
> > + }
> > +
> > + if (status & MTK_STAR_BIT_INT_STS_FNRC) {
> > + mtk_star_intr_disable_rx(priv);
> > + need_napi = true;
> > + }
> > +
> > + if (need_napi)
> > + napi_schedule(&priv->napi);
> > +
> > + /* One of the counters reached 0x8000000 - update stats and
> > + * reset all counters.
> > + */
> > + if (unlikely(status & MTK_STAR_REG_INT_STS_MIB_CNT_TH)) {
> > + mtk_star_intr_disable_stats(priv);
> > + schedule_work(&priv->stats_work);
> > + }
> > +
> > + mtk_star_intr_ack_all(priv);
> > + }
> > +
> > + return IRQ_HANDLED;
> > +}
> > +
> > +/* Wait for the completion of any previous command - CMD_START bit must be
> > + * cleared by hardware.
> > + */
> > +static int mtk_star_hash_wait_cmd_start(struct mtk_star_priv *priv)
> > +{
> > + unsigned int val;
> > +
> > + return regmap_read_poll_timeout_atomic(priv->regs,
> > + MTK_STAR_REG_HASH_CTRL, val,
> > + !(val & MTK_STAR_BIT_HASH_CTRL_CMD_START),
> > + 10, MTK_STAR_WAIT_TIMEOUT);
> > +}
> > +
> > +static int mtk_star_hash_wait_ok(struct mtk_star_priv *priv)
> > +{
> > + unsigned int val;
> > + int ret;
> > +
> > + /* Wait for BIST_DONE bit. */
> > + ret = regmap_read_poll_timeout_atomic(priv->regs,
> > + MTK_STAR_REG_HASH_CTRL, val,
> > + val & MTK_STAR_BIT_HASH_CTRL_BIST_DONE,
> > + 10, MTK_STAR_WAIT_TIMEOUT);
> > + if (ret)
> > + return ret;
> > +
> > + /* Check the BIST_OK bit. */
> > + regmap_read(priv->regs, MTK_STAR_REG_HASH_CTRL, &val);
> > + if (!(val & MTK_STAR_BIT_HASH_CTRL_BIST_OK))
> > + return -EIO;
> > +
> > + return 0;
> > +}
> > +
> > +static int mtk_star_set_hashbit(struct mtk_star_priv *priv,
> > + unsigned int hash_addr)
> > +{
> > + unsigned int val;
> > + int ret;
> > +
> > + ret = mtk_star_hash_wait_cmd_start(priv);
> > + if (ret)
> > + return ret;
> > +
> > + val = hash_addr & MTK_STAR_MSK_HASH_CTRL_HASH_BIT_ADDR;
> > + val |= MTK_STAR_BIT_HASH_CTRL_ACC_CMD;
> > + val |= MTK_STAR_BIT_HASH_CTRL_CMD_START;
> > + val |= MTK_STAR_BIT_HASH_CTRL_BIST_EN;
> > + val |= MTK_STAR_BIT_HASH_CTRL_HASH_BIT_DATA;
> > + regmap_write(priv->regs, MTK_STAR_REG_HASH_CTRL, val);
> > +
> > + return mtk_star_hash_wait_ok(priv);
> > +}
> > +
> > +static int mtk_star_reset_hash_table(struct mtk_star_priv *priv)
> > +{
> > + int ret;
> > +
> > + ret = mtk_star_hash_wait_cmd_start(priv);
> > + if (ret)
> > + return ret;
> > +
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_HASH_CTRL,
> > + MTK_STAR_BIT_HASH_CTRL_BIST_EN,
> > + MTK_STAR_BIT_HASH_CTRL_BIST_EN);
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_TEST1,
> > + MTK_STAR_BIT_TEST1_RST_HASH_MBIST,
> > + MTK_STAR_BIT_TEST1_RST_HASH_MBIST);
> > +
> > + return mtk_star_hash_wait_ok(priv);
> > +}
> > +
> > +static void mtk_star_phy_config(struct mtk_star_priv *priv)
> > +{
> > + unsigned int val;
> > +
> > + if (priv->speed == SPEED_1000)
> > + val = MTK_STAR_VAL_PHY_CTRL1_FORCE_SPD_1000M;
> > + else if (priv->speed == SPEED_100)
> > + val = MTK_STAR_VAL_PHY_CTRL1_FORCE_SPD_100M;
> > + else
> > + val = MTK_STAR_VAL_PHY_CTRL1_FORCE_SPD_10M;
> > + val <<= MTK_STAR_OFF_PHY_CTRL1_FORCE_SPD;
> > +
> > + val |= MTK_STAR_BIT_PHY_CTRL1_AN_EN;
> > + val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_RX;
> > + val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_FC_TX;
> > + /* Only full-duplex supported for now. */
> > + val |= MTK_STAR_BIT_PHY_CTRL1_FORCE_DPX;
> > +
> > + regmap_write(priv->regs, MTK_STAR_REG_PHY_CTRL1, val);
> > +
> > + if (priv->pause) {
> > + val = MTK_STAR_VAL_FC_CFG_SEND_PAUSE_TH_2K;
> > + val <<= MTK_STAR_OFF_FC_CFG_SEND_PAUSE_TH;
> > + val |= MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR;
> > + } else {
> > + val = 0;
> > + }
> > +
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_FC_CFG,
> > + MTK_STAR_MSK_FC_CFG_SEND_PAUSE_TH |
> > + MTK_STAR_BIT_FC_CFG_UC_PAUSE_DIR, val);
> > +
> > + if (priv->pause) {
> > + val = MTK_STAR_VAL_EXT_CFG_SND_PAUSE_RLS_1K;
> > + val <<= MTK_STAR_OFF_EXT_CFG_SND_PAUSE_RLS;
> > + } else {
> > + val = 0;
> > + }
> > +
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_EXT_CFG,
> > + MTK_STAR_MSK_EXT_CFG_SND_PAUSE_RLS, val);
> > +}
> > +
> > +static void mtk_star_adjust_link(struct net_device *ndev)
> > +{
> > + struct mtk_star_priv *priv = netdev_priv(ndev);
> > + struct phy_device *phydev = priv->phydev;
> > + bool new_state = false;
> > +
> > + if (phydev->link) {
> > + if (!priv->link) {
> > + priv->link = phydev->link;
> > + new_state = true;
> > + }
> > +
> > + if (priv->speed != phydev->speed) {
> > + priv->speed = phydev->speed;
> > + new_state = true;
> > + }
> > +
> > + if (priv->pause != phydev->pause) {
> > + priv->pause = phydev->pause;
> > + new_state = true;
> > + }
> > + } else {
> > + if (priv->link) {
> > + priv->link = phydev->link;
> > + new_state = true;
> > + }
> > + }
> > +
> > + if (new_state) {
> > + if (phydev->link)
> > + mtk_star_phy_config(priv);
> > +
> > + phy_print_status(ndev->phydev);
> > + }
> > +}
> > +
> > +static void mtk_star_init_config(struct mtk_star_priv *priv)
> > +{
> > + unsigned int val;
> > +
> > + val = (MTK_STAR_BIT_MII_PAD_OUT_ENABLE |
> > + MTK_STAR_BIT_EXT_MDC_MODE |
> > + MTK_STAR_BIT_SWC_MII_MODE);
> > +
> > + regmap_write(priv->regs, MTK_STAR_REG_SYS_CONF, val);
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_MAC_CLK_CONF,
> > + MTK_STAR_MSK_MAC_CLK_CONF,
> > + MTK_STAR_BIT_CLK_DIV_10);
> > +}
> > +
> > +static void mtk_star_set_mode_rmii(struct mtk_star_priv *priv)
> > +{
> > + regmap_update_bits(priv->pericfg, MTK_PERICFG_REG_NIC_CFG_CON,
> > + MTK_PERICFG_MSK_NIC_CFG_CON_CFG_MII,
> > + MTK_PERICFG_BIT_NIC_CFG_CON_RMII);
> > +}
> > +
> > +static int mtk_star_enable(struct net_device *ndev)
> > +{
> > + struct mtk_star_priv *priv = netdev_priv(ndev);
> > + unsigned int val;
> > + int ret;
> > +
> > + mtk_star_nic_disable_pd(priv);
> > + mtk_star_intr_disable(priv);
> > + mtk_star_dma_stop(priv);
> > +
> > + mtk_star_set_mac_addr(ndev);
> > +
> > + /* Configure the MAC */
> > + val = MTK_STAR_VAL_MAC_CFG_IPG_96BIT;
> > + val <<= MTK_STAR_OFF_MAC_CFG_IPG;
> > + val |= MTK_STAR_BIT_MAC_CFG_MAXLEN_1522;
> > + val |= MTK_STAR_BIT_MAC_CFG_AUTO_PAD;
> > + val |= MTK_STAR_BIT_MAC_CFG_CRC_STRIP;
> > + regmap_write(priv->regs, MTK_STAR_REG_MAC_CFG, val);
> > +
> > + /* Enable Hash Table BIST and reset it */
> > + ret = mtk_star_reset_hash_table(priv);
> > + if (ret)
> > + return ret;
> > +
> > + /* Setup the hashing algorithm */
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_ARL_CFG,
> > + MTK_STAR_BIT_ARL_CFG_HASH_ALG |
> > + MTK_STAR_BIT_ARL_CFG_MISC_MODE, 0);
> > +
> > + /* Don't strip VLAN tags */
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_MAC_CFG,
> > + MTK_STAR_BIT_MAC_CFG_VLAN_STRIP, 0);
> > +
> > + /* Setup DMA */
> > + mtk_star_dma_init(priv);
> > +
> > + ret = mtk_star_prepare_rx_skbs(ndev);
> > + if (ret)
> > + goto err_out;
> > +
> > + /* Request the interrupt */
> > + ret = request_irq(ndev->irq, mtk_star_handle_irq,
> > + IRQF_TRIGGER_FALLING, ndev->name, ndev);
> > + if (ret)
> > + goto err_free_skbs;
> > +
> > + napi_enable(&priv->napi);
> > +
> > + mtk_star_intr_ack_all(priv);
> > + mtk_star_intr_enable(priv);
> > +
> > + /* Connect to and start PHY */
> > + priv->phydev = of_phy_connect(ndev, priv->phy_node,
> > + mtk_star_adjust_link, 0, priv->phy_intf);
> > + if (!priv->phydev) {
> > + netdev_err(ndev, "failed to connect to PHY\n");
> > + goto err_free_irq;
> > + }
> > +
> > + mtk_star_dma_start(priv);
> > + phy_start(priv->phydev);
> > + netif_start_queue(ndev);
> > +
> > + return 0;
> > +
> > +err_free_irq:
> > + free_irq(ndev->irq, ndev);
> > +err_free_skbs:
> > + mtk_star_free_rx_skbs(priv);
> > +err_out:
> > + return ret;
> > +}
> > +
> > +static void mtk_star_disable(struct net_device *ndev)
> > +{
> > + struct mtk_star_priv *priv = netdev_priv(ndev);
> > +
> > + netif_stop_queue(ndev);
> > + napi_disable(&priv->napi);
> > + mtk_star_intr_disable(priv);
> > + mtk_star_dma_disable(priv);
> > + mtk_star_intr_ack_all(priv);
> > + phy_stop(priv->phydev);
> > + phy_disconnect(priv->phydev);
> > + free_irq(ndev->irq, ndev);
> > + mtk_star_free_rx_skbs(priv);
> > + mtk_star_free_tx_skbs(priv);
> > +}
> > +
> > +static int mtk_star_netdev_open(struct net_device *ndev)
> > +{
> > + return mtk_star_enable(ndev);
> > +}
> > +
> > +static int mtk_star_netdev_stop(struct net_device *ndev)
> > +{
> > + mtk_star_disable(ndev);
> > +
> > + return 0;
> > +}
> > +
> > +static int mtk_star_netdev_ioctl(struct net_device *ndev,
> > + struct ifreq *req, int cmd)
> > +{
> > + if (!netif_running(ndev))
> > + return -EINVAL;
> > +
> > + return phy_mii_ioctl(ndev->phydev, req, cmd);
> > +}
> > +
> > +static int mtk_star_netdev_start_xmit(struct sk_buff *skb,
> > + struct net_device *ndev)
> > +{
> > + struct mtk_star_priv *priv = netdev_priv(ndev);
> > + struct mtk_star_ring *ring = &priv->tx_ring;
> > + struct device *dev = mtk_star_get_dev(priv);
> > + struct mtk_star_ring_desc_data desc_data;
> > +
> > + desc_data.dma_addr = mtk_star_dma_map_tx(priv, skb);
> > + if (dma_mapping_error(dev, desc_data.dma_addr))
> > + goto err_drop_packet;
> > +
> > + desc_data.skb = skb;
> > + desc_data.len = skb->len;
> > +
> > + spin_lock_bh(&priv->lock);
> > +
> > + mtk_star_ring_push_head_tx(ring, &desc_data);
> > +
> > + netdev_sent_queue(ndev, skb->len);
> > +
> > + if (mtk_star_ring_full(ring))
> > + netif_stop_queue(ndev);
> > +
> > + spin_unlock_bh(&priv->lock);
> > +
> > + mtk_star_dma_resume_tx(priv);
> > +
> > + return NETDEV_TX_OK;
> > +
> > +err_drop_packet:
> > + dev_kfree_skb(skb);
> > + ndev->stats.tx_dropped++;
> > + return NETDEV_TX_BUSY;
> > +}
> > +
> > +/* Returns the number of bytes sent or a negative number on the first
> > + * descriptor owned by DMA.
> > + */
> > +static int mtk_star_tx_complete_one(struct mtk_star_priv *priv)
> > +{
> > + struct mtk_star_ring *ring = &priv->tx_ring;
> > + struct mtk_star_ring_desc_data desc_data;
> > + int ret;
> > +
> > + ret = mtk_star_ring_pop_tail(ring, &desc_data);
> > + if (ret)
> > + return ret;
> > +
> > + mtk_star_dma_unmap_tx(priv, &desc_data);
> > + ret = desc_data.skb->len;
> > + dev_kfree_skb_irq(desc_data.skb);
> > +
> > + return ret;
> > +}
> > +
> > +static void mtk_star_tx_complete_all(struct mtk_star_priv *priv)
> > +{
> > + struct mtk_star_ring *ring = &priv->tx_ring;
> > + struct net_device *ndev = priv->ndev;
> > + int ret, pkts_compl, bytes_compl;
> > + bool wake = false;
> > +
> > + spin_lock(&priv->lock);
> > +
> > + for (pkts_compl = 0, bytes_compl = 0;;
> > + pkts_compl++, bytes_compl += ret, wake = true) {
> > + if (!mtk_star_ring_descs_available(ring))
> > + break;
> > +
> > + ret = mtk_star_tx_complete_one(priv);
> > + if (ret < 0)
> > + break;
> > + }
> > +
> > + netdev_completed_queue(ndev, pkts_compl, bytes_compl);
> > +
> > + if (wake && netif_queue_stopped(ndev))
> > + netif_wake_queue(ndev);
> > +
> > + mtk_star_intr_enable_tx(priv);
> > +
> > + spin_unlock(&priv->lock);
> > +}
> > +
> > +static void mtk_star_netdev_get_stats64(struct net_device *ndev,
> > + struct rtnl_link_stats64 *stats)
> > +{
> > + struct mtk_star_priv *priv = netdev_priv(ndev);
> > +
> > + mtk_star_update_stats(priv);
> > +
> > + memcpy(stats, &priv->stats, sizeof(*stats));
> > +}
> > +
> > +static void mtk_star_set_rx_mode(struct net_device *ndev)
> > +{
> > + struct mtk_star_priv *priv = netdev_priv(ndev);
> > + struct netdev_hw_addr *hw_addr;
> > + unsigned int hash_addr, i;
> > + int ret;
> > +
> > + if (ndev->flags & IFF_PROMISC) {
> > + regmap_update_bits(priv->regs, MTK_STAR_REG_ARL_CFG,
> > + MTK_STAR_BIT_ARL_CFG_MISC_MODE,
> > + MTK_STAR_BIT_ARL_CFG_MISC_MODE);
> > + } else if (netdev_mc_count(ndev) > MTK_STAR_HASHTABLE_MC_LIMIT ||
> > + ndev->flags & IFF_ALLMULTI) {
> > + for (i = 0; i < MTK_STAR_HASHTABLE_SIZE_MAX; i++) {
> > + ret = mtk_star_set_hashbit(priv, i);
> > + if (ret)
> > + goto hash_fail;
> > + }
> > + } else {
> > + /* Clear previous settings. */
> > + ret = mtk_star_reset_hash_table(priv);
> > + if (ret)
> > + goto hash_fail;
> > +
> > + netdev_for_each_mc_addr(hw_addr, ndev) {
> > + hash_addr = (hw_addr->addr[0] & 0x01) << 8;
> > + hash_addr += hw_addr->addr[5];
> > + ret = mtk_star_set_hashbit(priv, hash_addr);
> > + if (ret)
> > + goto hash_fail;
> > + }
> > + }
> > +
> > + return;
> > +
> > +hash_fail:
> > + if (ret == -ETIMEDOUT)
> > + netdev_err(ndev, "setting hash bit timed out\n");
> > + else
> > + /* Should be -EIO */
> > + netdev_err(ndev, "unable to set hash bit");
> > +}
> > +
> > +static const struct net_device_ops mtk_star_netdev_ops = {
> > + .ndo_open = mtk_star_netdev_open,
> > + .ndo_stop = mtk_star_netdev_stop,
> > + .ndo_start_xmit = mtk_star_netdev_start_xmit,
> > + .ndo_get_stats64 = mtk_star_netdev_get_stats64,
> > + .ndo_set_rx_mode = mtk_star_set_rx_mode,
> > + .ndo_do_ioctl = mtk_star_netdev_ioctl,
> > + .ndo_set_mac_address = eth_mac_addr,
> > + .ndo_validate_addr = eth_validate_addr,
> > +};
> > +
> > +static void mtk_star_get_drvinfo(struct net_device *dev,
> > + struct ethtool_drvinfo *info)
> > +{
> > + strlcpy(info->driver, MTK_STAR_DRVNAME, sizeof(info->driver));
> > +}
> > +
> > +/* TODO Add ethtool stats. */
> > +static const struct ethtool_ops mtk_star_ethtool_ops = {
> > + .get_drvinfo = mtk_star_get_drvinfo,
> > + .get_link = ethtool_op_get_link,
> > + .get_link_ksettings = phy_ethtool_get_link_ksettings,
> > + .set_link_ksettings = phy_ethtool_set_link_ksettings,
> > +};
> > +
> > +static int mtk_star_receive_packet(struct mtk_star_priv *priv)
> > +{
> > + struct mtk_star_ring *ring = &priv->rx_ring;
> > + struct device *dev = mtk_star_get_dev(priv);
> > + struct mtk_star_ring_desc_data desc_data;
> > + struct net_device *ndev = priv->ndev;
> > + struct sk_buff *curr_skb, *new_skb;
> > + dma_addr_t new_dma_addr;
> > + int ret;
> > +
> > + spin_lock(&priv->lock);
> > + ret = mtk_star_ring_pop_tail(ring, &desc_data);
> > + spin_unlock(&priv->lock);
> > + if (ret)
> > + return -1;
> > +
> > + curr_skb = desc_data.skb;
> > +
> > + if ((desc_data.flags & MTK_STAR_DESC_BIT_RX_CRCE) ||
> > + (desc_data.flags & MTK_STAR_DESC_BIT_RX_OSIZE)) {
> > + /* Error packet -> drop and reuse skb. */
> > + new_skb = curr_skb;
> > + goto push_new_skb;
> > + }
> > +
> > + /* Prepare new skb before receiving the current one. Reuse the current
> > + * skb if we fail at any point.
> > + */
> > + new_skb = mtk_star_alloc_skb(ndev);
> > + if (!new_skb) {
> > + ndev->stats.rx_dropped++;
> > + new_skb = curr_skb;
> > + goto push_new_skb;
> > + }
> > +
> > + new_dma_addr = mtk_star_dma_map_rx(priv, new_skb);
> > + if (dma_mapping_error(dev, new_dma_addr)) {
> > + ndev->stats.rx_dropped++;
> > + dev_kfree_skb(new_skb);
> > + new_skb = curr_skb;
> > + netdev_err(ndev, "DMA mapping error of RX descriptor\n");
> > + goto push_new_skb;
> > + }
> > +
> > + /* We can't fail anymore at this point: it's safe to unmap the skb. */
> > + mtk_star_dma_unmap_rx(priv, &desc_data);
> > +
> > + skb_put(desc_data.skb, desc_data.len);
> > + desc_data.skb->ip_summed = CHECKSUM_NONE;
> > + desc_data.skb->protocol = eth_type_trans(desc_data.skb, ndev);
> > + desc_data.skb->dev = ndev;
> > + netif_receive_skb(desc_data.skb);
> > +
> > +push_new_skb:
> > + desc_data.dma_addr = new_dma_addr;
> > + desc_data.len = skb_tailroom(new_skb);
> > + desc_data.skb = new_skb;
> > +
> > + spin_lock(&priv->lock);
> > + mtk_star_ring_push_head_rx(ring, &desc_data);
> > + spin_unlock(&priv->lock);
> > +
> > + return 0;
> > +}
> > +
> > +static int mtk_star_process_rx(struct mtk_star_priv *priv, int budget)
> > +{
> > + int received, ret;
> > +
> > + for (received = 0, ret = 0; received < budget && ret == 0; received++)
> > + ret = mtk_star_receive_packet(priv);
> > +
> > + mtk_star_dma_resume_rx(priv);
> > +
> > + return received;
> > +}
> > +
> > +static int mtk_star_poll(struct napi_struct *napi, int budget)
> > +{
> > + struct mtk_star_priv *priv;
> > + int received = 0;
> > +
> > + priv = container_of(napi, struct mtk_star_priv, napi);
> > +
> > + /* Clean-up all TX descriptors. */
> > + mtk_star_tx_complete_all(priv);
> > + /* Receive up to $budget packets. */
> > + received = mtk_star_process_rx(priv, budget);
> > +
> > + if (received < budget) {
> > + napi_complete_done(napi, received);
> > + mtk_star_intr_enable_rx(priv);
> > + }
> > +
> > + return received;
> > +}
> > +
> > +static void mtk_star_mdio_rwok_clear(struct mtk_star_priv *priv)
> > +{
> > + regmap_write(priv->regs, MTK_STAR_REG_PHY_CTRL0,
> > + MTK_STAR_BIT_PHY_CTRL0_RWOK);
> > +}
> > +
> > +static int mtk_star_mdio_rwok_wait(struct mtk_star_priv *priv)
> > +{
> > + unsigned int val;
> > +
> > + return regmap_read_poll_timeout(priv->regs, MTK_STAR_REG_PHY_CTRL0,
> > + val, val & MTK_STAR_BIT_PHY_CTRL0_RWOK,
> > + 10, MTK_STAR_WAIT_TIMEOUT);
> > +}
> > +
> > +static int mtk_star_mdio_read(struct mii_bus *mii, int phy_id, int regnum)
> > +{
> > + struct mtk_star_priv *priv = mii->priv;
> > + unsigned int val, data;
> > + int ret;
> > +
> > + if (regnum & MII_ADDR_C45)
> > + return -EOPNOTSUPP;
> > +
> > + mtk_star_mdio_rwok_clear(priv);
> > +
> > + val = (regnum << MTK_STAR_OFF_PHY_CTRL0_PREG);
> > + val &= MTK_STAR_MSK_PHY_CTRL0_PREG;
> > + val |= MTK_STAR_BIT_PHY_CTRL0_RDCMD;
> > +
> > + regmap_write(priv->regs, MTK_STAR_REG_PHY_CTRL0, val);
> > +
> > + ret = mtk_star_mdio_rwok_wait(priv);
> > + if (ret)
> > + return ret;
> > +
> > + regmap_read(priv->regs, MTK_STAR_REG_PHY_CTRL0, &data);
> > +
> > + data &= MTK_STAR_MSK_PHY_CTRL0_RWDATA;
> > + data >>= MTK_STAR_OFF_PHY_CTRL0_RWDATA;
> > +
> > + return data;
> > +}
> > +
> > +static int mtk_star_mdio_write(struct mii_bus *mii, int phy_id,
> > + int regnum, u16 data)
> > +{
> > + struct mtk_star_priv *priv = mii->priv;
> > + unsigned int val;
> > +
> > + if (regnum & MII_ADDR_C45)
> > + return -EOPNOTSUPP;
> > +
> > + mtk_star_mdio_rwok_clear(priv);
> > +
> > + val = data;
> > + val <<= MTK_STAR_OFF_PHY_CTRL0_RWDATA;
> > + val &= MTK_STAR_MSK_PHY_CTRL0_RWDATA;
> > + regnum <<= MTK_STAR_OFF_PHY_CTRL0_PREG;
> > + regnum &= MTK_STAR_MSK_PHY_CTRL0_PREG;
> > + val |= regnum;
> > + val |= MTK_STAR_BIT_PHY_CTRL0_WTCMD;
> > +
> > + regmap_write(priv->regs, MTK_STAR_REG_PHY_CTRL0, val);
> > +
> > + return mtk_star_mdio_rwok_wait(priv);
> > +}
> > +
> > +static int mtk_star_mdio_init(struct net_device *ndev)
> > +{
> > + struct mtk_star_priv *priv = netdev_priv(ndev);
> > + struct device *dev = mtk_star_get_dev(priv);
> > + struct device_node *of_node, *mdio_node;
> > + int ret;
> > +
> > + of_node = dev->of_node;
> > +
> > + mdio_node = of_get_child_by_name(of_node, "mdio");
> > + if (!mdio_node)
> > + return -ENODEV;
> > +
> > + if (!of_device_is_available(mdio_node)) {
> > + ret = -ENODEV;
> > + goto out_put_node;
> > + }
> > +
> > + priv->mii = devm_mdiobus_alloc(dev);
> > + if (!priv->mii) {
> > + ret = -ENOMEM;
> > + goto out_put_node;
> > + }
> > +
> > + snprintf(priv->mii->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
> > + priv->mii->name = "mtk-mac-mdio";
> > + priv->mii->parent = dev;
> > + priv->mii->read = mtk_star_mdio_read;
> > + priv->mii->write = mtk_star_mdio_write;
> > + priv->mii->priv = priv;
> > +
> > + ret = of_mdiobus_register(priv->mii, mdio_node);
> > +
> > +out_put_node:
> > + of_node_put(mdio_node);
> > + return ret;
> > +}
> > +
> > +static int mtk_star_suspend(struct device *dev)
> > +{
> > + struct mtk_star_priv *priv;
> > + struct net_device *ndev;
> > +
> > + ndev = dev_get_drvdata(dev);
> > + priv = netdev_priv(ndev);
> > +
> > + if (netif_running(ndev))
> > + mtk_star_disable(ndev);
> > +
> > + clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks);
> > +
> > + return 0;
> > +}
> > +
> > +static int mtk_star_resume(struct device *dev)
> > +{
> > + struct mtk_star_priv *priv;
> > + struct net_device *ndev;
> > + int ret;
> > +
> > + ndev = dev_get_drvdata(dev);
> > + priv = netdev_priv(ndev);
> > +
> > + ret = clk_bulk_prepare_enable(MTK_STAR_NCLKS, priv->clks);
> > + if (ret)
> > + return ret;
> > +
> > + if (netif_running(ndev)) {
> > + ret = mtk_star_enable(ndev);
> > + if (ret)
> > + clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks);
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static void mtk_star_clk_disable_unprepare(void *data)
> > +{
> > + struct mtk_star_priv *priv = data;
> > +
> > + clk_bulk_disable_unprepare(MTK_STAR_NCLKS, priv->clks);
> > +}
> > +
> > +static void mtk_star_mdiobus_unregister(void *data)
> > +{
> > + struct mtk_star_priv *priv = data;
> > +
> > + mdiobus_unregister(priv->mii);
> > +}
> > +
> > +static void mtk_star_unregister_netdev(void *data)
> > +{
> > + struct net_device *ndev = data;
> > +
> > + unregister_netdev(ndev);
> > +}
> > +
> > +static int mtk_star_probe(struct platform_device *pdev)
> > +{
> > + struct device_node *of_node;
> > + struct mtk_star_priv *priv;
> > + struct net_device *ndev;
> > + struct device *dev;
> > + void __iomem *base;
> > + int ret, i;
> > +
> > + dev = &pdev->dev;
> > + of_node = dev->of_node;
> > +
> > + ndev = devm_alloc_etherdev(dev, sizeof(*priv));
> > + if (!ndev)
> > + return -ENOMEM;
> > +
> > + priv = netdev_priv(ndev);
> > + priv->ndev = ndev;
> > + SET_NETDEV_DEV(ndev, dev);
> > + platform_set_drvdata(pdev, ndev);
> > +
> > + ndev->min_mtu = ETH_ZLEN;
> > + ndev->max_mtu = MTK_STAR_MAX_FRAME_SIZE;
> > +
> > + spin_lock_init(&priv->lock);
> > + INIT_WORK(&priv->stats_work, mtk_star_update_stats_work);
> > +
> > + base = devm_platform_ioremap_resource(pdev, 0);
> > + if (IS_ERR(base))
> > + return PTR_ERR(base);
> > +
> > + /* We won't be checking the return values of regmap read & write
> > + * functions. They can only fail for mmio if there's a clock attached
> > + * to regmap which is not the case here.
> > + */
> > + priv->regs = devm_regmap_init_mmio(dev, base,
> > + &mtk_star_regmap_config);
> > + if (IS_ERR(priv->regs))
> > + return PTR_ERR(priv->regs);
> > +
> > + priv->pericfg = syscon_regmap_lookup_by_phandle(of_node,
> > + "mediatek,pericfg");
> > + if (IS_ERR(priv->pericfg)) {
> > + dev_err(dev, "Failed to lookup the PERICFG syscon\n");
> > + return PTR_ERR(priv->pericfg);
> > + }
> > +
> > + ndev->irq = platform_get_irq(pdev, 0);
> > + if (ndev->irq < 0)
> > + return ndev->irq;
> > +
> > + for (i = 0; i < MTK_STAR_NCLKS; i++)
> > + priv->clks[i].id = mtk_star_clk_names[i];
> > + ret = devm_clk_bulk_get(dev, MTK_STAR_NCLKS, priv->clks);
> > + if (ret)
> > + return ret;
> > +
> > + ret = clk_bulk_prepare_enable(MTK_STAR_NCLKS, priv->clks);
> > + if (ret)
> > + return ret;
> > +
> > + ret = devm_add_action_or_reset(dev,
> > + mtk_star_clk_disable_unprepare, priv);
> > + if (ret)
> > + return ret;
> > +
> > + ret = of_get_phy_mode(of_node, &priv->phy_intf);
> > + if (ret) {
> > + return ret;
> > + } else if (priv->phy_intf != PHY_INTERFACE_MODE_RMII) {
> > + dev_err(dev, "unsupported phy mode: %s\n",
> > + phy_modes(priv->phy_intf));
> > + return -EINVAL;
> > + }
> > +
> > + priv->phy_node = of_parse_phandle(of_node, "phy-handle", 0);
> > + if (!priv->phy_node) {
> > + dev_err(dev, "failed to retrieve the phy handle from device tree\n");
> > + return -ENODEV;
> > + }
> > +
> > + mtk_star_set_mode_rmii(priv);
> > +
> > + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
> > + if (ret) {
> > + dev_err(dev, "unsupported DMA mask\n");
> > + return ret;
> > + }
> > +
> > + priv->ring_base = dmam_alloc_coherent(dev, MTK_STAR_DMA_SIZE,
> > + &priv->dma_addr,
> > + GFP_KERNEL | GFP_DMA);
> > + if (!priv->ring_base)
> > + return -ENOMEM;
> > +
> > + mtk_star_nic_disable_pd(priv);
> > + mtk_star_init_config(priv);
> > +
> > + ret = mtk_star_mdio_init(ndev);
> > + if (ret)
> > + return ret;
> > +
> > + ret = devm_add_action_or_reset(dev, mtk_star_mdiobus_unregister, priv);
> > + if (ret)
> > + return ret;
> > +
> > + ret = eth_platform_get_mac_address(dev, ndev->dev_addr);
> > + if (ret || !is_valid_ether_addr(ndev->dev_addr))
> > + eth_hw_addr_random(ndev);
> > +
> > + ndev->netdev_ops = &mtk_star_netdev_ops;
> > + ndev->ethtool_ops = &mtk_star_ethtool_ops;
> > +
> > + netif_napi_add(ndev, &priv->napi, mtk_star_poll, MTK_STAR_NAPI_WEIGHT);
> > +
> > + ret = register_netdev(ndev);
> > + if (ret)
> > + return ret;
> > +
> > + ret = devm_add_action_or_reset(dev, mtk_star_unregister_netdev, ndev);
> > + if (ret)
> > + return ret;
> > +
> > + return 0;
> > +}
> > +
> > +static const struct of_device_id mtk_star_of_match[] = {
> > + { .compatible = "mediatek,mt8516-eth", },
> > + { .compatible = "mediatek,mt8518-eth", },
> > + { .compatible = "mediatek,mt8175-eth", },
> > + { }
> > +};
> > +MODULE_DEVICE_TABLE(of, mtk_star_of_match);
> > +
> > +static SIMPLE_DEV_PM_OPS(mtk_star_pm_ops,
> > + mtk_star_suspend, mtk_star_resume);
> > +
> > +static struct platform_driver mtk_star_driver = {
> > + .driver = {
> > + .name = MTK_STAR_DRVNAME,
> > + .pm = &mtk_star_pm_ops,
> > + .of_match_table = of_match_ptr(mtk_star_of_match),
> > + },
> > + .probe = mtk_star_probe,
> > +};
> > +module_platform_driver(mtk_star_driver);
> > +
> > +MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
> > +MODULE_DESCRIPTION("Mediatek STAR Ethernet MAC Driver");
> > +MODULE_LICENSE("GPL");
> >
Hi Matthias
Please trim your emails when replying. It is really annoying to page
down, down and down looking for comments, and find there are none.
Andrew
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [soc:arm/dt] BUILD SUCCESS 9eddc06a3bc79402f50176703237ed045ae77b16
From: kbuild test robot @ 2020-05-22 23:24 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: arm, linux-arm-kernel
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git arm/dt
branch HEAD: 9eddc06a3bc79402f50176703237ed045ae77b16 Merge branch 'mmp/fixes' into arm/dt
elapsed time: 1154m
configs tested: 104
configs skipped: 1
The following configs have been built successfully.
More configs may be tested in the coming days.
arm64 allyesconfig
arm64 defconfig
arm64 allmodconfig
arm64 allnoconfig
arm defconfig
arm allyesconfig
arm allmodconfig
arm allnoconfig
sparc allyesconfig
mips allyesconfig
m68k allyesconfig
i386 allnoconfig
i386 allyesconfig
i386 defconfig
i386 debian-10.3
ia64 allmodconfig
ia64 defconfig
ia64 allnoconfig
ia64 allyesconfig
m68k allmodconfig
m68k allnoconfig
m68k sun3_defconfig
m68k defconfig
nios2 defconfig
nios2 allyesconfig
openrisc defconfig
c6x allyesconfig
c6x allnoconfig
openrisc allyesconfig
nds32 defconfig
nds32 allnoconfig
csky allyesconfig
csky defconfig
alpha defconfig
alpha allyesconfig
xtensa allyesconfig
h8300 allyesconfig
h8300 allmodconfig
xtensa defconfig
arc defconfig
arc allyesconfig
sh allmodconfig
sh allnoconfig
microblaze allnoconfig
mips allnoconfig
mips allmodconfig
parisc allnoconfig
parisc defconfig
parisc allyesconfig
parisc allmodconfig
powerpc defconfig
powerpc allyesconfig
powerpc rhel-kconfig
powerpc allmodconfig
powerpc allnoconfig
i386 randconfig-a001-20200521
i386 randconfig-a004-20200521
i386 randconfig-a006-20200521
i386 randconfig-a003-20200521
i386 randconfig-a002-20200521
i386 randconfig-a005-20200521
x86_64 randconfig-a015-20200522
x86_64 randconfig-a013-20200522
x86_64 randconfig-a016-20200522
x86_64 randconfig-a012-20200522
x86_64 randconfig-a014-20200522
x86_64 randconfig-a011-20200522
x86_64 randconfig-a002-20200521
x86_64 randconfig-a006-20200521
x86_64 randconfig-a005-20200521
x86_64 randconfig-a004-20200521
x86_64 randconfig-a003-20200521
x86_64 randconfig-a001-20200521
i386 randconfig-a013-20200522
i386 randconfig-a012-20200522
i386 randconfig-a015-20200522
i386 randconfig-a011-20200522
i386 randconfig-a016-20200522
i386 randconfig-a014-20200522
riscv allyesconfig
riscv allnoconfig
riscv defconfig
riscv allmodconfig
s390 allyesconfig
s390 allnoconfig
s390 allmodconfig
s390 defconfig
x86_64 defconfig
sparc defconfig
sparc64 defconfig
sparc64 allnoconfig
sparc64 allyesconfig
sparc64 allmodconfig
um allnoconfig
um allyesconfig
um defconfig
um allmodconfig
x86_64 rhel
x86_64 rhel-7.6
x86_64 rhel-7.6-kselftests
x86_64 rhel-7.2-clear
x86_64 lkp
x86_64 fedora-25
x86_64 kexec
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [soc:arm/fixes] BUILD SUCCESS ccffeae7afa41c8ec6d9070d1b4ca1fb210f9f28
From: kbuild test robot @ 2020-05-22 23:24 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: arm, linux-arm-kernel
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/soc/soc.git arm/fixes
branch HEAD: ccffeae7afa41c8ec6d9070d1b4ca1fb210f9f28 Merge branch 'v5.7-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/matthias.bgg/linux into arm/fixes
elapsed time: 1154m
configs tested: 110
configs skipped: 1
The following configs have been built successfully.
More configs may be tested in the coming days.
arm defconfig
arm allyesconfig
arm allmodconfig
arm allnoconfig
arm64 allyesconfig
arm64 defconfig
arm64 allmodconfig
arm64 allnoconfig
sparc allyesconfig
mips allyesconfig
m68k allyesconfig
i386 allnoconfig
i386 allyesconfig
i386 defconfig
i386 debian-10.3
ia64 allmodconfig
ia64 defconfig
ia64 allnoconfig
ia64 allyesconfig
m68k allmodconfig
m68k allnoconfig
m68k sun3_defconfig
m68k defconfig
nios2 defconfig
nios2 allyesconfig
openrisc defconfig
c6x allyesconfig
c6x allnoconfig
openrisc allyesconfig
nds32 defconfig
nds32 allnoconfig
csky allyesconfig
csky defconfig
alpha defconfig
alpha allyesconfig
xtensa allyesconfig
h8300 allyesconfig
h8300 allmodconfig
xtensa defconfig
arc defconfig
arc allyesconfig
sh allmodconfig
sh allnoconfig
microblaze allnoconfig
mips allnoconfig
mips allmodconfig
parisc allnoconfig
parisc defconfig
parisc allyesconfig
parisc allmodconfig
powerpc defconfig
powerpc allyesconfig
powerpc rhel-kconfig
powerpc allmodconfig
powerpc allnoconfig
i386 randconfig-a001-20200521
i386 randconfig-a004-20200521
i386 randconfig-a006-20200521
i386 randconfig-a003-20200521
i386 randconfig-a002-20200521
i386 randconfig-a005-20200521
x86_64 randconfig-a015-20200522
x86_64 randconfig-a013-20200522
x86_64 randconfig-a016-20200522
x86_64 randconfig-a012-20200522
x86_64 randconfig-a014-20200522
x86_64 randconfig-a011-20200522
x86_64 randconfig-a002-20200521
x86_64 randconfig-a006-20200521
x86_64 randconfig-a005-20200521
x86_64 randconfig-a004-20200521
x86_64 randconfig-a003-20200521
x86_64 randconfig-a001-20200521
i386 randconfig-a013-20200522
i386 randconfig-a012-20200522
i386 randconfig-a015-20200522
i386 randconfig-a011-20200522
i386 randconfig-a016-20200522
i386 randconfig-a014-20200522
i386 randconfig-a013-20200521
i386 randconfig-a012-20200521
i386 randconfig-a015-20200521
i386 randconfig-a011-20200521
i386 randconfig-a016-20200521
i386 randconfig-a014-20200521
riscv allyesconfig
riscv allnoconfig
riscv defconfig
riscv allmodconfig
s390 allyesconfig
s390 allnoconfig
s390 allmodconfig
s390 defconfig
x86_64 defconfig
sparc defconfig
sparc64 defconfig
sparc64 allnoconfig
sparc64 allyesconfig
sparc64 allmodconfig
um allnoconfig
um allyesconfig
um defconfig
um allmodconfig
x86_64 rhel
x86_64 rhel-7.6
x86_64 rhel-7.6-kselftests
x86_64 rhel-7.2-clear
x86_64 lkp
x86_64 fedora-25
x86_64 kexec
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [RESEND PATCH v14 04/11] pwm: clps711x: Cast period to u32 before use as divisor
From: Guru Das Srinagesh @ 2020-05-22 23:19 UTC (permalink / raw)
To: Daniel Thompson
Cc: linux-arm-kernel, linux-pwm, Arnd Bergmann, David Collins,
Stephen Boyd, linux-kernel, Thierry Reding, Geert Uytterhoeven,
Dan Carpenter, Uwe Kleine-König, Joe Perches,
Subbaraman Narayanamurthy, Lee Jones, Guenter Roeck
In-Reply-To: <20200522093738.cko5rj4wrxfd4hxu@holly.lan>
On Fri, May 22, 2020 at 10:37:38AM +0100, Daniel Thompson wrote:
> On Thu, May 21, 2020 at 01:25:25PM -0700, Guru Das Srinagesh wrote:
> > On Thu, May 21, 2020 at 11:19:34AM +0100, Daniel Thompson wrote:
> > > On Wed, May 20, 2020 at 03:55:57PM -0700, Guru Das Srinagesh wrote:
> > > > Since the PWM framework is switching struct pwm_args.period's datatype
> > > > to u64, prepare for this transition by typecasting it to u32.
> > > >
> > > > Also, since the dividend is still a 32-bit number, any divisor greater
> > > > than the numerator will cause the quotient to be zero, so return 0 in
> > > > that case to efficiently skip the division.
> > > >
> > > > Signed-off-by: Guru Das Srinagesh <gurus@codeaurora.org>
> > > > ---
> > > > drivers/pwm/pwm-clps711x.c | 5 ++++-
> > > > 1 file changed, 4 insertions(+), 1 deletion(-)> > >
> > > > diff --git a/drivers/pwm/pwm-clps711x.c b/drivers/pwm/pwm-clps711x.c
> > > > index 924d39a..da771b1 100644
> > > > --- a/drivers/pwm/pwm-clps711x.c
> > > > +++ b/drivers/pwm/pwm-clps711x.c
> > > > @@ -43,7 +43,10 @@ static void clps711x_pwm_update_val(struct clps711x_chip *priv, u32 n, u32 v)
> > > > static unsigned int clps711x_get_duty(struct pwm_device *pwm, unsigned int v)
> > > > {
> > > > /* Duty cycle 0..15 max */
> > > > - return DIV_ROUND_CLOSEST(v * 0xf, pwm->args.period);
> > > > + if (pwm->args.period > (v * 0xf))
> > > > + return 0;
> > >
> > > This doesn't look right to me.
> > >
> > > DIV_ROUND_CLOSEST() does rounded division and the short circuit doesn't
> > > implement that.
> >
> > My initial patch [1] was to simply use DIV64_U64_ROUND_CLOSEST(), but I
> > got review feedback to add a short-circuit (same thread, [2]). I feel
> > like I should skip the short-circuiting and type casting and simply just
> > use DIV64_U64_ROUND_CLOSEST() - what do you think?
>
> A trivial review of pwm-clps711x.c suggests that the period is always
> 32-bit anyway so why not just throw away the short circuit entirely and
> replace with a comment saying that CLPS711X has a hard coded period
> that is always >1000000000 ?
Sorry, I don't follow the significance of 1000000000 - could you please
explain?
Just to clarify, what I was saying in my previous email was the
following: I think it might be simpler to just throw away the short
circuit and just do:
s/DIV_ROUND_CLOSEST/DIV64_U64_ROUND_CLOSEST
like in another patch in this series [1]. That should handle the
rounding properly as per design. Is that okay?
[1] https://lore.kernel.org/lkml/ca783e0f5ff7b517ce0854908f0e89b07551bfe5.1588616856.git.gurus@codeaurora.org/
Thank you.
Guru Das.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH -next] soc: fsl: dpio: Remove unused inline function qbman_write_eqcr_am_rt_register
From: Li Yang @ 2020-05-22 23:11 UTC (permalink / raw)
To: YueHaibing
Cc: Roy Pledge, linuxppc-dev, Youri Querry,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE, lkml
In-Reply-To: <20200508140947.28712-1-yuehaibing@huawei.com>
On Fri, May 8, 2020 at 9:13 AM YueHaibing <yuehaibing@huawei.com> wrote:
>
> There's no callers in-tree anymore since commit
> 3b2abda7d28c ("soc: fsl: dpio: Replace QMAN array mode with ring mode enqueue")
>
> Signed-off-by: YueHaibing <yuehaibing@huawei.com>
Applied to next. Thanks.
Regards,
Leo
> ---
> drivers/soc/fsl/dpio/qbman-portal.c | 12 ------------
> 1 file changed, 12 deletions(-)
>
> diff --git a/drivers/soc/fsl/dpio/qbman-portal.c b/drivers/soc/fsl/dpio/qbman-portal.c
> index 804b8ba9bf5c..e2e9fbb58a72 100644
> --- a/drivers/soc/fsl/dpio/qbman-portal.c
> +++ b/drivers/soc/fsl/dpio/qbman-portal.c
> @@ -572,18 +572,6 @@ void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, u32 qdid,
> #define EQAR_VB(eqar) ((eqar) & 0x80)
> #define EQAR_SUCCESS(eqar) ((eqar) & 0x100)
>
> -static inline void qbman_write_eqcr_am_rt_register(struct qbman_swp *p,
> - u8 idx)
> -{
> - if (idx < 16)
> - qbman_write_register(p, QBMAN_CINH_SWP_EQCR_AM_RT + idx * 4,
> - QMAN_RT_MODE);
> - else
> - qbman_write_register(p, QBMAN_CINH_SWP_EQCR_AM_RT2 +
> - (idx - 16) * 4,
> - QMAN_RT_MODE);
> -}
> -
> #define QB_RT_BIT ((u32)0x100)
> /**
> * qbman_swp_enqueue_direct() - Issue an enqueue command
> --
> 2.17.1
>
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] soc: fsl: qe: clean up an indentation issue
From: Li Yang @ 2020-05-22 23:01 UTC (permalink / raw)
To: Colin King
Cc: kernel-janitors, linuxppc-dev, lkml,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
Qiang Zhao
In-Reply-To: <20200327161349.284679-1-colin.king@canonical.com>
On Fri, Mar 27, 2020 at 11:15 AM Colin King <colin.king@canonical.com> wrote:
>
> From: Colin Ian King <colin.king@canonical.com>
>
> There is a statement that not indented correctly, remove the
> extraneous space.
>
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
Applied for next. Thanks.
> ---
> drivers/soc/fsl/qe/ucc.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/soc/fsl/qe/ucc.c b/drivers/soc/fsl/qe/ucc.c
> index d6c93970df4d..cac0fb7693a0 100644
> --- a/drivers/soc/fsl/qe/ucc.c
> +++ b/drivers/soc/fsl/qe/ucc.c
> @@ -519,7 +519,7 @@ int ucc_set_tdm_rxtx_clk(u32 tdm_num, enum qe_clock clock,
> int clock_bits;
> u32 shift;
> struct qe_mux __iomem *qe_mux_reg;
> - __be32 __iomem *cmxs1cr;
> + __be32 __iomem *cmxs1cr;
>
> qe_mux_reg = &qe_immr->qmx;
>
> --
> 2.25.1
>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v13 1/3] dt-bindings: i2c: npcm7xx: add NPCM I2C controller
From: Rob Herring @ 2020-05-22 22:47 UTC (permalink / raw)
To: Tali Perry
Cc: devicetree, Benjamin Fair, kfting, Avi Fishman, Patrick Venture,
OpenBMC Maillist, Wolfram Sang, Brendan Higgins,
linux-kernel@vger.kernel.org, Ofer Yehielli, Nancy Yuen,
Linux I2C, Andy Shevchenko,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
Tomer Maimon
In-Reply-To: <20200522224217.GA847856@bogus>
On Fri, May 22, 2020 at 4:42 PM Rob Herring <robh@kernel.org> wrote:
>
> On Fri, 22 May 2020 14:33:10 +0300, Tali Perry wrote:
> > Added device tree binding documentation for Nuvoton BMC
> > NPCM I2C controller.
> >
> > Signed-off-by: Tali Perry <tali.perry1@gmail.com>
> > ---
> > .../bindings/i2c/nuvoton,npcm7xx-i2c.yaml | 60 +++++++++++++++++++
> > 1 file changed, 60 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/i2c/nuvoton,npcm7xx-i2c.yaml
> >
>
>
> My bot found errors running 'make dt_binding_check' on your patch:
>
> Error: Documentation/devicetree/bindings/i2c/nuvoton,npcm7xx-i2c.example.dts:22.28-29 syntax error
> FATAL ERROR: Unable to parse input tree
> scripts/Makefile.lib:312: recipe for target 'Documentation/devicetree/bindings/i2c/nuvoton,npcm7xx-i2c.example.dt.yaml' failed
> make[1]: *** [Documentation/devicetree/bindings/i2c/nuvoton,npcm7xx-i2c.example.dt.yaml] Error 1
> make[1]: *** Waiting for unfinished jobs....
> Makefile:1300: recipe for target 'dt_binding_check' failed
> make: *** [dt_binding_check] Error 2
>
> See https://patchwork.ozlabs.org/patch/1296162
>
> If you already ran 'make dt_binding_check' and didn't see the above
> error(s), then make sure dt-schema is up to date:
>
> pip3 install git+https://github.com/devicetree-org/dt-schema.git@master --upgrade
>
> Please check and re-submit.
Why do you keep sending new versions with the same problem? It won't
get reviewed until this is fixed. This isn't a free automated service
to throw things at to see if they work. I have to review the failures.
Rob
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v8 19/19] mtd: spi-nor: micron-st: allow using MT35XU512ABA in Octal DTR mode
From: Pratyush Yadav @ 2020-05-22 22:40 UTC (permalink / raw)
To: Tudor Ambarus, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Mark Brown, Nicolas Ferre, Alexandre Belloni,
Ludovic Desroches, Matthias Brugger, Michal Simek, linux-mtd,
linux-kernel, linux-spi, linux-arm-kernel, linux-mediatek
Cc: Mason Yang, Boris Brezillon, Sekhar Nori, Pratyush Yadav
In-Reply-To: <20200522224042.29970-1-p.yadav@ti.com>
Since this flash doesn't have a Profile 1.0 table, the Octal DTR
capabilities are enabled in the post SFDP fixup, along with the 8D-8D-8D
fast read settings.
Enable Octal DTR mode with 20 dummy cycles to allow running at the
maximum supported frequency of 200Mhz.
The flash supports the soft reset sequence. So, add the flag in the
flash's info.
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
drivers/mtd/spi-nor/micron-st.c | 112 +++++++++++++++++++++++++++++++-
1 file changed, 111 insertions(+), 1 deletion(-)
diff --git a/drivers/mtd/spi-nor/micron-st.c b/drivers/mtd/spi-nor/micron-st.c
index 3dca5b9af3b6..3414c44a5c96 100644
--- a/drivers/mtd/spi-nor/micron-st.c
+++ b/drivers/mtd/spi-nor/micron-st.c
@@ -8,10 +8,120 @@
#include "core.h"
+#define SPINOR_OP_MT_DTR_RD 0xfd /* Fast Read opcode in DTR mode */
+#define SPINOR_OP_MT_RD_ANY_REG 0x85 /* Read volatile register */
+#define SPINOR_OP_MT_WR_ANY_REG 0x81 /* Write volatile register */
+#define SPINOR_REG_MT_CFR0V 0x00 /* For setting octal DTR mode */
+#define SPINOR_REG_MT_CFR1V 0x01 /* For setting dummy cycles */
+#define SPINOR_MT_DTR_NO_DQS 0xc7 /* Enable Octal DTR without DQS. */
+#define SPINOR_MT_EXSPI 0xff /* Enable Extended SPI (default) */
+
+static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor, bool enable)
+{
+ struct spi_mem_op op;
+ u8 *buf = nor->bouncebuf;
+ u8 addr_width;
+ int ret;
+
+ if (enable)
+ addr_width = 3;
+ else
+ addr_width = 4;
+
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ return ret;
+
+ if (enable)
+ *buf = SPINOR_MT_DTR_NO_DQS;
+ else
+ *buf = SPINOR_MT_EXSPI;
+ op = (struct spi_mem_op)
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1),
+ SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR0V, 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(1, buf, 1));
+
+ if (!enable)
+ spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret) {
+ dev_err(nor->dev, "Failed to enable octal DTR mode\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mt35xu512aba_setup(struct spi_nor *nor,
+ const struct spi_nor_hwcaps *hwcaps)
+{
+ struct spi_mem_op op;
+ u8 *buf = nor->bouncebuf;
+ u8 addr_width = 3;
+ int ret;
+
+ if (!nor->spimem) {
+ dev_err(nor->dev,
+ "operation not supported for non-spimem drivers\n");
+ return -ENOTSUPP;
+ }
+
+ /* Set dummy cycles for Fast Read to the default of 20. */
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ return ret;
+
+ *buf = 20;
+ op = (struct spi_mem_op)
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1),
+ SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR1V, 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(1, buf, 1));
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret)
+ return ret;
+
+ ret = spi_nor_wait_till_ready(nor);
+ if (ret)
+ return ret;
+
+
+ return spi_nor_default_setup(nor, hwcaps);
+}
+
+static void mt35xu512aba_default_init(struct spi_nor *nor)
+{
+ nor->params->octal_dtr_enable = spi_nor_micron_octal_dtr_enable;
+ nor->params->setup = mt35xu512aba_setup;
+}
+
+static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor)
+{
+ /* Set the Fast Read settings. */
+ nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
+ spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_8_8_8_DTR],
+ 0, 20, SPINOR_OP_MT_DTR_RD,
+ SNOR_PROTO_8_8_8_DTR);
+
+ nor->params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR;
+
+ nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
+ nor->params->rdsr_dummy = 8;
+ nor->params->rdsr_addr_nbytes = 0;
+}
+
+static struct spi_nor_fixups mt35xu512aba_fixups = {
+ .default_init = mt35xu512aba_default_init,
+ .post_sfdp = mt35xu512aba_post_sfdp_fixup,
+};
+
static const struct flash_info micron_parts[] = {
{ "mt35xu512aba", INFO(0x2c5b1a, 0, 128 * 1024, 512,
SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ |
- SPI_NOR_4B_OPCODES) },
+ SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_DTR_READ)
+ .fixups = &mt35xu512aba_fixups},
{ "mt35xu02g", INFO(0x2c5b1c, 0, 128 * 1024, 2048,
SECT_4K | USE_FSR | SPI_NOR_OCTAL_READ |
SPI_NOR_4B_OPCODES) },
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v8 18/19] mtd: spi-nor: spansion: add support for Cypress Semper flash
From: Pratyush Yadav @ 2020-05-22 22:40 UTC (permalink / raw)
To: Tudor Ambarus, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Mark Brown, Nicolas Ferre, Alexandre Belloni,
Ludovic Desroches, Matthias Brugger, Michal Simek, linux-mtd,
linux-kernel, linux-spi, linux-arm-kernel, linux-mediatek
Cc: Mason Yang, Boris Brezillon, Sekhar Nori, Pratyush Yadav
In-Reply-To: <20200522224042.29970-1-p.yadav@ti.com>
The Cypress Semper flash is an xSPI compliant octal DTR flash. Add
support for using it in octal DTR mode.
The flash by default boots in a hybrid sector mode. But the sector map
table on the part I had was programmed incorrectly and the SMPT values
on the flash don't match the public datasheet. Specifically, in some
places erase type 3 was used instead of 4. In addition, the region sizes
were incorrect in some places. So, for testing I set CFR3N[3] to enable
uniform sector sizes. Since the uniform sector mode bit is a
non-volatile bit, this series does not change it to avoid making any
permanent changes to the flash configuration. The correct data to
implement a fixup is not available right now and will be done in a
follow-up patch if needed.
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
drivers/mtd/spi-nor/spansion.c | 167 +++++++++++++++++++++++++++++++++
1 file changed, 167 insertions(+)
diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c
index 88183eba8ac1..e5dc36b70e4e 100644
--- a/drivers/mtd/spi-nor/spansion.c
+++ b/drivers/mtd/spi-nor/spansion.c
@@ -8,6 +8,169 @@
#include "core.h"
+/* For Cypress flash. */
+#define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */
+#define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */
+#define SPINOR_REG_CYPRESS_CFR2V 0x00800003
+#define SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24 0xb
+#define SPINOR_REG_CYPRESS_CFR3V 0x00800004
+#define SPINOR_REG_CYPRESS_CFR3V_PGSZ BIT(4) /* Page size. */
+#define SPINOR_REG_CYPRESS_CFR5V 0x00800006
+#define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN 0x3
+#define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS 0
+#define SPINOR_OP_CYPRESS_RD_FAST 0xee
+
+/**
+ * spi_nor_cypress_octal_dtr_enable() - Enable octal DTR on Cypress flashes.
+ * @nor: pointer to a 'struct spi_nor'
+ *
+ * This also sets the memory access latency cycles to 24 to allow the flash to
+ * run at up to 200MHz.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_cypress_octal_dtr_enable(struct spi_nor *nor, bool enable)
+{
+ struct spi_mem_op op;
+ u8 *buf = nor->bouncebuf;
+ u8 addr_width;
+ int ret;
+
+ if (enable)
+ addr_width = 3;
+ else
+ addr_width = 4;
+
+ if (enable) {
+ /* Use 24 dummy cycles for memory array reads. */
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ return ret;
+
+ *buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24;
+ op = (struct spi_mem_op)
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1),
+ SPI_MEM_OP_ADDR(addr_width,
+ SPINOR_REG_CYPRESS_CFR2V,
+ 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(1, buf, 1));
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret) {
+ dev_warn(nor->dev,
+ "failed to set default memory latency value: %d\n",
+ ret);
+ return ret;
+ }
+ ret = spi_nor_wait_till_ready(nor);
+ if (ret)
+ return ret;
+
+ nor->read_dummy = 24;
+ }
+
+ /* Set/unset the octal and DTR enable bits. */
+ ret = spi_nor_write_enable(nor);
+ if (ret)
+ return ret;
+
+ if (enable)
+ *buf = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN;
+ else
+ *buf = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS;
+ op = (struct spi_mem_op)
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1),
+ SPI_MEM_OP_ADDR(addr_width,
+ SPINOR_REG_CYPRESS_CFR5V,
+ 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(1, buf, 1));
+
+ if (!enable)
+ spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret) {
+ dev_warn(nor->dev, "Failed to enable octal DTR mode\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void s28hs512t_default_init(struct spi_nor *nor)
+{
+ nor->params->octal_dtr_enable = spi_nor_cypress_octal_dtr_enable;
+}
+
+static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor)
+{
+ /*
+ * On older versions of the flash the xSPI Profile 1.0 table has the
+ * 8D-8D-8D Fast Read opcode as 0x00. But it actually should be 0xEE.
+ */
+ if (nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0)
+ nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode =
+ SPINOR_OP_CYPRESS_RD_FAST;
+
+ nor->params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR;
+
+ /* This flash is also missing the 4-byte Page Program opcode bit. */
+ spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP],
+ SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1);
+ /*
+ * Since xSPI Page Program opcode is backward compatible with
+ * Legacy SPI, use Legacy SPI opcode there as well.
+ */
+ spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
+ SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR);
+
+ /*
+ * The xSPI Profile 1.0 table advertises the number of additional
+ * address bytes needed for Read Status Register command as 0 but the
+ * actual value for that is 4.
+ */
+ nor->params->rdsr_addr_nbytes = 4;
+}
+
+static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor,
+ const struct sfdp_parameter_header *bfpt_header,
+ const struct sfdp_bfpt *bfpt,
+ struct spi_nor_flash_parameter *params)
+{
+ struct spi_mem_op op;
+ u8 *buf = nor->bouncebuf;
+ u8 addr_width = 3;
+ int ret;
+
+ /*
+ * The BFPT table advertises a 512B page size but the page size is
+ * actually configurable (with the default being 256B). Read from
+ * CFR3V[4] and set the correct size.
+ */
+ op = (struct spi_mem_op)
+ SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 1),
+ SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_CYPRESS_CFR3V, 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_IN(1, buf, 1));
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret)
+ return ret;
+
+ if (*buf & SPINOR_REG_CYPRESS_CFR3V_PGSZ)
+ params->page_size = 512;
+ else
+ params->page_size = 256;
+
+ return 0;
+}
+
+static struct spi_nor_fixups s28hs512t_fixups = {
+ .default_init = s28hs512t_default_init,
+ .post_sfdp = s28hs512t_post_sfdp_fixup,
+ .post_bfpt = s28hs512t_post_bfpt_fixup,
+};
+
static const struct flash_info spansion_parts[] = {
/* Spansion/Cypress -- single (large) sector size only, at least
* for the chips listed here (without boot sectors).
@@ -72,6 +235,10 @@ static const struct flash_info spansion_parts[] = {
{ "s25fl256l", INFO(0x016019, 0, 64 * 1024, 512,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_4B_OPCODES) },
+ { "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256,
+ SECT_4K | SPI_NOR_OCTAL_DTR_READ)
+ .fixups = &s28hs512t_fixups,
+ },
};
static void spansion_post_sfdp_fixups(struct spi_nor *nor)
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v8 17/19] mtd: spi-nor: core: expose spi_nor_default_setup() in core.h
From: Pratyush Yadav @ 2020-05-22 22:40 UTC (permalink / raw)
To: Tudor Ambarus, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Mark Brown, Nicolas Ferre, Alexandre Belloni,
Ludovic Desroches, Matthias Brugger, Michal Simek, linux-mtd,
linux-kernel, linux-spi, linux-arm-kernel, linux-mediatek
Cc: Mason Yang, Boris Brezillon, Sekhar Nori, Pratyush Yadav
In-Reply-To: <20200522224042.29970-1-p.yadav@ti.com>
Flashes might want to add a custom setup hook to configure the flash in
the proper mode for operation. But after that, they would still want to
run the default setup hook because it selects the read, program, and
erase operations. Since there is little point in repeating all that
code, expose the spi_nor_default_setup() in core.h to
manufacturer-specific files.
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
drivers/mtd/spi-nor/core.c | 4 ++--
drivers/mtd/spi-nor/core.h | 3 +++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 63ab588299f4..30d9149fd17b 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -2790,8 +2790,8 @@ static int spi_nor_select_erase(struct spi_nor *nor)
return 0;
}
-static int spi_nor_default_setup(struct spi_nor *nor,
- const struct spi_nor_hwcaps *hwcaps)
+int spi_nor_default_setup(struct spi_nor *nor,
+ const struct spi_nor_hwcaps *hwcaps)
{
struct spi_nor_flash_parameter *params = nor->params;
u32 ignored_mask, shared_mask;
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index 79ce952c0539..d37a9b1d111f 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -452,6 +452,9 @@ int spi_nor_post_bfpt_fixups(struct spi_nor *nor,
const struct sfdp_bfpt *bfpt,
struct spi_nor_flash_parameter *params);
+int spi_nor_default_setup(struct spi_nor *nor,
+ const struct spi_nor_hwcaps *hwcaps);
+
static struct spi_nor __maybe_unused *mtd_to_spi_nor(struct mtd_info *mtd)
{
return mtd->priv;
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH v13 1/3] dt-bindings: i2c: npcm7xx: add NPCM I2C controller
From: Rob Herring @ 2020-05-22 22:42 UTC (permalink / raw)
To: Tali Perry
Cc: devicetree, benjaminfair, kfting, avifishman70, venture, openbmc,
wsa, brendanhiggins, linux-kernel, ofery, yuenn, robh+dt,
linux-i2c, andriy.shevchenko, linux-arm-kernel, tmaimon77
In-Reply-To: <20200522113312.181413-2-tali.perry1@gmail.com>
On Fri, 22 May 2020 14:33:10 +0300, Tali Perry wrote:
> Added device tree binding documentation for Nuvoton BMC
> NPCM I2C controller.
>
> Signed-off-by: Tali Perry <tali.perry1@gmail.com>
> ---
> .../bindings/i2c/nuvoton,npcm7xx-i2c.yaml | 60 +++++++++++++++++++
> 1 file changed, 60 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/i2c/nuvoton,npcm7xx-i2c.yaml
>
My bot found errors running 'make dt_binding_check' on your patch:
Error: Documentation/devicetree/bindings/i2c/nuvoton,npcm7xx-i2c.example.dts:22.28-29 syntax error
FATAL ERROR: Unable to parse input tree
scripts/Makefile.lib:312: recipe for target 'Documentation/devicetree/bindings/i2c/nuvoton,npcm7xx-i2c.example.dt.yaml' failed
make[1]: *** [Documentation/devicetree/bindings/i2c/nuvoton,npcm7xx-i2c.example.dt.yaml] Error 1
make[1]: *** Waiting for unfinished jobs....
Makefile:1300: recipe for target 'dt_binding_check' failed
make: *** [dt_binding_check] Error 2
See https://patchwork.ozlabs.org/patch/1296162
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure dt-schema is up to date:
pip3 install git+https://github.com/devicetree-org/dt-schema.git@master --upgrade
Please check and re-submit.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v8 16/19] mtd: spi-nor: core: disable Octal DTR mode on suspend.
From: Pratyush Yadav @ 2020-05-22 22:40 UTC (permalink / raw)
To: Tudor Ambarus, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Mark Brown, Nicolas Ferre, Alexandre Belloni,
Ludovic Desroches, Matthias Brugger, Michal Simek, linux-mtd,
linux-kernel, linux-spi, linux-arm-kernel, linux-mediatek
Cc: Mason Yang, Boris Brezillon, Sekhar Nori, Pratyush Yadav
In-Reply-To: <20200522224042.29970-1-p.yadav@ti.com>
On resume, the init procedure will be run that will re-enable it.
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
drivers/mtd/spi-nor/core.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 68559386f6f8..63ab588299f4 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -3239,6 +3239,23 @@ static void spi_nor_soft_reset(struct spi_nor *nor)
usleep_range(SPI_NOR_SRST_SLEEP_MIN, SPI_NOR_SRST_SLEEP_MAX);
}
+/* mtd suspend handler */
+static int spi_nor_suspend(struct mtd_info *mtd)
+{
+ struct spi_nor *nor = mtd_to_spi_nor(mtd);
+ struct device *dev = nor->dev;
+ int ret;
+
+ /* Disable octal DTR mode if we enabled it. */
+ ret = spi_nor_octal_dtr_enable(nor, false);
+ if (ret) {
+ dev_err(dev, "suspend() failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
/* mtd resume handler */
static void spi_nor_resume(struct mtd_info *mtd)
{
@@ -3432,6 +3449,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name,
mtd->size = nor->params->size;
mtd->_erase = spi_nor_erase;
mtd->_read = spi_nor_read;
+ mtd->_suspend = spi_nor_suspend;
mtd->_resume = spi_nor_resume;
if (nor->params->locking_ops) {
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v8 15/19] mtd: spi-nor: core: perform a Soft Reset on shutdown
From: Pratyush Yadav @ 2020-05-22 22:40 UTC (permalink / raw)
To: Tudor Ambarus, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Mark Brown, Nicolas Ferre, Alexandre Belloni,
Ludovic Desroches, Matthias Brugger, Michal Simek, linux-mtd,
linux-kernel, linux-spi, linux-arm-kernel, linux-mediatek
Cc: Mason Yang, Boris Brezillon, Sekhar Nori, Pratyush Yadav
In-Reply-To: <20200522224042.29970-1-p.yadav@ti.com>
Perform a Soft Reset on shutdown on flashes that support it so that the
flash can be reset to its initial state and any configurations made by
spi-nor (given that they're only done in volatile registers) will be
reset. This will hand back the flash in pristine state for any further
operations on it.
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
drivers/mtd/spi-nor/core.c | 42 +++++++++++++++++++++++++++++++++++++
include/linux/mtd/spi-nor.h | 2 ++
2 files changed, 44 insertions(+)
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index a94376344be5..68559386f6f8 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -40,6 +40,9 @@
#define SPI_NOR_MAX_ADDR_WIDTH 4
+#define SPI_NOR_SRST_SLEEP_MIN 200
+#define SPI_NOR_SRST_SLEEP_MAX 400
+
/**
* spi_nor_get_cmd_ext() - Get the command opcode extension based on the
* extension type.
@@ -3201,6 +3204,41 @@ static int spi_nor_init(struct spi_nor *nor)
return 0;
}
+static void spi_nor_soft_reset(struct spi_nor *nor)
+{
+ struct spi_mem_op op;
+ int ret;
+
+ op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRSTEN, 8),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_NO_DATA);
+ spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret) {
+ dev_warn(nor->dev, "Software reset failed: %d\n", ret);
+ return;
+ }
+
+ op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRST, 8),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_NO_DATA);
+ spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret) {
+ dev_warn(nor->dev, "Software reset failed: %d\n", ret);
+ return;
+ }
+
+ /*
+ * Software Reset is not instant, and the delay varies from flash to
+ * flash. Looking at a few flashes, most range somewhere below 100
+ * microseconds. So, sleep for a range of 200-400 us.
+ */
+ usleep_range(SPI_NOR_SRST_SLEEP_MIN, SPI_NOR_SRST_SLEEP_MAX);
+}
+
/* mtd resume handler */
static void spi_nor_resume(struct mtd_info *mtd)
{
@@ -3220,6 +3258,10 @@ void spi_nor_restore(struct spi_nor *nor)
if (nor->addr_width == 4 && !(nor->flags & SNOR_F_4B_OPCODES) &&
nor->flags & SNOR_F_BROKEN_RESET)
nor->params->set_4byte_addr_mode(nor, false);
+
+ if (nor->info->flags & SPI_NOR_OCTAL_DTR_READ &&
+ nor->flags & SNOR_F_SOFT_RESET)
+ spi_nor_soft_reset(nor);
}
EXPORT_SYMBOL_GPL(spi_nor_restore);
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index d251a5d02be2..06884a188315 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -51,6 +51,8 @@
#define SPINOR_OP_CLFSR 0x50 /* Clear flag status register */
#define SPINOR_OP_RDEAR 0xc8 /* Read Extended Address Register */
#define SPINOR_OP_WREAR 0xc5 /* Write Extended Address Register */
+#define SPINOR_OP_SRSTEN 0x66 /* Software Reset Enable */
+#define SPINOR_OP_SRST 0x99 /* Software Reset */
/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
#define SPINOR_OP_READ_4B 0x13 /* Read data bytes (low frequency) */
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v8 14/19] mtd: spi-nor: sfdp: detect Soft Reset sequence support from BFPT
From: Pratyush Yadav @ 2020-05-22 22:40 UTC (permalink / raw)
To: Tudor Ambarus, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Mark Brown, Nicolas Ferre, Alexandre Belloni,
Ludovic Desroches, Matthias Brugger, Michal Simek, linux-mtd,
linux-kernel, linux-spi, linux-arm-kernel, linux-mediatek
Cc: Mason Yang, Boris Brezillon, Sekhar Nori, Pratyush Yadav
In-Reply-To: <20200522224042.29970-1-p.yadav@ti.com>
A Soft Reset sequence will return the flash to Power-on-Reset (POR)
state. It consists of two commands: Soft Reset Enable and Soft Reset.
Find out if the sequence is supported from BFPT DWORD 16.
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
drivers/mtd/spi-nor/core.h | 1 +
drivers/mtd/spi-nor/sfdp.c | 4 ++++
drivers/mtd/spi-nor/sfdp.h | 2 ++
3 files changed, 7 insertions(+)
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index 6338d32a0d77..79ce952c0539 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -26,6 +26,7 @@ enum spi_nor_option_flags {
SNOR_F_HAS_SR_TB_BIT6 = BIT(11),
SNOR_F_HAS_4BIT_BP = BIT(12),
SNOR_F_HAS_SR_BP3_BIT6 = BIT(13),
+ SNOR_F_SOFT_RESET = BIT(14),
};
struct spi_nor_read_command {
diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c
index 9fd3d8d9a127..11109969dc3a 100644
--- a/drivers/mtd/spi-nor/sfdp.c
+++ b/drivers/mtd/spi-nor/sfdp.c
@@ -618,6 +618,10 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
break;
}
+ /* Soft Reset support. */
+ if (bfpt.dwords[BFPT_DWORD(16)] & BFPT_DWORD16_SOFT_RST)
+ nor->flags |= SNOR_F_SOFT_RESET;
+
/* Stop here if JESD216 rev B. */
if (bfpt_header->length == BFPT_DWORD_MAX_JESD216B)
return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt,
diff --git a/drivers/mtd/spi-nor/sfdp.h b/drivers/mtd/spi-nor/sfdp.h
index e15e30796d62..d1d43ee09a0a 100644
--- a/drivers/mtd/spi-nor/sfdp.h
+++ b/drivers/mtd/spi-nor/sfdp.h
@@ -84,6 +84,8 @@ struct sfdp_bfpt {
#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD (0x4UL << 20)
#define BFPT_DWORD15_QER_SR2_BIT1 (0x5UL << 20) /* Spansion */
+#define BFPT_DWORD16_SOFT_RST BIT(12)
+
#define BFPT_DWORD18_CMD_EXT_MASK GENMASK(30, 29)
#define BFPT_DWORD18_CMD_EXT_REP (0x0UL << 29) /* Repeat */
#define BFPT_DWORD18_CMD_EXT_INV (0x1UL << 29) /* Invert */
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v8 13/19] mtd: spi-nor: sfdp: do not make invalid quad enable fatal
From: Pratyush Yadav @ 2020-05-22 22:40 UTC (permalink / raw)
To: Tudor Ambarus, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Mark Brown, Nicolas Ferre, Alexandre Belloni,
Ludovic Desroches, Matthias Brugger, Michal Simek, linux-mtd,
linux-kernel, linux-spi, linux-arm-kernel, linux-mediatek
Cc: Mason Yang, Boris Brezillon, Sekhar Nori, Pratyush Yadav
In-Reply-To: <20200522224042.29970-1-p.yadav@ti.com>
The Micron MT35XU512ABA flash does not support the quad enable bit. But
instead of programming the Quad Enable Require field to 000b ("Device
does not have a QE bit"), it is programmed to 111b ("Reserved").
While this is technically incorrect, it is not reason enough to abort
BFPT parsing. Instead, continue BFPT parsing assuming there is no quad
enable bit present.
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
drivers/mtd/spi-nor/sfdp.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/drivers/mtd/spi-nor/sfdp.c b/drivers/mtd/spi-nor/sfdp.c
index 052cabb52df9..9fd3d8d9a127 100644
--- a/drivers/mtd/spi-nor/sfdp.c
+++ b/drivers/mtd/spi-nor/sfdp.c
@@ -576,10 +576,6 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
/* Quad Enable Requirements. */
switch (bfpt.dwords[BFPT_DWORD(15)] & BFPT_DWORD15_QER_MASK) {
- case BFPT_DWORD15_QER_NONE:
- params->quad_enable = NULL;
- break;
-
case BFPT_DWORD15_QER_SR2_BIT1_BUGGY:
/*
* Writing only one byte to the Status Register has the
@@ -616,8 +612,10 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
params->quad_enable = spi_nor_sr2_bit1_quad_enable;
break;
+ case BFPT_DWORD15_QER_NONE:
default:
- return -EINVAL;
+ params->quad_enable = NULL;
+ break;
}
/* Stop here if JESD216 rev B. */
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v8 12/19] mtd: spi-nor: core: enable octal DTR mode when possible
From: Pratyush Yadav @ 2020-05-22 22:40 UTC (permalink / raw)
To: Tudor Ambarus, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Mark Brown, Nicolas Ferre, Alexandre Belloni,
Ludovic Desroches, Matthias Brugger, Michal Simek, linux-mtd,
linux-kernel, linux-spi, linux-arm-kernel, linux-mediatek
Cc: Mason Yang, Boris Brezillon, Sekhar Nori, Pratyush Yadav
In-Reply-To: <20200522224042.29970-1-p.yadav@ti.com>
Allow flashes to specify a hook to enable octal DTR mode. Use this hook
whenever possible to get optimal transfer speeds.
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
drivers/mtd/spi-nor/core.c | 35 +++++++++++++++++++++++++++++++++++
drivers/mtd/spi-nor/core.h | 2 ++
2 files changed, 37 insertions(+)
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 5cb7e391cd29..a94376344be5 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -3097,6 +3097,35 @@ static int spi_nor_init_params(struct spi_nor *nor)
return 0;
}
+/** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed
+ * @nor: pointer to a 'struct spi_nor'
+ * @enable: whether to enable or disable Octal DTR
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
+{
+ int ret;
+
+ if (!nor->params->octal_dtr_enable)
+ return 0;
+
+ if (!(nor->read_proto == SNOR_PROTO_8_8_8_DTR &&
+ nor->write_proto == SNOR_PROTO_8_8_8_DTR))
+ return 0;
+
+ ret = nor->params->octal_dtr_enable(nor, enable);
+ if (ret)
+ return ret;
+
+ if (enable)
+ nor->reg_proto = SNOR_PROTO_8_8_8_DTR;
+ else
+ nor->reg_proto = SNOR_PROTO_1_1_1;
+
+ return 0;
+}
+
/**
* spi_nor_quad_enable() - enable Quad I/O if needed.
* @nor: pointer to a 'struct spi_nor'
@@ -3136,6 +3165,12 @@ static int spi_nor_init(struct spi_nor *nor)
{
int err;
+ err = spi_nor_octal_dtr_enable(nor, true);
+ if (err) {
+ dev_dbg(nor->dev, "octal mode not supported\n");
+ return err;
+ }
+
err = spi_nor_quad_enable(nor);
if (err) {
dev_dbg(nor->dev, "quad mode not supported\n");
diff --git a/drivers/mtd/spi-nor/core.h b/drivers/mtd/spi-nor/core.h
index 7e6df8322da0..6338d32a0d77 100644
--- a/drivers/mtd/spi-nor/core.h
+++ b/drivers/mtd/spi-nor/core.h
@@ -203,6 +203,7 @@ struct spi_nor_locking_ops {
* higher index in the array, the higher priority.
* @erase_map: the erase map parsed from the SFDP Sector Map Parameter
* Table.
+ * @octal_dtr_enable: enables SPI NOR octal DTR mode.
* @quad_enable: enables SPI NOR quad mode.
* @set_4byte_addr_mode: puts the SPI NOR in 4 byte addressing mode.
* @convert_addr: converts an absolute address into something the flash
@@ -226,6 +227,7 @@ struct spi_nor_flash_parameter {
struct spi_nor_erase_map erase_map;
+ int (*octal_dtr_enable)(struct spi_nor *nor, bool enable);
int (*quad_enable)(struct spi_nor *nor);
int (*set_4byte_addr_mode)(struct spi_nor *nor, bool enable);
u32 (*convert_addr)(struct spi_nor *nor, u32 addr);
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v8 11/19] mtd: spi-nor: core: do 2 byte reads for SR and FSR in DTR mode
From: Pratyush Yadav @ 2020-05-22 22:40 UTC (permalink / raw)
To: Tudor Ambarus, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Mark Brown, Nicolas Ferre, Alexandre Belloni,
Ludovic Desroches, Matthias Brugger, Michal Simek, linux-mtd,
linux-kernel, linux-spi, linux-arm-kernel, linux-mediatek
Cc: Mason Yang, Boris Brezillon, Sekhar Nori, Pratyush Yadav
In-Reply-To: <20200522224042.29970-1-p.yadav@ti.com>
Some controllers, like the cadence qspi controller, have trouble reading
only 1 byte in DTR mode. So, do 2 byte reads for SR and FSR commands in
DTR mode, and then discard the second byte.
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
drivers/mtd/spi-nor/core.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 2ad248140b6c..5cb7e391cd29 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -350,7 +350,7 @@ int spi_nor_write_disable(struct spi_nor *nor)
* spi_nor_read_sr() - Read the Status Register.
* @nor: pointer to 'struct spi_nor'.
* @sr: pointer to a DMA-able buffer where the value of the
- * Status Register will be written.
+ * Status Register will be written. Should be at least 2 bytes.
*
* Return: 0 on success, -errno otherwise.
*/
@@ -371,6 +371,11 @@ static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
op.addr.nbytes = addr_bytes;
op.addr.val = 0;
op.dummy.nbytes = dummy;
+ /*
+ * We don't want to read only one byte in DTR mode. So,
+ * read 2 and then discard the second byte.
+ */
+ op.data.nbytes = 2;
}
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
@@ -394,7 +399,8 @@ static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
* spi_nor_read_fsr() - Read the Flag Status Register.
* @nor: pointer to 'struct spi_nor'
* @fsr: pointer to a DMA-able buffer where the value of the
- * Flag Status Register will be written.
+ * Flag Status Register will be written. Should be at least 2
+ * bytes.
*
* Return: 0 on success, -errno otherwise.
*/
@@ -415,6 +421,11 @@ static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
op.addr.nbytes = addr_bytes;
op.addr.val = 0;
op.dummy.nbytes = dummy;
+ /*
+ * We don't want to read only one byte in DTR mode. So,
+ * read 2 and then discard the second byte.
+ */
+ op.data.nbytes = 2;
}
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v8 10/19] mtd: spi-nor: core: use dummy cycle and address width info from SFDP
From: Pratyush Yadav @ 2020-05-22 22:40 UTC (permalink / raw)
To: Tudor Ambarus, Miquel Raynal, Richard Weinberger,
Vignesh Raghavendra, Mark Brown, Nicolas Ferre, Alexandre Belloni,
Ludovic Desroches, Matthias Brugger, Michal Simek, linux-mtd,
linux-kernel, linux-spi, linux-arm-kernel, linux-mediatek
Cc: Mason Yang, Boris Brezillon, Sekhar Nori, Pratyush Yadav
In-Reply-To: <20200522224042.29970-1-p.yadav@ti.com>
The xSPI Profile 1.0 table specifies how many dummy cycles and address
bytes are needed for the Read Status Register command in octal DTR mode.
Use that information to send the correct Read SR command.
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
drivers/mtd/spi-nor/core.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 642e3c07acf9..2ad248140b6c 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -357,6 +357,8 @@ int spi_nor_write_disable(struct spi_nor *nor)
static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
{
int ret;
+ u8 addr_bytes = nor->params->rdsr_addr_nbytes;
+ u8 dummy = nor->params->rdsr_dummy;
if (nor->spimem) {
struct spi_mem_op op =
@@ -365,10 +367,21 @@ static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_DATA_IN(1, sr, 1));
+ if (spi_nor_protocol_is_dtr(nor->reg_proto)) {
+ op.addr.nbytes = addr_bytes;
+ op.addr.val = 0;
+ op.dummy.nbytes = dummy;
+ }
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
ret = spi_mem_exec_op(nor->spimem, &op);
} else {
- ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDSR,
- sr, 1);
+ if (spi_nor_protocol_is_dtr(nor->reg_proto))
+ ret = -ENOTSUPP;
+ else
+ ret = nor->controller_ops->read_reg(nor, SPINOR_OP_RDSR,
+ sr, 1);
}
if (ret)
@@ -388,6 +401,8 @@ static int spi_nor_read_sr(struct spi_nor *nor, u8 *sr)
static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
{
int ret;
+ u8 addr_bytes = nor->params->rdsr_addr_nbytes;
+ u8 dummy = nor->params->rdsr_dummy;
if (nor->spimem) {
struct spi_mem_op op =
@@ -396,6 +411,12 @@ static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
SPI_MEM_OP_NO_DUMMY,
SPI_MEM_OP_DATA_IN(1, fsr, 1));
+ if (spi_nor_protocol_is_dtr(nor->reg_proto)) {
+ op.addr.nbytes = addr_bytes;
+ op.addr.val = 0;
+ op.dummy.nbytes = dummy;
+ }
+
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
ret = spi_mem_exec_op(nor->spimem, &op);
--
2.26.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox