* Re: [PATCH v5 0/8] clocksource: Fix MIPS GIC and DW APB Timer for Baikal-T1 SoC support
From: Serge Semin @ 2020-05-22 15:41 UTC (permalink / raw)
To: Daniel Lezcano
Cc: Serge Semin, Thomas Gleixner, Thomas Bogendoerfer, Alexey Malahov,
Maxim Kaurkin, Pavel Parkhomenko, Ramil Zaripov,
Ekaterina Skachko, Vadim Vlasov, Alexey Kolotnikov, Paul Burton,
Ralf Baechle, Arnd Bergmann, Alessandro Zummo, Alexandre Belloni,
Rob Herring, linux-mips, linux-rtc, devicetree, linux-kernel
In-Reply-To: <211ab91d-6085-3073-1cbc-2300abade1b7@linaro.org>
On Fri, May 22, 2020 at 05:28:42PM +0200, Daniel Lezcano wrote:
> On 21/05/2020 22:48, Serge Semin wrote:
> > As for all Baikal-T1 SoC related patchsets, which need this, we replaced
> > the DW APB Timer legacy plain text-based dt-binding file with DT schema.
> > Similarly the MIPS GIC bindings file is also converted to DT schema seeing
> > it also defines the MIPS GIC Timer binding.
> >
> > Aside from MIPS-specific r4k timer Baikal-T1 chip also provides a
> > functionality of two another timers: embedded into the MIPS GIC timer and
> > three external DW timers available over APB bus. But we can't use them
> > before the corresponding drivers are properly fixed. First of all DW APB
> > Timer shouldn't be bound to a single CPU, since as being accessible over
> > APB they are external with respect to all possible CPUs. Secondly there
> > might be more than just two DW APB Timers in the system (Baikal-T1 has
> > three of them), so permit the driver to use one of them as a clocksource
> > and the rest - for clockevents. Thirdly it's possible to use MIPS GIC
> > timer as a clocksource so register it in the corresponding subsystem
> > (the patch has been found in the Paul Burton MIPS repo so I left the
> > original Signed-off-by attribute). Finally in the same way as r4k timer
> > the MIPS GIC timer should be used with care when CPUFREQ config is enabled
> > since in case of CM2 the timer counting depends on the CPU reference clock
> > frequency while the clocksource subsystem currently doesn't support the
> > timers with non-stable clock.
> >
> > This patchset is rebased and tested on the mainline Linux kernel 5.7-rc4:
> > base-commit: 0e698dfa2822 ("Linux 5.7-rc4")
> > tag: v5.7-rc4
>
> Applied patch 1,2,4,5,6,7,8
>
> Thanks!
Great! Thanks. Am I right to expect the series in: git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git
at the branch timers/core?
-Sergey
>
> -- Daniel
>
>
> --
> <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
>
> Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
> <http://twitter.com/#!/linaroorg> Twitter |
> <http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply
* Re: [PATCH V5 4/5] iio: adc: Update debug prints
From: Andy Shevchenko @ 2020-05-22 15:39 UTC (permalink / raw)
To: Jishnu Prakash
Cc: agross, Bjorn Andersson, devicetree, Linux Kernel Mailing List,
Matthias Kaehlcke, Linus Walleij, Jonathan Cameron, Amit Kucheria,
smohanad, kgunda, aghayal, Jonathan Cameron, Hartmut Knaack,
Lars-Peter Clausen, Peter Meerwald-Stadler, linux-arm-msm,
linux-iio, linux-arm-msm-owner
In-Reply-To: <1590157452-27179-5-git-send-email-jprakash@codeaurora.org>
On Fri, May 22, 2020 at 5:25 PM Jishnu Prakash <jprakash@codeaurora.org> wrote:
>
> Change pr_err/pr_debug statements to dev_err/dev_dbg for
> increased clarity.
>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
In the same way you should have patch with removal of ' < 0' parts.
> Signed-off-by: Jishnu Prakash <jprakash@codeaurora.org>
> ---
> drivers/iio/adc/qcom-spmi-adc5.c | 18 +++++++++---------
> 1 file changed, 9 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c
> index e1482fd..11eb97c 100644
> --- a/drivers/iio/adc/qcom-spmi-adc5.c
> +++ b/drivers/iio/adc/qcom-spmi-adc5.c
> @@ -249,11 +249,11 @@ static int adc5_read_voltage_data(struct adc5_chip *adc, u16 *data)
> *data = (rslt_msb << 8) | rslt_lsb;
>
> if (*data == ADC5_USR_DATA_CHECK) {
> - pr_err("Invalid data:0x%x\n", *data);
> + dev_err(adc->dev, "Invalid data:0x%x\n", *data);
> return -EINVAL;
> }
>
> - pr_debug("voltage raw code:0x%x\n", *data);
> + dev_dbg(adc->dev, "voltage raw code:0x%x\n", *data);
>
> return 0;
> }
> @@ -385,24 +385,24 @@ static int adc5_do_conversion(struct adc5_chip *adc,
>
> ret = adc5_configure(adc, prop);
> if (ret) {
> - pr_err("ADC configure failed with %d\n", ret);
> + dev_err(adc->dev, "ADC configure failed with %d\n", ret);
> goto unlock;
> }
>
> if (adc->poll_eoc) {
> ret = adc5_poll_wait_eoc(adc);
> if (ret) {
> - pr_err("EOC bit not set\n");
> + dev_err(adc->dev, "EOC bit not set\n");
> goto unlock;
> }
> } else {
> ret = wait_for_completion_timeout(&adc->complete,
> ADC5_CONV_TIMEOUT);
> if (!ret) {
> - pr_debug("Did not get completion timeout.\n");
> + dev_dbg(adc->dev, "Did not get completion timeout.\n");
> ret = adc5_poll_wait_eoc(adc);
> if (ret) {
> - pr_err("EOC bit not set\n");
> + dev_err(adc->dev, "EOC bit not set\n");
> goto unlock;
> }
> }
> @@ -724,7 +724,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
> channel_name = of_get_property(node,
> "label", NULL) ? : node->name;
> if (!channel_name) {
> - pr_err("Invalid channel name\n");
> + dev_err(dev, "Invalid channel name\n");
> return -EINVAL;
> }
> prop->datasheet_name = channel_name;
> @@ -767,7 +767,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
> return ret;
> }
>
> - pr_debug("dig_ver:minor:%d, major:%d\n", dig_version[0],
> + dev_dbg(dev, "dig_ver:minor:%d, major:%d\n", dig_version[0],
> dig_version[1]);
> /* Digital controller >= 5.3 have hw_settle_2 option */
> if ((dig_version[0] >= ADC5_HW_SETTLE_DIFF_MINOR &&
> @@ -971,7 +971,7 @@ static int adc5_probe(struct platform_device *pdev)
>
> ret = adc5_get_dt_data(adc, node);
> if (ret) {
> - pr_err("adc get dt data failed\n");
> + dev_err(dev, "adc get dt data failed\n");
> return ret;
> }
>
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH 09/12] dt-bindings: arm: fsl: Add msi-map device-tree binding for fsl-mc bus
From: Laurentiu Tudor @ 2020-05-22 15:38 UTC (permalink / raw)
To: Rob Herring, Robin Murphy
Cc: devicetree, Hanjun Guo, Catalin Marinas, PCI, Sudeep Holla,
Rafael J. Wysocki, Linux IOMMU, linux-acpi, Makarand Pawagi,
Marc Zyngier, Diana Craciun, Bjorn Helgaas, Will Deacon,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <CAL_JsqKVyqc9QZhGD7FeNLpJ=x3oLzmY0zADBa+6ZaE46dN39w@mail.gmail.com>
On 5/22/2020 5:02 PM, Rob Herring wrote:
> On Fri, May 22, 2020 at 3:42 AM Robin Murphy <robin.murphy@arm.com> wrote:
>>
>> On 2020-05-22 00:10, Rob Herring wrote:
>>> On Thu, May 21, 2020 at 7:00 AM Lorenzo Pieralisi
>>> <lorenzo.pieralisi@arm.com> wrote:
>>>>
>>>> From: Laurentiu Tudor <laurentiu.tudor@nxp.com>
>>>>
>>>> The existing bindings cannot be used to specify the relationship
>>>> between fsl-mc devices and GIC ITSes.
>>>>
>>>> Add a generic binding for mapping fsl-mc devices to GIC ITSes, using
>>>> msi-map property.
>>>>
>>>> Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
>>>> Cc: Rob Herring <robh+dt@kernel.org>
>>>> ---
>>>> .../devicetree/bindings/misc/fsl,qoriq-mc.txt | 30 +++++++++++++++++--
>>>> 1 file changed, 27 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
>>>> index 9134e9bcca56..b0813b2d0493 100644
>>>> --- a/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
>>>> +++ b/Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
>>>> @@ -18,9 +18,9 @@ same hardware "isolation context" and a 10-bit value called an ICID
>>>> the requester.
>>>>
>>>> The generic 'iommus' property is insufficient to describe the relationship
>>>> -between ICIDs and IOMMUs, so an iommu-map property is used to define
>>>> -the set of possible ICIDs under a root DPRC and how they map to
>>>> -an IOMMU.
>>>> +between ICIDs and IOMMUs, so the iommu-map and msi-map properties are used
>>>> +to define the set of possible ICIDs under a root DPRC and how they map to
>>>> +an IOMMU and a GIC ITS respectively.
>>>>
>>>> For generic IOMMU bindings, see
>>>> Documentation/devicetree/bindings/iommu/iommu.txt.
>>>> @@ -28,6 +28,9 @@ Documentation/devicetree/bindings/iommu/iommu.txt.
>>>> For arm-smmu binding, see:
>>>> Documentation/devicetree/bindings/iommu/arm,smmu.yaml.
>>>>
>>>> +For GICv3 and GIC ITS bindings, see:
>>>> +Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.yaml.
>>>> +
>>>> Required properties:
>>>>
>>>> - compatible
>>>> @@ -119,6 +122,15 @@ Optional properties:
>>>> associated with the listed IOMMU, with the iommu-specifier
>>>> (i - icid-base + iommu-base).
>>>>
>>>> +- msi-map: Maps an ICID to a GIC ITS and associated iommu-specifier
>>>> + data.
>>>> +
>>>> + The property is an arbitrary number of tuples of
>>>> + (icid-base,iommu,iommu-base,length).
>>>
>>> I'm confused because the example has GIC ITS phandle, not an IOMMU.
>>>
>>> What is an iommu-base?
>>
>> Right, I was already halfway through writing a reply to say that all the
>> copy-pasted "iommu" references here should be using the terminology from
>> the pci-msi.txt binding instead.
>>
>>>> +
>>>> + Any ICID in the interval [icid-base, icid-base + length) is
>>>> + associated with the listed GIC ITS, with the iommu-specifier
>>>> + (i - icid-base + iommu-base).
>>>> Example:
>>>>
>>>> smmu: iommu@5000000 {
>>>> @@ -128,6 +140,16 @@ Example:
>>>> ...
>>>> };
>>>>
>>>> + gic: interrupt-controller@6000000 {
>>>> + compatible = "arm,gic-v3";
>>>> + ...
>>>> + its: gic-its@6020000 {
>>>> + compatible = "arm,gic-v3-its";
>>>> + msi-controller;
>>>> + ...
>>>> + };
>>>> + };
>>>> +
>>>> fsl_mc: fsl-mc@80c000000 {
>>>> compatible = "fsl,qoriq-mc";
>>>> reg = <0x00000008 0x0c000000 0 0x40>, /* MC portal base */
>>>> @@ -135,6 +157,8 @@ Example:
>>>> msi-parent = <&its>;
>>
>> Side note: is it right to keep msi-parent here? It rather implies that
>> the MC itself has a 'native' Device ID rather than an ICID, which I
>> believe is not strictly true. Plus it's extra-confusing that it doesn't
>> specify an ID either way, since that makes it look like the legacy PCI
>> case that gets treated implicitly as an identity msi-map, which makes no
>> sense at all to combine with an actual msi-map.
>
> No, it doesn't make sense from a binding perspective.
>
>>
>>>> /* define map for ICIDs 23-64 */
>>>> iommu-map = <23 &smmu 23 41>;
>>>> + /* define msi map for ICIDs 23-64 */
>>>> + msi-map = <23 &its 23 41>;
>>>
>>> Seeing 23 twice is odd. The numbers to the right of 'its' should be an
>>> ITS number space.
>>
>> On about 99% of systems the values in the SMMU Stream ID and ITS Device
>> ID spaces are going to be the same. Nobody's going to bother carrying
>> *two* sets of sideband data across the interconnect if they don't have to ;)
>
> I'm referring to the 23 on the left and right, not between the msi and
> iommu. If the left and right are the same, then what are we remapping
> exactly?
>
I also insisted a lot on keeping things simple and don't do any kind of
translation but Robin convinced me that this is not such a great idea.
The truth is that the hardware can be configured in such a way that the
assumption that icid -> streamid mapping is 1:1 no longer holds.
It just happens that we currently setup the hw to have 1:1 mappings.
P.S. No idea why, but somehow I got dropped from the thread. Weird.
---
Best Regards, Laurentiu
^ permalink raw reply
* Re: [PATCH v8 3/3] PM / AVS: SVS: Introduce SVS engine
From: Matthias Brugger @ 2020-05-22 15:38 UTC (permalink / raw)
To: Roger Lu, Enric Balletbo Serra
Cc: Kevin Hilman, Rob Herring, Nicolas Boichat, Stephen Boyd,
Mark Rutland, Nishanth Menon, Angus Lin,
devicetree@vger.kernel.org, Linux PM list, linux-kernel,
Xiaoqing Liu, YT Lee, Fan Chen,
moderated list:ARM/Mediatek SoC support, HenryC Chen,
Charles Yang, Linux ARM
In-Reply-To: <1590140434.4392.22.camel@mtksdaap41>
On 22/05/2020 11:40, Roger Lu wrote:
>
> Hi Enric,
>
> On Tue, 2020-05-19 at 17:30 +0200, Enric Balletbo Serra wrote:
>> Hi Roger,
>>
>> Thank you for your patch. I have the feeling that this driver is
>> complex and difficult to follow and I am wondering if it wouldn't be
>> better if you can send a version that simply adds basic functionality
>> for now. Some comments below.
>
> Thanks for the advices. I'll submit SVS v9 with basic functionality
> patch + step by step functionalities' patches.
>
>>
>> Missatge de Roger Lu <roger.lu@mediatek.com> del dia dl., 18 de maig
>> 2020 a les 11:25:
>>>
>>> The SVS (Smart Voltage Scaling) engine is a piece
>>> of hardware which is used to calculate optimized
>>> voltage values of several power domains,
>>> e.g. CPU/GPU/CCI, according to chip process corner,
>>> temperatures, and other factors. Then DVFS driver
>>> could apply those optimized voltage values to reduce
>>> power consumption.
>>>
>>> Signed-off-by: Roger Lu <roger.lu@mediatek.com>
>>> ---
>>> drivers/power/avs/Kconfig | 10 +
>>> drivers/power/avs/Makefile | 1 +
>>> drivers/power/avs/mtk_svs.c | 2119 +++++++++++++++++++++++++++++++++
>>> include/linux/power/mtk_svs.h | 23 +
>>> 4 files changed, 2153 insertions(+)
>>> create mode 100644 drivers/power/avs/mtk_svs.c
>>> create mode 100644 include/linux/power/mtk_svs.h
>>>
>>> diff --git a/drivers/power/avs/Kconfig b/drivers/power/avs/Kconfig
>>> index cdb4237bfd02..67089ac6040e 100644
>>> --- a/drivers/power/avs/Kconfig
>>> +++ b/drivers/power/avs/Kconfig
>>> @@ -35,3 +35,13 @@ config ROCKCHIP_IODOMAIN
>>> Say y here to enable support io domains on Rockchip SoCs. It is
>>> necessary for the io domain setting of the SoC to match the
>>> voltage supplied by the regulators.
>>> +
>>> +config MTK_SVS
>>> + bool "MediaTek Smart Voltage Scaling(SVS)"
>>
>> Can't be this a module? Why? In such case, you should use tristate option
>
> Generally, MTK_SVS is needed in MTK SoC(mt81xx) products. So, we don't provide
> module option in config. If, somehow, SVS isn't needed, we suggest
> CONFIG_MTK_SVS=n to be set.
>
The question here is if it needs to be probed before we probe the modules. If
not, we should add a Kconfig option for MT81xx SoCs to select MTK_SVS.
>>
>>> + depends on POWER_AVS && MTK_EFUSE && NVMEM
>>> + help
>>> + The SVS engine is a piece of hardware which is used to calculate
>>> + optimized voltage values of several power domains, e.g.
>>> + CPU clusters/GPU/CCI, according to chip process corner, temperatures,
>>> + and other factors. Then DVFS driver could apply those optimized voltage
>>> + values to reduce power consumption.
>>> diff --git a/drivers/power/avs/Makefile b/drivers/power/avs/Makefile
>>> index 9007d05853e2..231adf078582 100644
>>> --- a/drivers/power/avs/Makefile
>>> +++ b/drivers/power/avs/Makefile
>>> @@ -2,3 +2,4 @@
>>> obj-$(CONFIG_POWER_AVS_OMAP) += smartreflex.o
>>> obj-$(CONFIG_QCOM_CPR) += qcom-cpr.o
>>> obj-$(CONFIG_ROCKCHIP_IODOMAIN) += rockchip-io-domain.o
>>> +obj-$(CONFIG_MTK_SVS) += mtk_svs.o
>>
>> Will this driver be SoC specific or the idea is to support different
>> SoCs? If the answer to the first question is yes, please name the file
>> with the SoC prefix (i.e mt8183_svs). However, If the answer to the
>> second question is yes, make sure you prefix common
>> functions/structs/defines with a generic prefix mtk_svs but use the
>> SoC prefix for the ones you expect will be different between SoC, i.e
>> mt8183_svs_. This helps the readability of the driver. Also, try to
>> avoid too generic names.
>
> MTK_SVS is designed for supporting different MTK SoCs.Therefore, the answer is second
> question and thanks for the heads-up.
>
>>
>>> diff --git a/drivers/power/avs/mtk_svs.c b/drivers/power/avs/mtk_svs.c
>>> new file mode 100644
>>> index 000000000000..a4083b3ef175
>>> --- /dev/null
>>> +++ b/drivers/power/avs/mtk_svs.c
>>> @@ -0,0 +1,2119 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>
>> I suspect you want this only GPLv2 compliant. Use GPL-2.0-only
>
> OK. I'll use GPL-2.0-only.Thanks.
>
>>
>>> +/*
>>> + * Copyright (C) 2020 MediaTek Inc.
>>> + */
>>> +
>>> +#define pr_fmt(fmt) "[mtk_svs] " fmt
>>
>> I don't see any reason to use pr_fmt in this driver. Use dev_*
>> functions instead and remove the above.
>
> Ok. I will remove it. Thanks.
>
>>
>>> +
>>> +#include <linux/bits.h>
>>> +#include <linux/clk.h>
>>> +#include <linux/completion.h>
>>> +#include <linux/init.h>
>>> +#include <linux/interrupt.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/kthread.h>
>>> +#include <linux/module.h>
>>> +#include <linux/mutex.h>
>>> +#include <linux/nvmem-consumer.h>
>>> +#include <linux/of_address.h>
>>> +#include <linux/of_irq.h>
>>> +#include <linux/of_platform.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/pm_domain.h>
>>> +#include <linux/pm_opp.h>
>>> +#include <linux/pm_qos.h>
>>> +#include <linux/pm_runtime.h>
>>> +#include <linux/power/mtk_svs.h>
>>> +#include <linux/proc_fs.h>
>>> +#include <linux/regulator/consumer.h>
>>> +#include <linux/reset.h>
>>> +#include <linux/seq_file.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/spinlock.h>
>>> +#include <linux/thermal.h>
>>> +#include <linux/uaccess.h>
>>> +
>>> +/* svs 1-line sw id */
>>> +#define SVS_CPU_LITTLE BIT(0)
>>> +#define SVS_CPU_BIG BIT(1)
>>> +#define SVS_CCI BIT(2)
>>> +#define SVS_GPU BIT(3)
>>> +
>>> +/* svs bank mode support */
>>> +#define SVSB_MODE_ALL_DISABLE (0)
>>
>> nit: SVS_BMODE_?
>
> Oh. If we add bank wording like SVS_Bxxx, it might cause some confusion when B combines
> with other words. So, I'll keep SVSB for SVS Bank representation.
> E.g: SVS_BDC_SIGNED_BIT might lead to be explained differently ("SVS bank + DC_SIGNED_BIT" or "SVS + BDC_SIGNED_BIT")
> - "SVS bank + DC_SIGNED_BIT" is what we want for naming SVS_BDC_SIGNED_BIT but it might be misunderstood.
>
>>
>>> +#define SVSB_MODE_INIT01 BIT(1)
>>> +#define SVSB_MODE_INIT02 BIT(2)
>>> +#define SVSB_MODE_MON BIT(3)
>>> +
>>> +/* svs bank init01 condition */
>>> +#define SVSB_INIT01_VOLT_IGNORE BIT(1)
>>> +#define SVSB_INIT01_VOLT_INC_ONLY BIT(2)
>>> +
>>> +/* svs bank common setting */
>>> +#define HIGH_TEMP_MAX (U32_MAX)
>>
>> nit: SVS_*
>
> ok. I will add SVS or SVSB when it refers to SVS BANK.
>
>>
>>> +#define RUNCONFIG_DEFAULT (0x80000000)
>>
>> Btw, there is any public datasheet where I can see those addresses and
>> registers and bit fields?
>
> Excuse us, there is no public datasheet. We can reply it on patchwork. Thanks.
>
>>
>>> +#define DC_SIGNED_BIT (0x8000)
>>> +#define INTEN_INIT0x (0x00005f01)
>>> +#define INTEN_MONVOPEN (0x00ff0000)
>>> +#define SVSEN_OFF (0x0)
>>> +#define SVSEN_MASK (0x7)
>>> +#define SVSEN_INIT01 (0x1)
>>> +#define SVSEN_INIT02 (0x5)
>>> +#define SVSEN_MON (0x2)
>>> +#define INTSTS_MONVOP (0x00ff0000)
>>> +#define INTSTS_COMPLETE (0x1)
>>> +#define INTSTS_CLEAN (0x00ffffff)
>>> +
>>> +#define proc_fops_rw(name) \
>>> + static int name ## _proc_open(struct inode *inode, \
>>> + struct file *file) \
>>> + { \
>>> + return single_open(file, name ## _proc_show, \
>>> + PDE_DATA(inode)); \
>>> + } \
>>> + static const struct proc_ops name ## _proc_fops = { \
>>> + .proc_open = name ## _proc_open, \
>>> + .proc_read = seq_read, \
>>> + .proc_lseek = seq_lseek, \
>>> + .proc_release = single_release, \
>>> + .proc_write = name ## _proc_write, \
>>> + }
>>> +
>>> +#define proc_fops_ro(name) \
>>> + static int name ## _proc_open(struct inode *inode, \
>>> + struct file *file) \
>>> + { \
>>> + return single_open(file, name ## _proc_show, \
>>> + PDE_DATA(inode)); \
>>> + } \
>>> + static const struct proc_ops name ## _proc_fops = { \
>>> + .proc_open = name ## _proc_open, \
>>> + .proc_read = seq_read, \
>>> + .proc_lseek = seq_lseek, \
>>> + .proc_release = single_release, \
>>> + }
>>> +
>>> +#define proc_entry(name) {__stringify(name), &name ## _proc_fops}
>>> +
>>
>> /proc is usually the old way of exporting files to userspace, so
>> unless you have a really good reason use sysfs instead, or even
>> better, if it is only for debug purposes use debugfs. Also, you should
>> document the entries in Documentation.
>
> Ok. I'll change it to debugfs and could you give us an example about entries in documentation?
> We can follow them. Thanks.
>
>>
>>> +static DEFINE_SPINLOCK(mtk_svs_lock);
>>> +struct mtk_svs;
>>> +
>>> +enum svsb_phase {
>>
>> nit: mtk_svs_bphase?
>
> ditto
>
>>
>>> + SVSB_PHASE_INIT01 = 0,
>>
>> nit: SVS_BPHASE_?
>
> ditto
>
>>
>>> + SVSB_PHASE_INIT02,
>>> + SVSB_PHASE_MON,
>>> + SVSB_PHASE_ERROR,
>>> +};
>>> +
>>> +enum reg_index {
>>
>> nit: svs_reg_index?
>
> OK. Thanks.
>
>>
>>> + TEMPMONCTL0 = 0,
>>> + TEMPMONCTL1,
>>> + TEMPMONCTL2,
>>> + TEMPMONINT,
>>> + TEMPMONINTSTS,
>>> + TEMPMONIDET0,
>>> + TEMPMONIDET1,
>>> + TEMPMONIDET2,
>>> + TEMPH2NTHRE,
>>> + TEMPHTHRE,
>>> + TEMPCTHRE,
>>> + TEMPOFFSETH,
>>> + TEMPOFFSETL,
>>> + TEMPMSRCTL0,
>>> + TEMPMSRCTL1,
>>> + TEMPAHBPOLL,
>>> + TEMPAHBTO,
>>> + TEMPADCPNP0,
>>> + TEMPADCPNP1,
>>> + TEMPADCPNP2,
>>> + TEMPADCMUX,
>>> + TEMPADCEXT,
>>> + TEMPADCEXT1,
>>> + TEMPADCEN,
>>> + TEMPPNPMUXADDR,
>>> + TEMPADCMUXADDR,
>>> + TEMPADCEXTADDR,
>>> + TEMPADCEXT1ADDR,
>>> + TEMPADCENADDR,
>>> + TEMPADCVALIDADDR,
>>> + TEMPADCVOLTADDR,
>>> + TEMPRDCTRL,
>>> + TEMPADCVALIDMASK,
>>> + TEMPADCVOLTAGESHIFT,
>>> + TEMPADCWRITECTRL,
>>> + TEMPMSR0,
>>> + TEMPMSR1,
>>> + TEMPMSR2,
>>> + TEMPADCHADDR,
>>> + TEMPIMMD0,
>>> + TEMPIMMD1,
>>> + TEMPIMMD2,
>>> + TEMPMONIDET3,
>>> + TEMPADCPNP3,
>>> + TEMPMSR3,
>>> + TEMPIMMD3,
>>> + TEMPPROTCTL,
>>> + TEMPPROTTA,
>>> + TEMPPROTTB,
>>> + TEMPPROTTC,
>>> + TEMPSPARE0,
>>> + TEMPSPARE1,
>>> + TEMPSPARE2,
>>> + TEMPSPARE3,
>>> + TEMPMSR0_1,
>>> + TEMPMSR1_1,
>>> + TEMPMSR2_1,
>>> + TEMPMSR3_1,
>>> + DESCHAR,
>>> + TEMPCHAR,
>>> + DETCHAR,
>>> + AGECHAR,
>>> + DCCONFIG,
>>> + AGECONFIG,
>>> + FREQPCT30,
>>> + FREQPCT74,
>>> + LIMITVALS,
>>> + VBOOT,
>>> + DETWINDOW,
>>> + CONFIG,
>>> + TSCALCS,
>>> + RUNCONFIG,
>>> + SVSEN,
>>> + INIT2VALS,
>>> + DCVALUES,
>>> + AGEVALUES,
>>> + VOP30,
>>> + VOP74,
>>> + TEMP,
>>> + INTSTS,
>>> + INTSTSRAW,
>>> + INTEN,
>>> + CHKINT,
>>> + CHKSHIFT,
>>> + STATUS,
>>> + VDESIGN30,
>>> + VDESIGN74,
>>> + DVT30,
>>> + DVT74,
>>> + AGECOUNT,
>>> + SMSTATE0,
>>> + SMSTATE1,
>>> + CTL0,
>>> + DESDETSEC,
>>> + TEMPAGESEC,
>>> + CTRLSPARE0,
>>> + CTRLSPARE1,
>>> + CTRLSPARE2,
>>> + CTRLSPARE3,
>>> + CORESEL,
>>> + THERMINTST,
>>> + INTST,
>>> + THSTAGE0ST,
>>> + THSTAGE1ST,
>>> + THSTAGE2ST,
>>> + THAHBST0,
>>> + THAHBST1,
>>> + SPARE0,
>>> + SPARE1,
>>> + SPARE2,
>>> + SPARE3,
>>> + THSLPEVEB,
>>> + reg_num,
>>> +};
>>> +
>>> +static const u32 svs_regs_v2[] = {
>>
>> Is this SoC specific or shared between SoCs?
>
> Shared between SoCs. Some SVS in MTK SoCs use v2 register map.
>
And which silicon uses v1 then? Is v2 a MediaTek internal naming you want to keep?
>>
>>> + [TEMPMONCTL0] = 0x000,
>>> + [TEMPMONCTL1] = 0x004,
>>> + [TEMPMONCTL2] = 0x008,
>>> + [TEMPMONINT] = 0x00c,
>>> + [TEMPMONINTSTS] = 0x010,
>>> + [TEMPMONIDET0] = 0x014,
>>> + [TEMPMONIDET1] = 0x018,
>>> + [TEMPMONIDET2] = 0x01c,
>>> + [TEMPH2NTHRE] = 0x024,
>>> + [TEMPHTHRE] = 0x028,
>>> + [TEMPCTHRE] = 0x02c,
>>> + [TEMPOFFSETH] = 0x030,
>>> + [TEMPOFFSETL] = 0x034,
>>> + [TEMPMSRCTL0] = 0x038,
>>> + [TEMPMSRCTL1] = 0x03c,
>>> + [TEMPAHBPOLL] = 0x040,
>>> + [TEMPAHBTO] = 0x044,
>>> + [TEMPADCPNP0] = 0x048,
>>> + [TEMPADCPNP1] = 0x04c,
>>> + [TEMPADCPNP2] = 0x050,
>>> + [TEMPADCMUX] = 0x054,
>>> + [TEMPADCEXT] = 0x058,
>>> + [TEMPADCEXT1] = 0x05c,
>>> + [TEMPADCEN] = 0x060,
>>> + [TEMPPNPMUXADDR] = 0x064,
>>> + [TEMPADCMUXADDR] = 0x068,
>>> + [TEMPADCEXTADDR] = 0x06c,
>>> + [TEMPADCEXT1ADDR] = 0x070,
>>> + [TEMPADCENADDR] = 0x074,
>>> + [TEMPADCVALIDADDR] = 0x078,
>>> + [TEMPADCVOLTADDR] = 0x07c,
>>> + [TEMPRDCTRL] = 0x080,
>>> + [TEMPADCVALIDMASK] = 0x084,
>>> + [TEMPADCVOLTAGESHIFT] = 0x088,
>>> + [TEMPADCWRITECTRL] = 0x08c,
>>> + [TEMPMSR0] = 0x090,
>>> + [TEMPMSR1] = 0x094,
>>> + [TEMPMSR2] = 0x098,
>>> + [TEMPADCHADDR] = 0x09c,
>>> + [TEMPIMMD0] = 0x0a0,
>>> + [TEMPIMMD1] = 0x0a4,
>>> + [TEMPIMMD2] = 0x0a8,
>>> + [TEMPMONIDET3] = 0x0b0,
>>> + [TEMPADCPNP3] = 0x0b4,
>>> + [TEMPMSR3] = 0x0b8,
>>> + [TEMPIMMD3] = 0x0bc,
>>> + [TEMPPROTCTL] = 0x0c0,
>>> + [TEMPPROTTA] = 0x0c4,
>>> + [TEMPPROTTB] = 0x0c8,
>>> + [TEMPPROTTC] = 0x0cc,
>>> + [TEMPSPARE0] = 0x0f0,
>>> + [TEMPSPARE1] = 0x0f4,
>>> + [TEMPSPARE2] = 0x0f8,
>>> + [TEMPSPARE3] = 0x0fc,
>>> + [TEMPMSR0_1] = 0x190,
>>> + [TEMPMSR1_1] = 0x194,
>>> + [TEMPMSR2_1] = 0x198,
>>> + [TEMPMSR3_1] = 0x1b8,
>>> + [DESCHAR] = 0xc00,
>>> + [TEMPCHAR] = 0xc04,
>>> + [DETCHAR] = 0xc08,
>>> + [AGECHAR] = 0xc0c,
>>> + [DCCONFIG] = 0xc10,
>>> + [AGECONFIG] = 0xc14,
>>> + [FREQPCT30] = 0xc18,
>>> + [FREQPCT74] = 0xc1c,
>>> + [LIMITVALS] = 0xc20,
>>> + [VBOOT] = 0xc24,
>>> + [DETWINDOW] = 0xc28,
>>> + [CONFIG] = 0xc2c,
>>> + [TSCALCS] = 0xc30,
>>> + [RUNCONFIG] = 0xc34,
>>> + [SVSEN] = 0xc38,
>>> + [INIT2VALS] = 0xc3c,
>>> + [DCVALUES] = 0xc40,
>>> + [AGEVALUES] = 0xc44,
>>> + [VOP30] = 0xc48,
>>> + [VOP74] = 0xc4c,
>>> + [TEMP] = 0xc50,
>>> + [INTSTS] = 0xc54,
>>> + [INTSTSRAW] = 0xc58,
>>> + [INTEN] = 0xc5c,
>>> + [CHKINT] = 0xc60,
>>> + [CHKSHIFT] = 0xc64,
>>> + [STATUS] = 0xc68,
>>> + [VDESIGN30] = 0xc6c,
>>> + [VDESIGN74] = 0xc70,
>>> + [DVT30] = 0xc74,
>>> + [DVT74] = 0xc78,
>>> + [AGECOUNT] = 0xc7c,
>>> + [SMSTATE0] = 0xc80,
>>> + [SMSTATE1] = 0xc84,
>>> + [CTL0] = 0xc88,
>>> + [DESDETSEC] = 0xce0,
>>> + [TEMPAGESEC] = 0xce4,
>>> + [CTRLSPARE0] = 0xcf0,
>>> + [CTRLSPARE1] = 0xcf4,
>>> + [CTRLSPARE2] = 0xcf8,
>>> + [CTRLSPARE3] = 0xcfc,
>>> + [CORESEL] = 0xf00,
>>> + [THERMINTST] = 0xf04,
>>> + [INTST] = 0xf08,
>>> + [THSTAGE0ST] = 0xf0c,
>>> + [THSTAGE1ST] = 0xf10,
>>> + [THSTAGE2ST] = 0xf14,
>>> + [THAHBST0] = 0xf18,
>>> + [THAHBST1] = 0xf1c,
>>> + [SPARE0] = 0xf20,
>>> + [SPARE1] = 0xf24,
>>> + [SPARE2] = 0xf28,
>>> + [SPARE3] = 0xf2c,
>>> + [THSLPEVEB] = 0xf30,
>>> +};
>>> +
>>> +struct thermal_parameter {
>>
>> In general, not only in this struct, would be good have some
>> documentation to have a better undestanding of the fields. That makes
>> the job of the reviewer a bit easier.
>
> Ok. Could you share a documentation example to us? We'll share the
> information as much as we can. Thanks a lot.
>
you should find that in all drivers, eg:
https://elixir.bootlin.com/linux/latest/source/drivers/soc/mediatek/mtk-scpsys.c#L111
Regards,
Matthias
^ permalink raw reply
* Re: [PATCH V5 3/5] iio: adc: Add support for PMIC7 ADC
From: Andy Shevchenko @ 2020-05-22 15:37 UTC (permalink / raw)
To: Jishnu Prakash
Cc: agross, Bjorn Andersson, devicetree, Linux Kernel Mailing List,
Matthias Kaehlcke, Linus Walleij, Jonathan Cameron, Amit Kucheria,
smohanad, kgunda, aghayal, Jonathan Cameron, Hartmut Knaack,
Lars-Peter Clausen, Peter Meerwald-Stadler, linux-arm-msm,
linux-iio, linux-arm-msm-owner
In-Reply-To: <1590157452-27179-4-git-send-email-jprakash@codeaurora.org>
On Fri, May 22, 2020 at 5:25 PM Jishnu Prakash <jprakash@codeaurora.org> wrote:
>
> The ADC architecture on PMIC7 is changed as compared to PMIC5. The
> major change from PMIC5 is that all SW communication to ADC goes through
> PMK8350, which communicates with other PMICs through PBS when the ADC
> on PMK8350 works in master mode. The SID register is used to identify the
> PMICs with which the PBS needs to communicate. Add support for the same.
Below should be in a separate patch, but it's a bikeshedding. So, I
left it to maintainers to decide.
Fine with me
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
...
> @@ -285,7 +304,7 @@ static int adc5_configure(struct adc5_chip *adc,
>
> /* Read registers 0x42 through 0x46 */
> ret = adc5_read(adc, ADC5_USR_DIG_PARAM, buf, sizeof(buf));
> - if (ret < 0)
> + if (ret)
> return ret;
>
> /* Digital param selection */
...
> @@ -331,7 +391,7 @@ static int adc5_do_conversion(struct adc5_chip *adc,
>
> if (adc->poll_eoc) {
> ret = adc5_poll_wait_eoc(adc);
> - if (ret < 0) {
> + if (ret) {
> pr_err("EOC bit not set\n");
> goto unlock;
> }
> @@ -341,7 +401,7 @@ static int adc5_do_conversion(struct adc5_chip *adc,
> if (!ret) {
> pr_debug("Did not get completion timeout.\n");
> ret = adc5_poll_wait_eoc(adc);
> - if (ret < 0) {
> + if (ret) {
> pr_err("EOC bit not set\n");
> goto unlock;
> }
...
> @@ -406,8 +519,38 @@ static int adc5_read_raw(struct iio_dev *indio_dev,
> default:
> return -EINVAL;
> }
> +}
>
> - return 0;
(this one looks like standalone change from above)
...
> @@ -570,7 +762,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc,
>
> ret = adc5_read(adc, ADC5_USR_REVISION1, dig_version,
> sizeof(dig_version));
> - if (ret < 0) {
> + if (ret) {
> dev_err(dev, "Invalid dig version read %d\n", ret);
> return ret;
> }
...
> + if (of_device_is_compatible(node, "qcom,spmi-adc7"))
> + indio_dev->info = &adc7_info;
> + else
> + indio_dev->info = &adc5_info;
Can we use driver_data?
...
> + if (adcmap7_die_temp[0].x > voltage) {
> + *result_mdec = DIE_TEMP_ADC7_SCALE_1;
> + return 0;
> + } else if (adcmap7_die_temp[i].x <= voltage) {
As per previous comment, redundant 'else' and please use value of i
directly here.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [v4,7/7] thermal: mediatek: use spinlock to protect PTPCORESEL
From: Daniel Lezcano @ 2020-05-22 15:36 UTC (permalink / raw)
To: Michael Kao, Matthias Brugger, Zhang Rui, Eduardo Valentin,
Rob Herring, Mark Rutland, hsinyi, linux-pm, srv_heupstream
Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <20200323121537.22697-8-michael.kao@mediatek.com>
On 23/03/2020 13:15, Michael Kao wrote:
> From: "michael.kao" <michael.kao@mediatek.com>
>
> The driver of thermal and svs will use the
> same register for the project which should select
> bank before reading sensor value.
Here there is a design problem AFAICT. The sensor should not be using
external locks.
> Signed-off-by: Michael Kao <michael.kao@mediatek.com>
> ---
> drivers/thermal/mtk_thermal.c | 9 ++++-----
> 1 file changed, 4 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c
> index 9eaca432920e..594ad4f0f8cd 100644
> --- a/drivers/thermal/mtk_thermal.c
> +++ b/drivers/thermal/mtk_thermal.c
> @@ -22,6 +22,7 @@
> #include <linux/thermal.h>
> #include <linux/reset.h>
> #include <linux/types.h>
> +#include <linux/power/mtk_svs.h>
>
> /* AUXADC Registers */
> #define AUXADC_CON1_SET_V 0x008
> @@ -262,7 +263,7 @@ struct mtk_thermal {
> struct clk *clk_peri_therm;
> struct clk *clk_auxadc;
> /* lock: for getting and putting banks */
> - struct mutex lock;
> + unsigned long flags;
>
> /* Calibration values */
> s32 adc_ge;
> @@ -561,7 +562,7 @@ static void mtk_thermal_get_bank(struct mtk_thermal_bank *bank)
> u32 val;
>
> if (mt->conf->need_switch_bank) {
> - mutex_lock(&mt->lock);
> + mt->flags = claim_mtk_svs_lock();
>
> val = readl(mt->thermal_base + PTPCORESEL);
> val &= ~0xf;
> @@ -581,7 +582,7 @@ static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank)
> struct mtk_thermal *mt = bank->mt;
>
> if (mt->conf->need_switch_bank)
> - mutex_unlock(&mt->lock);
> + release_mtk_svs_lock(mt->flags);
> }
>
> /**
> @@ -938,8 +939,6 @@ static int mtk_thermal_probe(struct platform_device *pdev)
> if (ret)
> return ret;
>
> - mutex_init(&mt->lock);
> -
> mt->dev = &pdev->dev;
>
> auxadc = of_parse_phandle(np, "mediatek,auxadc", 0);
>
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply
* Re: [PATCH v5 06/11] net: ethernet: mtk-star-emac: new driver
From: Bartosz Golaszewski @ 2020-05-22 15:35 UTC (permalink / raw)
To: Matthias Brugger
Cc: Bartosz Golaszewski, Rob Herring, David S . Miller, John Crispin,
Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann, Fabien Parent,
Heiner Kallweit, Edwin Peer, linux-devicetree, LKML, netdev,
arm-soc, linux-mediatek, Stephane Le Provost, Pedro Tsai,
Andrew Perepech
In-Reply-To: <5627e304-3463-9229-fa86-d7d31cad7a61@gmail.com>
pt., 22 maj 2020 o 17:06 Matthias Brugger <matthias.bgg@gmail.com> napisał(a):
>
>
>
> 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?
>
It's used on MT81**, MT83** and MT85**. What's wrong with the
description anyway?
Bart
^ permalink raw reply
* Re: [v4,5/7] thermal: mediatek: mt8183: fix bank number settings
From: Daniel Lezcano @ 2020-05-22 15:33 UTC (permalink / raw)
To: Michael Kao, Matthias Brugger, Zhang Rui, Eduardo Valentin,
Rob Herring, Mark Rutland, hsinyi, linux-pm, srv_heupstream
Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <20200323121537.22697-6-michael.kao@mediatek.com>
On 23/03/2020 13:15, Michael Kao wrote:
> MT8183_NUM_ZONES should be set to 1
> because MT8183 doesn't have multiple banks.
Apparently this is a hot fix. Can you confirm and explain what is the
procedure to hit the bug?
I'll pick it for the next -rc if possible
> Fixes: a4ffe6b52d27 ("thermal: mediatek: add support for MT8183")
> Signed-off-by: Michael Kao <michael.kao@mediatek.com>
> Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org>
> ---
> drivers/thermal/mtk_thermal.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c
> index 76e30603d4d5..6b7ef1993d7e 100644
> --- a/drivers/thermal/mtk_thermal.c
> +++ b/drivers/thermal/mtk_thermal.c
> @@ -211,6 +211,9 @@ enum {
> /* The total number of temperature sensors in the MT8183 */
> #define MT8183_NUM_SENSORS 6
>
> +/* The number of banks in the MT8183 */
> +#define MT8183_NUM_ZONES 1
> +
> /* The number of sensing points per bank */
> #define MT8183_NUM_SENSORS_PER_ZONE 6
>
> @@ -497,7 +500,7 @@ static const struct mtk_thermal_data mt7622_thermal_data = {
> */
> static const struct mtk_thermal_data mt8183_thermal_data = {
> .auxadc_channel = MT8183_TEMP_AUXADC_CHANNEL,
> - .num_banks = MT8183_NUM_SENSORS_PER_ZONE,
> + .num_banks = MT8183_NUM_ZONES,
> .num_sensors = MT8183_NUM_SENSORS,
> .vts_index = mt8183_vts_index,
> .cali_val = MT8183_CALIBRATION,
>
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply
* Re: [v4,6/7] thermal: mediatek: add another get_temp ops for thermal sensors
From: Daniel Lezcano @ 2020-05-22 15:32 UTC (permalink / raw)
To: Michael Kao, Matthias Brugger, Zhang Rui, Eduardo Valentin,
Rob Herring, Mark Rutland, hsinyi, linux-pm, srv_heupstream
Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <20200323121537.22697-7-michael.kao@mediatek.com>
On 23/03/2020 13:15, Michael Kao wrote:
> Provide thermal zone to read thermal sensor
> in the SoC. We can read all the thermal sensors
> value in the SoC by the node /sys/class/thermal/
>
> In mtk_thermal_bank_temperature, return -EAGAIN instead of -EACCESS
> on the first read of sensor that often are bogus values.
> This can avoid following warning on boot:
>
> thermal thermal_zone6: failed to read out thermal zone (-13)
What the source problem of the sensor returning bogus values?
> Signed-off-by: Michael Kao <michael.kao@mediatek.com>
> Signed-off-by: Hsin-Yi Wang <hsinyi@chromium.org>
> ---
> drivers/thermal/mtk_thermal.c | 74 +++++++++++++++++++++++++++++++----
> 1 file changed, 67 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c
> index 6b7ef1993d7e..9eaca432920e 100644
> --- a/drivers/thermal/mtk_thermal.c
> +++ b/drivers/thermal/mtk_thermal.c
> @@ -225,6 +225,11 @@ enum {
>
> struct mtk_thermal;
>
> +struct mtk_thermal_zone {
> + struct mtk_thermal *mt;
> + int id;
> +};
> +
> struct thermal_bank_cfg {
> unsigned int num_sensors;
> const int *sensors;
> @@ -607,7 +612,7 @@ static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
> * not immediately shut down.
> */
> if (temp > 200000)
> - temp = 0;
> + temp = -EAGAIN;
>
> if (temp > max)
> max = temp;
> @@ -618,7 +623,8 @@ static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank)
>
> static int mtk_read_temp(void *data, int *temperature)
> {
> - struct mtk_thermal *mt = data;
> + struct mtk_thermal_zone *tz = data;
> + struct mtk_thermal *mt = tz->mt;
> int i;
> int tempmax = INT_MIN;
>
> @@ -637,10 +643,44 @@ static int mtk_read_temp(void *data, int *temperature)
> return 0;
> }
>
> +static int mtk_read_sensor_temp(void *data, int *temperature)
> +{
> + struct mtk_thermal_zone *tz = data;
> + struct mtk_thermal *mt = tz->mt;
> + const struct mtk_thermal_data *conf = mt->conf;
> + int id = tz->id - 1;
> + int temp = INT_MIN;
> + u32 raw;
> +
> + if (id < 0)
> + return -EACCES;
> +
> + raw = readl(mt->thermal_base + conf->msr[id]);
> +
> + temp = raw_to_mcelsius(mt, id, raw);
> +
> + /*
> + * The first read of a sensor often contains very high bogus
> + * temperature value. Filter these out so that the system does
> + * not immediately shut down.
> + */
> +
> + if (temp > 200000)
> + return -EAGAIN;
> +
> + *temperature = temp;
> +
> + return 0;
> +}
> +
> static const struct thermal_zone_of_device_ops mtk_thermal_ops = {
> .get_temp = mtk_read_temp,
> };
>
> +static const struct thermal_zone_of_device_ops mtk_thermal_sensor_ops = {
> + .get_temp = mtk_read_sensor_temp,
> +};
> +
> static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num,
> u32 apmixed_phys_base, u32 auxadc_phys_base,
> int ctrl_id)
> @@ -873,6 +913,7 @@ static int mtk_thermal_probe(struct platform_device *pdev)
> struct resource *res;
> u64 auxadc_phys_base, apmixed_phys_base;
> struct thermal_zone_device *tzdev;
> + struct mtk_thermal_zone *tz;
>
> mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL);
> if (!mt)
> @@ -954,11 +995,30 @@ static int mtk_thermal_probe(struct platform_device *pdev)
>
> platform_set_drvdata(pdev, mt);
>
> - tzdev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, mt,
> - &mtk_thermal_ops);
> - if (IS_ERR(tzdev)) {
> - ret = PTR_ERR(tzdev);
> - goto err_disable_clk_peri_therm;
> + for (i = 0; i < mt->conf->num_sensors + 1; i++) {
> + tz = kmalloc(sizeof(*tz), GFP_KERNEL);
> + if (!tz)
> + return -ENOMEM;
> +
> + tz->mt = mt;
> + tz->id = i;
> +
> + tzdev = devm_thermal_zone_of_sensor_register(&pdev->dev, i,
> + tz, (i == 0) ?
> + &mtk_thermal_ops : &mtk_thermal_sensor_ops);
> +
> + if (IS_ERR(tzdev)) {
> + if (PTR_ERR(tzdev) == -ENODEV) {
> + dev_warn(&pdev->dev,
> + "sensor %d not registered in thermal zone in dt\n",
> + i);
> + continue;
> + }
> + if (PTR_ERR(tzdev) == -EACCES) {
> + ret = PTR_ERR(tzdev);
> + goto err_disable_clk_peri_therm;
> + }
> + }
> }
>
> return 0;
>
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply
* Re: [PATCH V4 3/5] iio: adc: Add support for PMIC7 ADC
From: Andy Shevchenko @ 2020-05-22 15:31 UTC (permalink / raw)
To: Jishnu Prakash
Cc: agross, Bjorn Andersson, devicetree, Linux Kernel Mailing List,
Matthias Kaehlcke, Linus Walleij, Jonathan Cameron, Amit Kucheria,
smohanad, kgunda, aghayal, Jonathan Cameron, Hartmut Knaack,
Lars-Peter Clausen, Peter Meerwald-Stadler, linux-arm-msm,
linux-iio, linux-arm-msm-owner
In-Reply-To: <50ad0f74-22cc-c74f-afa4-df654e29bebb@codeaurora.org>
On Fri, May 22, 2020 at 2:58 PM Jishnu Prakash <jprakash@codeaurora.org> wrote:
> On 5/13/2020 3:18 PM, Andy Shevchenko wrote:
> > On Wed, May 13, 2020 at 12:23 PM Jishnu Prakash <jprakash@codeaurora.org> wrote:
...
> >> +static int qcom_vadc7_scale_hw_calib_die_temp(
> >> + const struct vadc_prescale_ratio *prescale,
> >> + const struct adc5_data *data,
> >> + u16 adc_code, int *result_mdec)
> >> +{
> >> +
> >> + int voltage, vtemp0, temp, i = ARRAY_SIZE(adcmap7_die_temp) - 1;
> > How assignment to i is useful?
>
>
> I'm using it in adcmap7_die_temp[i] below, to keep it within the
> character limit per line. I think it's more readable that way.
>
> >
> >> + voltage = qcom_vadc_scale_code_voltage_factor(adc_code,
> >> + prescale, data, 1);
> >> +
> >> + if (adcmap7_die_temp[0].x > voltage) {
> >> + *result_mdec = DIE_TEMP_ADC7_SCALE_1;
> >> + return 0;
> >> + } else if (adcmap7_die_temp[i].x <= voltage) {
I see now i in use, please, replace with direct meaning.
> > Redundant 'else'.
> The expression is different, it's adcmap7_die_temp[i] here, not
> adcmap7_die_temp[0].
if (a) {
...
return;
} else if (b) {
...
}
'else' is redundant due to 'return'. Same when it's 'goto'.
> >> + *result_mdec = DIE_TEMP_ADC7_MAX;
> >> + return 0;
> >> + }
> >> +
> >> + for (i = 0; i < ARRAY_SIZE(adcmap7_die_temp); i++)
> >> + if (adcmap7_die_temp[i].x > voltage)
> >> + break;
> >> +
> >> + vtemp0 = adcmap7_die_temp[i - 1].x;
> >> + voltage = voltage - vtemp0;
> >> + temp = div64_s64(voltage * DIE_TEMP_ADC7_SCALE_FACTOR,
> >> + adcmap7_die_temp[i - 1].y);
> >> + temp += DIE_TEMP_ADC7_SCALE_1 + (DIE_TEMP_ADC7_SCALE_2 * (i - 1));
> >> + *result_mdec = temp;
> >> +
> >> + return 0;
> >> +}
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply
* Re: [PATCH v5 0/8] clocksource: Fix MIPS GIC and DW APB Timer for Baikal-T1 SoC support
From: Daniel Lezcano @ 2020-05-22 15:28 UTC (permalink / raw)
To: Serge Semin, Thomas Gleixner, Thomas Bogendoerfer
Cc: Serge Semin, Alexey Malahov, Maxim Kaurkin, Pavel Parkhomenko,
Ramil Zaripov, Ekaterina Skachko, Vadim Vlasov, Alexey Kolotnikov,
Paul Burton, Ralf Baechle, Arnd Bergmann, Alessandro Zummo,
Alexandre Belloni, Rob Herring, linux-mips, linux-rtc, devicetree,
linux-kernel
In-Reply-To: <20200521204818.25436-1-Sergey.Semin@baikalelectronics.ru>
On 21/05/2020 22:48, Serge Semin wrote:
> As for all Baikal-T1 SoC related patchsets, which need this, we replaced
> the DW APB Timer legacy plain text-based dt-binding file with DT schema.
> Similarly the MIPS GIC bindings file is also converted to DT schema seeing
> it also defines the MIPS GIC Timer binding.
>
> Aside from MIPS-specific r4k timer Baikal-T1 chip also provides a
> functionality of two another timers: embedded into the MIPS GIC timer and
> three external DW timers available over APB bus. But we can't use them
> before the corresponding drivers are properly fixed. First of all DW APB
> Timer shouldn't be bound to a single CPU, since as being accessible over
> APB they are external with respect to all possible CPUs. Secondly there
> might be more than just two DW APB Timers in the system (Baikal-T1 has
> three of them), so permit the driver to use one of them as a clocksource
> and the rest - for clockevents. Thirdly it's possible to use MIPS GIC
> timer as a clocksource so register it in the corresponding subsystem
> (the patch has been found in the Paul Burton MIPS repo so I left the
> original Signed-off-by attribute). Finally in the same way as r4k timer
> the MIPS GIC timer should be used with care when CPUFREQ config is enabled
> since in case of CM2 the timer counting depends on the CPU reference clock
> frequency while the clocksource subsystem currently doesn't support the
> timers with non-stable clock.
>
> This patchset is rebased and tested on the mainline Linux kernel 5.7-rc4:
> base-commit: 0e698dfa2822 ("Linux 5.7-rc4")
> tag: v5.7-rc4
Applied patch 1,2,4,5,6,7,8
Thanks!
-- Daniel
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply
* Re: [PATCH v5 06/11] net: ethernet: mtk-star-emac: new driver
From: Bartosz Golaszewski @ 2020-05-22 15:26 UTC (permalink / raw)
To: Matthias Brugger
Cc: Bartosz Golaszewski, Rob Herring, David S . Miller, John Crispin,
Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann, Fabien Parent,
Heiner Kallweit, Edwin Peer, linux-devicetree, LKML, netdev,
arm-soc, linux-mediatek, Stephane Le Provost, Pedro Tsai,
Andrew Perepech
In-Reply-To: <5627e304-3463-9229-fa86-d7d31cad7a61@gmail.com>
pt., 22 maj 2020 o 17:06 Matthias Brugger <matthias.bgg@gmail.com> napisał(a):
>
> 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?
>
MT81** and MT85** are very closely related. This IP is currently used
on MT85**, MT81** and MT83**. It may be used in new designs in the
future too.
Bart
^ permalink raw reply
* Re: [PATCH v4 01/16] spi: dw: Add Tx/Rx finish wait methods to the MID DMA
From: Mark Brown @ 2020-05-22 15:22 UTC (permalink / raw)
To: Serge Semin
Cc: Andy Shevchenko, Serge Semin, Linus Walleij, Vinod Koul,
Feng Tang, Grant Likely, Alan Cox, Georgy Vlasov, Ramil Zaripov,
Alexey Malahov, Thomas Bogendoerfer, Paul Burton, Ralf Baechle,
Arnd Bergmann, Rob Herring, linux-mips, devicetree,
Wan Ahmad Zainie, Thomas Gleixner, Jarkko Nikula, wuxu.wu,
Clement Leger, Linus Walleij, linux-spi, linux-kernel
In-Reply-To: <20200522144542.brhibh453wid2d6v@mobilestation>
[-- Attachment #1: Type: text/plain, Size: 911 bytes --]
On Fri, May 22, 2020 at 05:45:42PM +0300, Serge Semin wrote:
> On Fri, May 22, 2020 at 05:36:39PM +0300, Andy Shevchenko wrote:
> > My point is: let's warn and see if anybody comes with a bug report. We will
> > solve an issue when it appears.
> In my environment the stack trace happened (strictly speaking it has been a
> BUG() invoked due to the sleep_range() called within the tasklet) when SPI bus
> had been enabled to work with !8MHz! clock. It's quite normal bus speed.
> So we'll get the bug report pretty soon.)
Right, that definitely needs to be fixed then - 8MHz is indeed a totally
normal clock rate for SPI so people will hit it. I guess if there's a
noticable performance hit to defer to thread then we could implement
both and look at how long the delay is going to be to decide which to
use, that's annoyingly complicated though so if the overhead is small
enough we could just not bother.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v10 5/5] MIPS: Loongson64: Switch to generic PCI driver
From: Lorenzo Pieralisi @ 2020-05-22 15:22 UTC (permalink / raw)
To: Thomas Bogendoerfer
Cc: Jiaxun Yang, linux-pci, Bjorn Helgaas, Rob Herring, Huacai Chen,
Paul Burton, devicetree, linux-kernel, linux-mips
In-Reply-To: <20200522142550.GB15261@alpha.franken.de>
On Fri, May 22, 2020 at 04:25:50PM +0200, Thomas Bogendoerfer wrote:
> On Thu, May 14, 2020 at 09:16:41PM +0800, Jiaxun Yang wrote:
> > We can now enable generic PCI driver in Kconfig, and remove legacy
> > PCI driver code.
> >
> > Radeon vbios quirk is moved to the platform folder to fit the
> > new structure.
> >
> > Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > --
> > v9: Fix licenses tag
> > ---
> > arch/mips/Kconfig | 1 +
> > arch/mips/loongson64/Makefile | 2 +-
> > arch/mips/loongson64/vbios_quirk.c | 29 ++++++++
> > arch/mips/pci/Makefile | 1 -
> > arch/mips/pci/fixup-loongson3.c | 71 ------------------
> > arch/mips/pci/ops-loongson3.c | 116 -----------------------------
> > 6 files changed, 31 insertions(+), 189 deletions(-)
> > create mode 100644 arch/mips/loongson64/vbios_quirk.c
> > delete mode 100644 arch/mips/pci/fixup-loongson3.c
> > delete mode 100644 arch/mips/pci/ops-loongson3.c
>
> Acked-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
This patch (so the series) does not apply to v5.7-rc1 which is our
baseline. I reiterate the point, isn't it better to take the whole
series through the MIPS tree ? Failing that, the series has to
be rebased (or split differently so that it can be taken through
different trees), just let me know.
Thanks,
Lorenzo
^ permalink raw reply
* Re: [PATCH 1/4] clk: sunxi-ng: add support for the Allwinner A100 CCU
From: Maxime Ripard @ 2020-05-22 15:14 UTC (permalink / raw)
To: Frank Lee
Cc: wens, robh+dt, mturquette, sboyd, linus.walleij, p.zabel,
huangshuosheng, tiny.windzz, linux-arm-kernel, devicetree,
linux-kernel, linux-clk, linux-gpio
In-Reply-To: <20200522030743.10204-2-frank@allwinnertech.com>
[-- Attachment #1: Type: text/plain, Size: 60865 bytes --]
Hi,
On Fri, May 22, 2020 at 11:07:40AM +0800, Frank Lee wrote:
> Add support for a100 in the sunxi-ng CCU framework.
>
> Signed-off-by: Frank Lee <frank@allwinnertech.com>
> ---
> drivers/clk/sunxi-ng/Kconfig | 10 +
> drivers/clk/sunxi-ng/Makefile | 2 +
> drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c | 206 +++
> drivers/clk/sunxi-ng/ccu-sun50i-a100-r.h | 14 +
> drivers/clk/sunxi-ng/ccu-sun50i-a100.c | 1255 +++++++++++++++++
> drivers/clk/sunxi-ng/ccu-sun50i-a100.h | 14 +
> include/dt-bindings/clock/sun50i-a100-ccu.h | 141 ++
> include/dt-bindings/clock/sun50i-a100-r-ccu.h | 25 +
> include/dt-bindings/reset/sun50i-a100-ccu.h | 68 +
> include/dt-bindings/reset/sun50i-a100-r-ccu.h | 18 +
> 10 files changed, 1753 insertions(+)
> create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
> create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-a100-r.h
> create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-a100.c
> create mode 100644 drivers/clk/sunxi-ng/ccu-sun50i-a100.h
> create mode 100644 include/dt-bindings/clock/sun50i-a100-ccu.h
> create mode 100644 include/dt-bindings/clock/sun50i-a100-r-ccu.h
> create mode 100644 include/dt-bindings/reset/sun50i-a100-ccu.h
> create mode 100644 include/dt-bindings/reset/sun50i-a100-r-ccu.h
>
> diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
> index cdf333003c30..ce5f5847d5d3 100644
> --- a/drivers/clk/sunxi-ng/Kconfig
> +++ b/drivers/clk/sunxi-ng/Kconfig
> @@ -17,6 +17,16 @@ config SUN50I_A64_CCU
> default ARM64 && ARCH_SUNXI
> depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
>
> +config SUN50I_A100_CCU
> + bool "Support for the Allwinner A100 CCU"
> + default ARM64 && ARCH_SUNXI
> + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
> +
> +config SUN50I_A100_R_CCU
> + bool "Support for the Allwinner A100 PRCM CCU"
> + default ARM64 && ARCH_SUNXI
> + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
> +
> config SUN50I_H6_CCU
> bool "Support for the Allwinner H6 CCU"
> default ARM64 && ARCH_SUNXI
> diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
> index 4c7bee883f2f..3eb5cff40eac 100644
> --- a/drivers/clk/sunxi-ng/Makefile
> +++ b/drivers/clk/sunxi-ng/Makefile
> @@ -23,6 +23,8 @@ obj-y += ccu_mp.o
> # SoC support
> obj-$(CONFIG_SUNIV_F1C100S_CCU) += ccu-suniv-f1c100s.o
> obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i-a64.o
> +obj-$(CONFIG_SUN50I_A100_CCU) += ccu-sun50i-a100.o
> +obj-$(CONFIG_SUN50I_A100_R_CCU) += ccu-sun50i-a100-r.o
> obj-$(CONFIG_SUN50I_H6_CCU) += ccu-sun50i-h6.o
> obj-$(CONFIG_SUN50I_H6_R_CCU) += ccu-sun50i-h6-r.o
> obj-$(CONFIG_SUN4I_A10_CCU) += ccu-sun4i-a10.o
> diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
> new file mode 100644
> index 000000000000..31875269ef90
> --- /dev/null
> +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c
> @@ -0,0 +1,206 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2020 Frank Lee <frank@allwinner.com>
The domain doesn't match the one used to send that patch, is that intentional?
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +
> +#include "ccu_common.h"
> +#include "ccu_reset.h"
> +
> +#include "ccu_div.h"
> +#include "ccu_gate.h"
> +#include "ccu_mp.h"
> +#include "ccu_nm.h"
> +
> +#include "ccu-sun50i-a100-r.h"
> +
> +static const char * const cpus_r_apb2_parents[] = { "dcxo24M", "osc32k",
> + "iosc", "pll-periph0" };
> +static const struct ccu_mux_var_prediv cpus_r_apb2_predivs[] = {
> + { .index = 3, .shift = 0, .width = 5 },
> +};
> +
> +static struct ccu_div cpus_clk = {
> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO),
> +
> + .mux = {
> + .shift = 24,
> + .width = 2,
> +
> + .var_predivs = cpus_r_apb2_predivs,
> + .n_var_predivs = ARRAY_SIZE(cpus_r_apb2_predivs),
> + },
> +
> + .common = {
> + .reg = 0x000,
> + .features = CCU_FEATURE_VARIABLE_PREDIV,
> + .hw.init = CLK_HW_INIT_PARENTS("cpus",
> + cpus_r_apb2_parents,
> + &ccu_div_ops,
> + 0),
> + },
> +};
> +
> +static CLK_FIXED_FACTOR_HW(r_ahb_clk, "r-ahb", &cpus_clk.common.hw, 1, 1, 0);
> +
> +static struct ccu_div r_apb1_clk = {
> + .div = _SUNXI_CCU_DIV(0, 2),
> +
> + .common = {
> + .reg = 0x00c,
> + .hw.init = CLK_HW_INIT("r-apb1",
> + "r-ahb",
> + &ccu_div_ops,
> + 0),
> + },
> +};
> +
> +static struct ccu_div r_apb2_clk = {
> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO),
> +
> + .mux = {
> + .shift = 24,
> + .width = 2,
> +
> + .var_predivs = cpus_r_apb2_predivs,
> + .n_var_predivs = ARRAY_SIZE(cpus_r_apb2_predivs),
> + },
> +
> + .common = {
> + .reg = 0x010,
> + .features = CCU_FEATURE_VARIABLE_PREDIV,
> + .hw.init = CLK_HW_INIT_PARENTS("r-apb2",
> + cpus_r_apb2_parents,
> + &ccu_div_ops,
> + 0),
> + },
> +};
> +
> +static SUNXI_CCU_GATE(r_apb1_timer_clk, "r-apb1-timer", "r-apb1",
> + 0x11c, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(r_apb1_twd_clk, "r-apb1-twd", "r-apb1",
> + 0x12c, BIT(0), 0);
> +
> +static const char * const r_apb1_pwm_clk_parents[] = { "dcxo24M", "osc32k",
> + "iosc" };
> +static SUNXI_CCU_MUX(r_apb1_pwm_clk, "r-apb1-pwm", r_apb1_pwm_clk_parents,
> + 0x130, 24, 2, 0);
> +
> +static SUNXI_CCU_GATE(r_apb1_bus_pwm_clk, "r-apb1-bus-pwm", "r-apb1",
> + 0x13c, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(r_apb1_ppu_clk, "r-apb1-ppu", "r-apb1",
> + 0x17c, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(r_apb2_uart_clk, "r-apb2-uart", "r-apb2",
> + 0x18c, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(r_apb2_i2c0_clk, "r-apb2-i2c0", "r-apb2",
> + 0x19c, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(r_apb2_i2c1_clk, "r-apb2-i2c1", "r-apb2",
> + 0x19c, BIT(1), 0);
You should be using SUNXI_CCU_GATE_DATA here
> +static const char * const r_apb1_ir_rx_parents[] = { "osc32k", "dcxo24M" };
> +static SUNXI_CCU_MP_WITH_MUX_GATE(r_apb1_ir_rx_clk, "r-apb1-ir-rx",
> + r_apb1_ir_rx_parents, 0x1c0,
> + 0, 5, /* M */
> + 8, 2, /* P */
> + 24, 1, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_GATE(r_apb1_bus_ir_rx_clk, "r-apb1-bus-ir-rx", "r-apb1",
> + 0x1cc, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(r_ahb_bus_rtc_clk, "r-ahb-rtc", "r-ahb",
> + 0x20c, BIT(0), 0);
> +
> +static struct ccu_common *sun50i_a100_r_ccu_clks[] = {
> + &cpus_clk.common,
> + &r_apb1_clk.common,
> + &r_apb2_clk.common,
> + &r_apb1_timer_clk.common,
> + &r_apb1_twd_clk.common,
> + &r_apb1_pwm_clk.common,
> + &r_apb1_bus_pwm_clk.common,
> + &r_apb1_ppu_clk.common,
> + &r_apb2_uart_clk.common,
> + &r_apb2_i2c0_clk.common,
> + &r_apb2_i2c1_clk.common,
> + &r_apb1_ir_rx_clk.common,
> + &r_apb1_bus_ir_rx_clk.common,
> + &r_ahb_bus_rtc_clk.common,
> +};
> +
> +static struct clk_hw_onecell_data sun50i_a100_r_hw_clks = {
> + .hws = {
> + [CLK_CPUS] = &cpus_clk.common.hw,
> + [CLK_R_AHB] = &r_ahb_clk.hw,
Having some consistency here would be great, CLK_R_CPUS would be best I guess.
> + [CLK_R_APB1] = &r_apb1_clk.common.hw,
> + [CLK_R_APB2] = &r_apb2_clk.common.hw,
> + [CLK_R_APB1_TIMER] = &r_apb1_timer_clk.common.hw,
> + [CLK_R_APB1_TWD] = &r_apb1_twd_clk.common.hw,
> + [CLK_R_APB1_PWM] = &r_apb1_pwm_clk.common.hw,
> + [CLK_R_APB1_BUS_PWM] = &r_apb1_bus_pwm_clk.common.hw,
> + [CLK_R_APB1_PPU] = &r_apb1_ppu_clk.common.hw,
> + [CLK_R_APB2_UART] = &r_apb2_uart_clk.common.hw,
> + [CLK_R_APB2_I2C0] = &r_apb2_i2c0_clk.common.hw,
> + [CLK_R_APB2_I2C1] = &r_apb2_i2c1_clk.common.hw,
> + [CLK_R_APB1_IR] = &r_apb1_ir_rx_clk.common.hw,
> + [CLK_R_APB1_BUS_IR] = &r_apb1_bus_ir_rx_clk.common.hw,
> + [CLK_R_AHB_BUS_RTC] = &r_ahb_bus_rtc_clk.common.hw,
> + },
> + .num = CLK_NUMBER,
> +};
> +
> +static struct ccu_reset_map sun50i_a100_r_ccu_resets[] = {
> + [RST_R_APB1_TIMER] = { 0x11c, BIT(16) },
> + [RST_R_APB1_BUS_PWM] = { 0x13c, BIT(16) },
> + [RST_R_APB1_PPU] = { 0x17c, BIT(16) },
> + [RST_R_APB2_UART] = { 0x18c, BIT(16) },
> + [RST_R_APB2_I2C0] = { 0x19c, BIT(16) },
> + [RST_R_APB2_I2C1] = { 0x19c, BIT(17) },
> + [RST_R_APB1_BUS_IR] = { 0x1cc, BIT(16) },
> + [RST_R_AHB_BUS_RTC] = { 0x20c, BIT(16) },
> +};
> +
> +static const struct sunxi_ccu_desc sun50i_a100_r_ccu_desc = {
> + .ccu_clks = sun50i_a100_r_ccu_clks,
> + .num_ccu_clks = ARRAY_SIZE(sun50i_a100_r_ccu_clks),
> +
> + .hw_clks = &sun50i_a100_r_hw_clks,
> +
> + .resets = sun50i_a100_r_ccu_resets,
> + .num_resets = ARRAY_SIZE(sun50i_a100_r_ccu_resets),
> +};
> +
> +static int sun50i_a100_r_ccu_probe(struct platform_device *pdev)
> +{
> + void __iomem *reg;
> +
> + reg = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(reg))
> + return PTR_ERR(reg);
> +
> + return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a100_r_ccu_desc);
> +}
> +
> +static const struct of_device_id sun50i_a100_r_ccu_ids[] = {
> + { .compatible = "allwinner,sun50i-a100-r-ccu" },
> + { }
> +};
You're going to need a DT binding here too.
> +static struct platform_driver sun50i_a100_r_ccu_driver = {
> + .probe = sun50i_a100_r_ccu_probe,
> + .driver = {
> + .name = "sun50i-a100-r-ccu",
> + .of_match_table = sun50i_a100_r_ccu_ids,
> + },
> +};
> +module_platform_driver(sun50i_a100_r_ccu_driver);
> diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.h b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.h
> new file mode 100644
> index 000000000000..c26a08b924db
> --- /dev/null
> +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.h
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2020 Frank Lee <frank@allwinner.com>
> + */
> +
> +#ifndef _CCU_SUN50IW10_R_H
> +#define _CCU_SUN50IW10_R_H
> +
> +#include <dt-bindings/clock/sun50i-a100-r-ccu.h>
> +#include <dt-bindings/reset/sun50i-a100-r-ccu.h>
> +
> +#define CLK_NUMBER (CLK_R_AHB_BUS_RTC + 1)
> +
> +#endif /* _CCU_SUN50IW10_R_H */
> diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c
> new file mode 100644
> index 000000000000..f9a0a7754eed
> --- /dev/null
> +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c
> @@ -0,0 +1,1255 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2020 Frank Lee <frank@allwinner.com>
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +
> +#include "ccu_common.h"
> +#include "ccu_reset.h"
> +
> +#include "ccu_div.h"
> +#include "ccu_gate.h"
> +#include "ccu_mp.h"
> +#include "ccu_mult.h"
> +#include "ccu_nk.h"
> +#include "ccu_nkm.h"
> +#include "ccu_nkmp.h"
> +#include "ccu_nm.h"
> +
> +#include "ccu-sun50i-a100.h"
> +
> +/*
> + * The CPU PLL is actually NP clock, with P being /1, /2 or /4. However
> + * P should only be used for output frequencies lower than 288 MHz.
> + *
> + * For now we can just model it as a multiplier clock, and force P to /1.
> + *
> + * The M factor is present in the register's description, but not in the
> + * frequency formula, and it's documented as "M is only used for backdoor
> + * testing", so it's not modelled and then force to 0.
> + */
> +#define SUN50I_A100_PLL_CPUX_REG 0x000
> +static struct ccu_mult pll_cpux_clk = {
> + .enable = BIT(27),
> + .lock = BIT(28),
> + .mult = _SUNXI_CCU_MULT_MIN(8, 8, 12),
> + .common = {
> + .reg = 0x000,
> + .hw.init = CLK_HW_INIT("pll-cpux", "dcxo24M",
> + &ccu_mult_ops,
> + CLK_SET_RATE_UNGATE),
> + },
> +};
> +
> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
> +#define SUN50I_A100_PLL_DDR0_REG 0x010
> +static struct ccu_nkmp pll_ddr0_clk = {
> + .enable = BIT(27),
> + .lock = BIT(28),
> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12),
> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */
> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */
> + .common = {
> + .reg = 0x010,
> + .hw.init = CLK_HW_INIT("pll-ddr0", "dcxo24M",
> + &ccu_nkmp_ops,
> + CLK_SET_RATE_UNGATE |
> + CLK_IS_CRITICAL),
> + },
> +};
> +
> +#define SUN50I_A100_PLL_PERIPH0_REG 0x020
> +static struct ccu_nkmp pll_periph0_clk = {
> + .enable = BIT(27),
> + .lock = BIT(28),
> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12),
> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */
> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */
> + .fixed_post_div = 2,
> + .common = {
> + .reg = 0x020,
> + .features = CCU_FEATURE_FIXED_POSTDIV,
> + .hw.init = CLK_HW_INIT("pll-periph0", "dcxo24M",
> + &ccu_nkmp_ops,
> + CLK_SET_RATE_UNGATE),
> + },
> +};
> +
> +#define SUN50I_A100_PLL_PERIPH1_REG 0x028
> +static struct ccu_nkmp pll_periph1_clk = {
> + .enable = BIT(27),
> + .lock = BIT(28),
> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12),
> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */
> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */
> + .fixed_post_div = 2,
> + .common = {
> + .reg = 0x028,
> + .features = CCU_FEATURE_FIXED_POSTDIV,
> + .hw.init = CLK_HW_INIT("pll-periph1", "dcxo24M",
> + &ccu_nkmp_ops,
> + CLK_SET_RATE_UNGATE),
> + },
> +};
> +#define SUN50I_A100_PLL_PERIPH1_PATTERN0_REG 0x128
> +
> +#define SUN50I_A100_PLL_GPU_REG 0x030
> +static struct ccu_nkmp pll_gpu_clk = {
> + .enable = BIT(27),
> + .lock = BIT(28),
> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12),
> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */
> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */
> + .common = {
> + .reg = 0x030,
> + .hw.init = CLK_HW_INIT("pll-gpu", "dcxo24M",
> + &ccu_nkmp_ops,
> + CLK_SET_RATE_UNGATE),
> + },
> +};
> +
> +/*
> + * For Video PLLs, the output divider is described as "used for testing"
> + * in the user manual. So it's not modelled and forced to 0.
> + */
> +#define SUN50I_A100_PLL_VIDEO0_REG 0x040
> +static struct ccu_nm pll_video0_clk = {
> + .enable = BIT(27),
> + .lock = BIT(28),
> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12),
> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */
> + .fixed_post_div = 4,
> + .common = {
> + .reg = 0x040,
> + .features = CCU_FEATURE_FIXED_POSTDIV,
> + .hw.init = CLK_HW_INIT("pll-video0", "dcxo24M",
> + &ccu_nm_ops,
> + CLK_SET_RATE_UNGATE),
> + },
> +};
> +
> +#define SUN50I_A100_PLL_VIDEO1_REG 0x048
> +static struct ccu_nm pll_video1_clk = {
> + .enable = BIT(27),
> + .lock = BIT(28),
> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12),
> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */
> + .fixed_post_div = 4,
> + .common = {
> + .reg = 0x048,
> + .features = CCU_FEATURE_FIXED_POSTDIV,
> + .hw.init = CLK_HW_INIT("pll-video1", "dcxo24M",
> + &ccu_nm_ops,
> + CLK_SET_RATE_UNGATE),
> + },
> +};
> +
> +#define SUN50I_A100_PLL_VIDEO2_REG 0x050
> +static struct ccu_nm pll_video2_clk = {
> + .enable = BIT(27),
> + .lock = BIT(28),
> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12),
> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */
> + .fixed_post_div = 4,
> + .common = {
> + .reg = 0x050,
> + .features = CCU_FEATURE_FIXED_POSTDIV,
> + .hw.init = CLK_HW_INIT("pll-video2", "dcxo24M",
> + &ccu_nm_ops,
> + CLK_SET_RATE_UNGATE),
> + },
> +};
> +
> +#define SUN50I_A100_PLL_VE_REG 0x058
> +static struct ccu_nkmp pll_ve_clk = {
> + .enable = BIT(27),
> + .lock = BIT(28),
> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12),
> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */
> + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */
> + .common = {
> + .reg = 0x058,
> + .hw.init = CLK_HW_INIT("pll-ve", "dcxo24M",
> + &ccu_nkmp_ops,
> + CLK_SET_RATE_UNGATE),
> + },
> +};
> +
> +/*
> + * The COM PLL has m0 dividers in addition to the usual N, M
> + * factors. Since we only need 1 frequencies from this PLL: 45.1584 MHz,
> + * ignore it for now.
> + */
> +#define SUN50I_A100_PLL_COM_REG 0x060
> +static struct ccu_sdm_setting pll_com_sdm_table[] = {
> + { .rate = 451584000, .pattern = 0xc0014396, .m = 2, .n = 37 },
> +};
> +
> +static struct ccu_nm pll_com_clk = {
> + .enable = BIT(27),
> + .lock = BIT(28),
> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12),
> + .m = _SUNXI_CCU_DIV(0, 1),
> + .sdm = _SUNXI_CCU_SDM(pll_com_sdm_table, BIT(24),
> + 0x160, BIT(31)),
> + .common = {
> + .reg = 0x060,
> + .features = CCU_FEATURE_SIGMA_DELTA_MOD,
> + .hw.init = CLK_HW_INIT("pll-com", "dcxo24M",
> + &ccu_nm_ops,
> + CLK_SET_RATE_UNGATE),
> + },
> +};
> +
> +#define SUN50I_A100_PLL_VIDEO3_REG 0x068
> +static struct ccu_nm pll_video3_clk = {
> + .enable = BIT(27),
> + .lock = BIT(28),
> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12),
> + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */
> + .fixed_post_div = 4,
> + .common = {
> + .reg = 0x068,
> + .features = CCU_FEATURE_FIXED_POSTDIV,
> + .hw.init = CLK_HW_INIT("pll-video3", "dcxo24M",
> + &ccu_nm_ops,
> + CLK_SET_RATE_UNGATE),
> + },
> +};
> +
> +/*
> + * The Audio PLL has m0, m1 dividers in addition to the usual N, M
> + * factors. Since we only need 4 frequencies from this PLL: 22.5792 MHz,
> + * 24.576 MHz, 90.3168MHz and 98.304MHz ignore them for now.
> + * Enforce the default for them, which is m0 = 1, m1 = 0.
> + */
> +#define SUN50I_A100_PLL_AUDIO_REG 0x078
> +static struct ccu_sdm_setting pll_audio_sdm_table[] = {
> + { .rate = 45158400, .pattern = 0xc001bcd3, .m = 18, .n = 33 },
> + { .rate = 49152000, .pattern = 0xc001eb85, .m = 20, .n = 40 },
> + { .rate = 180633600, .pattern = 0xc001288d, .m = 3, .n = 22 },
> + { .rate = 196608000, .pattern = 0xc001eb85, .m = 5, .n = 40 },
> +};
> +
> +static struct ccu_nm pll_audio_clk = {
> + .enable = BIT(27),
> + .lock = BIT(28),
> + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12),
> + .m = _SUNXI_CCU_DIV(16, 6),
> + .fixed_post_div = 2,
> + .sdm = _SUNXI_CCU_SDM(pll_audio_sdm_table, BIT(24),
> + 0x178, BIT(31)),
> + .common = {
> + .reg = 0x078,
> + .features = CCU_FEATURE_FIXED_POSTDIV |
> + CCU_FEATURE_SIGMA_DELTA_MOD,
> + .hw.init = CLK_HW_INIT("pll-audio", "dcxo24M",
> + &ccu_nm_ops,
> + CLK_SET_RATE_UNGATE),
> + },
> +};
> +
> +static const char * const cpux_parents[] = { "dcxo24M", "osc32k",
> + "iosc", "pll-cpux",
> + "pll-periph0" };
> +static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents,
> + 0x500, 24, 3, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
> +static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x500, 0, 2, 0);
> +static SUNXI_CCU_M(cpux_apb_clk, "cpux-apb", "cpux", 0x500, 8, 2, 0);
> +
> +static const char * const psi_ahb1_ahb2_parents[] = { "dcxo24M", "osc32k",
> + "iosc", "pll-periph0",
> + "pll-periph0-2x" };
> +static SUNXI_CCU_MP_WITH_MUX(psi_ahb1_ahb2_clk, "psi-ahb1-ahb2",
> + psi_ahb1_ahb2_parents,
> + 0x510,
> + 0, 2, /* M */
> + 8, 2, /* P */
> + 24, 3, /* mux */
> + 0);
> +
> +static const char * const ahb3_apb1_apb2_parents[] = { "dcxo24M", "osc32k",
> + "psi-ahb1-ahb2",
> + "pll-periph0",
> + "pll-periph0-2x" };
> +static SUNXI_CCU_MP_WITH_MUX(ahb3_clk, "ahb3", ahb3_apb1_apb2_parents, 0x51c,
> + 0, 2, /* M */
> + 8, 2, /* P */
> + 24, 3, /* mux */
> + 0);
> +
> +static SUNXI_CCU_MP_WITH_MUX(apb1_clk, "apb1", ahb3_apb1_apb2_parents, 0x520,
> + 0, 2, /* M */
> + 8, 2, /* P */
> + 24, 3, /* mux */
> + 0);
> +
> +static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", ahb3_apb1_apb2_parents, 0x524,
> + 0, 2, /* M */
> + 8, 2, /* P */
> + 24, 3, /* mux */
> + 0);
> +
> +static const char * const mbus_parents[] = { "dcxo24M", "pll-ddr0",
> + "pll-periph0",
> + "pll-periph0-2x" };
> +static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, 0x540,
> + 0, 3, /* M */
> + 24, 2, /* mux */
> + BIT(31), /* gate */
> + CLK_IS_CRITICAL);
> +
> +static const char * const de_parents[] = { "pll-com", "pll-periph0-2x" };
> +static SUNXI_CCU_M_WITH_MUX_GATE(de_clk, "de0", de_parents, 0x600,
> + 0, 4, /* M */
> + 24, 1, /* mux */
> + BIT(31), /* gate */
> + CLK_SET_RATE_PARENT);
> +
> +static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "psi-ahb1-ahb2",
> + 0x60c, BIT(0), 0);
> +
> +static const char * const g2d_parents[] = { "pll-com", "pll-periph0-2x",
> + "pll-video0-2x", "pll-video1-2x",
> + "pll-video2-2x"};
> +static SUNXI_CCU_M_WITH_MUX_GATE(g2d_clk, "g2d",
> + g2d_parents,
> + 0x630,
> + 0, 4, /* M */
> + 24, 3, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_GATE(bus_g2d_clk, "bus-g2d", "psi-ahb1-ahb2",
> + 0x63c, BIT(0), 0);
> +
> +static const char * const gpu_parents[] = { "pll-gpu" };
> +static SUNXI_CCU_M_WITH_MUX_GATE(gpu_clk, "gpu", gpu_parents, 0x670,
> + 0, 2, /* M */
> + 24, 1, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "psi-ahb1-ahb2",
> + 0x67c, BIT(0), 0);
> +
> +static const char * const ce_parents[] = { "dcxo24M", "pll-periph0-2x" };
> +static SUNXI_CCU_MP_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680,
> + 0, 4, /* M */
> + 8, 2, /* N */
> + 24, 1, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_GATE(bus_ce_clk, "bus-ce", "psi-ahb1-ahb2",
> + 0x68c, BIT(0), 0);
> +
> +static const char * const ve_parents[] = { "pll-ve" };
> +static SUNXI_CCU_M_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690,
> + 0, 3, /* M */
> + 24, 1, /* mux */
> + BIT(31), /* gate */
> + CLK_SET_RATE_PARENT);
> +
> +static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "psi-ahb1-ahb2",
> + 0x69c, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "psi-ahb1-ahb2",
> + 0x70c, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "psi-ahb1-ahb2",
> + 0x71c, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "psi-ahb1-ahb2",
> + 0x72c, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "psi-ahb1-ahb2",
> + 0x73c, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(avs_clk, "avs", "dcxo24M", 0x740, BIT(31), 0);
> +
> +static SUNXI_CCU_GATE(bus_dbg_clk, "bus-dbg", "psi-ahb1-ahb2",
> + 0x78c, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(bus_psi_clk, "bus-psi", "psi-ahb1-ahb2",
> + 0x79c, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(bus_pwm_clk, "bus-pwm", "apb1", 0x7ac, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(bus_iommu_clk, "bus-iommu", "apb1", 0x7bc, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(mbus_dma_clk, "mbus-dma", "mbus",
> + 0x804, BIT(0), 0);
> +static SUNXI_CCU_GATE(mbus_ve_clk, "mbus-ve", "mbus",
> + 0x804, BIT(1), 0);
> +static SUNXI_CCU_GATE(mbus_ce_clk, "mbus-ce", "mbus",
> + 0x804, BIT(2), 0);
> +static SUNXI_CCU_GATE(mbus_nand_clk, "mbus-nand", "mbus",
> + 0x804, BIT(5), 0);
> +static SUNXI_CCU_GATE(mbus_csi_clk, "mbus-csi", "mbus",
> + 0x804, BIT(8), 0);
> +static SUNXI_CCU_GATE(mbus_isp_clk, "mbus-isp", "mbus",
> + 0x804, BIT(9), 0);
> +static SUNXI_CCU_GATE(mbus_g2d_clk, "mbus-g2d", "mbus",
> + 0x804, BIT(10), 0);
> +
> +static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "psi-ahb1-ahb2",
> + 0x80c, BIT(0), CLK_IS_CRITICAL);
> +
> +static const char * const nand_spi_parents[] = { "dcxo24M",
> + "pll-periph0",
> + "pll-periph1",
> + "pll-periph0-2x",
> + "pll-periph1-2x" };
> +static SUNXI_CCU_MP_WITH_MUX_GATE(nand0_clk, "nand0", nand_spi_parents, 0x810,
> + 0, 4, /* M */
> + 8, 2, /* N */
> + 24, 3, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_MP_WITH_MUX_GATE(nand1_clk, "nand1", nand_spi_parents, 0x814,
> + 0, 4, /* M */
> + 8, 2, /* N */
> + 24, 3, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb3", 0x82c, BIT(0), 0);
> +
> +/* don't use postdiv for bsp kernel */
> +static const char * const mmc_parents[] = { "dcxo24M", "pll-periph0-2x",
> + "pll-periph1-2x" };
> +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc_parents, 0x830,
> + 0, 4, /* M */
> + 8, 2, /* N */
> + 24, 2, /* mux */
> + BIT(31), /* gate */
> + CLK_SET_RATE_NO_REPARENT);
> +
> +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc_parents, 0x834,
> + 0, 4, /* M */
> + 8, 2, /* N */
> + 24, 2, /* mux */
> + BIT(31), /* gate */
> + CLK_SET_RATE_NO_REPARENT);
> +
> +static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc_parents, 0x838,
> + 0, 4, /* M */
> + 8, 2, /* N */
> + 24, 2, /* mux */
> + BIT(31), /* gate */
> + CLK_SET_RATE_NO_REPARENT);
> +
> +static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb3", 0x84c, BIT(0), 0);
> +static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb3", 0x84c, BIT(1), 0);
> +static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb3", 0x84c, BIT(2), 0);
> +
> +static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", 0x90c, BIT(0), 0);
> +static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", 0x90c, BIT(1), 0);
> +static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", 0x90c, BIT(2), 0);
> +static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", 0x90c, BIT(3), 0);
> +static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2", 0x90c, BIT(4), 0);
> +
> +static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", 0x91c, BIT(0), 0);
> +static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", 0x91c, BIT(1), 0);
> +static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", 0x91c, BIT(2), 0);
> +static SUNXI_CCU_GATE(bus_i2c3_clk, "bus-i2c3", "apb2", 0x91c, BIT(3), 0);
> +
> +static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", nand_spi_parents, 0x940,
> + 0, 4, /* M */
> + 8, 2, /* N */
> + 24, 3, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", nand_spi_parents, 0x944,
> + 0, 4, /* M */
> + 8, 2, /* N */
> + 24, 3, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_MP_WITH_MUX_GATE(spi2_clk, "spi2", nand_spi_parents, 0x948,
> + 0, 4, /* M */
> + 8, 2, /* N */
> + 24, 3, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb3", 0x96c, BIT(0), 0);
> +static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb3", 0x96c, BIT(1), 0);
> +static SUNXI_CCU_GATE(bus_spi2_clk, "bus-spi2", "ahb3", 0x96c, BIT(2), 0);
> +
> +static SUNXI_CCU_GATE(emac_25m_clk, "emac-25m", "ahb3", 0x970,
> + BIT(31) | BIT(30), 0);
> +
> +static SUNXI_CCU_GATE(bus_emac_clk, "bus-emac", "ahb3", 0x97c, BIT(0), 0);
> +
> +static const char * const ir_parents[] = { "osc32k", "iosc",
> + "pll-periph0", "pll-periph1" };
> +static SUNXI_CCU_MP_WITH_MUX_GATE(ir_rx_clk, "ir-rx", ir_parents, 0x990,
> + 0, 4, /* M */
> + 8, 2, /* N */
> + 24, 3, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_GATE(bus_ir_rx_clk, "bus-ir-rx", "ahb3", 0x99c, BIT(0), 0);
> +
> +static SUNXI_CCU_MP_WITH_MUX_GATE(ir_tx_clk, "ir-tx", ir_parents, 0x9c0,
> + 0, 4, /* M */
> + 8, 2, /* N */
> + 24, 3, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_GATE(bus_ir_tx_clk, "bus-ir-tx", "apb1", 0x9cc, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(bus_gpadc_clk, "bus-gpadc", "apb1", 0x9ec, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(bus_ths_clk, "bus-ths", "apb1", 0x9fc, BIT(0), 0);
> +
> +static const char * const audio_parents[] = { "pll-audio", "pll-com-audio" };
> +static struct ccu_div i2s0_clk = {
> + .enable = BIT(31),
> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO),
> + .mux = _SUNXI_CCU_MUX(24, 2),
> + .common = {
> + .reg = 0xa10,
> + .hw.init = CLK_HW_INIT_PARENTS("i2s0",
> + audio_parents,
> + &ccu_div_ops,
> + CLK_SET_RATE_PARENT),
> + },
> +};
> +
> +static struct ccu_div i2s1_clk = {
> + .enable = BIT(31),
> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO),
> + .mux = _SUNXI_CCU_MUX(24, 2),
> + .common = {
> + .reg = 0xa14,
> + .hw.init = CLK_HW_INIT_PARENTS("i2s1",
> + audio_parents,
> + &ccu_div_ops,
> + CLK_SET_RATE_PARENT),
> + },
> +};
> +
> +static struct ccu_div i2s2_clk = {
> + .enable = BIT(31),
> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO),
> + .mux = _SUNXI_CCU_MUX(24, 2),
> + .common = {
> + .reg = 0xa18,
> + .hw.init = CLK_HW_INIT_PARENTS("i2s2",
> + audio_parents,
> + &ccu_div_ops,
> + CLK_SET_RATE_PARENT),
> + },
> +};
> +
> +static struct ccu_div i2s3_clk = {
> + .enable = BIT(31),
> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO),
> + .mux = _SUNXI_CCU_MUX(24, 2),
> + .common = {
> + .reg = 0xa1c,
> + .hw.init = CLK_HW_INIT_PARENTS("i2s3",
> + audio_parents,
> + &ccu_div_ops,
> + CLK_SET_RATE_PARENT),
> + },
> +};
> +
> +static SUNXI_CCU_GATE(bus_i2s0_clk, "bus-i2s0", "apb1", 0xa20, BIT(0), 0);
> +static SUNXI_CCU_GATE(bus_i2s1_clk, "bus-i2s1", "apb1", 0xa20, BIT(1), 0);
> +static SUNXI_CCU_GATE(bus_i2s2_clk, "bus-i2s2", "apb1", 0xa20, BIT(2), 0);
> +static SUNXI_CCU_GATE(bus_i2s3_clk, "bus-i2s3", "apb1", 0xa20, BIT(3), 0);
> +
> +static struct ccu_div spdif_clk = {
> + .enable = BIT(31),
> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO),
> + .mux = _SUNXI_CCU_MUX(24, 2),
> + .common = {
> + .reg = 0xa24,
> + .hw.init = CLK_HW_INIT_PARENTS("spdif",
> + audio_parents,
> + &ccu_div_ops,
> + 0),
> + },
> +};
> +
> +static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1", 0xa2c, BIT(0), 0);
> +
> +static struct ccu_div dmic_clk = {
> + .enable = BIT(31),
> + .div = _SUNXI_CCU_DIV_FLAGS(8, 2, CLK_DIVIDER_POWER_OF_TWO),
> + .mux = _SUNXI_CCU_MUX(24, 2),
> + .common = {
> + .reg = 0xa40,
> + .hw.init = CLK_HW_INIT_PARENTS("dmic",
> + audio_parents,
> + &ccu_div_ops,
> + 0),
> + },
> +};
> +
> +static SUNXI_CCU_GATE(bus_dmic_clk, "bus-dmic", "apb1", 0xa4c, BIT(0), 0);
> +
> +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_dac_clk, "audio-codec-dac",
> + audio_parents, 0xa50,
> + 0, 4, /* M */
> + 24, 2, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_adc_clk, "audio-codec-adc",
> + audio_parents, 0xa54,
> + 0, 4, /* M */
> + 24, 2, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_M_WITH_MUX_GATE(audio_codec_4x_clk, "audio-codec-4x",
> + audio_parents, 0xa58,
> + 0, 4, /* M */
> + 24, 2, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_GATE(bus_audio_codec_clk, "bus-audio-codec", "apb1", 0xa5c,
> + BIT(0), 0);
> +
> +/*
> + * There are OHCI 12M clock source selection bits for 2 USB 2.0 ports.
> + * We will force them to 0 (12M divided from 48M).
> + */
> +#define SUN50I_A100_USB0_CLK_REG 0xa70
> +#define SUN50I_A100_USB1_CLK_REG 0xa74
> +
> +static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc12M", 0xa70, BIT(31), 0);
> +static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "dcxo24M", 0xa70, BIT(29), 0);
> +
> +static SUNXI_CCU_GATE(usb_ohci1_clk, "usb-ohci1", "osc12M", 0xa74, BIT(31), 0);
> +static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "dcxo24M", 0xa74, BIT(29), 0);
> +
> +static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb3", 0xa8c, BIT(0), 0);
> +static SUNXI_CCU_GATE(bus_ohci1_clk, "bus-ohci1", "ahb3", 0xa8c, BIT(1), 0);
> +static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb3", 0xa8c, BIT(4), 0);
> +static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb3", 0xa8c, BIT(5), 0);
> +static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb3", 0xa8c, BIT(8), 0);
> +
> +static SUNXI_CCU_GATE(bus_lradc_clk, "bus-lradc", "ahb3", 0xa9c, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(bus_dpss_top0_clk, "bus-dpss-top0", "ahb3",
> + 0xabc, BIT(0), 0);
> +
> +static SUNXI_CCU_GATE(bus_dpss_top1_clk, "bus-dpss-top1", "ahb3",
> + 0xacc, BIT(0), 0);
> +
> +static const char * const mipi_dsi_parents[] = { "dcxo24M", "pll-periph0-2x",
> + "pll-periph0" };
> +static SUNXI_CCU_M_WITH_MUX_GATE(mipi_dsi_clk, "mipi-dsi",
> + mipi_dsi_parents,
> + 0xb24,
> + 0, 4, /* M */
> + 24, 2, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_GATE(bus_mipi_dsi_clk, "bus-mipi-dsi", "ahb3",
> + 0xb4c, BIT(0), 0);
> +
> +static const char * const tcon_lcd_parents[] = { "pll-video0-4x",
> + "pll-video1-4x",
> + "pll-video2-4x",
> + "pll-video3-4x",
> + "pll-periph0-2x" };
> +static SUNXI_CCU_MP_WITH_MUX_GATE(tcon_lcd_clk, "tcon-lcd0",
> + tcon_lcd_parents, 0xb60,
> + 0, 4, /* M */
> + 8, 2, /* N */
> + 24, 3, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_GATE(bus_tcon_lcd_clk, "bus-tcon-lcd0", "ahb3",
> + 0xb7c, BIT(0), 0);
> +
> +static const char * const ledc_parents[] = { "dcxo24M",
> + "pll-periph0" };
> +static SUNXI_CCU_MP_WITH_MUX_GATE(ledc_clk, "ledc",
> + ledc_parents, 0xbf0,
> + 0, 4, /* M */
> + 8, 2, /* N */
> + 24, 3, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_GATE(bus_ledc_clk, "bus-ledc", "ahb3", 0xbfc, BIT(0), 0);
> +
> +static const char * const csi_top_parents[] = { "pll-periph0-2x",
> + "pll-video0-2x",
> + "pll-video1-2x",
> + "pll-video2-2x",
> + "pll-video3-2x" };
> +static SUNXI_CCU_M_WITH_MUX_GATE(csi_top_clk, "csi-top",
> + csi_top_parents, 0xc04,
> + 0, 4, /* M */
> + 24, 3, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static const char * const csi0_mclk_parents[] = { "dcxo24M", "pll-video2",
> + "pll-video3", "pll-video0",
> + "pll-video1" };
> +static SUNXI_CCU_M_WITH_MUX_GATE(csi0_mclk_clk, "csi0-mclk",
> + csi0_mclk_parents, 0xc08,
> + 0, 5, /* M */
> + 24, 3, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static const char * const csi1_mclk_parents[] = { "dcxo24M", "pll-video3",
> + "pll-video0", "pll-video1",
> + "pll-video2" };
> +static SUNXI_CCU_M_WITH_MUX_GATE(csi1_mclk_clk, "csi1-mclk",
> + csi1_mclk_parents, 0xc0c,
> + 0, 5, /* M */
> + 24, 3, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +static SUNXI_CCU_GATE(bus_csi_clk, "bus-csi", "ahb3", 0xc1c, BIT(0), 0);
> +
> +static const char * const csi_isp_parents[] = { "pll-periph0-2x",
> + "pll-video0-2x",
> + "pll-video1-2x",
> + "pll-video2-2x",
> + "pll-video3-2x" };
> +static SUNXI_CCU_M_WITH_MUX_GATE(csi_isp_clk, "csi-isp",
> + csi_isp_parents, 0xc20,
> + 0, 5, /* M */
> + 24, 3, /* mux */
> + BIT(31), /* gate */
> + 0);
> +
> +/* Fixed factor clocks */
> +static CLK_FIXED_FACTOR_FW_NAME(osc12M_clk, "osc12M", "hosc", 2, 1, 0);
> +
> +static CLK_FIXED_FACTOR_HW(pll_com_audio_clk, "pll-com-audio",
> + &pll_com_clk.common.hw,
> + 5, 1, CLK_SET_RATE_PARENT);
> +
> +static CLK_FIXED_FACTOR_HW(pll_periph0_2x_clk, "pll-periph0-2x",
> + &pll_periph0_clk.common.hw,
> + 1, 2, 0);
> +
> +static CLK_FIXED_FACTOR_HW(pll_periph1_2x_clk, "pll-periph1-2x",
> + &pll_periph1_clk.common.hw,
> + 1, 2, 0);
> +
> +static const struct clk_hw *pll_video0_parents[] = {
> + &pll_video0_clk.common.hw
> +};
> +static CLK_FIXED_FACTOR_HWS(pll_video0_4x_clk, "pll-video0-4x",
> + pll_video0_parents,
> + 1, 4, CLK_SET_RATE_PARENT);
> +static CLK_FIXED_FACTOR_HWS(pll_video0_2x_clk, "pll-video0-2x",
> + pll_video0_parents,
> + 1, 2, CLK_SET_RATE_PARENT);
> +
> +static const struct clk_hw *pll_video1_parents[] = {
> + &pll_video1_clk.common.hw
> +};
> +static CLK_FIXED_FACTOR_HWS(pll_video1_4x_clk, "pll-video1-4x",
> + pll_video1_parents,
> + 1, 4, CLK_SET_RATE_PARENT);
> +static CLK_FIXED_FACTOR_HWS(pll_video1_2x_clk, "pll-video1-2x",
> + pll_video1_parents,
> + 1, 2, CLK_SET_RATE_PARENT);
> +
> +static const struct clk_hw *pll_video2_parents[] = {
> + &pll_video2_clk.common.hw
> +};
> +static CLK_FIXED_FACTOR_HWS(pll_video2_4x_clk, "pll-video2-4x",
> + pll_video2_parents,
> + 1, 4, CLK_SET_RATE_PARENT);
> +static CLK_FIXED_FACTOR_HWS(pll_video2_2x_clk, "pll-video2-2x",
> + pll_video2_parents,
> + 1, 2, CLK_SET_RATE_PARENT);
> +
> +static const struct clk_hw *pll_video3_parents[] = {
> + &pll_video3_clk.common.hw
> +};
> +static CLK_FIXED_FACTOR_HWS(pll_video3_4x_clk, "pll-video3-4x",
> + pll_video3_parents,
> + 1, 4, CLK_SET_RATE_PARENT);
> +static CLK_FIXED_FACTOR_HWS(pll_video3_2x_clk, "pll-video3-2x",
> + pll_video3_parents,
> + 1, 2, CLK_SET_RATE_PARENT);
> +
> +static struct ccu_common *sun50i_a100_ccu_clks[] = {
> + &pll_cpux_clk.common,
> + &pll_ddr0_clk.common,
> + &pll_periph0_clk.common,
> + &pll_periph1_clk.common,
> + &pll_gpu_clk.common,
> + &pll_video0_clk.common,
> + &pll_video1_clk.common,
> + &pll_video2_clk.common,
> + &pll_video3_clk.common,
> + &pll_ve_clk.common,
> + &pll_com_clk.common,
> + &pll_audio_clk.common,
> + &cpux_clk.common,
> + &axi_clk.common,
> + &cpux_apb_clk.common,
> + &psi_ahb1_ahb2_clk.common,
> + &ahb3_clk.common,
> + &apb1_clk.common,
> + &apb2_clk.common,
> + &mbus_clk.common,
> + &de_clk.common,
> + &bus_de_clk.common,
> + &g2d_clk.common,
> + &bus_g2d_clk.common,
> + &gpu_clk.common,
> + &bus_gpu_clk.common,
> + &ce_clk.common,
> + &bus_ce_clk.common,
> + &ve_clk.common,
> + &bus_ve_clk.common,
> + &bus_dma_clk.common,
> + &bus_msgbox_clk.common,
> + &bus_spinlock_clk.common,
> + &bus_hstimer_clk.common,
> + &avs_clk.common,
> + &bus_dbg_clk.common,
> + &bus_psi_clk.common,
> + &bus_pwm_clk.common,
> + &bus_iommu_clk.common,
> + &mbus_dma_clk.common,
> + &mbus_ve_clk.common,
> + &mbus_ce_clk.common,
> + &mbus_nand_clk.common,
> + &mbus_csi_clk.common,
> + &mbus_isp_clk.common,
> + &mbus_g2d_clk.common,
> + &bus_dram_clk.common,
> + &nand0_clk.common,
> + &nand1_clk.common,
> + &bus_nand_clk.common,
> + &mmc0_clk.common,
> + &mmc1_clk.common,
> + &mmc2_clk.common,
> + &bus_mmc0_clk.common,
> + &bus_mmc1_clk.common,
> + &bus_mmc2_clk.common,
> + &bus_uart0_clk.common,
> + &bus_uart1_clk.common,
> + &bus_uart2_clk.common,
> + &bus_uart3_clk.common,
> + &bus_uart4_clk.common,
> + &bus_i2c0_clk.common,
> + &bus_i2c1_clk.common,
> + &bus_i2c2_clk.common,
> + &bus_i2c3_clk.common,
> + &spi0_clk.common,
> + &spi1_clk.common,
> + &spi2_clk.common,
> + &bus_spi0_clk.common,
> + &bus_spi1_clk.common,
> + &bus_spi2_clk.common,
> + &emac_25m_clk.common,
> + &bus_emac_clk.common,
> + &ir_rx_clk.common,
> + &bus_ir_rx_clk.common,
> + &ir_tx_clk.common,
> + &bus_ir_tx_clk.common,
> + &bus_gpadc_clk.common,
> + &bus_ths_clk.common,
> + &i2s0_clk.common,
> + &i2s1_clk.common,
> + &i2s2_clk.common,
> + &i2s3_clk.common,
> + &bus_i2s0_clk.common,
> + &bus_i2s1_clk.common,
> + &bus_i2s2_clk.common,
> + &bus_i2s3_clk.common,
> + &spdif_clk.common,
> + &bus_spdif_clk.common,
> + &dmic_clk.common,
> + &bus_dmic_clk.common,
> + &audio_codec_dac_clk.common,
> + &audio_codec_adc_clk.common,
> + &audio_codec_4x_clk.common,
> + &bus_audio_codec_clk.common,
> + &usb_ohci0_clk.common,
> + &usb_phy0_clk.common,
> + &usb_ohci1_clk.common,
> + &usb_phy1_clk.common,
> + &bus_ohci0_clk.common,
> + &bus_ohci1_clk.common,
> + &bus_ehci0_clk.common,
> + &bus_ehci1_clk.common,
> + &bus_otg_clk.common,
> + &bus_lradc_clk.common,
> + &bus_dpss_top0_clk.common,
> + &bus_dpss_top1_clk.common,
> + &mipi_dsi_clk.common,
> + &bus_mipi_dsi_clk.common,
> + &tcon_lcd_clk.common,
> + &bus_tcon_lcd_clk.common,
> + &ledc_clk.common,
> + &bus_ledc_clk.common,
> + &csi_top_clk.common,
> + &csi0_mclk_clk.common,
> + &csi1_mclk_clk.common,
> + &bus_csi_clk.common,
> + &csi_isp_clk.common,
> +};
> +
> +static struct clk_hw_onecell_data sun50i_a100_hw_clks = {
> + .hws = {
> + [CLK_OSC12M] = &osc12M_clk.hw,
> + [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw,
> + [CLK_PLL_DDR0] = &pll_ddr0_clk.common.hw,
> + [CLK_PLL_PERIPH0] = &pll_periph0_clk.common.hw,
> + [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.hw,
> + [CLK_PLL_PERIPH1] = &pll_periph1_clk.common.hw,
> + [CLK_PLL_PERIPH1_2X] = &pll_periph1_2x_clk.hw,
> + [CLK_PLL_GPU] = &pll_gpu_clk.common.hw,
> + [CLK_PLL_VIDEO0] = &pll_video0_clk.common.hw,
> + [CLK_PLL_VIDEO0_2X] = &pll_video0_2x_clk.hw,
> + [CLK_PLL_VIDEO0_4X] = &pll_video0_4x_clk.hw,
> + [CLK_PLL_VIDEO1] = &pll_video1_clk.common.hw,
> + [CLK_PLL_VIDEO1_2X] = &pll_video1_2x_clk.hw,
> + [CLK_PLL_VIDEO1_4X] = &pll_video1_4x_clk.hw,
> + [CLK_PLL_VIDEO2] = &pll_video2_clk.common.hw,
> + [CLK_PLL_VIDEO2_2X] = &pll_video2_2x_clk.hw,
> + [CLK_PLL_VIDEO2_4X] = &pll_video2_4x_clk.hw,
> + [CLK_PLL_VIDEO3] = &pll_video3_clk.common.hw,
> + [CLK_PLL_VIDEO3_2X] = &pll_video3_2x_clk.hw,
> + [CLK_PLL_VIDEO3_4X] = &pll_video3_4x_clk.hw,
> + [CLK_PLL_VE] = &pll_ve_clk.common.hw,
> + [CLK_PLL_COM] = &pll_com_clk.common.hw,
> + [CLK_PLL_COM_AUDIO] = &pll_com_audio_clk.hw,
> + [CLK_PLL_AUDIO] = &pll_audio_clk.common.hw,
> + [CLK_CPUX] = &cpux_clk.common.hw,
> + [CLK_AXI] = &axi_clk.common.hw,
> + [CLK_CPUX_APB] = &cpux_apb_clk.common.hw,
> + [CLK_PSI_AHB1_AHB2] = &psi_ahb1_ahb2_clk.common.hw,
> + [CLK_AHB3] = &ahb3_clk.common.hw,
> + [CLK_APB1] = &apb1_clk.common.hw,
> + [CLK_APB2] = &apb2_clk.common.hw,
> + [CLK_MBUS] = &mbus_clk.common.hw,
> + [CLK_DE] = &de_clk.common.hw,
> + [CLK_BUS_DE] = &bus_de_clk.common.hw,
> + [CLK_G2D] = &g2d_clk.common.hw,
> + [CLK_BUS_G2D] = &bus_g2d_clk.common.hw,
> + [CLK_GPU] = &gpu_clk.common.hw,
> + [CLK_BUS_GPU] = &bus_gpu_clk.common.hw,
> + [CLK_CE] = &ce_clk.common.hw,
> + [CLK_BUS_CE] = &bus_ce_clk.common.hw,
> + [CLK_VE] = &ve_clk.common.hw,
> + [CLK_BUS_VE] = &bus_ve_clk.common.hw,
> + [CLK_BUS_DMA] = &bus_dma_clk.common.hw,
> + [CLK_BUS_MSGBOX] = &bus_msgbox_clk.common.hw,
> + [CLK_BUS_SPINLOCK] = &bus_spinlock_clk.common.hw,
> + [CLK_BUS_HSTIMER] = &bus_hstimer_clk.common.hw,
> + [CLK_AVS] = &avs_clk.common.hw,
> + [CLK_BUS_DBG] = &bus_dbg_clk.common.hw,
> + [CLK_BUS_PSI] = &bus_psi_clk.common.hw,
> + [CLK_BUS_PWM] = &bus_pwm_clk.common.hw,
> + [CLK_BUS_IOMMU] = &bus_iommu_clk.common.hw,
> + [CLK_MBUS_DMA] = &mbus_dma_clk.common.hw,
> + [CLK_MBUS_VE] = &mbus_ve_clk.common.hw,
> + [CLK_MBUS_CE] = &mbus_ce_clk.common.hw,
> + [CLK_MBUS_NAND] = &mbus_nand_clk.common.hw,
> + [CLK_MBUS_CSI] = &mbus_csi_clk.common.hw,
> + [CLK_MBUS_ISP] = &mbus_isp_clk.common.hw,
> + [CLK_MBUS_G2D] = &mbus_g2d_clk.common.hw,
> + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw,
> + [CLK_NAND0] = &nand0_clk.common.hw,
> + [CLK_NAND1] = &nand1_clk.common.hw,
> + [CLK_BUS_NAND] = &bus_nand_clk.common.hw,
> + [CLK_MMC0] = &mmc0_clk.common.hw,
> + [CLK_MMC1] = &mmc1_clk.common.hw,
> + [CLK_MMC2] = &mmc2_clk.common.hw,
> + [CLK_BUS_MMC0] = &bus_mmc0_clk.common.hw,
> + [CLK_BUS_MMC1] = &bus_mmc1_clk.common.hw,
> + [CLK_BUS_MMC2] = &bus_mmc2_clk.common.hw,
> + [CLK_BUS_UART0] = &bus_uart0_clk.common.hw,
> + [CLK_BUS_UART1] = &bus_uart1_clk.common.hw,
> + [CLK_BUS_UART2] = &bus_uart2_clk.common.hw,
> + [CLK_BUS_UART3] = &bus_uart3_clk.common.hw,
> + [CLK_BUS_UART4] = &bus_uart4_clk.common.hw,
> + [CLK_BUS_I2C0] = &bus_i2c0_clk.common.hw,
> + [CLK_BUS_I2C1] = &bus_i2c1_clk.common.hw,
> + [CLK_BUS_I2C2] = &bus_i2c2_clk.common.hw,
> + [CLK_BUS_I2C3] = &bus_i2c3_clk.common.hw,
> + [CLK_SPI0] = &spi0_clk.common.hw,
> + [CLK_SPI1] = &spi1_clk.common.hw,
> + [CLK_SPI2] = &spi2_clk.common.hw,
> + [CLK_BUS_SPI0] = &bus_spi0_clk.common.hw,
> + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw,
> + [CLK_BUS_SPI2] = &bus_spi2_clk.common.hw,
> + [CLK_EMAC_25M] = &emac_25m_clk.common.hw,
> + [CLK_BUS_EMAC] = &bus_emac_clk.common.hw,
> + [CLK_IR_RX] = &ir_rx_clk.common.hw,
> + [CLK_BUS_IR_RX] = &bus_ir_rx_clk.common.hw,
> + [CLK_IR_TX] = &ir_tx_clk.common.hw,
> + [CLK_BUS_IR_TX] = &bus_ir_tx_clk.common.hw,
> + [CLK_BUS_GPADC] = &bus_gpadc_clk.common.hw,
> + [CLK_BUS_THS] = &bus_ths_clk.common.hw,
> + [CLK_I2S0] = &i2s0_clk.common.hw,
> + [CLK_I2S1] = &i2s1_clk.common.hw,
> + [CLK_I2S2] = &i2s2_clk.common.hw,
> + [CLK_I2S3] = &i2s3_clk.common.hw,
> + [CLK_BUS_I2S0] = &bus_i2s0_clk.common.hw,
> + [CLK_BUS_I2S1] = &bus_i2s1_clk.common.hw,
> + [CLK_BUS_I2S2] = &bus_i2s2_clk.common.hw,
> + [CLK_BUS_I2S3] = &bus_i2s3_clk.common.hw,
> + [CLK_SPDIF] = &spdif_clk.common.hw,
> + [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw,
> + [CLK_DMIC] = &dmic_clk.common.hw,
> + [CLK_BUS_DMIC] = &bus_dmic_clk.common.hw,
> + [CLK_AUDIO_DAC] = &audio_codec_dac_clk.common.hw,
> + [CLK_AUDIO_ADC] = &audio_codec_adc_clk.common.hw,
> + [CLK_AUDIO_4X] = &audio_codec_4x_clk.common.hw,
> + [CLK_BUS_AUDIO_CODEC] = &bus_audio_codec_clk.common.hw,
> + [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw,
> + [CLK_USB_PHY0] = &usb_phy0_clk.common.hw,
> + [CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw,
> + [CLK_USB_PHY1] = &usb_phy1_clk.common.hw,
> + [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw,
> + [CLK_BUS_OHCI1] = &bus_ohci1_clk.common.hw,
> + [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw,
> + [CLK_BUS_EHCI1] = &bus_ehci1_clk.common.hw,
> + [CLK_BUS_OTG] = &bus_otg_clk.common.hw,
> + [CLK_BUS_LRADC] = &bus_lradc_clk.common.hw,
> + [CLK_BUS_DPSS_TOP0] = &bus_dpss_top0_clk.common.hw,
> + [CLK_BUS_DPSS_TOP1] = &bus_dpss_top1_clk.common.hw,
> + [CLK_MIPI_DSI] = &mipi_dsi_clk.common.hw,
> + [CLK_BUS_MIPI_DSI] = &bus_mipi_dsi_clk.common.hw,
> + [CLK_TCON_LCD] = &tcon_lcd_clk.common.hw,
> + [CLK_BUS_TCON_LCD] = &bus_tcon_lcd_clk.common.hw,
> + [CLK_LEDC] = &ledc_clk.common.hw,
> + [CLK_BUS_LEDC] = &bus_ledc_clk.common.hw,
> + [CLK_CSI_TOP] = &csi_top_clk.common.hw,
> + [CLK_CSI0_MCLK] = &csi0_mclk_clk.common.hw,
> + [CLK_CSI1_MCLK] = &csi1_mclk_clk.common.hw,
> + [CLK_BUS_CSI] = &bus_csi_clk.common.hw,
> + [CLK_CSI_ISP] = &csi_isp_clk.common.hw,
> + },
> + .num = CLK_NUMBER,
> +};
> +
> +static struct ccu_reset_map sun50i_a100_ccu_resets[] = {
> + [RST_MBUS] = { 0x540, BIT(30) },
> +
> + [RST_BUS_DE] = { 0x60c, BIT(16) },
> + [RST_BUS_G2D] = { 0x63c, BIT(16) },
> + [RST_BUS_GPU] = { 0x67c, BIT(16) },
> + [RST_BUS_CE] = { 0x68c, BIT(16) },
> + [RST_BUS_VE] = { 0x69c, BIT(16) },
> + [RST_BUS_DMA] = { 0x70c, BIT(16) },
> + [RST_BUS_MSGBOX] = { 0x71c, BIT(16) },
> + [RST_BUS_SPINLOCK] = { 0x72c, BIT(16) },
> + [RST_BUS_HSTIMER] = { 0x73c, BIT(16) },
> + [RST_BUS_DBG] = { 0x78c, BIT(16) },
> + [RST_BUS_PSI] = { 0x79c, BIT(16) },
> + [RST_BUS_PWM] = { 0x7ac, BIT(16) },
> + [RST_BUS_DRAM] = { 0x80c, BIT(16) },
> + [RST_BUS_NAND] = { 0x82c, BIT(16) },
> + [RST_BUS_MMC0] = { 0x84c, BIT(16) },
> + [RST_BUS_MMC1] = { 0x84c, BIT(17) },
> + [RST_BUS_MMC2] = { 0x84c, BIT(18) },
> + [RST_BUS_UART0] = { 0x90c, BIT(16) },
> + [RST_BUS_UART1] = { 0x90c, BIT(17) },
> + [RST_BUS_UART2] = { 0x90c, BIT(18) },
> + [RST_BUS_UART3] = { 0x90c, BIT(19) },
> + [RST_BUS_UART4] = { 0x90c, BIT(20) },
> + [RST_BUS_I2C0] = { 0x91c, BIT(16) },
> + [RST_BUS_I2C1] = { 0x91c, BIT(17) },
> + [RST_BUS_I2C2] = { 0x91c, BIT(18) },
> + [RST_BUS_I2C3] = { 0x91c, BIT(19) },
> + [RST_BUS_SPI0] = { 0x96c, BIT(16) },
> + [RST_BUS_SPI1] = { 0x96c, BIT(17) },
> + [RST_BUS_SPI2] = { 0x96c, BIT(18) },
> + [RST_BUS_EMAC] = { 0x97c, BIT(16) },
> + [RST_BUS_IR_RX] = { 0x99c, BIT(16) },
> + [RST_BUS_IR_TX] = { 0x9cc, BIT(16) },
> + [RST_BUS_GPADC] = { 0x9ec, BIT(16) },
> + [RST_BUS_THS] = { 0x9fc, BIT(16) },
> + [RST_BUS_I2S0] = { 0xa20, BIT(16) },
> + [RST_BUS_I2S1] = { 0xa20, BIT(17) },
> + [RST_BUS_I2S2] = { 0xa20, BIT(18) },
> + [RST_BUS_I2S3] = { 0xa20, BIT(19) },
> + [RST_BUS_SPDIF] = { 0xa2c, BIT(16) },
> + [RST_BUS_DMIC] = { 0xa4c, BIT(16) },
> + [RST_BUS_AUDIO_CODEC] = { 0xa5c, BIT(16) },
> +
> + [RST_USB_PHY0] = { 0xa70, BIT(30) },
> + [RST_USB_PHY1] = { 0xa74, BIT(30) },
> +
> + [RST_BUS_OHCI0] = { 0xa8c, BIT(16) },
> + [RST_BUS_OHCI1] = { 0xa8c, BIT(17) },
> + [RST_BUS_EHCI0] = { 0xa8c, BIT(20) },
> + [RST_BUS_EHCI1] = { 0xa8c, BIT(21) },
> + [RST_BUS_OTG] = { 0xa8c, BIT(24) },
> +
> + [RST_BUS_LRADC] = { 0xa9c, BIT(16) },
> + [RST_BUS_DPSS_TOP0] = { 0xabc, BIT(16) },
> + [RST_BUS_DPSS_TOP1] = { 0xacc, BIT(16) },
> + [RST_BUS_MIPI_DSI] = { 0xb4c, BIT(16) },
> + [RST_BUS_TCON_LCD] = { 0xb7c, BIT(16) },
> + [RST_BUS_LVDS] = { 0xbac, BIT(16) },
> + [RST_BUS_LEDC] = { 0xbfc, BIT(16) },
> + [RST_BUS_CSI] = { 0xc1c, BIT(16) },
> + [RST_BUS_CSI_ISP] = { 0xc2c, BIT(16) },
> +};
> +
> +static const struct sunxi_ccu_desc sun50i_a100_ccu_desc = {
> + .ccu_clks = sun50i_a100_ccu_clks,
> + .num_ccu_clks = ARRAY_SIZE(sun50i_a100_ccu_clks),
> +
> + .hw_clks = &sun50i_a100_hw_clks,
> +
> + .resets = sun50i_a100_ccu_resets,
> + .num_resets = ARRAY_SIZE(sun50i_a100_ccu_resets),
> +};
> +
> +static const u32 pll_regs[] = {
> + SUN50I_A100_PLL_CPUX_REG,
> + SUN50I_A100_PLL_DDR0_REG,
> + SUN50I_A100_PLL_PERIPH0_REG,
> + SUN50I_A100_PLL_PERIPH1_REG,
> + SUN50I_A100_PLL_GPU_REG,
> + SUN50I_A100_PLL_VIDEO0_REG,
> + SUN50I_A100_PLL_VIDEO1_REG,
> + SUN50I_A100_PLL_VIDEO2_REG,
> + SUN50I_A100_PLL_VIDEO3_REG,
> + SUN50I_A100_PLL_VE_REG,
> + SUN50I_A100_PLL_COM_REG,
> + SUN50I_A100_PLL_AUDIO_REG,
> +};
> +
> +static const u32 pll_video_regs[] = {
> + SUN50I_A100_PLL_VIDEO0_REG,
> + SUN50I_A100_PLL_VIDEO1_REG,
> + SUN50I_A100_PLL_VIDEO2_REG,
> + SUN50I_A100_PLL_VIDEO3_REG,
> +};
> +
> +static const u32 usb2_clk_regs[] = {
> + SUN50I_A100_USB0_CLK_REG,
> + SUN50I_A100_USB1_CLK_REG,
> +};
Using the same prefix that we use everywhere else would be nice too.
> +static struct ccu_pll_nb sun50i_a100_pll_cpu_nb = {
> + .common = &pll_cpux_clk.common,
> + /* copy from pll_cpux_clk */
> + .enable = BIT(27),
> + .lock = BIT(28),
> +};
> +
> +static struct ccu_mux_nb sun50i_a100_cpu_nb = {
> + .common = &cpux_clk.common,
> + .cm = &cpux_clk.mux,
> + .delay_us = 1,
> + .bypass_index = 4, /* index of pll periph0 */
> +};
> +
> +static int sun50i_a100_ccu_probe(struct platform_device *pdev)
> +{
> + void __iomem *reg;
> + u32 val;
> + int i, ret;
> +
> + reg = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(reg))
> + return PTR_ERR(reg);
> +
> + /* Enable the lock bits on all PLLs */
> + for (i = 0; i < ARRAY_SIZE(pll_regs); i++) {
> + val = readl(reg + pll_regs[i]);
> + val |= BIT(29);
Having a define for that would be nice here
> + writel(val, reg + pll_regs[i]);
> + }
> +
> + /*
> + * In order to pass the EMI certification, the SDM function of
> + * the peripheral 1 bus is enabled, and the frequency is still
> + * calculated using the previous division factor.
> + */
> + writel(0xd1303333, reg + SUN50I_A100_PLL_PERIPH1_PATTERN0_REG);
Same here
> + val = readl(reg + SUN50I_A100_PLL_PERIPH1_REG);
> + val |= BIT(24);
> + writel(val, reg + SUN50I_A100_PLL_PERIPH1_REG);
Same here
> + /*
> + * Force the output divider of video PLLs to 0.
> + *
> + * See the comment before pll-video0 definition for the reason.
> + */
> + for (i = 0; i < ARRAY_SIZE(pll_video_regs); i++) {
> + val = readl(reg + pll_video_regs[i]);
> + val &= ~BIT(0);
> + writel(val, reg + pll_video_regs[i]);
> + }
> +
> + /* Enforce m1 = 0, m0 = 1 for Audio PLL */
Why?
> + val = readl(reg + SUN50I_A100_PLL_AUDIO_REG);
> + val &= ~BIT(1);
> + val |= BIT(0);
> + writel(val, reg + SUN50I_A100_PLL_AUDIO_REG);
> +
> + /*
> + * Force OHCI 12M clock sources to 00 (12MHz divided from 48MHz)
> + *
> + * This clock mux is still mysterious, and the code just enforces
> + * it to have a valid clock parent.
> + */
> + for (i = 0; i < ARRAY_SIZE(usb2_clk_regs); i++) {
> + val = readl(reg + usb2_clk_regs[i]);
> + val &= ~GENMASK(25, 24);
> + writel(val, reg + usb2_clk_regs[i]);
> + }
> +
> + ret = sunxi_ccu_probe(pdev->dev.of_node, reg, &sun50i_a100_ccu_desc);
> + if (ret)
> + return ret;
> +
> + /* Gate then ungate PLL CPU after any rate changes */
> + ccu_pll_notifier_register(&sun50i_a100_pll_cpu_nb);
> +
> + /* Reparent CPU during PLL CPU rate changes */
> + ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
> + &sun50i_a100_cpu_nb);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id sun50i_a100_ccu_ids[] = {
> + { .compatible = "allwinner,sun50i-a100-ccu" },
> + { }
> +};
> +
> +static struct platform_driver sun50i_a100_ccu_driver = {
> + .probe = sun50i_a100_ccu_probe,
> + .driver = {
> + .name = "sun50i-a100-ccu",
> + .of_match_table = sun50i_a100_ccu_ids,
> + },
> +};
> +module_platform_driver(sun50i_a100_ccu_driver);
> diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100.h b/drivers/clk/sunxi-ng/ccu-sun50i-a100.h
> new file mode 100644
> index 000000000000..4fbf2e1a6697
> --- /dev/null
> +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100.h
> @@ -0,0 +1,14 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2020 Frank Lee <frank@allwinner.com>
> + */
> +
> +#ifndef _CCU_SUN50I_A100_H_
> +#define _CCU_SUN50I_A100_H_
> +
> +#include <dt-bindings/clock/sun50i-a100-ccu.h>
> +#include <dt-bindings/reset/sun50i-a100-ccu.h>
> +
> +#define CLK_NUMBER (CLK_CSI_ISP + 1)
> +
> +#endif /* _CCU_SUN50I_A100_H_ */
> diff --git a/include/dt-bindings/clock/sun50i-a100-ccu.h b/include/dt-bindings/clock/sun50i-a100-ccu.h
> new file mode 100644
> index 000000000000..8186b1a7bcfe
> --- /dev/null
> +++ b/include/dt-bindings/clock/sun50i-a100-ccu.h
> @@ -0,0 +1,141 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
> +/*
> + * Copyright (c) 2020 Frank Lee <frank@allwinner.com>
> + */
> +
> +#ifndef _DT_BINDINGS_CLK_SUN50I_A100_H_
> +#define _DT_BINDINGS_CLK_SUN50I_A100_H_
> +
> +#define CLK_OSC12M 0
> +#define CLK_PLL_CPUX 1
> +#define CLK_PLL_DDR0 2
> +#define CLK_PLL_PERIPH0 3
> +#define CLK_PLL_PERIPH0_2X 4
> +#define CLK_PLL_PERIPH1 5
> +#define CLK_PLL_PERIPH1_2X 6
> +#define CLK_PLL_GPU 7
> +#define CLK_PLL_VIDEO0 8
> +#define CLK_PLL_VIDEO0_2X 9
> +#define CLK_PLL_VIDEO0_4X 10
> +#define CLK_PLL_VIDEO1 11
> +#define CLK_PLL_VIDEO1_2X 12
> +#define CLK_PLL_VIDEO1_4X 13
> +#define CLK_PLL_VIDEO2 14
> +#define CLK_PLL_VIDEO2_2X 15
> +#define CLK_PLL_VIDEO2_4X 16
> +#define CLK_PLL_VIDEO3 17
> +#define CLK_PLL_VIDEO3_2X 18
> +#define CLK_PLL_VIDEO3_4X 19
> +#define CLK_PLL_VE 20
> +#define CLK_PLL_COM 21
> +#define CLK_PLL_COM_AUDIO 22
> +#define CLK_PLL_AUDIO 23
> +#define CLK_CPUX 24
> +#define CLK_AXI 25
> +#define CLK_CPUX_APB 26
> +#define CLK_PSI_AHB1_AHB2 27
> +#define CLK_AHB3 28
> +#define CLK_APB1 29
> +#define CLK_APB2 30
> +#define CLK_MBUS 31
> +#define CLK_DE 32
> +#define CLK_BUS_DE 33
> +#define CLK_G2D 34
> +#define CLK_BUS_G2D 35
> +#define CLK_GPU 36
> +#define CLK_BUS_GPU 37
> +#define CLK_CE 38
> +#define CLK_BUS_CE 39
> +#define CLK_VE 40
> +#define CLK_BUS_VE 41
> +#define CLK_BUS_DMA 42
> +#define CLK_BUS_MSGBOX 43
> +#define CLK_BUS_SPINLOCK 44
> +#define CLK_BUS_HSTIMER 45
> +#define CLK_AVS 46
> +#define CLK_BUS_DBG 47
> +#define CLK_BUS_PSI 48
> +#define CLK_BUS_PWM 49
> +#define CLK_BUS_IOMMU 50
> +#define CLK_MBUS_DMA 51
> +#define CLK_MBUS_VE 52
> +#define CLK_MBUS_CE 53
> +#define CLK_MBUS_NAND 54
> +#define CLK_MBUS_CSI 55
> +#define CLK_MBUS_ISP 56
> +#define CLK_MBUS_G2D 57
> +#define CLK_BUS_DRAM 58
> +#define CLK_NAND0 59
> +#define CLK_NAND1 60
> +#define CLK_BUS_NAND 61
> +#define CLK_MMC0 62
> +#define CLK_MMC1 63
> +#define CLK_MMC2 64
> +#define CLK_MMC3 65
> +#define CLK_BUS_MMC0 66
> +#define CLK_BUS_MMC1 67
> +#define CLK_BUS_MMC2 68
> +#define CLK_BUS_UART0 69
> +#define CLK_BUS_UART1 70
> +#define CLK_BUS_UART2 71
> +#define CLK_BUS_UART3 72
> +#define CLK_BUS_UART4 73
> +#define CLK_BUS_I2C0 74
> +#define CLK_BUS_I2C1 75
> +#define CLK_BUS_I2C2 76
> +#define CLK_BUS_I2C3 77
> +#define CLK_SPI0 78
> +#define CLK_SPI1 79
> +#define CLK_SPI2 80
> +#define CLK_BUS_SPI0 81
> +#define CLK_BUS_SPI1 82
> +#define CLK_BUS_SPI2 83
> +#define CLK_EMAC_25M 84
> +#define CLK_BUS_EMAC 85
> +#define CLK_IR_RX 86
> +#define CLK_BUS_IR_RX 87
> +#define CLK_IR_TX 88
> +#define CLK_BUS_IR_TX 89
> +#define CLK_BUS_GPADC 90
> +#define CLK_BUS_THS 91
> +#define CLK_I2S0 92
> +#define CLK_I2S1 93
> +#define CLK_I2S2 94
> +#define CLK_I2S3 95
> +#define CLK_BUS_I2S0 96
> +#define CLK_BUS_I2S1 97
> +#define CLK_BUS_I2S2 98
> +#define CLK_BUS_I2S3 99
> +#define CLK_SPDIF 100
> +#define CLK_BUS_SPDIF 101
> +#define CLK_DMIC 102
> +#define CLK_BUS_DMIC 103
> +#define CLK_AUDIO_DAC 104
> +#define CLK_AUDIO_ADC 105
> +#define CLK_AUDIO_4X 106
> +#define CLK_BUS_AUDIO_CODEC 107
> +#define CLK_USB_OHCI0 108
> +#define CLK_USB_PHY0 109
> +#define CLK_USB_OHCI1 110
> +#define CLK_USB_PHY1 111
> +#define CLK_BUS_OHCI0 112
> +#define CLK_BUS_OHCI1 113
> +#define CLK_BUS_EHCI0 114
> +#define CLK_BUS_EHCI1 115
> +#define CLK_BUS_OTG 116
> +#define CLK_BUS_LRADC 117
> +#define CLK_BUS_DPSS_TOP0 118
> +#define CLK_BUS_DPSS_TOP1 119
> +#define CLK_MIPI_DSI 120
> +#define CLK_BUS_MIPI_DSI 121
> +#define CLK_TCON_LCD 122
> +#define CLK_BUS_TCON_LCD 123
> +#define CLK_LEDC 124
> +#define CLK_BUS_LEDC 125
> +#define CLK_CSI_TOP 126
> +#define CLK_CSI0_MCLK 127
> +#define CLK_CSI1_MCLK 128
> +#define CLK_BUS_CSI 129
> +#define CLK_CSI_ISP 130
> +
> +#endif /* _DT_BINDINGS_CLK_SUN50I_A100_H_ */
So we don't really want to expose all the clocks in the binding here, but only
the one that are going to be used by the devices (and not the "internal" ones),
so that will be usually the bus gates and the module gates.
If we need a PLL at some point, we can always export it, but that should be the
exception, not the default.
> diff --git a/include/dt-bindings/clock/sun50i-a100-r-ccu.h b/include/dt-bindings/clock/sun50i-a100-r-ccu.h
> new file mode 100644
> index 000000000000..a4486c31924a
> --- /dev/null
> +++ b/include/dt-bindings/clock/sun50i-a100-r-ccu.h
> @@ -0,0 +1,25 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2020 Frank Lee <frank@allwinner.com>
> + */
> +
> +#ifndef _DT_BINDINGS_CLK_SUN50I_A100_R_CCU_H_
> +#define _DT_BINDINGS_CLK_SUN50I_A100_R_CCU_H_
> +
> +#define CLK_CPUS 0
> +#define CLK_R_AHB 1
> +#define CLK_R_APB1 2
> +#define CLK_R_APB2 3
> +#define CLK_R_APB1_TIMER 4
> +#define CLK_R_APB1_TWD 5
> +#define CLK_R_APB1_PWM 6
> +#define CLK_R_APB1_BUS_PWM 7
> +#define CLK_R_APB1_PPU 8
> +#define CLK_R_APB2_UART 9
> +#define CLK_R_APB2_I2C0 10
> +#define CLK_R_APB2_I2C1 11
> +#define CLK_R_APB1_IR 12
> +#define CLK_R_APB1_BUS_IR 13
> +#define CLK_R_AHB_BUS_RTC 14
> +
> +#endif /* _DT_BINDINGS_CLK_SUN50I_A100_R_CCU_H_ */
Same story here
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH v5 06/11] net: ethernet: mtk-star-emac: new driver
From: Matthias Brugger @ 2020-05-22 15:06 UTC (permalink / raw)
To: Bartosz Golaszewski, Rob Herring, David S . Miller, John Crispin,
Sean Wang, Mark Lee, Jakub Kicinski, Arnd Bergmann, Fabien Parent,
Heiner Kallweit, Edwin Peer
Cc: devicetree, linux-kernel, netdev, linux-arm-kernel,
linux-mediatek, Stephane Le Provost, Pedro Tsai, Andrew Perepech,
Bartosz Golaszewski
In-Reply-To: <20200522120700.838-7-brgl@bgdev.pl>
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");
>
^ permalink raw reply
* Re: [PATCH 0/4] Allwinner A100 Initial support
From: Maxime Ripard @ 2020-05-22 15:02 UTC (permalink / raw)
To: Frank Lee
Cc: wens, robh+dt, mturquette, sboyd, linus.walleij, p.zabel,
huangshuosheng, tiny.windzz, linux-arm-kernel, devicetree,
linux-kernel, linux-clk, linux-gpio
In-Reply-To: <20200522030743.10204-1-frank@allwinnertech.com>
[-- Attachment #1: Type: text/plain, Size: 433 bytes --]
Hi,
On Fri, May 22, 2020 at 11:07:39AM +0800, Frank Lee wrote:
> This patch set adds initial support for allwinner a100 soc,
> which is a 64-bit tablet chip.
The patches are mostly good for a first iteration, thanks!
Could you provide a bit more context on what that SoC is and if the user manual
is available somewhere? It will be pretty hard to review without it.
Also, is that perf1 board available somewhere?
Thanks!
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH v15 2/2] i2c: core: support bus regulator controlling in adapter
From: Wolfram Sang @ 2020-05-22 15:00 UTC (permalink / raw)
To: Bibby Hsieh
Cc: Bartosz Golaszewski, linux-i2c, tfiga, drinkcat, srv_heupstream,
robh+dt, mark.rutland, devicetree, Rafael J . Wysocki
In-Reply-To: <20200519084833.GH1094@ninjato>
[-- Attachment #1: Type: text/plain, Size: 642 bytes --]
On Tue, May 19, 2020 at 10:48:33AM +0200, Wolfram Sang wrote:
> On Tue, May 19, 2020 at 03:27:29PM +0800, Bibby Hsieh wrote:
> > Although in the most platforms, the bus power of i2c
> > are alway on, some platforms disable the i2c bus power
> > in order to meet low power request.
> >
> > We get and enable bulk regulator in i2c adapter device.
> >
> > Signed-off-by: Bibby Hsieh <bibby.hsieh@mediatek.com>
>
> Applied to for-next, thanks! I added Tomasz Rev-by: for you.
Reverted because of regression reports in linux-next. I am all open for
the change in general, but it looks to me that we should wait another
cycle.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* [PATCH AUTOSEL 5.6 02/41] ARM: dts: rockchip: fix phy nodename for rk3228-evb
From: Sasha Levin @ 2020-05-22 14:49 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Johan Jonker, Heiko Stuebner, Sasha Levin, linux-arm-kernel,
linux-rockchip, devicetree
In-Reply-To: <20200522144959.434379-1-sashal@kernel.org>
From: Johan Jonker <jbx6244@gmail.com>
[ Upstream commit 287e0d538fcec2f6e8eb1e565bf0749f3b90186d ]
A test with the command below gives for example this error:
arch/arm/boot/dts/rk3228-evb.dt.yaml: phy@0:
'#phy-cells' is a required property
The phy nodename is normally used by a phy-handle.
This node is however compatible with
"ethernet-phy-id1234.d400", "ethernet-phy-ieee802.3-c22"
which is just been added to 'ethernet-phy.yaml'.
So change nodename to 'ethernet-phy' for which '#phy-cells'
is not a required property
make ARCH=arm dtbs_check
DT_SCHEMA_FILES=~/.local/lib/python3.5/site-packages/dtschema/schemas/
phy/phy-provider.yaml
Signed-off-by: Johan Jonker <jbx6244@gmail.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Link: https://lore.kernel.org/r/20200416170321.4216-1-jbx6244@gmail.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/arm/boot/dts/rk3228-evb.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/rk3228-evb.dts b/arch/arm/boot/dts/rk3228-evb.dts
index 5670b33fd1bd..aed879db6c15 100644
--- a/arch/arm/boot/dts/rk3228-evb.dts
+++ b/arch/arm/boot/dts/rk3228-evb.dts
@@ -46,7 +46,7 @@
#address-cells = <1>;
#size-cells = <0>;
- phy: phy@0 {
+ phy: ethernet-phy@0 {
compatible = "ethernet-phy-id1234.d400", "ethernet-phy-ieee802.3-c22";
reg = <0>;
clocks = <&cru SCLK_MAC_PHY>;
--
2.25.1
^ permalink raw reply related
* [PATCH AUTOSEL 5.6 04/41] arm64: dts: rockchip: fix status for &gmac2phy in rk3328-evb.dts
From: Sasha Levin @ 2020-05-22 14:49 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Johan Jonker, Heiko Stuebner, Sasha Levin, devicetree,
linux-arm-kernel, linux-rockchip
In-Reply-To: <20200522144959.434379-1-sashal@kernel.org>
From: Johan Jonker <jbx6244@gmail.com>
[ Upstream commit c617ed88502d0b05149e7f32f3b3fd8a0663f7e2 ]
The status was removed of the '&gmac2phy' node with the apply
of a patch long time ago, so fix status for '&gmac2phy'
in 'rk3328-evb.dts'.
Signed-off-by: Johan Jonker <jbx6244@gmail.com>
Link: https://lore.kernel.org/r/20200425122345.12902-2-jbx6244@gmail.com
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/arm64/boot/dts/rockchip/rk3328-evb.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3328-evb.dts b/arch/arm64/boot/dts/rockchip/rk3328-evb.dts
index 6abc6f4a86cf..05265b38cc02 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328-evb.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3328-evb.dts
@@ -86,7 +86,7 @@
assigned-clock-rate = <50000000>;
assigned-clocks = <&cru SCLK_MAC2PHY>;
assigned-clock-parents = <&cru SCLK_MAC2PHY_SRC>;
-
+ status = "okay";
};
&i2c1 {
--
2.25.1
^ permalink raw reply related
* [PATCH AUTOSEL 5.6 05/41] arm64: dts: rockchip: swap interrupts interrupt-names rk3399 gpu node
From: Sasha Levin @ 2020-05-22 14:49 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Johan Jonker, Heiko Stuebner, Sasha Levin, devicetree,
linux-arm-kernel, linux-rockchip
In-Reply-To: <20200522144959.434379-1-sashal@kernel.org>
From: Johan Jonker <jbx6244@gmail.com>
[ Upstream commit c604fd810bda667bdc20b2c041917baa7803e0fb ]
Dts files with Rockchip rk3399 'gpu' nodes were manually verified.
In order to automate this process arm,mali-midgard.txt
has been converted to yaml. In the new setup dtbs_check with
arm,mali-midgard.yaml expects interrupts and interrupt-names values
in the same order. Fix this for rk3399.
make ARCH=arm64 dtbs_check
DT_SCHEMA_FILES=Documentation/devicetree/bindings/gpu/
arm,mali-midgard.yaml
Signed-off-by: Johan Jonker <jbx6244@gmail.com>
Link: https://lore.kernel.org/r/20200425143837.18706-1-jbx6244@gmail.com
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/arm64/boot/dts/rockchip/rk3399.dtsi | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 5c4238a80144..c341172ec208 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1890,10 +1890,10 @@
gpu: gpu@ff9a0000 {
compatible = "rockchip,rk3399-mali", "arm,mali-t860";
reg = <0x0 0xff9a0000 0x0 0x10000>;
- interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH 0>,
- <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH 0>,
- <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH 0>;
- interrupt-names = "gpu", "job", "mmu";
+ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH 0>,
+ <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH 0>;
+ interrupt-names = "job", "mmu", "gpu";
clocks = <&cru ACLK_GPU>;
#cooling-cells = <2>;
power-domains = <&power RK3399_PD_GPU>;
--
2.25.1
^ permalink raw reply related
* [PATCH AUTOSEL 5.6 06/41] ARM: dts: rockchip: swap clock-names of gpu nodes
From: Sasha Levin @ 2020-05-22 14:49 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Johan Jonker, Heiko Stuebner, Sasha Levin, linux-arm-kernel,
linux-rockchip, devicetree
In-Reply-To: <20200522144959.434379-1-sashal@kernel.org>
From: Johan Jonker <jbx6244@gmail.com>
[ Upstream commit b14f3898d2c25a9b47a61fb879d0b1f3af92c59b ]
Dts files with Rockchip 'gpu' nodes were manually verified.
In order to automate this process arm,mali-utgard.txt
has been converted to yaml. In the new setup dtbs_check with
arm,mali-utgard.yaml expects clock-names values
in the same order, so fix that.
Signed-off-by: Johan Jonker <jbx6244@gmail.com>
Link: https://lore.kernel.org/r/20200425192500.1808-1-jbx6244@gmail.com
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/arm/boot/dts/rk3036.dtsi | 2 +-
arch/arm/boot/dts/rk322x.dtsi | 2 +-
arch/arm/boot/dts/rk3xxx.dtsi | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi
index cf36e25195b4..8c4b8f56c9e0 100644
--- a/arch/arm/boot/dts/rk3036.dtsi
+++ b/arch/arm/boot/dts/rk3036.dtsi
@@ -128,7 +128,7 @@
assigned-clocks = <&cru SCLK_GPU>;
assigned-clock-rates = <100000000>;
clocks = <&cru SCLK_GPU>, <&cru SCLK_GPU>;
- clock-names = "core", "bus";
+ clock-names = "bus", "core";
resets = <&cru SRST_GPU>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi
index 4e90efdc9630..729119952c68 100644
--- a/arch/arm/boot/dts/rk322x.dtsi
+++ b/arch/arm/boot/dts/rk322x.dtsi
@@ -561,7 +561,7 @@
"pp1",
"ppmmu1";
clocks = <&cru ACLK_GPU>, <&cru ACLK_GPU>;
- clock-names = "core", "bus";
+ clock-names = "bus", "core";
resets = <&cru SRST_GPU_A>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi
index 241f43e29c77..bb5ff10b9110 100644
--- a/arch/arm/boot/dts/rk3xxx.dtsi
+++ b/arch/arm/boot/dts/rk3xxx.dtsi
@@ -84,7 +84,7 @@
compatible = "arm,mali-400";
reg = <0x10090000 0x10000>;
clocks = <&cru ACLK_GPU>, <&cru ACLK_GPU>;
- clock-names = "core", "bus";
+ clock-names = "bus", "core";
assigned-clocks = <&cru ACLK_GPU>;
assigned-clock-rates = <100000000>;
resets = <&cru SRST_GPU>;
--
2.25.1
^ permalink raw reply related
* [PATCH AUTOSEL 5.6 07/41] ARM: dts: rockchip: fix pinctrl sub nodename for spi in rk322x.dtsi
From: Sasha Levin @ 2020-05-22 14:49 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Johan Jonker, Heiko Stuebner, Sasha Levin, linux-arm-kernel,
linux-rockchip, devicetree
In-Reply-To: <20200522144959.434379-1-sashal@kernel.org>
From: Johan Jonker <jbx6244@gmail.com>
[ Upstream commit 855bdca1781c79eb661f89c8944c4a719ce720e8 ]
A test with the command below gives these errors:
arch/arm/boot/dts/rk3229-evb.dt.yaml: spi-0:
'#address-cells' is a required property
arch/arm/boot/dts/rk3229-evb.dt.yaml: spi-1:
'#address-cells' is a required property
arch/arm/boot/dts/rk3229-xms6.dt.yaml: spi-0:
'#address-cells' is a required property
arch/arm/boot/dts/rk3229-xms6.dt.yaml: spi-1:
'#address-cells' is a required property
The $nodename pattern for spi nodes is
"^spi(@.*|-[0-9a-f])*$". To prevent warnings rename
'spi-0' and 'spi-1' pinctrl sub nodenames to
'spi0' and 'spi1' in 'rk322x.dtsi'.
make ARCH=arm dtbs_check
DT_SCHEMA_FILES=Documentation/devicetree/bindings/spi/spi-controller.yaml
Signed-off-by: Johan Jonker <jbx6244@gmail.com>
Link: https://lore.kernel.org/r/20200424123923.8192-1-jbx6244@gmail.com
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
arch/arm/boot/dts/rk322x.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi
index 729119952c68..a83f65486ad4 100644
--- a/arch/arm/boot/dts/rk322x.dtsi
+++ b/arch/arm/boot/dts/rk322x.dtsi
@@ -1033,7 +1033,7 @@
};
};
- spi-0 {
+ spi0 {
spi0_clk: spi0-clk {
rockchip,pins = <0 RK_PB1 2 &pcfg_pull_up>;
};
@@ -1051,7 +1051,7 @@
};
};
- spi-1 {
+ spi1 {
spi1_clk: spi1-clk {
rockchip,pins = <0 RK_PC7 2 &pcfg_pull_up>;
};
--
2.25.1
^ permalink raw reply related
* [PATCH AUTOSEL 5.6 10/41] ARM: dts: omap4-droid4: Fix flakey wlan by disabling internal pull for gpio
From: Sasha Levin @ 2020-05-22 14:49 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Tony Lindgren, Sasha Levin, devicetree, linux-arm-kernel
In-Reply-To: <20200522144959.434379-1-sashal@kernel.org>
From: Tony Lindgren <tony@atomide.com>
[ Upstream commit 30fa60c678eaa27b8f2a531920d77f7184658f73 ]
The wlan on droid4 is flakey on some devices, and experiments have shown this
gets fixed if we disable the internal pull for wlan gpio interrupt line.
The symptoms are that the wlan connection is very slow and almost useless
with lots of wlcore firmware reboot warnings in the dmesg.
In addition to configuring the wlan gpio pulls, let's also configure the rest
of the wlan sd pins. We have not configured those eariler as we're booting
using kexec.
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
.../boot/dts/motorola-mapphone-common.dtsi | 33 +++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/arch/arm/boot/dts/motorola-mapphone-common.dtsi b/arch/arm/boot/dts/motorola-mapphone-common.dtsi
index 9067e0ef4240..01ea9a1e2c86 100644
--- a/arch/arm/boot/dts/motorola-mapphone-common.dtsi
+++ b/arch/arm/boot/dts/motorola-mapphone-common.dtsi
@@ -367,6 +367,8 @@
};
&mmc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc3_pins>;
vmmc-supply = <&wl12xx_vmmc>;
/* uart2_tx.sdmmc3_dat1 pad as wakeirq */
interrupts-extended = <&wakeupgen GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH
@@ -472,6 +474,37 @@
>;
};
+ /*
+ * Android uses PIN_OFF_INPUT_PULLDOWN | PIN_INPUT_PULLUP | MUX_MODE3
+ * for gpio_100, but the internal pull makes wlan flakey on some
+ * devices. Off mode value should be tested if we have off mode working
+ * later on.
+ */
+ mmc3_pins: pinmux_mmc3_pins {
+ pinctrl-single,pins = <
+ /* 0x4a10008e gpmc_wait2.gpio_100 d23 */
+ OMAP4_IOPAD(0x08e, PIN_INPUT | MUX_MODE3)
+
+ /* 0x4a100102 abe_mcbsp1_dx.sdmmc3_dat2 ab25 */
+ OMAP4_IOPAD(0x102, PIN_INPUT_PULLUP | MUX_MODE1)
+
+ /* 0x4a100104 abe_mcbsp1_fsx.sdmmc3_dat3 ac27 */
+ OMAP4_IOPAD(0x104, PIN_INPUT_PULLUP | MUX_MODE1)
+
+ /* 0x4a100118 uart2_cts.sdmmc3_clk ab26 */
+ OMAP4_IOPAD(0x118, PIN_INPUT | MUX_MODE1)
+
+ /* 0x4a10011a uart2_rts.sdmmc3_cmd ab27 */
+ OMAP4_IOPAD(0x11a, PIN_INPUT_PULLUP | MUX_MODE1)
+
+ /* 0x4a10011c uart2_rx.sdmmc3_dat0 aa25 */
+ OMAP4_IOPAD(0x11c, PIN_INPUT_PULLUP | MUX_MODE1)
+
+ /* 0x4a10011e uart2_tx.sdmmc3_dat1 aa26 */
+ OMAP4_IOPAD(0x11e, PIN_INPUT_PULLUP | MUX_MODE1)
+ >;
+ };
+
/* gpmc_ncs0.gpio_50 */
poweroff_gpio: pinmux_poweroff_pins {
pinctrl-single,pins = <
--
2.25.1
^ permalink raw reply related
* Re: [PATCH v15 1/2] dt-binding: i2c: add bus-supply property
From: Wolfram Sang @ 2020-05-22 14:59 UTC (permalink / raw)
To: Bibby Hsieh
Cc: Bartosz Golaszewski, linux-i2c, tfiga, drinkcat, srv_heupstream,
robh+dt, mark.rutland, devicetree, Rafael J . Wysocki
In-Reply-To: <20200519084800.GG1094@ninjato>
[-- Attachment #1: Type: text/plain, Size: 470 bytes --]
On Tue, May 19, 2020 at 10:48:00AM +0200, Wolfram Sang wrote:
> On Tue, May 19, 2020 at 03:27:28PM +0800, Bibby Hsieh wrote:
> > In some platforms, they disable the power-supply of i2c due
> > to power consumption reduction. This patch add bus-supply property.
> >
> > Signed-off-by: Bibby Hsieh <bibby.hsieh@mediatek.com>
> > Acked-by: Rob Herring <robh@kernel.org>
>
> Applied to for-next, thanks!
Reverted because of regression reports in linux-next.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
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