* [PATCH 2/2] iommu/mediatek: Convert M4Uv1 to iommu_fwspec
From: Honghui Zhang @ 2016-10-19 7:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <a40dbcc1ff40bf09483316354d2fdcb2d432eb81.1476704508.git.robin.murphy@arm.com>
On Mon, 2016-10-17 at 12:49 +0100, Robin Murphy wrote:
> Our per-device data consists of the M4U instance and firmware-provided
> list of LARB IDs, which is a perfect fit for the generic iommu_fwspec
> machinery. Use that directly instead of the custom archdata code - while
> we can't rely on the of_xlate() mechanism to initialise things until the
> 32-bit ARM DMA code learns about groups and default domains, it still
> results in a reasonable simplification overall.
>
> CC: Honghui Zhang <honghui.zhang@mediatek.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Thanks Robin.
Tested-by: Honghui Zhang <honghui.zhang@mediatek.com>
> ---
> drivers/iommu/mtk_iommu.h | 6 ---
> drivers/iommu/mtk_iommu_v1.c | 95 +++++++++++++++++---------------------------
> 2 files changed, 36 insertions(+), 65 deletions(-)
>
^ permalink raw reply
* [PATCH] Revert "gpio/mvebu: convert to use irq_domain_add_simple()"
From: Gregory CLEMENT @ 2016-10-19 7:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476831396-24359-1-git-send-email-jgunthorpe@obsidianresearch.com>
Hi Jason,
On mer., oct. 19 2016, Jason Gunthorpe <jgunthorpe@obsidianresearch.com> wrote:
> This reverts commit ce931f571b6dcf8534e8740e8cd16565cf362536.
>
> The only difference betwen _simple and _legacy is that _simple
> calls irq_alloc_descs, however mvebu_gpio_probe already called
> irq_alloc_descs a few lines above.
And what about removing the irq_alloc_descs ?
Going back to use the _legacy version seems wrong for me.
Gregory
>
> This fixes these kernel error messages from the double call
> to irq_alloc_descs:
>
> irq: Cannot allocate irq_descs @ IRQ34, assuming pre-allocated
> irq: Cannot allocate irq_descs @ IRQ66, assuming pre-allocated
>
> Cc: Rob Herring <rob.herring@calxeda.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> Cc: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
> Cc: Andrew Lunn <andrew@lunn.ch>
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Fixes: ce931f571b6d ("gpio/mvebu: convert to use irq_domain_add_simple()")
> Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
> ---
> drivers/gpio/gpio-mvebu.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
> index cd5dc27320a2..2e0c8d8b7792 100644
> --- a/drivers/gpio/gpio-mvebu.c
> +++ b/drivers/gpio/gpio-mvebu.c
> @@ -807,8 +807,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
> IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
>
> /* Setup irq domain on top of the generic chip. */
> - mvchip->domain = irq_domain_add_simple(np, mvchip->chip.ngpio,
> - mvchip->irqbase,
> + mvchip->domain = irq_domain_add_legacy(np, mvchip->chip.ngpio,
> + mvchip->irqbase, 0,
> &irq_domain_simple_ops,
> mvchip);
> if (!mvchip->domain) {
> --
> 2.1.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply
* [PATCH] ARM: dts: am335x-baltos-ir5221: use both musb channels in host mode
From: yegorslists at googlemail.com @ 2016-10-19 7:09 UTC (permalink / raw)
To: linux-arm-kernel
From: Yegor Yefremov <yegorslists@googlemail.com>
Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
---
arch/arm/boot/dts/am335x-baltos-ir5221.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/am335x-baltos-ir5221.dts b/arch/arm/boot/dts/am335x-baltos-ir5221.dts
index d0faa7b..f599350 100644
--- a/arch/arm/boot/dts/am335x-baltos-ir5221.dts
+++ b/arch/arm/boot/dts/am335x-baltos-ir5221.dts
@@ -114,7 +114,7 @@
&usb1 {
status = "okay";
- dr_mode = "otg";
+ dr_mode = "host";
};
&cpsw_emac0 {
--
2.1.4
^ permalink raw reply related
* [PATCH v9 2/2] ARM: dts: add TOPEET itop elite based board
From: Krzysztof Kozlowski @ 2016-10-19 5:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <58DB0A67-6C74-409B-80B2-9F02492D3A55@soulik.info>
On Wed, Oct 19, 2016 at 4:15 AM, Ayaka <ayaka@soulik.info> wrote:
>
>
> ??? iPad ??
>
>> Krzysztof Kozlowski <krzk@kernel.org> ? 2016?10?19? ??1:37 ???
>>
>>> On Wed, Oct 19, 2016 at 01:18:49AM +0800, Randy Li wrote:
>>> The TOPEET itop exynos 4412 have three versions base board. The
>>> Elite version is the cheap one without too much peripheral devices
>>> on it.
>>>
>>> Currently supported are serial console, wired networking(USB),
>>> USB OTG in peripheral mode, USB host, SD storage, GPIO buttons,
>>> PWM beeper, ADC and LEDs. The WM8960 analog audio codec is also
>>> enabled.
>>>
>>> The FIMC is not used for camera currently, I enabled it just for a
>>> colorspace converter.
>>>
>>> Signed-off-by: Randy Li <ayaka@soulik.info>
>>> Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
>>
>> Thanks, applied, with missing Rob's ack, minor changes in commit msg and
>> fix in pin function (you used macro for pull up/down instead of
>> function).
> The last time I saw the other dts have applied that, but they are not now. A header file is also missed reported by kbuild, but I didn't meet that.
I wonder why I didn't encounter the build error on my machine... This
needs a follow up fix.
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH 3/3] ARM: socfpga: defconfig: enable qspi
From: Steffen Trumtrar @ 2016-10-19 5:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.02.1610181600570.27375@linux-builds1>
On Tue, Oct 18, 2016 at 04:03:01PM -0500, Dinh Nguyen wrote:
> On Tue, 18 Oct 2016, Steffen Trumtrar wrote:
>
> > Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
> > ---
> > arch/arm/configs/socfpga_defconfig | 3 +++
> > 1 file changed, 3 insertions(+)
> >
> > diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig
> > index 9f84be5b3ac5..466050663c86 100644
> > --- a/arch/arm/configs/socfpga_defconfig
> > +++ b/arch/arm/configs/socfpga_defconfig
>
> Thanks Steffen, all patches applied. I'll fixup the commit header for the DTS
> patches. The arm-soc maintainers prefer the DTS patches to be:
>
> "ARM: dts: <platform>"
Oops.
Thanks,
Steffen
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* [PATCH 4/4] i2c: digicolor: Fix module autoload
From: Baruch Siach @ 2016-10-19 5:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476824508-4679-5-git-send-email-javier@osg.samsung.com>
Hi Javier Martinez Canillas,
On Tue, Oct 18, 2016 at 06:01:48PM -0300, Javier Martinez Canillas wrote:
> If the driver is built as a module, autoload won't work because the module
> alias information is not filled. So user-space can't match the registered
> device with the corresponding module.
>
> Export the module alias information using the MODULE_DEVICE_TABLE() macro.
>
> Before this patch:
>
> $ modinfo drivers/i2c/busses/i2c-digicolor.ko | grep alias
> $
>
> After this patch:
>
> $ modinfo drivers/i2c/busses/i2c-digicolor.ko | grep alias
> alias: of:N*T*Ccnxt,cx92755-i2cC*
> alias: of:N*T*Ccnxt,cx92755-i2c
>
> Signed-off-by: Javier Martinez Canillas <javier@osg.samsung.com>
Acked-by: Baruch Siach <baruch@tkos.co.il>
Thanks,
baruch
> drivers/i2c/busses/i2c-digicolor.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c
> index 9604024e0eb0..49f2084f7bb5 100644
> --- a/drivers/i2c/busses/i2c-digicolor.c
> +++ b/drivers/i2c/busses/i2c-digicolor.c
> @@ -368,6 +368,7 @@ static const struct of_device_id dc_i2c_match[] = {
> { .compatible = "cnxt,cx92755-i2c" },
> { },
> };
> +MODULE_DEVICE_TABLE(of, dc_i2c_match);
>
> static struct platform_driver dc_i2c_driver = {
> .probe = dc_i2c_probe,
--
http://baruch.siach.name/blog/ ~. .~ Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{=
- baruch at tkos.co.il - tel: +972.52.368.4656, http://www.tkos.co.il -
^ permalink raw reply
* [PATCH 4/9] regulator: lp873x: Add support for populating input supply
From: Lokesh Vutla @ 2016-10-19 4:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161018142743.xfgjuaw4wlssmoxq@rob-hp-laptop>
On Tuesday 18 October 2016 07:57 PM, Rob Herring wrote:
> On Fri, Oct 14, 2016 at 06:30:28PM +0530, Lokesh Vutla wrote:
>> In order to have a proper topology of regulators for a platform, each
>> registering regulator needs to populate supply_name field for identifying
>> its supply's name. Add supply_name field for lp873x regulators.
>>
>> Cc: Lee Jones <lee.jones@linaro.org>
>> Cc: Keerthy <j-keerthy@ti.com>
>> Signed-off-by: Lokesh Vutla <lokeshvutla@ti.com>
>> ---
>> Documentation/devicetree/bindings/mfd/lp873x.txt | 8 ++++++++
>> drivers/regulator/lp873x-regulator.c | 1 +
>> 2 files changed, 9 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/lp873x.txt b/Documentation/devicetree/bindings/mfd/lp873x.txt
>> index 52766c2..936cba3 100644
>> --- a/Documentation/devicetree/bindings/mfd/lp873x.txt
>> +++ b/Documentation/devicetree/bindings/mfd/lp873x.txt
>> @@ -7,6 +7,9 @@ Required properties:
>> - #gpio-cells: Should be two. The first cell is the pin number and
>> the second cell is used to specify flags.
>> See ../gpio/gpio.txt for more information.
>> + - xxx-supply: Phandle to parent supply node of each regulator
>> + populated under regulators node. xxx should match
>> + the supply_name populated in driver.
>
> xxx-in-supply?
Oops. Right. Ill update it and repost.
Thanks and regards,
Lokesh
^ permalink raw reply
* [PATCH] i2c: uniphier[-f]: fix bool logic calculation
From: Masahiro Yamada @ 2016-10-19 4:38 UTC (permalink / raw)
To: linux-arm-kernel
This code is working, but it should not depend on how "bool" is
typedef'ed, or the bit position of I2C_M_RD.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
---
drivers/i2c/busses/i2c-uniphier-f.c | 2 +-
drivers/i2c/busses/i2c-uniphier.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c
index db9105e..b54448e 100644
--- a/drivers/i2c/busses/i2c-uniphier-f.c
+++ b/drivers/i2c/busses/i2c-uniphier-f.c
@@ -309,7 +309,7 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
struct i2c_msg *msg, bool stop)
{
struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
- bool is_read = msg->flags & I2C_M_RD;
+ bool is_read = !!(msg->flags & I2C_M_RD);
unsigned long time_left;
dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n",
diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c
index 56e92af..cc80bb2 100644
--- a/drivers/i2c/busses/i2c-uniphier.c
+++ b/drivers/i2c/busses/i2c-uniphier.c
@@ -177,7 +177,7 @@ static int uniphier_i2c_stop(struct i2c_adapter *adap)
static int uniphier_i2c_master_xfer_one(struct i2c_adapter *adap,
struct i2c_msg *msg, bool stop)
{
- bool is_read = msg->flags & I2C_M_RD;
+ bool is_read = !!(msg->flags & I2C_M_RD);
bool recovery = false;
int ret;
--
1.9.1
^ permalink raw reply related
* [PATCH] ARM: dts: socfpga: enable qspi on the Cyclone5 devkit
From: dinguyen at opensource.altera.com @ 2016-10-19 4:11 UTC (permalink / raw)
To: linux-arm-kernel
From: Dinh Nguyen <dinguyen@opensource.altera.com>
Enable the qspi controller on the devkit and add the flash chip.
Signed-off-by: Dinh Nguyen <dinguyen@opensource.altera.com>
---
arch/arm/boot/dts/socfpga_cyclone5_socdk.dts | 32 ++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
index 15e43f4..a0868e9 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
+++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts
@@ -87,6 +87,38 @@
status = "okay";
};
+&qspi {
+ status = "okay";
+
+ flash0: n25q00 at 0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "n25q00";
+ reg = <0>; /* chip select */
+ spi-max-frequency = <100000000>;
+
+ cdns,page-size = <256>;
+ cdns,block-size = <16>;
+ cdns,read-delay = <4>;
+ cdns,tshsl-ns = <50>;
+ cdns,tsd2d-ns = <50>;
+ cdns,tchsh-ns = <4>;
+ cdns,tslch-ns = <4>;
+
+ partition at qspi-boot {
+ /* 8MB for raw data. */
+ label = "Flash 0 Raw Data";
+ reg = <0x0 0x800000>;
+ };
+
+ partition at qspi-rootfs {
+ /* 120MB for jffs2 data. */
+ label = "Flash 0 jffs2 Filesystem";
+ reg = <0x800000 0x7800000>;
+ };
+ };
+};
+
&usb1 {
status = "okay";
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH 2/3] clk: hisilicon: add CRG driver for Hi3516CV300 SoC
From: Jiancheng Xue @ 2016-10-19 3:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAL_JsqK18RHFhDSWA_j+v_pJL6vk+a=GD7oo6O3JJaV4hHHEBg@mail.gmail.com>
? 2016/10/19 10:45, Rob Herring ??:
> On Tue, Oct 18, 2016 at 9:38 PM, Jiancheng Xue
> <xuejiancheng@hisilicon.com> wrote:
>>
>>
>> ? 2016/10/18 23:58, Rob Herring ??:
>>> On Mon, Oct 17, 2016 at 08:07:04PM +0800, Pan Wen wrote:
>>>> Add CRG driver for Hi3516CV300 SoC. CRG(Clock and Reset
>>>> Generator) module generates clock and reset signals used
>>>> by other module blocks on SoC.
>>>>
>>>> Signed-off-by: Pan Wen <wenpan@hisilicon.com>
>>>> ---
>>>> .../devicetree/bindings/clock/hisi-crg.txt | 50 ++++
>>>> drivers/clk/hisilicon/Kconfig | 8 +
>>>> drivers/clk/hisilicon/Makefile | 1 +
>>>> drivers/clk/hisilicon/crg-hi3516cv300.c | 330 +++++++++++++++++++++
>>>> drivers/clk/hisilicon/crg.h | 34 +++
>>>> include/dt-bindings/clock/hi3516cv300-clock.h | 48 +++
>>>> 6 files changed, 471 insertions(+)
>>>> create mode 100644 Documentation/devicetree/bindings/clock/hisi-crg.txt
>>>> create mode 100644 drivers/clk/hisilicon/crg-hi3516cv300.c
>>>> create mode 100644 drivers/clk/hisilicon/crg.h
>>>> create mode 100644 include/dt-bindings/clock/hi3516cv300-clock.h
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/clock/hisi-crg.txt b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>>>> new file mode 100644
>>>> index 0000000..cc60b3d
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>>>> @@ -0,0 +1,50 @@
>>>> +* HiSilicon Clock and Reset Generator(CRG)
>>>
>>> Seems kind of generic given there's already various HiSi clock bindings
>>> documented.
>>>
>>>> +
>>>> +The CRG module provides clock and reset signals to various
>>>> +modules within the SoC.
>>>> +
>>>> +This binding uses the following bindings:
>>>> + Documentation/devicetree/bindings/clock/clock-bindings.txt
>>>> + Documentation/devicetree/bindings/reset/reset.txt
>>>> +
>>>> +Required Properties:
>>>> +
>>>> +- compatible: should be one of the following.
>>>> + - "hisilicon,hi3516cv300-crg"
>>>> + - "hisilicon,hi3516cv300-sysctrl"
>>>> + - "hisilicon,hi3519-crg"
>>>
>>> There is already a binding for this. Please merge them.
>>>
>> Hi Rob,
>>
>> Pan Wen and I work together. There's really a same file included in the patch
>> https://lkml.org/lkml/2016/9/18/42 ([PATCH v2] clk: hisilicon: add CRG driver for Hi3798CV200 SoC).
>> But that patch has not been acked. This binding file will be merged if that
>> patch is accepted first. Could you give me more comments on that patch or
>> help me to ack it? Thank you very much.
>
> If I haven't commented, then likely it was not sent to the DT list.
Hi,
I'm pretty sure that the patch was sent to the DT list devicetree at vger.kernel.org.
You had asked a question about "hi3798cv200-sysctrl" and I replied (https://lkml.org/lkml/2016/10/10/517).
I'm waiting for your new comments. If there's some misunderstatnding, please let me know.
Thanks,
Jiancheng
>
> Rob
>
> .
>
^ permalink raw reply
* [PATCH v2] ARM: dts: rockchip: temporarily remove emmc hs200 speed from rk3288-veyron-speedy.
From: Vagrant Cascadian @ 2016-10-19 3:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476824417.1031.9.camel@paulk.fr>
On 2016-10-18, Paul Kocialkowski wrote:
> Le mardi 18 octobre 2016 ? 11:21 +0200, Heiko St?bner a ?crit?:
>> Am Sonntag, 16. Oktober 2016, 21:49:43 schrieb Paul Kocialkowski:
>> > Le mardi 27 septembre 2016 ? 13:53 -0700, Vagrant Cascadian a ?crit :
>> > >
>> > > This essentially mimics what was done with rk3288-veyron-minnie in
>> > > commit 984926781122f034d5bc9962815d135b6c4a8e1d.
>> > >
>> > > The eMMC of the speedy Chromebook also appears to need the same tuning
>> > > workaround, as it frequently fails to recognize the eMMC without it.
>> >
>> > I have a device where (without this patch) eMMC sometimes fails, with:
>> > [????3.561010] dwmmc_rockchip ff0f0000.dwmmc: Successfully tuned phase to
>> > 175 [????3.571742] mmc2: new HS200 MMC card at address 0001
>> > [????3.571943] mmcblk2: mmc2:0001 HAG2e 14.7 GiB?
>> > [????3.572026] mmcblk2boot0: mmc2:0001 HAG2e partition 1 4.00 MiB
>> > [????3.572107] mmcblk2boot1: mmc2:0001 HAG2e partition 2 4.00 MiB
>> > [????3.572181] mmcblk2rpmb: mmc2:0001 HAG2e partition 3 4.00 MiB
>> > [????3.685647] mmcblk2: error -110 transferring data, sector 0, nr 8, cmd
>> > response 0x900, card status 0x0
>> > And sometimes works, with:
>> > [????3.451058] dwmmc_rockchip ff0f0000.dwmmc: Successfully tuned phase to
>> > 176 [????3.491093] mmc2: new HS200 MMC card at address 0001
>> > [????3.491277] mmcblk2: mmc2:0001 HAG2e 14.7 GiB?
>> > [????3.491345] mmcblk2boot0: mmc2:0001 HAG2e partition 1 4.00 MiB
>> > [????3.491409] mmcblk2boot1: mmc2:0001 HAG2e partition 2 4.00 MiB
>> > [????3.491474] mmcblk2rpmb: mmc2:0001 HAG2e partition 3 4.00 MiB
>> > [????3.493548]??mmcblk2: p1 p2
This is similar behavior to my veyron-speedy. Here are several boot logs
>From running 4.8.0-rc7, with some failures and some successes:
https://cascadia.aikidev.net/~vagrant/veyron-speedy/
>> > However, with this change, it always fails, with:
>> > [????3.322129] mmc_host mmc2: Bus speed (slot 0) = 50000000Hz (slot req
>> > 52000000Hz, actual 50000000HZ div = 0) [????3.333174] mmc2: error -110
>> > whilst initialising MMC card
>> >
>> > I don't have so much time to investigate this issue, but it's clear that
>> > this patch doesn't fix the issue (and actually worsens it) for my device.
Well, that makes things more complicated.
>> As discussed on IRC we now have varying reports of the emmc working or not?
>> working with and without that patch applied. So it's not really a bandaid fix?
>> and I've thus dropped this patch again.
>
> Thanks for dropping it! For the record, my eMMC shows up as:
> mmcblk2: mmc2:0001 HAG2e 14.7 GiB
Mine looks similar, although reporting as mmc0:
[ 3.166550] mmcblk0: mmc0:0001 HAG2e 14.7 GiB
> Maybe it could help to share what each tested device reports as eMMC model and
> associate that with the current behavior, in spite of getting a clearer idea of
> what issue affects what model.
FWIW, I'm using a veyron-speedy with 4GB of ram, not sure what other
information might be useful to distinguish between different models.
On the bottom of the case, it claims to be a C201P. Near the serial,
it's marked as C201PA-DS02-LG.
live well,
vagrant
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 800 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161018/643b245b/attachment.sig>
^ permalink raw reply
* [PATCH v2] ARM: bcm2835: Add names for the Raspberry Pi GPIO lines
From: Eric Anholt @ 2016-10-19 3:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAPoCmYJC1TebBrspD_=mTETULSjg9or5a0Yda8p945y6ZWL99Q@mail.gmail.com>
Gottfried Haider <gottfried.haider@gmail.com> writes:
> Hi Eric, Linus,
>
> I'll hopefully find time to look at the more recent changes to the gpio
> subsystem (lsgpio?!), but since this patch is up for discussion now - what
> I was wondering: how does this change relate to /sys/class/gpio/gpio%d? Is
> this completely orthogonal - or would this change the sysfs interface as
> well?
>
> Regarding the proposed format using the header pin numbers: From what I've
> seen in terms of existing educational materials, it seems the overwhelming
> majority ends up using GPIO numbers instead of physical pin header
> numbering. (e.g. [1] [2])
> Would it be too confusing to try to pick GPIO 5 from an alphabetically
> sorted list like this "P11_GPIO17", "P12_GPIO18"? (I know, alphabetical
> sorting is an issue here already for a different reason. But applications
> might do it, I guess?)
I added the pin numbers because it was a consistent response to the
first version. I do think the GPIO numbers without pin numbers would be
the most clear.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 800 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161018/cae67ff7/attachment.sig>
^ permalink raw reply
* [RFC PATCH] mtd: nand: Add OX820 NAND Support
From: Rob Herring @ 2016-10-19 3:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161018090927.1990-1-narmstrong@baylibre.com>
On Tue, Oct 18, 2016 at 11:09:27AM +0200, Neil Armstrong wrote:
> Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
> This is a simple memory mapped NAND controller with single chip select and
> software ECC.
>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
> .../devicetree/bindings/mtd/oxnas-nand.txt | 24 ++++
Acked-by: Rob Herring <robh@kernel.org>
> drivers/mtd/nand/Kconfig | 5 +
> drivers/mtd/nand/Makefile | 1 +
> drivers/mtd/nand/oxnas_nand.c | 144 +++++++++++++++++++++
> 4 files changed, 174 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
> create mode 100644 drivers/mtd/nand/oxnas_nand.c
^ permalink raw reply
* [PATCH v2 0/8] crypto: ARM/arm64 - big endian fixes
From: Herbert Xu @ 2016-10-19 3:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKv+Gu9wuXnrq77a3Zk0GnHgnkpURh=EegwgP+vAwMC=rdm3qA@mail.gmail.com>
On Tue, Oct 18, 2016 at 01:14:38PM +0100, Ard Biesheuvel wrote:
> On 18 October 2016 at 12:49, Catalin Marinas <catalin.marinas@arm.com> wrote:
> > On Tue, Oct 11, 2016 at 07:15:12PM +0100, Ard Biesheuvel wrote:
> >> As it turns out, none of the accelerated crypto routines under arch/arm64/crypto
> >> currently work, or have ever worked correctly when built for big endian. So this
> >> series fixes all of them. This v2 now includes a similar fix for 32-bit ARM as
> >> well, and an additional fix for XTS which escaped my attention before.
> >>
> >> Each of these patches carries a fixes tag, and could be backported to stable.
> >> However, for patches #1 and #5, the fixes tag denotes the oldest commit that the
> >> fix is compatible with, not the patch that introduced the algorithm.
> >
> > I think for future reference, the Fixes tag should denote the commit
> > that introduced the issue. An explicit Cc: stable tag would state how
> > far back it should be applied.
> >
>
> OK, that sounds reasonable.
>
> >> Ard Biesheuvel (8):
> >> crypto: arm64/aes-ce - fix for big endian
> >> crypto: arm64/ghash-ce - fix for big endian
> >> crypto: arm64/sha1-ce - fix for big endian
> >> crypto: arm64/sha2-ce - fix for big endian
> >> crypto: arm64/aes-ccm-ce: fix for big endian
> >> crypto: arm64/aes-neon - fix for big endian
> >> crypto: arm64/aes-xts-ce: fix for big endian
> >> crypto: arm/aes-ce - fix for big endian
> >
> > The changes look fine to me but I can't claim I fully understand these
> > algorithms. FWIW:
> >
> > Acked-by: Catalin Marinas <catalin.marinas@arm.com>
> >
> > (Will may pick them up for 4.9-rcX)
>
> Thanks, although I was kind of expecting Herbert to pick these up,
> given that #8 affects ARM not arm64.
>
> But if you (or Will) can pick up #1 to #7, that is also fine, then I
> can drop #8 into rmk's patch database.
I was planning merging these for 4.10. But I'm fine with them
going through the arm tree. Let me know what you guys want to
do.
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* [PATCH] mfd: axp20x-i2c: Add i2c-ids to fix module auto-loading
From: Sebastian Reichel @ 2016-10-19 2:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161019025154.rmw56aoh27wbrene@earth>
Hi,
On Wed, Oct 19, 2016 at 04:51:55AM +0200, Sebastian Reichel wrote:
> > diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
> > index b1b8658..d35a5fe 100644
> > --- a/drivers/mfd/axp20x-i2c.c
> > +++ b/drivers/mfd/axp20x-i2c.c
> > @@ -69,10 +69,11 @@ static const struct of_device_id axp20x_i2c_of_match[] = {
> > };
> > MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match);
> >
> > -/*
> > - * This is useless for OF-enabled devices, but it is needed by I2C subsystem
> > - */
> > static const struct i2c_device_id axp20x_i2c_id[] = {
> > + { "axp152", 0 },
> > + { "axp202", 0 },
> > + { "axp209", 0 },
> > + { "axp221", 0 },
> > { },
> > };
> > MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
>
> Thanks, queued.
My mistake. It should obviously go through mfd. So take this instead:
Acked-By: Sebastian Reichel <sre@kernel.org>
-- Sebastian
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161019/aa748c19/attachment.sig>
^ permalink raw reply
* [PATCH] mfd: axp20x-i2c: Add i2c-ids to fix module auto-loading
From: Sebastian Reichel @ 2016-10-19 2:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161005155112.13774-2-hdegoede@redhat.com>
Hi,
On Wed, Oct 05, 2016 at 05:51:12PM +0200, Hans de Goede wrote:
> The i2c subsys does not load modules by compatible, only by
> i2c-id, with e.g. a modalias of: "i2c:axp209".
>
> Populate the axp20x_i2c_id[] table with supported ids, so that
> module auto-loading will work.
>
> Reported-by: Dennis Gilmore <dennis@ausil.us>
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
> drivers/mfd/axp20x-i2c.c | 7 ++++---
> 1 file changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
> index b1b8658..d35a5fe 100644
> --- a/drivers/mfd/axp20x-i2c.c
> +++ b/drivers/mfd/axp20x-i2c.c
> @@ -69,10 +69,11 @@ static const struct of_device_id axp20x_i2c_of_match[] = {
> };
> MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match);
>
> -/*
> - * This is useless for OF-enabled devices, but it is needed by I2C subsystem
> - */
> static const struct i2c_device_id axp20x_i2c_id[] = {
> + { "axp152", 0 },
> + { "axp202", 0 },
> + { "axp209", 0 },
> + { "axp221", 0 },
> { },
> };
> MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
Thanks, queued.
-- Sebastian
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161019/fe135abd/attachment.sig>
^ permalink raw reply
* [PATCH v2] arm64: kernel: numa: fix ACPI boot cpu numa node mapping
From: Leizhen (ThunderTown) @ 2016-10-19 2:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <728ef882-b1ee-9518-d291-ee475e9006eb@linaro.org>
On 2016/10/18 16:39, Hanjun Guo wrote:
> On 2016/10/17 22:56, Lorenzo Pieralisi wrote:
>> Commit 7ba5f605f3a0 ("arm64/numa: remove the limitation that cpu0 must
>> bind to node0") removed the numa cpu<->node mapping restriction whereby
>> logical cpu 0 always corresponds to numa node 0; removing the
>> restriction was correct, in that it does not really exist in practice
>> but the commit only updated the early mapping of logical cpu 0 to its
>> real numa node for the DT boot path, missing the ACPI one, leading to
>> boot failures on ACPI systems owing to missing cpu<->node map for
>> logical cpu 0.
>>
>> Fix the issue by updating the ACPI boot path with code that carries out
>> the early cpu<->node mapping also for the boot cpu (ie cpu 0), mirroring
>> what is currently done in the DT boot path.
>>
>> Fixes: 7ba5f605f3a0 ("arm64/numa: remove the limitation that cpu0 must bind to node0")
>> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
>> Tested-by: Laszlo Ersek <lersek@redhat.com>
>> Reported-by: Laszlo Ersek <lersek@redhat.com>
>> Cc: Will Deacon <will.deacon@arm.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Hanjun Guo <hanjun.guo@linaro.org>
>
> Thanks for the quick response and fix,
>
> Acked-by: Hanjun Guo <hanjun.guo@linaro.org>
>
> By the way, I got another boot failure [1] when we have multi
> NUMA nodes system with some memory-less nodes (only one node
> have memory), we are looking into it now, this patch needs
> to be merged first.
You should apply my numa MEMORYLESS patches first, because the two patches have not been upstreamed yet.
I just tested it base on 4.9-rc1 for dt numa, it worked well. I will connect you to check what's wrong on ACPI numa.
>
> Thanks
> Hanjun
>
> [1]: boot failure log:
> [ 0.000000] NUMA: Adding memblock [0x0 - 0x3fffffff] on node 0
> [ 0.000000] ACPI: SRAT: Node 0 PXM 0 [mem 0x00000000-0x3fffffff]
> [ 0.000000] NUMA: Adding memblock [0x1400000000 - 0x17ffffffff] on node 1
> [ 0.000000] ACPI: SRAT: Node 1 PXM 1 [mem 0x1400000000-0x17ffffffff]
> [ 0.000000] NUMA: Adding memblock [0x1000000000 - 0x13ffffffff] on node 0
> [ 0.000000] ACPI: SRAT: Node 0 PXM 0 [mem 0x1000000000-0x13ffffffff]
> [ 0.000000] NUMA: Initmem setup node 0 [mem 0x00000000-0x13fbffffff]
> [ 0.000000] NUMA: NODE_DATA [mem 0x13fbffe500-0x13fbffffff]
> [ 0.000000] NUMA: Initmem setup node 1 [mem 0x1400000000-0x17fbffffff]
> [ 0.000000] NUMA: NODE_DATA [mem 0x17fbfec500-0x17fbfedfff]
> [ 0.000000] NUMA: Initmem setup node 2 [mem 0x00000000-0xffffffffffffffff]
> [ 0.000000] NUMA: NODE_DATA [mem 0x17fbfeaa00-0x17fbfec4ff]
> [ 0.000000] NUMA: NODE_DATA(2) on node 1
> [ 0.000000] NUMA: Initmem setup node 3 [mem 0x00000000-0xffffffffffffffff]
> [ 0.000000] NUMA: NODE_DATA [mem 0x17fbfe8f00-0x17fbfea9ff]
> [ 0.000000] NUMA: NODE_DATA(3) on node 1
> [ 0.000000] Zone ranges:
> [ 0.000000] DMA [mem 0x0000000000000000-0x00000000ffffffff]
> [ 0.000000] Normal [mem 0x0000000100000000-0x00000017fbffffff]
> [ 0.000000] Movable zone start for each node
> [ 0.000000] Early memory node ranges
> [ 0.000000] node 0: [mem 0x0000000000000000-0x0000000000024fff]
> [ 0.000000] node 0: [mem 0x0000000000026000-0x00000000319dffff]
> [ 0.000000] node 0: [mem 0x00000000319e0000-0x0000000031a4ffff]
> [ 0.000000] node 0: [mem 0x0000000031a50000-0x0000000031b2ffff]
> [ 0.000000] node 0: [mem 0x0000000031b30000-0x0000000031b3ffff]
> [ 0.000000] node 0: [mem 0x0000000031b40000-0x0000000039baffff]
> [ 0.000000] node 0: [mem 0x0000000039bb0000-0x000000003a143fff]
> [ 0.000000] node 0: [mem 0x000000003a144000-0x000000003f12ffff]
> [ 0.000000] node 0: [mem 0x000000003f130000-0x000000003f15ffff]
> [ 0.000000] node 0: [mem 0x000000003f160000-0x000000003fbfffff]
> [ 0.000000] node 0: [mem 0x0000001040000000-0x00000013fbffffff]
> [ 0.000000] node 1: [mem 0x0000001400000000-0x00000017fbffffff]
> [ 0.000000] Initmem setup node 0 [mem 0x0000000000000000-0x00000013fbffffff]
> [ 0.000000] Initmem setup node 1 [mem 0x0000001400000000-0x00000017fbffffff]
> [ 0.000000] Could not find start_pfn for node 2
> [ 0.000000] Initmem setup node 2 [mem 0x0000000000000000-0x0000000000000000]
> [ 0.000000] Could not find start_pfn for node 3
> [ 0.000000] Initmem setup node 3 [mem 0x0000000000000000-0x0000000000000000]
> [ 0.000000] psci: probing for conduit method from ACPI.
> [ 0.000000] ------------[ cut here ]------------
> [ 0.000000] kernel BUG at mm/percpu.c:1916!
> [ 0.000000] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP
> [ 0.000000] Modules linked in:
> [ 0.000000] CPU: 0 PID: 0 Comm: swapper Not tainted 4.9.0-rc1-00083-g3dd62e5 #680
> [ 0.000000] Hardware name: Hisilicon Hi1616 Evaluation Board (DT)
> [ 0.000000] task: ffff000008d5e980 task.stack: ffff000008d50000
> [ 0.000000] PC is at pcpu_embed_first_chunk+0x464/0x754
> [ 0.000000] LR is at pcpu_embed_first_chunk+0x3f8/0x754
> [ 0.000000] pc : [<ffff000008c65af0>] lr : [<ffff000008c65a84>] pstate: 200000c5
> [ 0.000000] sp : ffff000008d53e90
> [ 0.000000] x29: ffff000008d53e90 [ 0.000000] x28: 0000000000000000
> [ 0.000000]
> [ 0.000000] x27: ffff000008d55e50 [ 0.000000] x26: 0000000000000042
> [ 0.000000]
> [ 0.000000] x25: ffff000008d55d28 [ 0.000000] x24: 0000000000000046
> [ 0.000000]
> [ 0.000000] x23: 0000000000000040 [ 0.000000] x22: ffff8017fbfcff00
> [ 0.000000]
> [ 0.000000] x21: ffff000008ca6e20 [ 0.000000] x20: ffff8017fbfd0518
> [ 0.000000]
> [ 0.000000] x19: 0000000000000042 [ 0.000000] x18: ffff000008e3fb60
> [ 0.000000]
> [ 0.000000] x17: 000000000000001b [ 0.000000] x16: 000000000000000b
> [ 0.000000]
> [ 0.000000] x15: 0000001400000000 [ 0.000000] x14: 0000000000000004
> [ 0.000000]
> [ 0.000000] x13: 0000000000000000 [ 0.000000] x12: 0000000000000069
> [ 0.000000]
> [ 0.000000] x11: 00000017fbffff00 [ 0.000000] x10: 0000000000000004
> [ 0.000000]
> [ 0.000000] x9 : 0000000000000000 [ 0.000000] x8 : ffff8017fbfd0f00
> [ 0.000000]
> [ 0.000000] x7 : 0000000000000000 [ 0.000000] x6 : 0000000000000000
> [ 0.000000]
> [ 0.000000] x5 : 0000000000000000 [ 0.000000] x4 : 000000000000003f
> [ 0.000000]
> [ 0.000000] x3 : 0000000000000040 [ 0.000000] x2 : 0000000000000040
> [ 0.000000]
> [ 0.000000] x1 : 0000000000000001 [ 0.000000] x0 : ffff000008ca7328
> [ 0.000000]
> [ 0.000000]
> [ 0.000000] Process swapper (pid: 0, stack limit = 0xffff000008d50020)
> [ 0.000000] Stack: (0xffff000008d53e90 to 0xffff000008d54000)
> [ 0.000000] 3e80: ffff000008d53f60 ffff000008c5616c
> [ 0.000000] 3ea0: ffff000008ca5a08 ffff000008e2a000 ffff000008e2a000 ffff000008d55000
> [ 0.000000] 3ec0: ffff000008ca5a08 ffff8017fbfffe80 0000000000000168 000000003c96a518
> [ 0.000000] 3ee0: 000000003c971b98 0000000000c50018 ffff000008d53f60 ffff000008c56078
> [ 0.000000] 3f00: ffff000008d1f000 ffff000008d14000 0000000000007480 0000000000002000
> [ 0.000000] 3f20: ffff000008c560b0 0000000000001000 ffff000008d55e50 ffff000008d55d28
> [ 0.000000] 3f40: ffff000008ca6000 0000000000000040 0000000000000001 0000000000000040
> [ 0.000000] 3f60: ffff000008d53fa0 ffff000008c508d4 ffff000008ca5a08 ffff000008e2a000
> [ 0.000000] 3f80: ffff000008e2a000 ffff000008d55000 ffff000008ca5a08 ffff000008c508d0
> [ 0.000000] 3fa0: ffff000008d53ff0 ffff000008c501d8 000000003c94fa98 000000001e400000
> [ 0.000000] 3fc0: 000000001e400000 000000025497ba19 0000000000000000 000000003f198a08
> [ 0.000000] 3fe0: 0000000000000000 ffff000008ca5a08 0000000000000000 00000000008a325c
> [ 0.000000] Call trace:
> [ 0.000000] Exception stack(0xffff000008d53cc0 to 0xffff000008d53df0)
> [ 0.000000] 3cc0: 0000000000000042 0001000000000000 ffff000008d53e90 ffff000008c65af0
> [ 0.000000] 3ce0: ffff000008d53d30 ffff0000081aa024 0000000000000001 0000000000001000
> [ 0.000000] 3d00: ffff000008d53d30 ffff0000081aa034 0000000000000001 0000000000001000
> [ 0.000000] 3d20: 00000017fbfcff00 0000000000000004 ffff000008d53d90 ffff0000081aa2c8
> [ 0.000000] 3d40: 00000017fbfcff00 0000000000001000 0000000000000000 0000000000000000
> [ 0.000000] 3d60: ffff000008ca7328 0000000000000001 0000000000000040 0000000000000040
> [ 0.000000] 3d80: 000000000000003f 0000000000000000 0000000000000000 0000000000000000
> [ 0.000000] 3da0: ffff8017fbfd0f00 0000000000000000 0000000000000004 00000017fbffff00
> [ 0.000000] 3dc0: 0000000000000069 0000000000000000 0000000000000004 0000001400000000
> [ 0.000000] 3de0: 000000000000000b 000000000000001b
> [ 0.000000] [<ffff000008c65af0>] pcpu_embed_first_chunk+0x464/0x754
> [ 0.000000] [<ffff000008c5616c>] setup_per_cpu_areas+0x3c/0xcc
> [ 0.000000] [<ffff000008c508d4>] start_kernel+0x10c/0x398
> [ 0.000000] [<ffff000008c501d8>] __primary_switched+0x5c/0x64
> [ 0.000000] Code: 0b000318 17ffffd8 6b17031f 54000080 (d4210000)
> [ 0.000000] ---[ end trace 0000000000000000 ]---
> [ 0.000000] Kernel panic - not syncing: Attempted to kill the idle task!
> [ 0.000000] ---[ end Kernel panic - not syncing: Attempted to kill the idle task!
>
>
> .
>
^ permalink raw reply
* [v12, 0/8] Fix eSDHC host version register bug
From: Y.B. Lu @ 2016-10-19 2:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAPDyKFoit0sTPpfi2=AHcdZsDwOJxbBX68O-1jBFL=5JN0m6_w@mail.gmail.com>
+ Greg
Hi Greg,
I submitted this patchset for a MMC bug fix, and introduce the below patch which needs your ACK.
> > Arnd Bergmann (1):
> > base: soc: introduce soc_device_match() interface
https://patchwork.kernel.org/patch/9342913/
Could you help to review it and give some comments or ACK.
Thank you very much.
Best regards,
Yangbo Lu
> -----Original Message-----
> From: Ulf Hansson [mailto:ulf.hansson at linaro.org]
> Sent: Tuesday, October 18, 2016 6:48 PM
> To: Y.B. Lu
> Cc: linux-mmc; Scott Wood; Arnd Bergmann; linuxppc-dev at lists.ozlabs.org;
> devicetree at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org; linux-clk; linux-i2c at vger.kernel.org;
> iommu at lists.linux-foundation.org; netdev at vger.kernel.org; Mark Rutland;
> Rob Herring; Russell King; Jochen Friedrich; Joerg Roedel; Claudiu Manoil;
> Bhupesh Sharma; Qiang Zhao; Kumar Gala; Santosh Shilimkar; Leo Li; X.B.
> Xie; M.H. Lian
> Subject: Re: [v12, 0/8] Fix eSDHC host version register bug
>
> On 21 September 2016 at 08:57, Yangbo Lu <yangbo.lu@nxp.com> wrote:
> > This patchset is used to fix a host version register bug in the
> > T4240-R1.0-R2.0 eSDHC controller. To match the SoC version and
> > revision, 10 previous version patchsets had tried many methods but all
> of them were rejected by reviewers.
> > Such as
> > - dts compatible method
> > - syscon method
> > - ifdef PPC method
> > - GUTS driver getting SVR method Anrd suggested a
> > soc_device_match method in v10, and this is the only available method
> > left now. This v11 patchset introduces the soc_device_match interface
> > in soc driver.
> >
> > The first six patches of Yangbo are to add the GUTS driver. This is
> > used to register a soc device which contain soc version and revision
> information.
> > The other two patches introduce the soc_device_match method in soc
> > driver and apply it on esdhc driver to fix this bug.
> >
> > Arnd Bergmann (1):
> > base: soc: introduce soc_device_match() interface
> >
> > Yangbo Lu (7):
> > dt: bindings: update Freescale DCFG compatible
> > ARM64: dts: ls2080a: add device configuration node
> > dt: bindings: move guts devicetree doc out of powerpc directory
> > powerpc/fsl: move mpc85xx.h to include/linux/fsl
> > soc: fsl: add GUTS driver for QorIQ platforms
> > MAINTAINERS: add entry for Freescale SoC drivers
> > mmc: sdhci-of-esdhc: fix host version for T4240-R1.0-R2.0
> >
> > Documentation/devicetree/bindings/arm/fsl.txt | 6 +-
> > .../bindings/{powerpc => soc}/fsl/guts.txt | 3 +
> > MAINTAINERS | 11 +-
> > arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi | 6 +
> > arch/powerpc/kernel/cpu_setup_fsl_booke.S | 2 +-
> > arch/powerpc/sysdev/fsl_pci.c | 2 +-
> > drivers/base/Kconfig | 1 +
> > drivers/base/soc.c | 66 ++++++
> > drivers/clk/clk-qoriq.c | 3 +-
> > drivers/i2c/busses/i2c-mpc.c | 2 +-
> > drivers/iommu/fsl_pamu.c | 3 +-
> > drivers/mmc/host/Kconfig | 1 +
> > drivers/mmc/host/sdhci-of-esdhc.c | 20 ++
> > drivers/net/ethernet/freescale/gianfar.c | 2 +-
> > drivers/soc/Kconfig | 2 +-
> > drivers/soc/fsl/Kconfig | 19 ++
> > drivers/soc/fsl/Makefile | 1 +
> > drivers/soc/fsl/guts.c | 257
> +++++++++++++++++++++
> > include/linux/fsl/guts.h | 125 ++++++----
> > .../asm/mpc85xx.h => include/linux/fsl/svr.h | 4 +-
> > include/linux/sys_soc.h | 3 +
> > 21 files changed, 478 insertions(+), 61 deletions(-) rename
> > Documentation/devicetree/bindings/{powerpc => soc}/fsl/guts.txt (91%)
> > create mode 100644 drivers/soc/fsl/Kconfig create mode 100644
> > drivers/soc/fsl/guts.c rename arch/powerpc/include/asm/mpc85xx.h =>
> > include/linux/fsl/svr.h (97%)
> >
> > --
> > 2.1.0.27.g96db324
> >
>
> This looks good to me! I am not sure which tree you want this to be
> picked up through, but unless no other volunteers I can take it through
> my mmc tree.
>
> Although, before considering to apply, I need an ack from Scott/Arnd for
> the guts driver in patch 5/8 and I need an ack from Greg for patch 7/8,
> where the soc_device_match() interface is added (seems like you didn't
> add him on cc/to).
>
> Kind regards
> Uffe
^ permalink raw reply
* [PATCH 2/3] clk: hisilicon: add CRG driver for Hi3516CV300 SoC
From: Rob Herring @ 2016-10-19 2:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <7ce2e35b-19e1-9493-90a7-15b321fee2cc@hisilicon.com>
On Tue, Oct 18, 2016 at 9:38 PM, Jiancheng Xue
<xuejiancheng@hisilicon.com> wrote:
>
>
> ? 2016/10/18 23:58, Rob Herring ??:
>> On Mon, Oct 17, 2016 at 08:07:04PM +0800, Pan Wen wrote:
>>> Add CRG driver for Hi3516CV300 SoC. CRG(Clock and Reset
>>> Generator) module generates clock and reset signals used
>>> by other module blocks on SoC.
>>>
>>> Signed-off-by: Pan Wen <wenpan@hisilicon.com>
>>> ---
>>> .../devicetree/bindings/clock/hisi-crg.txt | 50 ++++
>>> drivers/clk/hisilicon/Kconfig | 8 +
>>> drivers/clk/hisilicon/Makefile | 1 +
>>> drivers/clk/hisilicon/crg-hi3516cv300.c | 330 +++++++++++++++++++++
>>> drivers/clk/hisilicon/crg.h | 34 +++
>>> include/dt-bindings/clock/hi3516cv300-clock.h | 48 +++
>>> 6 files changed, 471 insertions(+)
>>> create mode 100644 Documentation/devicetree/bindings/clock/hisi-crg.txt
>>> create mode 100644 drivers/clk/hisilicon/crg-hi3516cv300.c
>>> create mode 100644 drivers/clk/hisilicon/crg.h
>>> create mode 100644 include/dt-bindings/clock/hi3516cv300-clock.h
>>>
>>> diff --git a/Documentation/devicetree/bindings/clock/hisi-crg.txt b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>>> new file mode 100644
>>> index 0000000..cc60b3d
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>>> @@ -0,0 +1,50 @@
>>> +* HiSilicon Clock and Reset Generator(CRG)
>>
>> Seems kind of generic given there's already various HiSi clock bindings
>> documented.
>>
>>> +
>>> +The CRG module provides clock and reset signals to various
>>> +modules within the SoC.
>>> +
>>> +This binding uses the following bindings:
>>> + Documentation/devicetree/bindings/clock/clock-bindings.txt
>>> + Documentation/devicetree/bindings/reset/reset.txt
>>> +
>>> +Required Properties:
>>> +
>>> +- compatible: should be one of the following.
>>> + - "hisilicon,hi3516cv300-crg"
>>> + - "hisilicon,hi3516cv300-sysctrl"
>>> + - "hisilicon,hi3519-crg"
>>
>> There is already a binding for this. Please merge them.
>>
> Hi Rob,
>
> Pan Wen and I work together. There's really a same file included in the patch
> https://lkml.org/lkml/2016/9/18/42 ([PATCH v2] clk: hisilicon: add CRG driver for Hi3798CV200 SoC).
> But that patch has not been acked. This binding file will be merged if that
> patch is accepted first. Could you give me more comments on that patch or
> help me to ack it? Thank you very much.
If I haven't commented, then likely it was not sent to the DT list.
Rob
^ permalink raw reply
* [v12, 0/8] Fix eSDHC host version register bug
From: Y.B. Lu @ 2016-10-19 2:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAPDyKFoit0sTPpfi2=AHcdZsDwOJxbBX68O-1jBFL=5JN0m6_w@mail.gmail.com>
> -----Original Message-----
> From: Ulf Hansson [mailto:ulf.hansson at linaro.org]
> Sent: Tuesday, October 18, 2016 6:48 PM
> To: Y.B. Lu
> Cc: linux-mmc; Scott Wood; Arnd Bergmann; linuxppc-dev at lists.ozlabs.org;
> devicetree at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux-
> kernel at vger.kernel.org; linux-clk; linux-i2c at vger.kernel.org;
> iommu at lists.linux-foundation.org; netdev at vger.kernel.org; Mark Rutland;
> Rob Herring; Russell King; Jochen Friedrich; Joerg Roedel; Claudiu Manoil;
> Bhupesh Sharma; Qiang Zhao; Kumar Gala; Santosh Shilimkar; Leo Li; X.B.
> Xie; M.H. Lian
> Subject: Re: [v12, 0/8] Fix eSDHC host version register bug
>
> On 21 September 2016 at 08:57, Yangbo Lu <yangbo.lu@nxp.com> wrote:
> > This patchset is used to fix a host version register bug in the
> > T4240-R1.0-R2.0 eSDHC controller. To match the SoC version and
> > revision, 10 previous version patchsets had tried many methods but all
> of them were rejected by reviewers.
> > Such as
> > - dts compatible method
> > - syscon method
> > - ifdef PPC method
> > - GUTS driver getting SVR method Anrd suggested a
> > soc_device_match method in v10, and this is the only available method
> > left now. This v11 patchset introduces the soc_device_match interface
> > in soc driver.
> >
> > The first six patches of Yangbo are to add the GUTS driver. This is
> > used to register a soc device which contain soc version and revision
> information.
> > The other two patches introduce the soc_device_match method in soc
> > driver and apply it on esdhc driver to fix this bug.
> >
> > Arnd Bergmann (1):
> > base: soc: introduce soc_device_match() interface
> >
> > Yangbo Lu (7):
> > dt: bindings: update Freescale DCFG compatible
> > ARM64: dts: ls2080a: add device configuration node
> > dt: bindings: move guts devicetree doc out of powerpc directory
> > powerpc/fsl: move mpc85xx.h to include/linux/fsl
> > soc: fsl: add GUTS driver for QorIQ platforms
> > MAINTAINERS: add entry for Freescale SoC drivers
> > mmc: sdhci-of-esdhc: fix host version for T4240-R1.0-R2.0
> >
> > Documentation/devicetree/bindings/arm/fsl.txt | 6 +-
> > .../bindings/{powerpc => soc}/fsl/guts.txt | 3 +
> > MAINTAINERS | 11 +-
> > arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi | 6 +
> > arch/powerpc/kernel/cpu_setup_fsl_booke.S | 2 +-
> > arch/powerpc/sysdev/fsl_pci.c | 2 +-
> > drivers/base/Kconfig | 1 +
> > drivers/base/soc.c | 66 ++++++
> > drivers/clk/clk-qoriq.c | 3 +-
> > drivers/i2c/busses/i2c-mpc.c | 2 +-
> > drivers/iommu/fsl_pamu.c | 3 +-
> > drivers/mmc/host/Kconfig | 1 +
> > drivers/mmc/host/sdhci-of-esdhc.c | 20 ++
> > drivers/net/ethernet/freescale/gianfar.c | 2 +-
> > drivers/soc/Kconfig | 2 +-
> > drivers/soc/fsl/Kconfig | 19 ++
> > drivers/soc/fsl/Makefile | 1 +
> > drivers/soc/fsl/guts.c | 257
> +++++++++++++++++++++
> > include/linux/fsl/guts.h | 125 ++++++----
> > .../asm/mpc85xx.h => include/linux/fsl/svr.h | 4 +-
> > include/linux/sys_soc.h | 3 +
> > 21 files changed, 478 insertions(+), 61 deletions(-) rename
> > Documentation/devicetree/bindings/{powerpc => soc}/fsl/guts.txt (91%)
> > create mode 100644 drivers/soc/fsl/Kconfig create mode 100644
> > drivers/soc/fsl/guts.c rename arch/powerpc/include/asm/mpc85xx.h =>
> > include/linux/fsl/svr.h (97%)
> >
> > --
> > 2.1.0.27.g96db324
> >
>
> This looks good to me! I am not sure which tree you want this to be
> picked up through, but unless no other volunteers I can take it through
> my mmc tree.
>
> Although, before considering to apply, I need an ack from Scott/Arnd for
> the guts driver in patch 5/8 and I need an ack from Greg for patch 7/8,
> where the soc_device_match() interface is added (seems like you didn't
> add him on cc/to).
>
[Lu Yangbo-B47093] Thanks a lot for your clarifying, Uffe.
This patchset was based on mmc tree, and needed your picking up.
But I think it needs to be rebased now since I saw qbman driver was in drivers/soc/fsl/ now.
I will do that after collecting others' ACKs or comments.
Hi Scott and Arnd,
Could I get your ACTs if there're no other changes needed?
Thanks a lot.
> Kind regards
> Uffe
^ permalink raw reply
* [PATCH 2/3] clk: hisilicon: add CRG driver for Hi3516CV300 SoC
From: Jiancheng Xue @ 2016-10-19 2:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161018155835.qyoffwznacdac46y@rob-hp-laptop>
? 2016/10/18 23:58, Rob Herring ??:
> On Mon, Oct 17, 2016 at 08:07:04PM +0800, Pan Wen wrote:
>> Add CRG driver for Hi3516CV300 SoC. CRG(Clock and Reset
>> Generator) module generates clock and reset signals used
>> by other module blocks on SoC.
>>
>> Signed-off-by: Pan Wen <wenpan@hisilicon.com>
>> ---
>> .../devicetree/bindings/clock/hisi-crg.txt | 50 ++++
>> drivers/clk/hisilicon/Kconfig | 8 +
>> drivers/clk/hisilicon/Makefile | 1 +
>> drivers/clk/hisilicon/crg-hi3516cv300.c | 330 +++++++++++++++++++++
>> drivers/clk/hisilicon/crg.h | 34 +++
>> include/dt-bindings/clock/hi3516cv300-clock.h | 48 +++
>> 6 files changed, 471 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/clock/hisi-crg.txt
>> create mode 100644 drivers/clk/hisilicon/crg-hi3516cv300.c
>> create mode 100644 drivers/clk/hisilicon/crg.h
>> create mode 100644 include/dt-bindings/clock/hi3516cv300-clock.h
>>
>> diff --git a/Documentation/devicetree/bindings/clock/hisi-crg.txt b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>> new file mode 100644
>> index 0000000..cc60b3d
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/hisi-crg.txt
>> @@ -0,0 +1,50 @@
>> +* HiSilicon Clock and Reset Generator(CRG)
>
> Seems kind of generic given there's already various HiSi clock bindings
> documented.
>
>> +
>> +The CRG module provides clock and reset signals to various
>> +modules within the SoC.
>> +
>> +This binding uses the following bindings:
>> + Documentation/devicetree/bindings/clock/clock-bindings.txt
>> + Documentation/devicetree/bindings/reset/reset.txt
>> +
>> +Required Properties:
>> +
>> +- compatible: should be one of the following.
>> + - "hisilicon,hi3516cv300-crg"
>> + - "hisilicon,hi3516cv300-sysctrl"
>> + - "hisilicon,hi3519-crg"
>
> There is already a binding for this. Please merge them.
>
Hi Rob,
Pan Wen and I work together. There's really a same file included in the patch
https://lkml.org/lkml/2016/9/18/42 ([PATCH v2] clk: hisilicon: add CRG driver for Hi3798CV200 SoC).
But that patch has not been acked. This binding file will be merged if that
patch is accepted first. Could you give me more comments on that patch or
help me to ack it? Thank you very much.
Regards,
Jiancheng
>> + - "hisilicon,hi3798cv200-crg"
>> + - "hisilicon,hi3798cv200-sysctrl"
>> +
>> +- reg: physical base address of the controller and length of memory mapped
>> + region.
>> +
>> +- #clock-cells: should be 1.
>> +
>> +Each clock is assigned an identifier and client nodes use this identifier
>> +to specify the clock which they consume.
>> +
>> +All these identifier could be found in <dt-bindings/clock/hi3519-clock.h>.
>> +
>> +- #reset-cells: should be 2.
>> +
>> +A reset signal can be controlled by writing a bit register in the CRG module.
>> +The reset specifier consists of two cells. The first cell represents the
>> +register offset relative to the base address. The second cell represents the
>> +bit index in the register.
>> +
>> +Example: CRG nodes
>> +CRG: clock-reset-controller at 12010000 {
>> + compatible = "hisilicon,hi3519-crg";
>> + reg = <0x12010000 0x10000>;
>> + #clock-cells = <1>;
>> + #reset-cells = <2>;
>> +};
>> +
>> +Example: consumer nodes
>> +i2c0: i2c at 12110000 {
>> + compatible = "hisilicon,hi3519-i2c";
>> + reg = <0x12110000 0x1000>;
>> + clocks = <&CRG HI3519_I2C0_RST>;
>> + resets = <&CRG 0xe4 0>;
>> +};
>
> .
>
^ permalink raw reply
* [PATCH v7, 8/8] arm64: dts: mediatek: add USB3 DRD driver
From: Chunfeng Yun @ 2016-10-19 2:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476844107-31087-1-git-send-email-chunfeng.yun@mediatek.com>
USB3 DRD driver is added for MT8173-EVB, and xHCI driver
becomes its subnode
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 63 ++++++++++++++++++++++-----
arch/arm64/boot/dts/mediatek/mt8173.dtsi | 29 +++++++++---
2 files changed, 74 insertions(+), 18 deletions(-)
diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
index 2a7f731..0ecaad4 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -34,15 +34,6 @@
chosen { };
- usb_p1_vbus: regulator at 0 {
- compatible = "regulator-fixed";
- regulator-name = "usb_vbus";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- gpio = <&pio 130 GPIO_ACTIVE_HIGH>;
- enable-active-high;
- };
-
connector {
compatible = "hdmi-connector";
label = "hdmi";
@@ -54,6 +45,29 @@
};
};
};
+
+ extcon_usb: extcon_iddig {
+ compatible = "linux,extcon-usb-gpio";
+ id-gpio = <&pio 16 GPIO_ACTIVE_HIGH>;
+ };
+
+ usb_p1_vbus: regulator at 0 {
+ compatible = "regulator-fixed";
+ regulator-name = "usb_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&pio 130 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ usb_p0_vbus: regulator at 1 {
+ compatible = "regulator-fixed";
+ regulator-name = "vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&pio 9 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
};
&cec {
@@ -243,6 +257,20 @@
bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
};
};
+
+ usb_id_pins_float: usb_iddig_pull_up {
+ pins_iddig {
+ pinmux = <MT8173_PIN_16_IDDIG__FUNC_IDDIG>;
+ bias-pull-up;
+ };
+ };
+
+ usb_id_pins_ground: usb_iddig_pull_down {
+ pins_iddig {
+ pinmux = <MT8173_PIN_16_IDDIG__FUNC_IDDIG>;
+ bias-pull-down;
+ };
+ };
};
&pwm0 {
@@ -469,12 +497,25 @@
status = "okay";
};
+&ssusb {
+ vusb33-supply = <&mt6397_vusb_reg>;
+ vbus-supply = <&usb_p0_vbus>;
+ extcon = <&extcon_usb>;
+ dr_mode = "otg";
+ mediatek,enable-wakeup;
+ pinctrl-names = "default", "id_float", "id_ground";
+ pinctrl-0 = <&usb_id_pins_float>;
+ pinctrl-1 = <&usb_id_pins_float>;
+ pinctrl-2 = <&usb_id_pins_ground>;
+ status = "okay";
+};
+
&uart0 {
status = "okay";
};
-&usb30 {
+&usb_host {
vusb33-supply = <&mt6397_vusb_reg>;
vbus-supply = <&usb_p1_vbus>;
- mediatek,wakeup-src = <1>;
+ status = "okay";
};
diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 1c71e25..c2d588c 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -707,11 +707,14 @@
status = "disabled";
};
- usb30: usb at 11270000 {
- compatible = "mediatek,mt8173-xhci";
- reg = <0 0x11270000 0 0x1000>,
+ ssusb: usb at 11271000 {
+ compatible = "mediatek,mt8173-mtu3";
+ reg = <0 0x11271000 0 0x3000>,
<0 0x11280700 0 0x0100>;
- interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
+ reg-names = "mac", "ippc";
+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_LOW>;
+ phys = <&phy_port0 PHY_TYPE_USB3>,
+ <&phy_port1 PHY_TYPE_USB2>;
power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
clocks = <&topckgen CLK_TOP_USB30_SEL>,
<&pericfg CLK_PERI_USB0>,
@@ -719,10 +722,22 @@
clock-names = "sys_ck",
"wakeup_deb_p0",
"wakeup_deb_p1";
- phys = <&phy_port0 PHY_TYPE_USB3>,
- <&phy_port1 PHY_TYPE_USB2>;
mediatek,syscon-wakeup = <&pericfg>;
- status = "okay";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ status = "disabled";
+
+ usb_host: xhci at 11270000 {
+ compatible = "mediatek,mt8173-xhci";
+ reg = <0 0x11270000 0 0x1000>;
+ reg-names = "mac";
+ interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>;
+ clocks = <&topckgen CLK_TOP_USB30_SEL>;
+ clock-names = "sys_ck";
+ status = "disabled";
+ };
};
u3phy: usb-phy at 11290000 {
--
1.7.9.5
^ permalink raw reply related
* [PATCH v7, 7/8] usb: mtu3: dual-role mode support
From: Chunfeng Yun @ 2016-10-19 2:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476844107-31087-1-git-send-email-chunfeng.yun@mediatek.com>
support dual-role mode; there are two ways to switch between
host and device modes, one is by idpin, another is by debugfs
which depends on user input.
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
drivers/usb/mtu3/Kconfig | 15 +-
drivers/usb/mtu3/Makefile | 11 +-
drivers/usb/mtu3/mtu3.h | 34 +++-
drivers/usb/mtu3/mtu3_core.c | 14 +-
drivers/usb/mtu3/mtu3_dr.c | 379 ++++++++++++++++++++++++++++++++++++++++
drivers/usb/mtu3/mtu3_dr.h | 27 ++-
drivers/usb/mtu3/mtu3_gadget.c | 6 +-
drivers/usb/mtu3/mtu3_host.c | 6 +
drivers/usb/mtu3/mtu3_plat.c | 86 ++++++++-
9 files changed, 557 insertions(+), 21 deletions(-)
create mode 100644 drivers/usb/mtu3/mtu3_dr.c
diff --git a/drivers/usb/mtu3/Kconfig b/drivers/usb/mtu3/Kconfig
index 59e3f6f..25cd619 100644
--- a/drivers/usb/mtu3/Kconfig
+++ b/drivers/usb/mtu3/Kconfig
@@ -2,7 +2,7 @@
config USB_MTU3
tristate "MediaTek USB3 Dual Role controller"
- depends on (USB || USB_GADGET) && HAS_DMA
+ depends on EXTCON && (USB || USB_GADGET) && HAS_DMA
depends on ARCH_MEDIATEK || COMPILE_TEST
select USB_XHCI_MTK if USB_SUPPORT && USB_XHCI_HCD
help
@@ -19,6 +19,7 @@ config USB_MTU3
if USB_MTU3
choice
bool "MTU3 Mode Selection"
+ default USB_MTU3_DUAL_ROLE if (USB && USB_GADGET)
default USB_MTU3_HOST if (USB && !USB_GADGET)
default USB_MTU3_GADGET if (!USB && USB_GADGET)
@@ -36,6 +37,18 @@ config USB_MTU3_GADGET
Select this when you want to use MTU3 in gadget mode only,
thereby the host feature will be regressed.
+config USB_MTU3_DUAL_ROLE
+ bool "Dual Role mode"
+ depends on ((USB=y || USB=USB_MTU3) && (USB_GADGET=y || USB_GADGET=USB_MTU3))
+ help
+ This is the default mode of working of MTU3 controller where
+ both host and gadget features are enabled.
+
endchoice
+config USB_MTU3_DEBUG
+ bool "Enable Debugging Messages"
+ help
+ Say Y here to enable debugging messages in the MTU3 Driver.
+
endif
diff --git a/drivers/usb/mtu3/Makefile b/drivers/usb/mtu3/Makefile
index 41e45e9..60e0fff 100644
--- a/drivers/usb/mtu3/Makefile
+++ b/drivers/usb/mtu3/Makefile
@@ -1,11 +1,18 @@
+
+ccflags-$(CONFIG_USB_MTU3_DEBUG) += -DDEBUG
+
obj-$(CONFIG_USB_MTU3) += mtu3.o
mtu3-y := mtu3_plat.o
-ifneq ($(filter y,$(CONFIG_USB_MTU3_HOST)),)
+ifneq ($(filter y,$(CONFIG_USB_MTU3_HOST) $(CONFIG_USB_MTU3_DUAL_ROLE)),)
mtu3-y += mtu3_host.o
endif
-ifneq ($(filter y,$(CONFIG_USB_MTU3_GADGET)),)
+ifneq ($(filter y,$(CONFIG_USB_MTU3_GADGET) $(CONFIG_USB_MTU3_DUAL_ROLE)),)
mtu3-y += mtu3_core.o mtu3_gadget_ep0.o mtu3_gadget.o mtu3_qmu.o
endif
+
+ifneq ($(CONFIG_USB_MTU3_DUAL_ROLE),)
+ mtu3-y += mtu3_dr.o
+endif
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
index a7c0ce8..ba9df71 100644
--- a/drivers/usb/mtu3/mtu3.h
+++ b/drivers/usb/mtu3/mtu3.h
@@ -21,6 +21,7 @@
#include <linux/device.h>
#include <linux/dmapool.h>
+#include <linux/extcon.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/phy/phy.h>
@@ -172,15 +173,44 @@ struct mtu3_gpd_ring {
struct qmu_gpd *enqueue;
struct qmu_gpd *dequeue;
};
+
+/**
+* @vbus: vbus 5V used by host mode
+* @edev: external connector used to detect vbus and iddig changes
+* @vbus_nb: notifier for vbus detection
+* @vbus_nb: notifier for iddig(idpin) detection
+* @extcon_reg_dwork: delay work for extcon notifier register, waiting for
+* xHCI driver initialization, it's necessary for system bootup
+* as device.
+* @is_u3_drd: whether port0 supports usb3.0 dual-role device or not
+* @id_*: used to maually switch between host and device modes by idpin
+* @manual_drd_enabled: it's true when supports dual-role device by debugfs
+* to switch host/device modes depending on user input.
+*/
+struct otg_switch_mtk {
+ struct regulator *vbus;
+ struct extcon_dev *edev;
+ struct notifier_block vbus_nb;
+ struct notifier_block id_nb;
+ struct delayed_work extcon_reg_dwork;
+ bool is_u3_drd;
+ /* dual-role switch by debugfs */
+ struct pinctrl *id_pinctrl;
+ struct pinctrl_state *id_float;
+ struct pinctrl_state *id_ground;
+ bool manual_drd_enabled;
+};
+
/**
* @mac_base: register base address of device MAC, exclude xHCI's
- * @ippc_base: register base address of ip port controller interface (IPPC)
+ * @ippc_base: register base address of IP Power and Clock interface (IPPC)
* @vusb33: usb3.3V shared by device/host IP
* @sys_clk: system clock of mtu3, shared by device/host IP
* @dr_mode: works in which mode:
* host only, device only or dual-role mode
* @u2_ports: number of usb2.0 host ports
* @u3_ports: number of usb3.0 host ports
+ * @dbgfs_root: only used when supports manual dual-role switch via debugfs
* @wakeup_en: it's true when supports remote wakeup in host mode
* @wk_deb_p0: port0's wakeup debounce clock
* @wk_deb_p1: it's optional, and depends on port1 is supported or not
@@ -196,10 +226,12 @@ struct ssusb_mtk {
struct regulator *vusb33;
struct clk *sys_clk;
/* otg */
+ struct otg_switch_mtk otg_switch;
enum usb_dr_mode dr_mode;
bool is_host;
int u2_ports;
int u3_ports;
+ struct dentry *dbgfs_root;
/* usb wakeup for host mode */
bool wakeup_en;
struct clk *wk_deb_p0;
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
index 2eef972..520e55a 100644
--- a/drivers/usb/mtu3/mtu3_core.c
+++ b/drivers/usb/mtu3/mtu3_core.c
@@ -150,7 +150,6 @@ static void mtu3_intr_disable(struct mtu3 *mtu)
/* Disable level 1 interrupts */
mtu3_writel(mbase, U3D_LV1IECR, ~0x0);
-
/* Disable endpoint interrupts */
mtu3_writel(mbase, U3D_EPIECR, ~0x0);
}
@@ -161,13 +160,10 @@ static void mtu3_intr_status_clear(struct mtu3 *mtu)
/* Clear EP0 and Tx/Rx EPn interrupts status */
mtu3_writel(mbase, U3D_EPISR, ~0x0);
-
/* Clear U2 USB common interrupts status */
mtu3_writel(mbase, U3D_COMMON_USB_INTR, ~0x0);
-
/* Clear U3 LTSSM interrupts status */
mtu3_writel(mbase, U3D_LTSSM_INTR, ~0x0);
-
/* Clear speed change interrupt status */
mtu3_writel(mbase, U3D_DEV_LINK_INTR, ~0x0);
}
@@ -268,7 +264,6 @@ void mtu3_start(struct mtu3 *mtu)
/* Initialize the default interrupts */
mtu3_intr_enable(mtu);
-
mtu->is_active = 1;
if (mtu->softconnect)
@@ -516,7 +511,6 @@ static int mtu3_mem_alloc(struct mtu3 *mtu)
mtu->out_eps = &ep_array[mtu->num_eps];
/* ep0 uses in_eps[0], out_eps[0] is reserved */
mtu->ep0 = mtu->in_eps;
-
mtu->ep0->mtu = mtu;
mtu->ep0->epnum = 0;
@@ -560,6 +554,7 @@ static void mtu3_set_speed(struct mtu3 *mtu)
/* HS/FS detected by HW */
mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
}
+
dev_info(mtu->dev, "max_speed: %s\n",
usb_speed_string(mtu->max_speed));
}
@@ -586,13 +581,10 @@ static void mtu3_regs_init(struct mtu3 *mtu)
/* delay about 0.1us from detecting reset to send chirp-K */
mtu3_clrbits(mbase, U3D_LINK_RESET_INFO, WTCHRP_MSK);
-
/* U2/U3 detected by HW */
mtu3_writel(mbase, U3D_DEVICE_CONF, 0);
-
/* enable QMU 16B checksum */
mtu3_setbits(mbase, U3D_QCR0, QMU_CS16B_EN);
-
/* vbus detected by HW */
mtu3_clrbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON);
}
@@ -838,6 +830,10 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
goto gadget_err;
}
+ /* init as host mode, power down device IP for power saving */
+ if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG)
+ mtu3_stop(mtu);
+
dev_dbg(dev, " %s() done...\n", __func__);
return 0;
diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c
new file mode 100644
index 0000000..1a8987e
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_dr.c
@@ -0,0 +1,379 @@
+/*
+ * mtu3_dr.c - dual role switch and host glue layer
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+
+#include "mtu3.h"
+#include "mtu3_dr.h"
+
+#define USB2_PORT 2
+#define USB3_PORT 3
+
+enum mtu3_vbus_id_state {
+ MTU3_ID_FLOAT = 1,
+ MTU3_ID_GROUND,
+ MTU3_VBUS_OFF,
+ MTU3_VBUS_VALID,
+};
+
+static void toggle_opstate(struct ssusb_mtk *ssusb)
+{
+ if (!ssusb->otg_switch.is_u3_drd) {
+ mtu3_setbits(ssusb->mac_base, U3D_DEVICE_CONTROL, DC_SESSION);
+ mtu3_setbits(ssusb->mac_base, U3D_POWER_MANAGEMENT, SOFT_CONN);
+ }
+}
+
+/* only port0 supports dual-role mode */
+static int ssusb_port0_switch(struct ssusb_mtk *ssusb,
+ int version, bool tohost)
+{
+ void __iomem *ibase = ssusb->ippc_base;
+ u32 value;
+
+ dev_dbg(ssusb->dev, "%s (switch u%d port0 to %s)\n", __func__,
+ version, tohost ? "host" : "device");
+
+ if (version == USB2_PORT) {
+ /* 1. power off and disable u2 port0 */
+ value = mtu3_readl(ibase, SSUSB_U2_CTRL(0));
+ value |= SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS;
+ mtu3_writel(ibase, SSUSB_U2_CTRL(0), value);
+
+ /* 2. power on, enable u2 port0 and select its mode */
+ value = mtu3_readl(ibase, SSUSB_U2_CTRL(0));
+ value &= ~(SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS);
+ value = tohost ? (value | SSUSB_U2_PORT_HOST_SEL) :
+ (value & (~SSUSB_U2_PORT_HOST_SEL));
+ mtu3_writel(ibase, SSUSB_U2_CTRL(0), value);
+ } else {
+ /* 1. power off and disable u3 port0 */
+ value = mtu3_readl(ibase, SSUSB_U3_CTRL(0));
+ value |= SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS;
+ mtu3_writel(ibase, SSUSB_U3_CTRL(0), value);
+
+ /* 2. power on, enable u3 port0 and select its mode */
+ value = mtu3_readl(ibase, SSUSB_U3_CTRL(0));
+ value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS);
+ value = tohost ? (value | SSUSB_U3_PORT_HOST_SEL) :
+ (value & (~SSUSB_U3_PORT_HOST_SEL));
+ mtu3_writel(ibase, SSUSB_U3_CTRL(0), value);
+ }
+
+ return 0;
+}
+
+static void switch_port_to_host(struct ssusb_mtk *ssusb)
+{
+ u32 check_clk = 0;
+
+ dev_dbg(ssusb->dev, "%s\n", __func__);
+
+ ssusb_port0_switch(ssusb, USB2_PORT, true);
+
+ if (ssusb->otg_switch.is_u3_drd) {
+ ssusb_port0_switch(ssusb, USB3_PORT, true);
+ check_clk = SSUSB_U3_MAC_RST_B_STS;
+ }
+
+ ssusb_check_clocks(ssusb, check_clk);
+
+ /* after all clocks are stable */
+ toggle_opstate(ssusb);
+}
+
+static void switch_port_to_device(struct ssusb_mtk *ssusb)
+{
+ u32 check_clk = 0;
+
+ dev_dbg(ssusb->dev, "%s\n", __func__);
+
+ ssusb_port0_switch(ssusb, USB2_PORT, false);
+
+ if (ssusb->otg_switch.is_u3_drd) {
+ ssusb_port0_switch(ssusb, USB3_PORT, false);
+ check_clk = SSUSB_U3_MAC_RST_B_STS;
+ }
+
+ ssusb_check_clocks(ssusb, check_clk);
+}
+
+int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
+{
+ struct ssusb_mtk *ssusb =
+ container_of(otg_sx, struct ssusb_mtk, otg_switch);
+ struct regulator *vbus = otg_sx->vbus;
+ int ret;
+
+ /* vbus is optional */
+ if (!vbus)
+ return 0;
+
+ dev_dbg(ssusb->dev, "%s: turn %s\n", __func__, is_on ? "on" : "off");
+
+ if (is_on) {
+ ret = regulator_enable(vbus);
+ if (ret) {
+ dev_err(ssusb->dev, "vbus regulator enable failed\n");
+ return ret;
+ }
+ } else {
+ regulator_disable(vbus);
+ }
+
+ return 0;
+}
+
+/*
+ * switch to host: -> MTU3_VBUS_OFF --> MTU3_ID_GROUND
+ * switch to device: -> MTU3_ID_FLOAT --> MTU3_VBUS_VALID
+ */
+static void ssusb_set_mailbox(struct otg_switch_mtk *otg_sx,
+ enum mtu3_vbus_id_state status)
+{
+ struct ssusb_mtk *ssusb =
+ container_of(otg_sx, struct ssusb_mtk, otg_switch);
+ struct mtu3 *mtu = ssusb->u3d;
+
+ dev_dbg(ssusb->dev, "mailbox state(%d)\n", status);
+
+ switch (status) {
+ case MTU3_ID_GROUND:
+ switch_port_to_host(ssusb);
+ ssusb_set_vbus(otg_sx, 1);
+ ssusb->is_host = true;
+ break;
+ case MTU3_ID_FLOAT:
+ ssusb->is_host = false;
+ ssusb_set_vbus(otg_sx, 0);
+ switch_port_to_device(ssusb);
+ break;
+ case MTU3_VBUS_OFF:
+ mtu3_stop(mtu);
+ pm_relax(ssusb->dev);
+ break;
+ case MTU3_VBUS_VALID:
+ /* avoid suspend when works as device */
+ pm_stay_awake(ssusb->dev);
+ mtu3_start(mtu);
+ break;
+ default:
+ dev_err(ssusb->dev, "invalid state\n");
+ }
+}
+
+static int ssusb_id_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct otg_switch_mtk *otg_sx =
+ container_of(nb, struct otg_switch_mtk, id_nb);
+
+ if (event)
+ ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
+ else
+ ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
+
+ return NOTIFY_DONE;
+}
+
+static int ssusb_vbus_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct otg_switch_mtk *otg_sx =
+ container_of(nb, struct otg_switch_mtk, vbus_nb);
+
+ if (event)
+ ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
+ else
+ ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
+
+ return NOTIFY_DONE;
+}
+
+static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
+{
+ struct ssusb_mtk *ssusb =
+ container_of(otg_sx, struct ssusb_mtk, otg_switch);
+ struct extcon_dev *edev = otg_sx->edev;
+ int ret;
+
+ /* extcon is optional */
+ if (!edev)
+ return 0;
+
+ otg_sx->vbus_nb.notifier_call = ssusb_vbus_notifier;
+ ret = extcon_register_notifier(edev, EXTCON_USB,
+ &otg_sx->vbus_nb);
+ if (ret < 0)
+ dev_err(ssusb->dev, "failed to register notifier for USB\n");
+
+ otg_sx->id_nb.notifier_call = ssusb_id_notifier;
+ ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
+ &otg_sx->id_nb);
+ if (ret < 0)
+ dev_err(ssusb->dev, "failed to register notifier for USB-HOST\n");
+
+ dev_dbg(ssusb->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n",
+ extcon_get_cable_state_(edev, EXTCON_USB),
+ extcon_get_cable_state_(edev, EXTCON_USB_HOST));
+
+ /* default as host, switch to device mode if needed */
+ if (extcon_get_cable_state_(edev, EXTCON_USB_HOST) == false)
+ ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
+ if (extcon_get_cable_state_(edev, EXTCON_USB) == true)
+ ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
+
+ return 0;
+}
+
+static void extcon_register_dwork(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct otg_switch_mtk *otg_sx =
+ container_of(dwork, struct otg_switch_mtk, extcon_reg_dwork);
+
+ ssusb_extcon_register(otg_sx);
+}
+
+/*
+ * We provide an interface via debugfs to switch between host and device modes
+ * depending on user input.
+ * This is useful in special cases, such as uses TYPE-A receptacle but also
+ * wants to support dual-role mode.
+ * It generates cable state changes by pulling up/down IDPIN and
+ * notifies driver to switch mode by "extcon-usb-gpio".
+ * NOTE: when use MICRO receptacle, should not enable this interface.
+ */
+static void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host)
+{
+ struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+
+ if (to_host)
+ pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_ground);
+ else
+ pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_float);
+}
+
+
+static int ssusb_mode_show(struct seq_file *sf, void *unused)
+{
+ struct ssusb_mtk *ssusb = sf->private;
+
+ seq_printf(sf, "current mode: %s(%s drd)\n(echo device/host)\n",
+ ssusb->is_host ? "host" : "device",
+ ssusb->otg_switch.manual_drd_enabled ? "manual" : "auto");
+
+ return 0;
+}
+
+static int ssusb_mode_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ssusb_mode_show, inode->i_private);
+}
+
+static ssize_t ssusb_mode_write(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ struct seq_file *sf = file->private_data;
+ struct ssusb_mtk *ssusb = sf->private;
+ char buf[16];
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (!strncmp(buf, "host", 4) && !ssusb->is_host) {
+ ssusb_mode_manual_switch(ssusb, 1);
+ } else if (!strncmp(buf, "device", 6) && ssusb->is_host) {
+ ssusb_mode_manual_switch(ssusb, 0);
+ } else {
+ dev_err(ssusb->dev, "wrong or duplicated setting\n");
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static const struct file_operations ssusb_mode_fops = {
+ .open = ssusb_mode_open,
+ .write = ssusb_mode_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void ssusb_debugfs_init(struct ssusb_mtk *ssusb)
+{
+ struct dentry *root;
+ struct dentry *file;
+
+ root = debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root);
+ if (IS_ERR_OR_NULL(root)) {
+ if (!root)
+ dev_err(ssusb->dev, "create debugfs root failed\n");
+ return;
+ }
+ ssusb->dbgfs_root = root;
+
+ file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
+ ssusb, &ssusb_mode_fops);
+ if (!file)
+ dev_dbg(ssusb->dev, "create debugfs mode failed\n");
+}
+
+static void ssusb_debugfs_exit(struct ssusb_mtk *ssusb)
+{
+ debugfs_remove_recursive(ssusb->dbgfs_root);
+}
+
+int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
+{
+ struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+
+ INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork, extcon_register_dwork);
+
+ if (otg_sx->manual_drd_enabled)
+ ssusb_debugfs_init(ssusb);
+
+ /* It is enough to delay 1s for waiting for host initialization */
+ schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
+
+ return 0;
+}
+
+void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
+{
+ struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+
+ cancel_delayed_work(&otg_sx->extcon_reg_dwork);
+
+ if (otg_sx->edev) {
+ extcon_unregister_notifier(otg_sx->edev,
+ EXTCON_USB, &otg_sx->vbus_nb);
+ extcon_unregister_notifier(otg_sx->edev,
+ EXTCON_USB_HOST, &otg_sx->id_nb);
+ }
+
+ if (otg_sx->manual_drd_enabled)
+ ssusb_debugfs_exit(ssusb);
+}
diff --git a/drivers/usb/mtu3/mtu3_dr.h b/drivers/usb/mtu3/mtu3_dr.h
index 07066f4..9b228b5 100644
--- a/drivers/usb/mtu3/mtu3_dr.h
+++ b/drivers/usb/mtu3/mtu3_dr.h
@@ -19,7 +19,7 @@
#ifndef _MTU3_DR_H_
#define _MTU3_DR_H_
-#if IS_ENABLED(CONFIG_USB_MTU3_HOST)
+#if IS_ENABLED(CONFIG_USB_MTU3_HOST) || IS_ENABLED(CONFIG_USB_MTU3_DUAL_ROLE)
int ssusb_host_init(struct ssusb_mtk *ssusb, struct device_node *parent_dn);
void ssusb_host_exit(struct ssusb_mtk *ssusb);
@@ -69,7 +69,7 @@ static inline void ssusb_wakeup_disable(struct ssusb_mtk *ssusb)
#endif
-#if IS_ENABLED(CONFIG_USB_MTU3_GADGET)
+#if IS_ENABLED(CONFIG_USB_MTU3_GADGET) || IS_ENABLED(CONFIG_USB_MTU3_DUAL_ROLE)
int ssusb_gadget_init(struct ssusb_mtk *ssusb);
void ssusb_gadget_exit(struct ssusb_mtk *ssusb);
#else
@@ -82,4 +82,27 @@ static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
{}
#endif
+
+#if IS_ENABLED(CONFIG_USB_MTU3_DUAL_ROLE)
+int ssusb_otg_switch_init(struct ssusb_mtk *ssusb);
+void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb);
+int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on);
+
+#else
+
+static inline int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
+{
+ return 0;
+}
+
+static inline void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
+{}
+
+static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
+{
+ return 0;
+}
+
+#endif
+
#endif /* _MTU3_DR_H_ */
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index 84f3fe1..9dd2441 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -522,7 +522,8 @@ static int mtu3_gadget_start(struct usb_gadget *gadget,
mtu->softconnect = 0;
mtu->gadget_driver = driver;
- mtu3_start(mtu);
+ if (mtu->ssusb->dr_mode == USB_DR_MODE_PERIPHERAL)
+ mtu3_start(mtu);
spin_unlock_irqrestore(&mtu->lock, flags);
@@ -575,7 +576,8 @@ static int mtu3_gadget_stop(struct usb_gadget *g)
stop_activity(mtu);
mtu->gadget_driver = NULL;
- mtu3_stop(mtu);
+ if (mtu->ssusb->dr_mode == USB_DR_MODE_PERIPHERAL)
+ mtu3_stop(mtu);
spin_unlock_irqrestore(&mtu->lock, flags);
diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c
index 361d6d8..cd4d010 100644
--- a/drivers/usb/mtu3/mtu3_host.c
+++ b/drivers/usb/mtu3/mtu3_host.c
@@ -230,10 +230,16 @@ static void ssusb_host_setup(struct ssusb_mtk *ssusb)
* if support OTG, gadget driver will switch port0 to device mode
*/
ssusb_host_enable(ssusb);
+
+ /* if port0 supports dual-role, works as host mode by default */
+ ssusb_set_vbus(&ssusb->otg_switch, 1);
}
static void ssusb_host_cleanup(struct ssusb_mtk *ssusb)
{
+ if (ssusb->is_host)
+ ssusb_set_vbus(&ssusb->otg_switch, 0);
+
ssusb_host_disable(ssusb, false);
}
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
index facb76c..7833678 100644
--- a/drivers/usb/mtu3/mtu3_plat.c
+++ b/drivers/usb/mtu3/mtu3_plat.c
@@ -142,13 +142,10 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
phy_err:
ssusb_phy_exit(ssusb);
-
phy_init_err:
clk_disable_unprepare(ssusb->sys_clk);
-
clk_err:
regulator_disable(ssusb->vusb33);
-
vusb33_err:
return ret;
@@ -170,10 +167,39 @@ static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb)
mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
}
+static int get_iddig_pinctrl(struct ssusb_mtk *ssusb)
+{
+ struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
+
+ otg_sx->id_pinctrl = devm_pinctrl_get(ssusb->dev);
+ if (IS_ERR(otg_sx->id_pinctrl)) {
+ dev_err(ssusb->dev, "Cannot find id pinctrl!\n");
+ return PTR_ERR(otg_sx->id_pinctrl);
+ }
+
+ otg_sx->id_float =
+ pinctrl_lookup_state(otg_sx->id_pinctrl, "id_float");
+ if (IS_ERR(otg_sx->id_float)) {
+ dev_err(ssusb->dev, "Cannot find pinctrl id_float!\n");
+ return PTR_ERR(otg_sx->id_float);
+ }
+
+ otg_sx->id_ground =
+ pinctrl_lookup_state(otg_sx->id_pinctrl, "id_ground");
+ if (IS_ERR(otg_sx->id_ground)) {
+ dev_err(ssusb->dev, "Cannot find pinctrl id_ground!\n");
+ return PTR_ERR(otg_sx->id_ground);
+ }
+
+ return 0;
+}
+
static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
{
struct device_node *node = pdev->dev.of_node;
+ struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
struct device *dev = &pdev->dev;
+ struct regulator *vbus;
struct resource *res;
int i;
int ret;
@@ -230,6 +256,37 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
if (ret)
return ret;
+ if (ssusb->dr_mode != USB_DR_MODE_OTG)
+ return 0;
+
+ /* if dual-role mode is supported */
+ vbus = devm_regulator_get(&pdev->dev, "vbus");
+ if (IS_ERR(vbus)) {
+ dev_err(dev, "failed to get vbus\n");
+ return PTR_ERR(vbus);
+ }
+ otg_sx->vbus = vbus;
+
+ otg_sx->is_u3_drd = of_property_read_bool(node, "mediatek,usb3-drd");
+ otg_sx->manual_drd_enabled =
+ of_property_read_bool(node, "enable-manual-drd");
+
+ if (of_property_read_bool(node, "extcon")) {
+ otg_sx->edev = extcon_get_edev_by_phandle(ssusb->dev, 0);
+ if (IS_ERR(otg_sx->edev)) {
+ dev_err(ssusb->dev, "couldn't get extcon device\n");
+ return -EPROBE_DEFER;
+ }
+ if (otg_sx->manual_drd_enabled) {
+ ret = get_iddig_pinctrl(ssusb);
+ if (ret)
+ return ret;
+ }
+ }
+
+ dev_info(dev, "dr_mode: %d, is_u3_dr: %d\n",
+ ssusb->dr_mode, otg_sx->is_u3_drd);
+
return 0;
}
@@ -292,6 +349,21 @@ static int mtu3_probe(struct platform_device *pdev)
goto comm_exit;
}
break;
+ case USB_DR_MODE_OTG:
+ ret = ssusb_gadget_init(ssusb);
+ if (ret) {
+ dev_err(dev, "failed to initialize gadget\n");
+ goto comm_exit;
+ }
+
+ ret = ssusb_host_init(ssusb, node);
+ if (ret) {
+ dev_err(dev, "failed to initialize host\n");
+ goto gadget_exit;
+ }
+
+ ssusb_otg_switch_init(ssusb);
+ break;
default:
dev_err(dev, "unsupported mode: %d\n", ssusb->dr_mode);
ret = -EINVAL;
@@ -300,9 +372,10 @@ static int mtu3_probe(struct platform_device *pdev)
return 0;
+gadget_exit:
+ ssusb_gadget_exit(ssusb);
comm_exit:
ssusb_rscs_exit(ssusb);
-
comm_init_err:
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
@@ -321,6 +394,11 @@ static int mtu3_remove(struct platform_device *pdev)
case USB_DR_MODE_HOST:
ssusb_host_exit(ssusb);
break;
+ case USB_DR_MODE_OTG:
+ ssusb_otg_switch_exit(ssusb);
+ ssusb_gadget_exit(ssusb);
+ ssusb_host_exit(ssusb);
+ break;
default:
return -EINVAL;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v7, 6/8] usb: mtu3: host only mode support
From: Chunfeng Yun @ 2016-10-19 2:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476844107-31087-1-git-send-email-chunfeng.yun@mediatek.com>
supports host only mode and the code is ported from
host/xhci-mtk.c
IPPC register shared between host and device is moved
into common glue layer.
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
drivers/usb/mtu3/Kconfig | 9 ++
drivers/usb/mtu3/Makefile | 11 +-
drivers/usb/mtu3/mtu3.h | 47 ++++++-
drivers/usb/mtu3/mtu3_core.c | 42 +++++-
drivers/usb/mtu3/mtu3_dr.h | 85 +++++++++++++
drivers/usb/mtu3/mtu3_host.c | 288 +++++++++++++++++++++++++++++++++++++++++
drivers/usb/mtu3/mtu3_plat.c | 289 ++++++++++++++++++++++++++++++++----------
7 files changed, 691 insertions(+), 80 deletions(-)
create mode 100644 drivers/usb/mtu3/mtu3_dr.h
create mode 100644 drivers/usb/mtu3/mtu3_host.c
diff --git a/drivers/usb/mtu3/Kconfig b/drivers/usb/mtu3/Kconfig
index 54dadee..59e3f6f 100644
--- a/drivers/usb/mtu3/Kconfig
+++ b/drivers/usb/mtu3/Kconfig
@@ -4,6 +4,7 @@ config USB_MTU3
tristate "MediaTek USB3 Dual Role controller"
depends on (USB || USB_GADGET) && HAS_DMA
depends on ARCH_MEDIATEK || COMPILE_TEST
+ select USB_XHCI_MTK if USB_SUPPORT && USB_XHCI_HCD
help
Say Y or M here if your system runs on MediaTek SoCs with
Dual Role SuperSpeed USB controller. You can select usb
@@ -18,8 +19,16 @@ config USB_MTU3
if USB_MTU3
choice
bool "MTU3 Mode Selection"
+ default USB_MTU3_HOST if (USB && !USB_GADGET)
default USB_MTU3_GADGET if (!USB && USB_GADGET)
+config USB_MTU3_HOST
+ bool "Host only mode"
+ depends on USB=y || USB=USB_MTU3
+ help
+ Select this when you want to use MTU3 in host mode only,
+ thereby the gadget feature will be regressed.
+
config USB_MTU3_GADGET
bool "Gadget only mode"
depends on USB_GADGET=y || USB_GADGET=USB_MTU3
diff --git a/drivers/usb/mtu3/Makefile b/drivers/usb/mtu3/Makefile
index 532c257..41e45e9 100644
--- a/drivers/usb/mtu3/Makefile
+++ b/drivers/usb/mtu3/Makefile
@@ -1,2 +1,11 @@
obj-$(CONFIG_USB_MTU3) += mtu3.o
-mtu3-y := mtu3_plat.o mtu3_core.o mtu3_gadget_ep0.o mtu3_gadget.o mtu3_qmu.o
+
+mtu3-y := mtu3_plat.o
+
+ifneq ($(filter y,$(CONFIG_USB_MTU3_HOST)),)
+ mtu3-y += mtu3_host.o
+endif
+
+ifneq ($(filter y,$(CONFIG_USB_MTU3_GADGET)),)
+ mtu3-y += mtu3_core.o mtu3_gadget_ep0.o mtu3_gadget.o mtu3_qmu.o
+endif
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
index 41a0473..a7c0ce8 100644
--- a/drivers/usb/mtu3/mtu3.h
+++ b/drivers/usb/mtu3/mtu3.h
@@ -172,6 +172,40 @@ struct mtu3_gpd_ring {
struct qmu_gpd *enqueue;
struct qmu_gpd *dequeue;
};
+/**
+ * @mac_base: register base address of device MAC, exclude xHCI's
+ * @ippc_base: register base address of ip port controller interface (IPPC)
+ * @vusb33: usb3.3V shared by device/host IP
+ * @sys_clk: system clock of mtu3, shared by device/host IP
+ * @dr_mode: works in which mode:
+ * host only, device only or dual-role mode
+ * @u2_ports: number of usb2.0 host ports
+ * @u3_ports: number of usb3.0 host ports
+ * @wakeup_en: it's true when supports remote wakeup in host mode
+ * @wk_deb_p0: port0's wakeup debounce clock
+ * @wk_deb_p1: it's optional, and depends on port1 is supported or not
+ */
+struct ssusb_mtk {
+ struct device *dev;
+ struct mtu3 *u3d;
+ void __iomem *mac_base;
+ void __iomem *ippc_base;
+ struct phy **phys;
+ int num_phys;
+ /* common power & clock */
+ struct regulator *vusb33;
+ struct clk *sys_clk;
+ /* otg */
+ enum usb_dr_mode dr_mode;
+ bool is_host;
+ int u2_ports;
+ int u3_ports;
+ /* usb wakeup for host mode */
+ bool wakeup_en;
+ struct clk *wk_deb_p0;
+ struct clk *wk_deb_p1;
+ struct regmap *pericfg;
+};
/**
* @fifo_size: it is (@slot + 1) * @fifo_seg_size
@@ -210,6 +244,11 @@ struct mtu3_request {
int epnum;
};
+static inline struct ssusb_mtk *dev_to_ssusb(struct device *dev)
+{
+ return dev_get_drvdata(dev);
+}
+
/**
* struct mtu3 - device driver instance data.
* @slot: MTU3_U2_IP_SLOT_DEFAULT for U2 IP only,
@@ -222,12 +261,10 @@ struct mtu3_request {
*/
struct mtu3 {
spinlock_t lock;
+ struct ssusb_mtk *ssusb;
struct device *dev;
void __iomem *mac_base;
void __iomem *ippc_base;
- struct phy *phy;
- struct regulator *vusb33;
- struct clk *sys_clk;
int irq;
struct mtu3_fifo_info tx_fifo;
@@ -320,7 +357,7 @@ static inline void mtu3_clrbits(void __iomem *base, u32 offset, u32 bits)
writel((tmp & ~(bits)), addr);
}
-int ssusb_check_clocks(struct mtu3 *mtu, u32 ex_clks);
+int ssusb_check_clocks(struct ssusb_mtk *ssusb, u32 ex_clks);
struct usb_request *mtu3_alloc_request(struct usb_ep *ep, gfp_t gfp_flags);
void mtu3_free_request(struct usb_ep *ep, struct usb_request *req);
void mtu3_req_complete(struct mtu3_ep *mep,
@@ -341,8 +378,6 @@ int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
void mtu3_gadget_suspend(struct mtu3 *mtu);
void mtu3_gadget_resume(struct mtu3 *mtu);
void mtu3_gadget_disconnect(struct mtu3 *mtu);
-int ssusb_gadget_init(struct mtu3 *mtu);
-void ssusb_gadget_exit(struct mtu3 *mtu);
irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu);
extern const struct usb_ep_ops mtu3_ep0_ops;
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
index f9817ad..2eef972 100644
--- a/drivers/usb/mtu3/mtu3_core.c
+++ b/drivers/usb/mtu3/mtu3_core.c
@@ -116,7 +116,7 @@ static int mtu3_device_enable(struct mtu3 *mtu)
SSUSB_U2_PORT_HOST_SEL));
mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);
- return ssusb_check_clocks(mtu, check_clk);
+ return ssusb_check_clocks(mtu->ssusb, check_clk);
}
static void mtu3_device_disable(struct mtu3 *mtu)
@@ -765,11 +765,38 @@ static void mtu3_hw_exit(struct mtu3 *mtu)
/*-------------------------------------------------------------------------*/
-int ssusb_gadget_init(struct mtu3 *mtu)
+int ssusb_gadget_init(struct ssusb_mtk *ssusb)
{
- struct device *dev = mtu->dev;
- int ret;
+ struct device *dev = ssusb->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mtu3 *mtu = NULL;
+ struct resource *res;
+ int ret = -ENOMEM;
+
+ mtu = devm_kzalloc(dev, sizeof(struct mtu3), GFP_KERNEL);
+ if (mtu == NULL)
+ return -ENOMEM;
+
+ mtu->irq = platform_get_irq(pdev, 0);
+ if (mtu->irq <= 0) {
+ dev_err(dev, "fail to get irq number\n");
+ return -ENODEV;
+ }
+ dev_info(dev, "irq %d\n", mtu->irq);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mac");
+ mtu->mac_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(mtu->mac_base)) {
+ dev_err(dev, "error mapping memory for dev mac\n");
+ return PTR_ERR(mtu->mac_base);
+ }
+
+ spin_lock_init(&mtu->lock);
+ mtu->dev = dev;
+ mtu->ippc_base = ssusb->ippc_base;
+ ssusb->mac_base = mtu->mac_base;
+ ssusb->u3d = mtu;
+ mtu->ssusb = ssusb;
mtu->max_speed = usb_get_maximum_speed(dev);
/* check the max_speed parameter */
@@ -820,14 +847,17 @@ int ssusb_gadget_init(struct mtu3 *mtu)
irq_err:
mtu3_hw_exit(mtu);
+ ssusb->u3d = NULL;
dev_err(dev, " %s() fail...\n", __func__);
return ret;
}
-void ssusb_gadget_exit(struct mtu3 *mtu)
+void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
{
+ struct mtu3 *mtu = ssusb->u3d;
+
mtu3_gadget_cleanup(mtu);
- device_init_wakeup(mtu->dev, false);
+ device_init_wakeup(ssusb->dev, false);
mtu3_hw_exit(mtu);
}
diff --git a/drivers/usb/mtu3/mtu3_dr.h b/drivers/usb/mtu3/mtu3_dr.h
new file mode 100644
index 0000000..07066f4
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_dr.h
@@ -0,0 +1,85 @@
+/*
+ * mtu3_dr.h - dual role switch and host glue layer header
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _MTU3_DR_H_
+#define _MTU3_DR_H_
+
+#if IS_ENABLED(CONFIG_USB_MTU3_HOST)
+
+int ssusb_host_init(struct ssusb_mtk *ssusb, struct device_node *parent_dn);
+void ssusb_host_exit(struct ssusb_mtk *ssusb);
+int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
+ struct device_node *dn);
+int ssusb_host_enable(struct ssusb_mtk *ssusb);
+int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend);
+int ssusb_wakeup_enable(struct ssusb_mtk *ssusb);
+void ssusb_wakeup_disable(struct ssusb_mtk *ssusb);
+
+#else
+
+static inline int ssusb_host_init(struct ssusb_mtk *ssusb,
+
+ struct device_node *parent_dn)
+{
+ return 0;
+}
+
+static inline void ssusb_host_exit(struct ssusb_mtk *ssusb)
+{}
+
+static inline int ssusb_wakeup_of_property_parse(
+ struct ssusb_mtk *ssusb, struct device_node *dn)
+{
+ return 0;
+}
+
+static inline int ssusb_host_enable(struct ssusb_mtk *ssusb)
+{
+ return 0;
+}
+
+static inline int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
+{
+ return 0;
+}
+
+static inline int ssusb_wakeup_enable(struct ssusb_mtk *ssusb)
+{
+ return 0;
+}
+
+static inline void ssusb_wakeup_disable(struct ssusb_mtk *ssusb)
+{}
+
+#endif
+
+
+#if IS_ENABLED(CONFIG_USB_MTU3_GADGET)
+int ssusb_gadget_init(struct ssusb_mtk *ssusb);
+void ssusb_gadget_exit(struct ssusb_mtk *ssusb);
+#else
+static inline int ssusb_gadget_init(struct ssusb_mtk *ssusb)
+{
+ return 0;
+}
+
+static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
+{}
+#endif
+
+#endif /* _MTU3_DR_H_ */
diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c
new file mode 100644
index 0000000..361d6d8
--- /dev/null
+++ b/drivers/usb/mtu3/mtu3_host.c
@@ -0,0 +1,288 @@
+/*
+ * mtu3_dr.c - dual role switch and host glue layer
+ *
+ * Copyright (C) 2016 MediaTek Inc.
+ *
+ * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+
+#include "mtu3.h"
+#include "mtu3_dr.h"
+
+#define PERI_WK_CTRL1 0x404
+#define UWK_CTL1_IS_C(x) (((x) & 0xf) << 26)
+#define UWK_CTL1_IS_E BIT(25)
+#define UWK_CTL1_IDDIG_C(x) (((x) & 0xf) << 11) /* cycle debounce */
+#define UWK_CTL1_IDDIG_E BIT(10) /* enable debounce */
+#define UWK_CTL1_IDDIG_P BIT(9) /* polarity */
+#define UWK_CTL1_IS_P BIT(6) /* polarity for ip sleep */
+
+/*
+ * ip-sleep wakeup mode:
+ * all clocks can be turn off, but power domain should be kept on
+ */
+static void ssusb_wakeup_ip_sleep_en(struct ssusb_mtk *ssusb)
+{
+ u32 tmp;
+ struct regmap *pericfg = ssusb->pericfg;
+
+ regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
+ tmp &= ~UWK_CTL1_IS_P;
+ tmp &= ~(UWK_CTL1_IS_C(0xf));
+ tmp |= UWK_CTL1_IS_C(0x8);
+ regmap_write(pericfg, PERI_WK_CTRL1, tmp);
+ regmap_write(pericfg, PERI_WK_CTRL1, tmp | UWK_CTL1_IS_E);
+
+ regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
+ dev_dbg(ssusb->dev, "%s(): WK_CTRL1[P6,E25,C26:29]=%#x\n",
+ __func__, tmp);
+}
+
+static void ssusb_wakeup_ip_sleep_dis(struct ssusb_mtk *ssusb)
+{
+ u32 tmp;
+
+ regmap_read(ssusb->pericfg, PERI_WK_CTRL1, &tmp);
+ tmp &= ~UWK_CTL1_IS_E;
+ regmap_write(ssusb->pericfg, PERI_WK_CTRL1, tmp);
+}
+
+int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
+ struct device_node *dn)
+{
+ struct device *dev = ssusb->dev;
+
+ /*
+ * Wakeup function is optional, so it is not an error if this property
+ * does not exist, and in such case, no need to get relative
+ * properties anymore.
+ */
+ ssusb->wakeup_en = of_property_read_bool(dn, "mediatek,enable-wakeup");
+ if (!ssusb->wakeup_en)
+ return 0;
+
+ ssusb->wk_deb_p0 = devm_clk_get(dev, "wakeup_deb_p0");
+ if (IS_ERR(ssusb->wk_deb_p0)) {
+ dev_err(dev, "fail to get wakeup_deb_p0\n");
+ return PTR_ERR(ssusb->wk_deb_p0);
+ }
+
+ if (of_property_read_bool(dn, "wakeup_deb_p1")) {
+ ssusb->wk_deb_p1 = devm_clk_get(dev, "wakeup_deb_p1");
+ if (IS_ERR(ssusb->wk_deb_p1)) {
+ dev_err(dev, "fail to get wakeup_deb_p1\n");
+ return PTR_ERR(ssusb->wk_deb_p1);
+ }
+ }
+
+ ssusb->pericfg = syscon_regmap_lookup_by_phandle(dn,
+ "mediatek,syscon-wakeup");
+ if (IS_ERR(ssusb->pericfg)) {
+ dev_err(dev, "fail to get pericfg regs\n");
+ return PTR_ERR(ssusb->pericfg);
+ }
+
+ return 0;
+}
+
+static int ssusb_wakeup_clks_enable(struct ssusb_mtk *ssusb)
+{
+ int ret;
+
+ ret = clk_prepare_enable(ssusb->wk_deb_p0);
+ if (ret) {
+ dev_err(ssusb->dev, "failed to enable wk_deb_p0\n");
+ goto usb_p0_err;
+ }
+
+ ret = clk_prepare_enable(ssusb->wk_deb_p1);
+ if (ret) {
+ dev_err(ssusb->dev, "failed to enable wk_deb_p1\n");
+ goto usb_p1_err;
+ }
+
+ return 0;
+
+usb_p1_err:
+ clk_disable_unprepare(ssusb->wk_deb_p0);
+usb_p0_err:
+ return -EINVAL;
+}
+
+static void ssusb_wakeup_clks_disable(struct ssusb_mtk *ssusb)
+{
+ clk_disable_unprepare(ssusb->wk_deb_p1);
+ clk_disable_unprepare(ssusb->wk_deb_p0);
+}
+
+static void host_ports_num_get(struct ssusb_mtk *ssusb)
+{
+ u32 xhci_cap;
+
+ xhci_cap = mtu3_readl(ssusb->ippc_base, U3D_SSUSB_IP_XHCI_CAP);
+ ssusb->u2_ports = SSUSB_IP_XHCI_U2_PORT_NUM(xhci_cap);
+ ssusb->u3_ports = SSUSB_IP_XHCI_U3_PORT_NUM(xhci_cap);
+
+ dev_dbg(ssusb->dev, "host - u2_ports:%d, u3_ports:%d\n",
+ ssusb->u2_ports, ssusb->u3_ports);
+}
+
+/* only configure ports will be used later */
+int ssusb_host_enable(struct ssusb_mtk *ssusb)
+{
+ void __iomem *ibase = ssusb->ippc_base;
+ int num_u3p = ssusb->u3_ports;
+ int num_u2p = ssusb->u2_ports;
+ u32 check_clk;
+ u32 value;
+ int i;
+
+ /* power on host ip */
+ mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
+
+ /* power on and enable all u3 ports */
+ for (i = 0; i < num_u3p; i++) {
+ value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
+ value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS);
+ value |= SSUSB_U3_PORT_HOST_SEL;
+ mtu3_writel(ibase, SSUSB_U3_CTRL(i), value);
+ }
+
+ /* power on and enable all u2 ports */
+ for (i = 0; i < num_u2p; i++) {
+ value = mtu3_readl(ibase, SSUSB_U2_CTRL(i));
+ value &= ~(SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS);
+ value |= SSUSB_U2_PORT_HOST_SEL;
+ mtu3_writel(ibase, SSUSB_U2_CTRL(i), value);
+ }
+
+ check_clk = SSUSB_XHCI_RST_B_STS;
+ if (num_u3p)
+ check_clk = SSUSB_U3_MAC_RST_B_STS;
+
+ return ssusb_check_clocks(ssusb, check_clk);
+}
+
+int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
+{
+ void __iomem *ibase = ssusb->ippc_base;
+ int num_u3p = ssusb->u3_ports;
+ int num_u2p = ssusb->u2_ports;
+ u32 value;
+ int ret;
+ int i;
+
+ /* power down and disable all u3 ports */
+ for (i = 0; i < num_u3p; i++) {
+ value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
+ value |= SSUSB_U3_PORT_PDN;
+ value |= suspend ? 0 : SSUSB_U3_PORT_DIS;
+ mtu3_writel(ibase, SSUSB_U3_CTRL(i), value);
+ }
+
+ /* power down and disable all u2 ports */
+ for (i = 0; i < num_u2p; i++) {
+ value = mtu3_readl(ibase, SSUSB_U2_CTRL(i));
+ value |= SSUSB_U2_PORT_PDN;
+ value |= suspend ? 0 : SSUSB_U2_PORT_DIS;
+ mtu3_writel(ibase, SSUSB_U2_CTRL(i), value);
+ }
+
+ /* power down host ip */
+ mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
+
+ if (!suspend)
+ return 0;
+
+ /* wait for host ip to sleep */
+ ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS1, value,
+ (value & SSUSB_IP_SLEEP_STS), 100, 100000);
+ if (ret)
+ dev_err(ssusb->dev, "ip sleep failed!!!\n");
+
+ return ret;
+}
+
+static void ssusb_host_setup(struct ssusb_mtk *ssusb)
+{
+ host_ports_num_get(ssusb);
+
+ /*
+ * power on host and power on/enable all ports
+ * if support OTG, gadget driver will switch port0 to device mode
+ */
+ ssusb_host_enable(ssusb);
+}
+
+static void ssusb_host_cleanup(struct ssusb_mtk *ssusb)
+{
+ ssusb_host_disable(ssusb, false);
+}
+
+/*
+ * If host supports multiple ports, the VBUSes(5V) of ports except port0
+ * which supports OTG are better to be enabled by default in DTS.
+ * Because the host driver will keep link with devices attached when system
+ * enters suspend mode, so no need to control VBUSes after initialization.
+ */
+int ssusb_host_init(struct ssusb_mtk *ssusb, struct device_node *parent_dn)
+{
+ struct device *parent_dev = ssusb->dev;
+ int ret;
+
+ ssusb_host_setup(ssusb);
+
+ ret = of_platform_populate(parent_dn, NULL, NULL, parent_dev);
+ if (ret) {
+ dev_dbg(parent_dev, "failed to create child devices at %s\n",
+ parent_dn->full_name);
+ return ret;
+ }
+
+ dev_info(parent_dev, "xHCI platform device register success...\n");
+
+ return 0;
+}
+
+void ssusb_host_exit(struct ssusb_mtk *ssusb)
+{
+ of_platform_depopulate(ssusb->dev);
+ ssusb_host_cleanup(ssusb);
+}
+
+int ssusb_wakeup_enable(struct ssusb_mtk *ssusb)
+{
+ int ret = 0;
+
+ if (ssusb->wakeup_en) {
+ ret = ssusb_wakeup_clks_enable(ssusb);
+ ssusb_wakeup_ip_sleep_en(ssusb);
+ }
+ return ret;
+}
+
+void ssusb_wakeup_disable(struct ssusb_mtk *ssusb)
+{
+ if (ssusb->wakeup_en) {
+ ssusb_wakeup_ip_sleep_dis(ssusb);
+ ssusb_wakeup_clks_disable(ssusb);
+ }
+}
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
index 52fc0ed..facb76c 100644
--- a/drivers/usb/mtu3/mtu3_plat.c
+++ b/drivers/usb/mtu3/mtu3_plat.c
@@ -21,14 +21,16 @@
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include "mtu3.h"
+#include "mtu3_dr.h"
/* u2-port0 should be powered on and enabled; */
-int ssusb_check_clocks(struct mtu3 *mtu, u32 ex_clks)
+int ssusb_check_clocks(struct ssusb_mtk *ssusb, u32 ex_clks)
{
- void __iomem *ibase = mtu->ippc_base;
+ void __iomem *ibase = ssusb->ippc_base;
u32 value, check_val;
int ret;
@@ -38,136 +40,209 @@ int ssusb_check_clocks(struct mtu3 *mtu, u32 ex_clks)
ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS1, value,
(check_val == (value & check_val)), 100, 20000);
if (ret) {
- dev_err(mtu->dev, "clks of sts1 are not stable!\n");
+ dev_err(ssusb->dev, "clks of sts1 are not stable!\n");
return ret;
}
ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS2, value,
(value & SSUSB_U2_MAC_SYS_RST_B_STS), 100, 10000);
if (ret) {
- dev_err(mtu->dev, "mac2 clock is not stable\n");
+ dev_err(ssusb->dev, "mac2 clock is not stable\n");
return ret;
}
return 0;
}
-static int ssusb_rscs_init(struct mtu3 *mtu)
+static int ssusb_phy_init(struct ssusb_mtk *ssusb)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < ssusb->num_phys; i++) {
+ ret = phy_init(ssusb->phys[i]);
+ if (ret)
+ goto exit_phy;
+ }
+ return 0;
+
+exit_phy:
+ for (; i > 0; i--)
+ phy_exit(ssusb->phys[i - 1]);
+
+ return ret;
+}
+
+static int ssusb_phy_exit(struct ssusb_mtk *ssusb)
+{
+ int i;
+
+ for (i = 0; i < ssusb->num_phys; i++)
+ phy_exit(ssusb->phys[i]);
+
+ return 0;
+}
+
+static int ssusb_phy_power_on(struct ssusb_mtk *ssusb)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < ssusb->num_phys; i++) {
+ ret = phy_power_on(ssusb->phys[i]);
+ if (ret)
+ goto power_off_phy;
+ }
+ return 0;
+
+power_off_phy:
+ for (; i > 0; i--)
+ phy_power_off(ssusb->phys[i - 1]);
+
+ return ret;
+}
+
+static void ssusb_phy_power_off(struct ssusb_mtk *ssusb)
+{
+ unsigned int i;
+
+ for (i = 0; i < ssusb->num_phys; i++)
+ phy_power_off(ssusb->phys[i]);
+}
+
+static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
{
int ret = 0;
- ret = regulator_enable(mtu->vusb33);
+ ret = regulator_enable(ssusb->vusb33);
if (ret) {
- dev_err(mtu->dev, "failed to enable vusb33\n");
+ dev_err(ssusb->dev, "failed to enable vusb33\n");
goto vusb33_err;
}
- ret = clk_prepare_enable(mtu->sys_clk);
+ ret = clk_prepare_enable(ssusb->sys_clk);
if (ret) {
- dev_err(mtu->dev, "failed to enable sys_clk\n");
+ dev_err(ssusb->dev, "failed to enable sys_clk\n");
goto clk_err;
}
- ret = phy_init(mtu->phy);
+ ret = ssusb_phy_init(ssusb);
if (ret) {
- dev_err(mtu->dev, "failed to init phy\n");
+ dev_err(ssusb->dev, "failed to init phy\n");
goto phy_init_err;
}
- ret = phy_power_on(mtu->phy);
+ ret = ssusb_phy_power_on(ssusb);
if (ret) {
- dev_err(mtu->dev, "failed to power on phy\n");
+ dev_err(ssusb->dev, "failed to power on phy\n");
goto phy_err;
}
return 0;
phy_err:
- phy_exit(mtu->phy);
+ ssusb_phy_exit(ssusb);
phy_init_err:
- clk_disable_unprepare(mtu->sys_clk);
+ clk_disable_unprepare(ssusb->sys_clk);
clk_err:
- regulator_disable(mtu->vusb33);
+ regulator_disable(ssusb->vusb33);
vusb33_err:
return ret;
}
-static void ssusb_rscs_exit(struct mtu3 *mtu)
+static void ssusb_rscs_exit(struct ssusb_mtk *ssusb)
{
- clk_disable_unprepare(mtu->sys_clk);
- regulator_disable(mtu->vusb33);
- phy_power_off(mtu->phy);
- phy_exit(mtu->phy);
+ clk_disable_unprepare(ssusb->sys_clk);
+ regulator_disable(ssusb->vusb33);
+ ssusb_phy_power_off(ssusb);
+ ssusb_phy_exit(ssusb);
}
-static void ssusb_ip_sw_reset(struct mtu3 *mtu)
+static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb)
{
- mtu3_setbits(mtu->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
+ /* reset whole ip (xhci & u3d) */
+ mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
udelay(1);
- mtu3_clrbits(mtu->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
+ mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
}
-static int get_ssusb_rscs(struct platform_device *pdev, struct mtu3 *mtu)
+static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
{
struct device_node *node = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct resource *res;
+ int i;
+ int ret;
- mtu->phy = devm_of_phy_get_by_index(dev, node, 0);
- if (IS_ERR(mtu->phy)) {
- dev_err(dev, "failed to get phy\n");
- return PTR_ERR(mtu->phy);
- }
-
- mtu->irq = platform_get_irq(pdev, 0);
- if (mtu->irq <= 0) {
- dev_err(dev, "fail to get irq number\n");
- return -ENODEV;
+ ssusb->num_phys = of_count_phandle_with_args(node,
+ "phys", "#phy-cells");
+ if (ssusb->num_phys > 0) {
+ ssusb->phys = devm_kcalloc(dev, ssusb->num_phys,
+ sizeof(*ssusb->phys), GFP_KERNEL);
+ if (!ssusb->phys)
+ return -ENOMEM;
+ } else {
+ ssusb->num_phys = 0;
}
- dev_info(dev, "irq %d\n", mtu->irq);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mac");
- mtu->mac_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(mtu->mac_base)) {
- dev_err(dev, "error mapping memory for dev mac\n");
- return PTR_ERR(mtu->mac_base);
+ for (i = 0; i < ssusb->num_phys; i++) {
+ ssusb->phys[i] = devm_of_phy_get_by_index(dev, node, i);
+ if (IS_ERR(ssusb->phys[i])) {
+ dev_err(dev, "failed to get phy-%d\n", i);
+ return PTR_ERR(ssusb->phys[i]);
+ }
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ippc");
- mtu->ippc_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(mtu->ippc_base)) {
+ ssusb->ippc_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ssusb->ippc_base)) {
dev_err(dev, "failed to map memory for ippc\n");
- return PTR_ERR(mtu->ippc_base);
+ return PTR_ERR(ssusb->ippc_base);
}
- mtu->vusb33 = devm_regulator_get(&pdev->dev, "vusb33");
- if (IS_ERR(mtu->vusb33)) {
+ ssusb->vusb33 = devm_regulator_get(&pdev->dev, "vusb33");
+ if (IS_ERR(ssusb->vusb33)) {
dev_err(dev, "failed to get vusb33\n");
- return PTR_ERR(mtu->vusb33);
+ return PTR_ERR(ssusb->vusb33);
}
- mtu->sys_clk = devm_clk_get(dev, "sys_ck");
- if (IS_ERR(mtu->sys_clk)) {
+ ssusb->sys_clk = devm_clk_get(dev, "sys_ck");
+ if (IS_ERR(ssusb->sys_clk)) {
dev_err(dev, "failed to get sys clock\n");
- return PTR_ERR(mtu->sys_clk);
+ return PTR_ERR(ssusb->sys_clk);
+ }
+
+ ssusb->dr_mode = usb_get_dr_mode(dev);
+ if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN) {
+ dev_err(dev, "dr_mode is error\n");
+ return -EINVAL;
}
+ if (ssusb->dr_mode == USB_DR_MODE_PERIPHERAL)
+ return 0;
+
+ /* if host role is supported */
+ ret = ssusb_wakeup_of_property_parse(ssusb, node);
+ if (ret)
+ return ret;
+
return 0;
}
static int mtu3_probe(struct platform_device *pdev)
{
+ struct device_node *node = pdev->dev.of_node;
struct device *dev = &pdev->dev;
- struct mtu3 *mtu;
+ struct ssusb_mtk *ssusb;
int ret = -ENOMEM;
/* all elements are set to ZERO as default value */
- mtu = devm_kzalloc(dev, sizeof(struct mtu3), GFP_KERNEL);
- if (!mtu)
+ ssusb = devm_kzalloc(dev, sizeof(*ssusb), GFP_KERNEL);
+ if (!ssusb)
return -ENOMEM;
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
@@ -176,11 +251,10 @@ static int mtu3_probe(struct platform_device *pdev)
return -ENOTSUPP;
}
- platform_set_drvdata(pdev, mtu);
- mtu->dev = dev;
- spin_lock_init(&mtu->lock);
+ platform_set_drvdata(pdev, ssusb);
+ ssusb->dev = dev;
- ret = get_ssusb_rscs(pdev, mtu);
+ ret = get_ssusb_rscs(pdev, ssusb);
if (ret)
return ret;
@@ -189,22 +263,45 @@ static int mtu3_probe(struct platform_device *pdev)
pm_runtime_get_sync(dev);
device_enable_async_suspend(dev);
- ret = ssusb_rscs_init(mtu);
+ ret = ssusb_rscs_init(ssusb);
if (ret)
goto comm_init_err;
- ssusb_ip_sw_reset(mtu);
-
- ret = ssusb_gadget_init(mtu);
- if (ret) {
- dev_err(dev, "failed to initialize gadget\n");
+ ssusb_ip_sw_reset(ssusb);
+
+ if (IS_ENABLED(CONFIG_USB_MTU3_HOST))
+ ssusb->dr_mode = USB_DR_MODE_HOST;
+ else if (IS_ENABLED(CONFIG_USB_MTU3_GADGET))
+ ssusb->dr_mode = USB_DR_MODE_PERIPHERAL;
+
+ /* default as host */
+ ssusb->is_host = !(ssusb->dr_mode == USB_DR_MODE_PERIPHERAL);
+
+ switch (ssusb->dr_mode) {
+ case USB_DR_MODE_PERIPHERAL:
+ ret = ssusb_gadget_init(ssusb);
+ if (ret) {
+ dev_err(dev, "failed to initialize gadget\n");
+ goto comm_exit;
+ }
+ break;
+ case USB_DR_MODE_HOST:
+ ret = ssusb_host_init(ssusb, node);
+ if (ret) {
+ dev_err(dev, "failed to initialize host\n");
+ goto comm_exit;
+ }
+ break;
+ default:
+ dev_err(dev, "unsupported mode: %d\n", ssusb->dr_mode);
+ ret = -EINVAL;
goto comm_exit;
}
return 0;
comm_exit:
- ssusb_rscs_exit(mtu);
+ ssusb_rscs_exit(ssusb);
comm_init_err:
pm_runtime_put_sync(dev);
@@ -215,16 +312,73 @@ static int mtu3_probe(struct platform_device *pdev)
static int mtu3_remove(struct platform_device *pdev)
{
- struct mtu3 *mtu = platform_get_drvdata(pdev);
+ struct ssusb_mtk *ssusb = platform_get_drvdata(pdev);
+
+ switch (ssusb->dr_mode) {
+ case USB_DR_MODE_PERIPHERAL:
+ ssusb_gadget_exit(ssusb);
+ break;
+ case USB_DR_MODE_HOST:
+ ssusb_host_exit(ssusb);
+ break;
+ default:
+ return -EINVAL;
+ }
- ssusb_gadget_exit(mtu);
- ssusb_rscs_exit(mtu);
+ ssusb_rscs_exit(ssusb);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
}
+/*
+ * when support dual-role mode, we reject suspend when
+ * it works as device mode;
+ */
+static int __maybe_unused mtu3_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ssusb_mtk *ssusb = platform_get_drvdata(pdev);
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ /* REVISIT: disconnect it for only device mode? */
+ if (!ssusb->is_host)
+ return 0;
+
+ ssusb_host_disable(ssusb, true);
+ ssusb_phy_power_off(ssusb);
+ clk_disable_unprepare(ssusb->sys_clk);
+ ssusb_wakeup_enable(ssusb);
+
+ return 0;
+}
+
+static int __maybe_unused mtu3_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ssusb_mtk *ssusb = platform_get_drvdata(pdev);
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ if (!ssusb->is_host)
+ return 0;
+
+ ssusb_wakeup_disable(ssusb);
+ clk_prepare_enable(ssusb->sys_clk);
+ ssusb_phy_power_on(ssusb);
+ ssusb_host_enable(ssusb);
+
+ return 0;
+}
+
+static const struct dev_pm_ops mtu3_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mtu3_suspend, mtu3_resume)
+};
+
+#define DEV_PM_OPS (IS_ENABLED(CONFIG_PM) ? &mtu3_pm_ops : NULL)
+
#ifdef CONFIG_OF
static const struct of_device_id mtu3_of_match[] = {
@@ -241,6 +395,7 @@ static int mtu3_remove(struct platform_device *pdev)
.remove = mtu3_remove,
.driver = {
.name = MTU3_DRIVER_NAME,
+ .pm = DEV_PM_OPS,
.of_match_table = of_match_ptr(mtu3_of_match),
},
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH v7, 5/8] usb: mtu3: Super-Speed Peripheral mode support
From: Chunfeng Yun @ 2016-10-19 2:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476844107-31087-1-git-send-email-chunfeng.yun@mediatek.com>
add super-speed funtion for peripheral mode
Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
drivers/usb/mtu3/mtu3.h | 13 ++-
drivers/usb/mtu3/mtu3_core.c | 202 ++++++++++++++++++++++++++++++++----
drivers/usb/mtu3/mtu3_gadget.c | 45 +++++---
drivers/usb/mtu3/mtu3_gadget_ep0.c | 90 ++++++++++++++++
drivers/usb/mtu3/mtu3_hw_regs.h | 33 ++++++
5 files changed, 346 insertions(+), 37 deletions(-)
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
index ad1a133..41a0473 100644
--- a/drivers/usb/mtu3/mtu3.h
+++ b/drivers/usb/mtu3/mtu3.h
@@ -53,6 +53,7 @@
#define USB_QMU_TQSAR(epnum) (U3D_TXQSAR1 + (((epnum) - 1) * 0x10))
#define USB_QMU_TQCPR(epnum) (U3D_TXQCPR1 + (((epnum) - 1) * 0x10))
+#define SSUSB_U3_CTRL(p) (U3D_SSUSB_U3_CTRL_0P + ((p) * 0x08))
#define SSUSB_U2_CTRL(p) (U3D_SSUSB_U2_CTRL_0P + ((p) * 0x08))
#define MTU3_DRIVER_NAME "mtu3"
@@ -63,6 +64,7 @@
#define MTU3_EP_WEDGE BIT(2)
#define MTU3_EP_BUSY BIT(3)
+#define MTU3_U3_IP_SLOT_DEFAULT 2
#define MTU3_U2_IP_SLOT_DEFAULT 1
/**
@@ -87,6 +89,7 @@ enum mtu3_speed {
MTU3_SPEED_INACTIVE = 0,
MTU3_SPEED_FULL = 1,
MTU3_SPEED_HIGH = 3,
+ MTU3_SPEED_SUPER = 4,
};
/**
@@ -190,6 +193,7 @@ struct mtu3_ep {
struct list_head req_list;
struct mtu3_gpd_ring gpd_ring;
+ const struct usb_ss_ep_comp_descriptor *comp_desc;
const struct usb_endpoint_descriptor *desc;
int flags;
@@ -208,7 +212,8 @@ struct mtu3_request {
/**
* struct mtu3 - device driver instance data.
- * @slot: MTU3_U2_IP_SLOT_DEFAULT for U2 IP
+ * @slot: MTU3_U2_IP_SLOT_DEFAULT for U2 IP only,
+ * MTU3_U3_IP_SLOT_DEFAULT for U3 IP
* @may_wakeup: means device's remote wakeup is enabled
* @is_self_powered: is reported in device status and the config descriptor
* @ep0_req: dummy request used while handling standard USB requests
@@ -242,12 +247,16 @@ struct mtu3 {
struct usb_gadget_driver *gadget_driver;
struct mtu3_request ep0_req;
u8 setup_buf[EP0_RESPONSE_BUF];
+ u32 max_speed;
unsigned is_active:1;
unsigned may_wakeup:1;
unsigned is_self_powered:1;
unsigned test_mode:1;
unsigned softconnect:1;
+ unsigned u1_enable:1;
+ unsigned u2_enable:1;
+ unsigned is_u3_ip:1;
u8 address;
u8 test_mode_nr;
@@ -324,7 +333,7 @@ int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
void mtu3_ep0_setup(struct mtu3 *mtu);
void mtu3_start(struct mtu3 *mtu);
void mtu3_stop(struct mtu3 *mtu);
-void mtu3_hs_softconn_set(struct mtu3 *mtu, bool enable);
+void mtu3_dev_on_off(struct mtu3 *mtu, int is_on);
int mtu3_gadget_setup(struct mtu3 *mtu);
void mtu3_gadget_cleanup(struct mtu3 *mtu);
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c
index 33d21dd..f9817ad 100644
--- a/drivers/usb/mtu3/mtu3_core.c
+++ b/drivers/usb/mtu3/mtu3_core.c
@@ -72,8 +72,20 @@ static void ep_fifo_free(struct mtu3_ep *mep)
__func__, mep->fifo_seg_size, mep->fifo_size, start_bit);
}
+/* enable/disable U3D SS function */
+static inline void mtu3_ss_func_set(struct mtu3 *mtu, bool enable)
+{
+ /* If usb3_en==0, LTSSM will go to SS.Disable state */
+ if (enable)
+ mtu3_setbits(mtu->mac_base, U3D_USB3_CONFIG, USB3_EN);
+ else
+ mtu3_clrbits(mtu->mac_base, U3D_USB3_CONFIG, USB3_EN);
+
+ dev_dbg(mtu->dev, "USB3_EN = %d\n", !!enable);
+}
+
/* set/clear U3D HS device soft connect */
-void mtu3_hs_softconn_set(struct mtu3 *mtu, bool enable)
+static inline void mtu3_hs_softconn_set(struct mtu3 *mtu, bool enable)
{
if (enable) {
mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT,
@@ -92,6 +104,13 @@ static int mtu3_device_enable(struct mtu3 *mtu)
u32 check_clk = 0;
mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
+
+ if (mtu->is_u3_ip) {
+ check_clk = SSUSB_U3_MAC_RST_B_STS;
+ mtu3_clrbits(ibase, SSUSB_U3_CTRL(0),
+ (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN |
+ SSUSB_U3_PORT_HOST_SEL));
+ }
mtu3_clrbits(ibase, SSUSB_U2_CTRL(0),
(SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN |
SSUSB_U2_PORT_HOST_SEL));
@@ -104,6 +123,10 @@ static void mtu3_device_disable(struct mtu3 *mtu)
{
void __iomem *ibase = mtu->ippc_base;
+ if (mtu->is_u3_ip)
+ mtu3_setbits(ibase, SSUSB_U3_CTRL(0),
+ (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN));
+
mtu3_setbits(ibase, SSUSB_U2_CTRL(0),
SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN);
mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);
@@ -142,6 +165,9 @@ static void mtu3_intr_status_clear(struct mtu3 *mtu)
/* Clear U2 USB common interrupts status */
mtu3_writel(mbase, U3D_COMMON_USB_INTR, ~0x0);
+ /* Clear U3 LTSSM interrupts status */
+ mtu3_writel(mbase, U3D_LTSSM_INTR, ~0x0);
+
/* Clear speed change interrupt status */
mtu3_writel(mbase, U3D_DEV_LINK_INTR, ~0x0);
}
@@ -153,13 +179,20 @@ static void mtu3_intr_enable(struct mtu3 *mtu)
u32 value;
/*Enable level 1 interrupts (BMU, QMU, MAC3, DMA, MAC2, EPCTL) */
- value = BMU_INTR | QMU_INTR | MAC2_INTR | EP_CTRL_INTR;
+ value = BMU_INTR | QMU_INTR | MAC3_INTR | MAC2_INTR | EP_CTRL_INTR;
mtu3_writel(mbase, U3D_LV1IESR, value);
/* Enable U2 common USB interrupts */
value = SUSPEND_INTR | RESUME_INTR | RESET_INTR;
mtu3_writel(mbase, U3D_COMMON_USB_INTR_ENABLE, value);
+ if (mtu->is_u3_ip) {
+ /* Enable U3 LTSSM interrupts */
+ value = HOT_RST_INTR | WARM_RST_INTR | VBUS_RISE_INTR |
+ VBUS_FALL_INTR | ENTER_U3_INTR | EXIT_U3_INTR;
+ mtu3_writel(mbase, U3D_LTSSM_INTR_ENABLE, value);
+ }
+
/* Enable QMU interrupts. */
value = TXQ_CSERR_INT | TXQ_LENERR_INT | RXQ_CSERR_INT |
RXQ_LENERR_INT | RXQ_ZLPERR_INT;
@@ -205,6 +238,17 @@ void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set)
set ? "SEND STALL" : "CLEAR STALL, with EP RESET");
}
+void mtu3_dev_on_off(struct mtu3 *mtu, int is_on)
+{
+ if (mtu->is_u3_ip && (mtu->max_speed == USB_SPEED_SUPER))
+ mtu3_ss_func_set(mtu, is_on);
+ else
+ mtu3_hs_softconn_set(mtu, is_on);
+
+ dev_info(mtu->dev, "gadget (%s) pullup D%s\n",
+ usb_speed_string(mtu->max_speed), is_on ? "+" : "-");
+}
+
void mtu3_start(struct mtu3 *mtu)
{
void __iomem *mbase = mtu->mac_base;
@@ -214,13 +258,21 @@ void mtu3_start(struct mtu3 *mtu)
mtu3_clrbits(mtu->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
+ /*
+ * When disable U2 port, USB2_CSR's register will be reset to
+ * default value after re-enable it again(HS is enabled by default).
+ * So if force mac to work as FS, disable HS function.
+ */
+ if (mtu->max_speed == USB_SPEED_FULL)
+ mtu3_clrbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
+
/* Initialize the default interrupts */
mtu3_intr_enable(mtu);
mtu->is_active = 1;
if (mtu->softconnect)
- mtu3_hs_softconn_set(mtu, 1);
+ mtu3_dev_on_off(mtu, 1);
}
void mtu3_stop(struct mtu3 *mtu)
@@ -231,7 +283,7 @@ void mtu3_stop(struct mtu3 *mtu)
mtu3_intr_status_clear(mtu);
if (mtu->softconnect)
- mtu3_hs_softconn_set(mtu, 0);
+ mtu3_dev_on_off(mtu, 0);
mtu->is_active = 0;
mtu3_setbits(mtu->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
@@ -362,7 +414,10 @@ void mtu3_deconfig_ep(struct mtu3 *mtu, struct mtu3_ep *mep)
}
/*
- * 1. when supports only HS, the fifo is shared for all EPs, and
+ * Two scenarios:
+ * 1. when device IP supports SS, the fifo of EP0, TX EPs, RX EPs
+ * are separated;
+ * 2. when supports only HS, the fifo is shared for all EPs, and
* the capability registers of @EPNTXFFSZ or @EPNRXFFSZ indicate
* the total fifo size of non-ep0, and ep0's is fixed to 64B,
* so the total fifo size is 64B + @EPNTXFFSZ;
@@ -376,18 +431,33 @@ static void get_ep_fifo_config(struct mtu3 *mtu)
struct mtu3_fifo_info *rx_fifo;
u32 fifosize;
- fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNTXFFSZ);
- tx_fifo = &mtu->tx_fifo;
- tx_fifo->base = MTU3_U2_IP_EP0_FIFO_SIZE;
- tx_fifo->limit = (fifosize / MTU3_EP_FIFO_UNIT) >> 1;
- bitmap_zero(tx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
-
- rx_fifo = &mtu->rx_fifo;
- rx_fifo->base =
- tx_fifo->base + tx_fifo->limit * MTU3_EP_FIFO_UNIT;
- rx_fifo->limit = tx_fifo->limit;
- bitmap_zero(rx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
- mtu->slot = MTU3_U2_IP_SLOT_DEFAULT;
+ if (mtu->is_u3_ip) {
+ fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNTXFFSZ);
+ tx_fifo = &mtu->tx_fifo;
+ tx_fifo->base = 0;
+ tx_fifo->limit = fifosize / MTU3_EP_FIFO_UNIT;
+ bitmap_zero(tx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+
+ fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNRXFFSZ);
+ rx_fifo = &mtu->rx_fifo;
+ rx_fifo->base = 0;
+ rx_fifo->limit = fifosize / MTU3_EP_FIFO_UNIT;
+ bitmap_zero(rx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+ mtu->slot = MTU3_U3_IP_SLOT_DEFAULT;
+ } else {
+ fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNTXFFSZ);
+ tx_fifo = &mtu->tx_fifo;
+ tx_fifo->base = MTU3_U2_IP_EP0_FIFO_SIZE;
+ tx_fifo->limit = (fifosize / MTU3_EP_FIFO_UNIT) >> 1;
+ bitmap_zero(tx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+
+ rx_fifo = &mtu->rx_fifo;
+ rx_fifo->base =
+ tx_fifo->base + tx_fifo->limit * MTU3_EP_FIFO_UNIT;
+ rx_fifo->limit = tx_fifo->limit;
+ bitmap_zero(rx_fifo->bitmap, MTU3_FIFO_BIT_SIZE);
+ mtu->slot = MTU3_U2_IP_SLOT_DEFAULT;
+ }
dev_dbg(mtu->dev, "%s, TX: base-%d, limit-%d; RX: base-%d, limit-%d\n",
__func__, tx_fifo->base, tx_fifo->limit,
@@ -416,17 +486,21 @@ static int mtu3_mem_alloc(struct mtu3 *mtu)
void __iomem *mbase = mtu->mac_base;
struct mtu3_ep *ep_array;
int in_ep_num, out_ep_num;
- u32 cap_epinfo;
+ u32 cap_epinfo, cap_dev;
int ret;
int i;
mtu->hw_version = mtu3_readl(mtu->ippc_base, U3D_SSUSB_HW_ID);
+ cap_dev = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_DEV_CAP);
+ mtu->is_u3_ip = !!SSUSB_IP_DEV_U3_PORT_NUM(cap_dev);
+
cap_epinfo = mtu3_readl(mbase, U3D_CAP_EPINFO);
in_ep_num = CAP_TX_EP_NUM(cap_epinfo);
out_ep_num = CAP_RX_EP_NUM(cap_epinfo);
- dev_info(mtu->dev, "IP version 0x%x\n", mtu->hw_version);
+ dev_info(mtu->dev, "IP version 0x%x(%s IP)\n", mtu->hw_version,
+ mtu->is_u3_ip ? "U3" : "U2");
dev_info(mtu->dev, "fifosz/epnum: Tx=%#x/%d, Rx=%#x/%d\n",
mtu3_readl(mbase, U3D_CAP_EPNTXFFSZ), in_ep_num,
mtu3_readl(mbase, U3D_CAP_EPNRXFFSZ), out_ep_num);
@@ -469,6 +543,27 @@ static void mtu3_mem_free(struct mtu3 *mtu)
kfree(mtu->ep_array);
}
+static void mtu3_set_speed(struct mtu3 *mtu)
+{
+ void __iomem *mbase = mtu->mac_base;
+
+ if (!mtu->is_u3_ip && (mtu->max_speed > USB_SPEED_HIGH))
+ mtu->max_speed = USB_SPEED_HIGH;
+
+ if (mtu->max_speed == USB_SPEED_FULL) {
+ /* disable U3 SS function */
+ mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN);
+ /* disable HS function */
+ mtu3_clrbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
+ } else if (mtu->max_speed == USB_SPEED_HIGH) {
+ mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN);
+ /* HS/FS detected by HW */
+ mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
+ }
+ dev_info(mtu->dev, "max_speed: %s\n",
+ usb_speed_string(mtu->max_speed));
+}
+
static void mtu3_regs_init(struct mtu3 *mtu)
{
@@ -478,9 +573,16 @@ static void mtu3_regs_init(struct mtu3 *mtu)
mtu3_intr_disable(mtu);
mtu3_intr_status_clear(mtu);
- mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN);
- /* HS/FS detected by HW */
- mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
+ if (mtu->is_u3_ip) {
+ /* disable LGO_U1/U2 by default */
+ mtu3_clrbits(mbase, U3D_LINK_POWER_CONTROL,
+ SW_U1_ACCEPT_ENABLE | SW_U2_ACCEPT_ENABLE |
+ SW_U1_REQUEST_ENABLE | SW_U2_REQUEST_ENABLE);
+ /* device responses to u3_exit from host automatically */
+ mtu3_clrbits(mbase, U3D_LTSSM_CTRL, SOFT_U3_EXIT_EN);
+ }
+
+ mtu3_set_speed(mtu);
/* delay about 0.1us from detecting reset to send chirp-K */
mtu3_clrbits(mbase, U3D_LINK_RESET_INFO, WTCHRP_MSK);
@@ -530,6 +632,10 @@ static irqreturn_t mtu3_link_isr(struct mtu3 *mtu)
mtu3_setbits(mbase, U3D_POWER_MANAGEMENT,
LPM_BESL_STALL | LPM_BESLD_STALL);
break;
+ case MTU3_SPEED_SUPER:
+ udev_speed = USB_SPEED_SUPER;
+ maxpkt = 512;
+ break;
default:
udev_speed = USB_SPEED_UNKNOWN;
break;
@@ -548,6 +654,34 @@ static irqreturn_t mtu3_link_isr(struct mtu3 *mtu)
return IRQ_HANDLED;
}
+static irqreturn_t mtu3_u3_ltssm_isr(struct mtu3 *mtu)
+{
+ void __iomem *mbase = mtu->mac_base;
+ u32 ltssm;
+
+ ltssm = mtu3_readl(mbase, U3D_LTSSM_INTR);
+ ltssm &= mtu3_readl(mbase, U3D_LTSSM_INTR_ENABLE);
+ mtu3_writel(mbase, U3D_LTSSM_INTR, ltssm); /* W1C */
+ dev_dbg(mtu->dev, "=== LTSSM[%x] ===\n", ltssm);
+
+ if (ltssm & (HOT_RST_INTR | WARM_RST_INTR))
+ mtu3_gadget_reset(mtu);
+
+ if (ltssm & VBUS_FALL_INTR)
+ mtu3_ss_func_set(mtu, false);
+
+ if (ltssm & VBUS_RISE_INTR)
+ mtu3_ss_func_set(mtu, true);
+
+ if (ltssm & EXIT_U3_INTR)
+ mtu3_gadget_resume(mtu);
+
+ if (ltssm & ENTER_U3_INTR)
+ mtu3_gadget_suspend(mtu);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t mtu3_u2_common_isr(struct mtu3 *mtu)
{
void __iomem *mbase = mtu->mac_base;
@@ -588,6 +722,9 @@ irqreturn_t mtu3_irq(int irq, void *data)
if (level1 & MAC2_INTR)
mtu3_u2_common_isr(mtu);
+ if (level1 & MAC3_INTR)
+ mtu3_u3_ltssm_isr(mtu);
+
if (level1 & BMU_INTR)
mtu3_ep0_isr(mtu);
@@ -633,6 +770,27 @@ int ssusb_gadget_init(struct mtu3 *mtu)
struct device *dev = mtu->dev;
int ret;
+ mtu->max_speed = usb_get_maximum_speed(dev);
+
+ /* check the max_speed parameter */
+ switch (mtu->max_speed) {
+ case USB_SPEED_FULL:
+ case USB_SPEED_HIGH:
+ case USB_SPEED_SUPER:
+ break;
+ default:
+ dev_err(dev, "invalid max_speed: %s\n",
+ usb_speed_string(mtu->max_speed));
+ /* fall through */
+ case USB_SPEED_UNKNOWN:
+ /* default as SS */
+ mtu->max_speed = USB_SPEED_SUPER;
+ break;
+ }
+
+ dev_dbg(dev, "mac_base=0x%p, ippc_base=0x%p\n",
+ mtu->mac_base, mtu->ippc_base);
+
ret = mtu3_hw_init(mtu);
if (ret) {
dev_err(dev, "mtu3 hw init failed:%d\n", ret);
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c
index 0e25e0f..84f3fe1 100644
--- a/drivers/usb/mtu3/mtu3_gadget.c
+++ b/drivers/usb/mtu3/mtu3_gadget.c
@@ -73,6 +73,7 @@ static void nuke(struct mtu3_ep *mep, const int status)
static int mtu3_ep_enable(struct mtu3_ep *mep)
{
const struct usb_endpoint_descriptor *desc;
+ const struct usb_ss_ep_comp_descriptor *comp_desc;
struct mtu3 *mtu = mep->mtu;
u32 interval = 0;
u32 mult = 0;
@@ -81,11 +82,24 @@ static int mtu3_ep_enable(struct mtu3_ep *mep)
int ret;
desc = mep->desc;
+ comp_desc = mep->comp_desc;
mep->type = usb_endpoint_type(desc);
max_packet = usb_endpoint_maxp(desc);
mep->maxp = max_packet & GENMASK(10, 0);
switch (mtu->g.speed) {
+ case USB_SPEED_SUPER:
+ if (usb_endpoint_xfer_int(desc) ||
+ usb_endpoint_xfer_isoc(desc)) {
+ interval = desc->bInterval;
+ interval = clamp_val(interval, 1, 16) - 1;
+ if (usb_endpoint_xfer_isoc(desc) && comp_desc)
+ mult = comp_desc->bmAttributes;
+ }
+ if (comp_desc)
+ burst = comp_desc->bMaxBurst;
+
+ break;
case USB_SPEED_HIGH:
if (usb_endpoint_xfer_isoc(desc) ||
usb_endpoint_xfer_int(desc)) {
@@ -103,6 +117,7 @@ static int mtu3_ep_enable(struct mtu3_ep *mep)
mep->ep.maxpacket = mep->maxp;
mep->ep.desc = desc;
+ mep->ep.comp_desc = comp_desc;
/* slot mainly affects bulk/isoc transfer, so ignore int */
mep->slot = usb_endpoint_xfer_int(desc) ? 0 : mtu->slot;
@@ -135,6 +150,7 @@ static int mtu3_ep_disable(struct mtu3_ep *mep)
mep->desc = NULL;
mep->ep.desc = NULL;
+ mep->comp_desc = NULL;
mep->type = 0;
mep->flags = 0;
@@ -178,6 +194,7 @@ static int mtu3_gadget_ep_enable(struct usb_ep *ep,
spin_lock_irqsave(&mtu->lock, flags);
mep->desc = desc;
+ mep->comp_desc = ep->comp_desc;
ret = mtu3_ep_enable(mep);
if (ret)
@@ -439,13 +456,15 @@ static int mtu3_gadget_wakeup(struct usb_gadget *gadget)
return -EOPNOTSUPP;
spin_lock_irqsave(&mtu->lock, flags);
-
- mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
- spin_unlock_irqrestore(&mtu->lock, flags);
- usleep_range(10000, 11000);
- spin_lock_irqsave(&mtu->lock, flags);
- mtu3_clrbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
-
+ if (mtu->g.speed == USB_SPEED_SUPER) {
+ mtu3_setbits(mtu->mac_base, U3D_LINK_POWER_CONTROL, UX_EXIT);
+ } else {
+ mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
+ spin_unlock_irqrestore(&mtu->lock, flags);
+ usleep_range(10000, 11000);
+ spin_lock_irqsave(&mtu->lock, flags);
+ mtu3_clrbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
+ }
spin_unlock_irqrestore(&mtu->lock, flags);
return 0;
}
@@ -476,7 +495,7 @@ static int mtu3_gadget_pullup(struct usb_gadget *gadget, int is_on)
mtu->softconnect = is_on;
} else if (is_on != mtu->softconnect) {
mtu->softconnect = is_on;
- mtu3_hs_softconn_set(mtu, is_on);
+ mtu3_dev_on_off(mtu, is_on);
}
spin_unlock_irqrestore(&mtu->lock, flags);
@@ -524,7 +543,7 @@ static void stop_activity(struct mtu3 *mtu)
/* deactivate the hardware */
if (mtu->softconnect) {
mtu->softconnect = 0;
- mtu3_hs_softconn_set(mtu, 0);
+ mtu3_dev_on_off(mtu, 0);
}
/*
@@ -587,14 +606,14 @@ static void init_hw_ep(struct mtu3 *mtu, struct mtu3_ep *mep,
mep->ep.name = mep->name;
INIT_LIST_HEAD(&mep->ep.ep_list);
- /* initialize maxpacket as HS */
+ /* initialize maxpacket as SS */
if (!epnum) {
- usb_ep_set_maxpacket_limit(&mep->ep, 64);
+ usb_ep_set_maxpacket_limit(&mep->ep, 512);
mep->ep.caps.type_control = true;
mep->ep.ops = &mtu3_ep0_ops;
mtu->g.ep0 = &mep->ep;
} else {
- usb_ep_set_maxpacket_limit(&mep->ep, 512);
+ usb_ep_set_maxpacket_limit(&mep->ep, 1024);
mep->ep.caps.type_iso = true;
mep->ep.caps.type_bulk = true;
mep->ep.caps.type_int = true;
@@ -637,7 +656,7 @@ int mtu3_gadget_setup(struct mtu3 *mtu)
int ret;
mtu->g.ops = &mtu3_gadget_ops;
- mtu->g.max_speed = USB_SPEED_HIGH;
+ mtu->g.max_speed = mtu->max_speed;
mtu->g.speed = USB_SPEED_UNKNOWN;
mtu->g.sg_supported = 0;
mtu->g.name = MTU3_DRIVER_NAME;
diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c
index 4e2c2bab..2d7427b 100644
--- a/drivers/usb/mtu3/mtu3_gadget_ep0.c
+++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c
@@ -161,6 +161,41 @@ static void ep0_stall_set(struct mtu3_ep *mep0, bool set, u32 pktrdy)
static void ep0_dummy_complete(struct usb_ep *ep, struct usb_request *req)
{}
+static void ep0_set_sel_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct mtu3_request *mreq;
+ struct mtu3 *mtu;
+ struct usb_set_sel_req sel;
+
+ memcpy(&sel, req->buf, sizeof(sel));
+
+ mreq = to_mtu3_request(req);
+ mtu = mreq->mtu;
+ dev_dbg(mtu->dev, "u1sel:%d, u1pel:%d, u2sel:%d, u2pel:%d\n",
+ sel.u1_sel, sel.u1_pel, sel.u2_sel, sel.u2_pel);
+}
+
+/* queue data stage to handle 6 byte SET_SEL request */
+static int ep0_set_sel(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
+{
+ int ret;
+ u16 length = le16_to_cpu(setup->wLength);
+
+ if (unlikely(length != 6)) {
+ dev_err(mtu->dev, "%s wrong wLength:%d\n",
+ __func__, length);
+ return -EINVAL;
+ }
+
+ mtu->ep0_req.mep = mtu->ep0;
+ mtu->ep0_req.request.length = 6;
+ mtu->ep0_req.request.buf = mtu->setup_buf;
+ mtu->ep0_req.request.complete = ep0_set_sel_complete;
+ ret = ep0_queue(mtu->ep0, &mtu->ep0_req);
+
+ return ret < 0 ? ret : 1;
+}
+
static int
ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
{
@@ -174,6 +209,15 @@ static void ep0_dummy_complete(struct usb_ep *ep, struct usb_request *req)
case USB_RECIP_DEVICE:
result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED;
result[0] |= mtu->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
+ /* superspeed only */
+ if (mtu->g.speed == USB_SPEED_SUPER) {
+ result[0] |= mtu->u1_enable << USB_DEV_STAT_U1_ENABLED;
+ result[0] |= mtu->u2_enable << USB_DEV_STAT_U2_ENABLED;
+ }
+
+ dev_dbg(mtu->dev, "%s result=%x, U1=%x, U2=%x\n", __func__,
+ result[0], mtu->u1_enable, mtu->u2_enable);
+
break;
case USB_RECIP_INTERFACE:
break;
@@ -265,7 +309,9 @@ static int handle_test_mode(struct mtu3 *mtu, struct usb_ctrlrequest *setup)
static int ep0_handle_feature_dev(struct mtu3 *mtu,
struct usb_ctrlrequest *setup, bool set)
{
+ void __iomem *mbase = mtu->mac_base;
int handled = -EINVAL;
+ u32 lpc;
switch (le16_to_cpu(setup->wValue)) {
case USB_DEVICE_REMOTE_WAKEUP:
@@ -279,6 +325,36 @@ static int ep0_handle_feature_dev(struct mtu3 *mtu,
handled = handle_test_mode(mtu, setup);
break;
+ case USB_DEVICE_U1_ENABLE:
+ if (mtu->g.speed != USB_SPEED_SUPER ||
+ mtu->g.state != USB_STATE_CONFIGURED)
+ break;
+
+ lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
+ if (set)
+ lpc |= SW_U1_ACCEPT_ENABLE;
+ else
+ lpc &= ~SW_U1_ACCEPT_ENABLE;
+ mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc);
+
+ mtu->u1_enable = !!set;
+ handled = 1;
+ break;
+ case USB_DEVICE_U2_ENABLE:
+ if (mtu->g.speed != USB_SPEED_SUPER ||
+ mtu->g.state != USB_STATE_CONFIGURED)
+ break;
+
+ lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
+ if (set)
+ lpc |= SW_U2_ACCEPT_ENABLE;
+ else
+ lpc &= ~SW_U2_ACCEPT_ENABLE;
+ mtu3_writel(mbase, U3D_LINK_POWER_CONTROL, lpc);
+
+ mtu->u2_enable = !!set;
+ handled = 1;
+ break;
default:
handled = -EINVAL;
break;
@@ -303,6 +379,17 @@ static int ep0_handle_feature(struct mtu3 *mtu,
case USB_RECIP_DEVICE:
handled = ep0_handle_feature_dev(mtu, setup, set);
break;
+ case USB_RECIP_INTERFACE:
+ /* superspeed only */
+ if ((value == USB_INTRF_FUNC_SUSPEND)
+ && (mtu->g.speed == USB_SPEED_SUPER)) {
+ /*
+ * forward the request because function drivers
+ * should handle it
+ */
+ handled = 0;
+ }
+ break;
case USB_RECIP_ENDPOINT:
epnum = index & USB_ENDPOINT_NUMBER_MASK;
if (epnum == 0 || epnum >= mtu->num_eps ||
@@ -390,6 +477,9 @@ static int handle_standard_request(struct mtu3 *mtu,
case USB_REQ_GET_STATUS:
handled = ep0_get_status(mtu, setup);
break;
+ case USB_REQ_SET_SEL:
+ handled = ep0_set_sel(mtu, setup);
+ break;
case USB_REQ_SET_ISOCH_DELAY:
handled = 1;
break;
diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h
index 08c83c5..2123672 100644
--- a/drivers/usb/mtu3/mtu3_hw_regs.h
+++ b/drivers/usb/mtu3/mtu3_hw_regs.h
@@ -260,13 +260,46 @@
/*---------------- SSUSB_USB3_MAC_CSR REGISTER DEFINITION ----------------*/
+#define U3D_LTSSM_CTRL (SSUSB_USB3_MAC_CSR_BASE + 0x0010)
#define U3D_USB3_CONFIG (SSUSB_USB3_MAC_CSR_BASE + 0x001C)
+#define U3D_LTSSM_INTR_ENABLE (SSUSB_USB3_MAC_CSR_BASE + 0x013C)
+#define U3D_LTSSM_INTR (SSUSB_USB3_MAC_CSR_BASE + 0x0140)
+
/*---------------- SSUSB_USB3_MAC_CSR FIELD DEFINITION ----------------*/
+/* U3D_LTSSM_CTRL */
+#define FORCE_POLLING_FAIL BIT(4)
+#define FORCE_RXDETECT_FAIL BIT(3)
+#define SOFT_U3_EXIT_EN BIT(2)
+#define COMPLIANCE_EN BIT(1)
+#define U1_GO_U2_EN BIT(0)
+
/* U3D_USB3_CONFIG */
#define USB3_EN BIT(0)
+/* U3D_LTSSM_INTR_ENABLE */
+/* U3D_LTSSM_INTR */
+#define U3_RESUME_INTR BIT(18)
+#define U3_LFPS_TMOUT_INTR BIT(17)
+#define VBUS_FALL_INTR BIT(16)
+#define VBUS_RISE_INTR BIT(15)
+#define RXDET_SUCCESS_INTR BIT(14)
+#define EXIT_U3_INTR BIT(13)
+#define EXIT_U2_INTR BIT(12)
+#define EXIT_U1_INTR BIT(11)
+#define ENTER_U3_INTR BIT(10)
+#define ENTER_U2_INTR BIT(9)
+#define ENTER_U1_INTR BIT(8)
+#define ENTER_U0_INTR BIT(7)
+#define RECOVERY_INTR BIT(6)
+#define WARM_RST_INTR BIT(5)
+#define HOT_RST_INTR BIT(4)
+#define LOOPBACK_INTR BIT(3)
+#define COMPLIANCE_INTR BIT(2)
+#define SS_DISABLE_INTR BIT(1)
+#define SS_INACTIVE_INTR BIT(0)
+
/*---------------- SSUSB_USB3_SYS_CSR REGISTER DEFINITION ----------------*/
#define U3D_LINK_UX_INACT_TIMER (SSUSB_USB3_SYS_CSR_BASE + 0x020C)
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox