* [PATCH v2 01/11] dt-bindings: add rk3399 support for dw-mipi-rockchip
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484561311-494-1-git-send-email-zyw@rock-chips.com>
The dw-mipi-dsi of rk3399 is almost the same as rk3288, the rk3399 has
additional phy config clock.
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
---
.../devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
index 1753f0c..0f82568 100644
--- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
+++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
@@ -5,10 +5,12 @@ Required properties:
- #address-cells: Should be <1>.
- #size-cells: Should be <0>.
- compatible: "rockchip,rk3288-mipi-dsi", "snps,dw-mipi-dsi".
+ "rockchip,rk3399-mipi-dsi", "snps,dw-mipi-dsi".
- reg: Represent the physical address range of the controller.
- interrupts: Represent the controller's interrupt to the CPU(s).
- clocks, clock-names: Phandles to the controller's pll reference
- clock(ref) and APB clock(pclk), as described in [1].
+ clock(ref) and APB clock(pclk). For RK3399, a phy config clock
+ (phy_cfg) is additional required. As described in [1].
- rockchip,grf: this soc should set GRF regs to mux vopl/vopb.
- ports: contain a port node with endpoint definitions as defined in [2].
For vopb,set the reg = <0> and set the reg = <1> for vopl.
--
2.6.3
^ permalink raw reply related
* [PATCH v2 0/11] Rockchip dw-mipi-dsi driver
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: linux-arm-kernel
Hi all
This patch serial is for RK3399 MIPI DSI. The MIPI DSI controller of
RK3399 is almost the same as RK3288, except a little bit of difference
in phy clock controlling and port id selection register.
And these patches also fixes some driver bugs; add the power domain
support.
they have been tested on rk3399 and rk3288 evb board.
Chris Zhong (7):
dt-bindings: add rk3399 support for dw-mipi-rockchip
drm/rockchip/dsi: dw-mipi: support RK3399 mipi dsi
drm/rockchip/dsi: remove mode_valid function
dt-bindings: add power domain node for dw-mipi-rockchip
drm/rockchip/dsi: add dw-mipi power domain support
drm/rockchip/dsi: fix phy clk lane stop state timeout
drm/rockchip/dsi: fix insufficient bandwidth of some panel
Mark Yao (2):
drm/rockchip/dsi: return probe defer if attach panel failed
drm/rockchip/dsi: fix mipi display can't found at init time
xubilv (2):
drm/rockchip/dsi: fix the issue can not send commands
drm/rockchip/dsi: decrease the value of Ths-prepare
.../display/rockchip/dw_mipi_dsi_rockchip.txt | 7 +-
drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 254 +++++++++++++--------
2 files changed, 163 insertions(+), 98 deletions(-)
--
2.6.3
^ permalink raw reply
* [PATCH 09/10] ARM: dts: da850: add the SATA node
From: Bartosz Golaszewski @ 2017-01-16 10:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4eb4ada8-1d2d-2fa1-7961-21da56ea0082@lechnology.com>
2017-01-13 20:36 GMT+01:00 David Lechner <david@lechnology.com>:
> On 01/13/2017 06:38 AM, Bartosz Golaszewski wrote:
>>
>> Add the SATA node to the da850 device tree.
>>
>> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>> ---
>> arch/arm/boot/dts/da850.dtsi | 6 ++++++
>> 1 file changed, 6 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
>> index 1f6a47d..f5086b1 100644
>> --- a/arch/arm/boot/dts/da850.dtsi
>> +++ b/arch/arm/boot/dts/da850.dtsi
>> @@ -427,6 +427,12 @@
>> phy-names = "usb-phy";
>> status = "disabled";
>> };
>> + sata: ahci at 0x218000 {
>
>
> 0x needs to be omitted.
>
> sata: ahci at 218000 {
>
Will fix in v2.
Thanks,
Bartosz Golaszewski
^ permalink raw reply
* [PATCH v1 3/3] reset: zx2967: add reset controller driver for ZTE's zx2967 family
From: Philipp Zabel @ 2017-01-16 9:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484377530-30635-3-git-send-email-baoyou.xie@linaro.org>
On Sat, 2017-01-14 at 15:05 +0800, Baoyou Xie wrote:
> This patch adds reset controller driver for ZTE's zx2967 family.
>
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> ---
> drivers/reset/Kconfig | 6 ++
> drivers/reset/Makefile | 1 +
> drivers/reset/reset-zx2967.c | 136 +++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 143 insertions(+)
> create mode 100644 drivers/reset/reset-zx2967.c
>
> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
> index 172dc96..972d077 100644
> --- a/drivers/reset/Kconfig
> +++ b/drivers/reset/Kconfig
> @@ -92,6 +92,12 @@ config RESET_ZYNQ
> help
> This enables the reset controller driver for Xilinx Zynq SoCs.
>
> +config RESET_ZX2967
> + bool "ZX2967 Reset Driver"
> + depends on ARCH_ZX || COMPILE_TEST
> + help
> + This enables the reset controller driver for ZTE zx2967 family.
> +
> source "drivers/reset/sti/Kconfig"
> source "drivers/reset/hisilicon/Kconfig"
> source "drivers/reset/tegra/Kconfig"
> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
> index 13b346e..807b77b 100644
> --- a/drivers/reset/Makefile
> +++ b/drivers/reset/Makefile
> @@ -14,3 +14,4 @@ obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
> obj-$(CONFIG_TI_SYSCON_RESET) += reset-ti-syscon.o
> obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
> obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
> +obj-$(CONFIG_RESET_ZX2967) += reset-zx2967.o
> diff --git a/drivers/reset/reset-zx2967.c b/drivers/reset/reset-zx2967.c
> new file mode 100644
> index 0000000..63f9c41
> --- /dev/null
> +++ b/drivers/reset/reset-zx2967.c
> @@ -0,0 +1,136 @@
> +/*
> + * ZTE's zx2967 family thermal sensor driver
This description is incorrect.
> + *
> + * Copyright (C) 2017 ZTE Ltd.
> + *
> + * Author: Baoyou Xie <baoyou.xie@linaro.org>
> + *
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset-controller.h>
> +
> +struct zx2967_reset {
> + void __iomem *reg_base;
> + spinlock_t lock;
> + struct reset_controller_dev rcdev;
> +};
> +
> +static int zx2967_reset_assert(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + struct zx2967_reset *reset = NULL;
> + int bank = id / 32;
> + int offset = id % 32;
> + unsigned int reg;
> + unsigned long flags;
> +
> + reset = container_of(rcdev, struct zx2967_reset, rcdev);
> +
> + spin_lock_irqsave(&reset->lock, flags);
> +
> + reg = readl(reset->reg_base + (bank * 4));
> + writel(reg & ~BIT(offset), reset->reg_base + (bank * 4));
> + reg = readl(reset->reg_base + (bank * 4));
> +
> + spin_unlock_irqrestore(&reset->lock, flags);
> +
> + return 0;
> +}
> +
> +static int zx2967_reset_deassert(struct reset_controller_dev *rcdev,
> + unsigned long id)
> +{
> + struct zx2967_reset *reset = NULL;
> + int bank = id / 32;
> + int offset = id % 32;
> + unsigned int reg;
> + unsigned long flags;
> +
> + reset = container_of(rcdev, struct zx2967_reset, rcdev);
> +
> + spin_lock_irqsave(&reset->lock, flags);
> +
> + reg = readl(reset->reg_base + (bank * 4));
> + writel(reg | BIT(offset), reset->reg_base + (bank * 4));
> + reg = readl(reset->reg_base + (bank * 4));
> +
> + spin_unlock_irqrestore(&reset->lock, flags);
> +
> + return 0;
> +}
> +
> +static struct reset_control_ops zx2967_reset_ops = {
> + .assert = zx2967_reset_assert,
> + .deassert = zx2967_reset_deassert,
> +};
> +
> +static int zx2967_reset_probe(struct platform_device *pdev)
> +{
> + struct zx2967_reset *reset;
> + struct resource *res;
> +
> + reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
> + if (!reset)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + reset->reg_base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(reset->reg_base))
> + return PTR_ERR(reset->reg_base);
> +
> + spin_lock_init(&reset->lock);
> +
> + reset->rcdev.owner = THIS_MODULE;
> + reset->rcdev.nr_resets = resource_size(res) * 8;
> + reset->rcdev.ops = &zx2967_reset_ops;
> + reset->rcdev.of_node = pdev->dev.of_node;
> +
> + dev_info(&pdev->dev, "reset controller cnt:%d",
> + reset->rcdev.nr_resets);
> +
> + return reset_controller_register(&reset->rcdev);
As Shawn suggested, use the devm_ variant here. It allows you to drop
the remove function below.
> +}
> +
> +static int zx2967_reset_remove(struct platform_device *pdev)
> +{
> + struct zx2967_reset *reset = platform_get_drvdata(pdev);
> +
> + reset_controller_unregister(&reset->rcdev);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id zx2967_reset_dt_ids[] = {
> + { .compatible = "zte,zx296718-reset", },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, zx2967_reset_dt_ids);
> +
> +static struct platform_driver zx2967_reset_driver = {
> + .probe = zx2967_reset_probe,
> + .remove = zx2967_reset_remove,
> + .driver = {
> + .name = "zx2967-reset",
> + .of_match_table = zx2967_reset_dt_ids,
> + },
> +};
> +
> +static int __init zx2967_reset_init(void)
> +{
> + return platform_driver_register(&zx2967_reset_driver);
> +}
> +arch_initcall(zx2967_reset_init);
> +
> +static void __exit zx2967_reset_exit(void)
> +{
> + platform_driver_unregister(&zx2967_reset_driver);
> +}
> +module_exit(zx2967_reset_exit);
> +
> +MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
> +MODULE_DESCRIPTION("ZTE zx2967 Reset Controller Driver");
> +MODULE_LICENSE("GPL");
regards
Philipp
^ permalink raw reply
* [PATCH v1 1/3] dt: bindings: add documentation for zx2967 family reset controller
From: Philipp Zabel @ 2017-01-16 9:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484377530-30635-1-git-send-email-baoyou.xie@linaro.org>
Hi,
On Sat, 2017-01-14 at 15:05 +0800, Baoyou Xie wrote:
> This patch adds dt-binding documentation for zx2967 family
> reset controller.
>
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> ---
> .../devicetree/bindings/reset/zte,zx2967-reset.txt | 20 ++++++++++++++++++++
> 1 file changed, 20 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
>
> diff --git a/Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt b/Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
> new file mode 100644
> index 0000000..22d590e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/reset/zte,zx2967-reset.txt
> @@ -0,0 +1,20 @@
> +ZTE zx2967 SoCs Reset Controller
> +=======================================
> +
> +Please also refer to reset.txt in this directory for common reset
> +controller binding usage.
> +
> +Required properties:
> +- compatible: should be one of the following.
> + * zte,zx296718-reset
> +- reg: physical base address of the controller and length of memory mapped
> + region.
> +- #reset-cells: must be 1.
> +
> +example:
> +
> + toprst: reset at 1461060 {
That node should be named reset-controller.
> + compatible = "zte,zx296718-reset";
> + reg = <0x01461060 0x8>;
> + #reset-cells = <1>;
> + };
regards
Philipp
^ permalink raw reply
* [PATCH RFC 2/2] ARM: nommu: remap exception base address to RAM
From: Vladimir Murzin @ 2017-01-16 9:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170115114750.GA5456@afzalpc>
Hi,
On 15/01/17 11:47, Afzal Mohammed wrote:
> Hi,
>
> On Sat, Jan 07, 2017 at 10:43:39PM +0530, Afzal Mohammed wrote:
>> On Tue, Dec 13, 2016 at 10:02:26AM +0000, Russell King - ARM Linux wrote:
>
>>> Also, if the region setup for the vectors was moved as well, it would
>>> then be possible to check the ID registers to determine whether this
>>> is supported, and make the decision where to locate the vectors base
>>> more dynamically.
>>
>> This would affect Cortex-R's, which is a bit concerning due to lack of
>> those platforms with me, let me try to get it right.
>
> QEMU too doesn't seem to provide a Cortex-R target
>
>> Seems translating __setup_mpu() altogether to C
>
> afaics, a kind of C translation is already present as
> mpu_setup_region() in arch/arm/mm/nommu.c that takes care of
> MPU_RAM_REGION only. And that seems to be a kind of redundant as it is
> also done in asm at __setup_mpu(). Git blames asm & C to consecutive
> commits, that makes me a little shaky about the conclusion on it being
> redundant.
>
It is not redundant. MPU setup is done it two steps. The first step done in
asm to enable caches, there only kernel image is covered; the second step takes
care on the whole RAM given via dt or "mem=" parameter.
I think other regions are kept there to avoid C side dancing in case of SMP.
>> & installing at a later, but suitable place might be better.
>
> But looks like enabling MPU can't be moved to C & that would
> necessitate keeping at least some portion of__setu_mpu() in asm.
>
> Instead, moving region setup only for vectors to C as Russell
> suggested at first would have to be done.
>
> A kind of diff at the end is in my mind, with additional changes to
> handle the similar during secondary cpu bringup too.
>
> Thinking of invoking mpu_setup() from secondary_start_kernel() in
> arch/arm/kernel/smp.c, with mpu_setup() being slightly modified to
> avoid storing region details again when invoked by secondary cpu's.
I have wip patches on reworking MPU setup code. The idea is to start using
mpu_rgn_info[] actively, so asm part for secondariness would just sync-up
content of that array. Additionally, it seems that we can reuse free MPU slots
to cover memory which is discarded due to MPU alignment restrictions...
>
> Vladimir, once changes are done after a revisit, i would need your
> help to test on Cortex-R.
I'm more than happy to help, but currently I have limited bandwidth, so if it
can wait till the next dev cycle I'd try to make MPU rework finished by that
time.
>
> As an aside, wasn't aware of the fact that Cortex-R supports SMP
> Linux, had thought that, of !MMU one's, only Blackfin & J2 had it.
>
>
>> Also !MMU Kernel could boot on 3 ARM v7-A platforms - AM335x Beagle
>> Bone (A8), AM437x IDK (A9) & Vybrid VF610 (on A5 core, note that it
>> has M4 core too)
>
> Talking about Cortex-M, AMx3's too have it, to be specific M3, but
> they are not Linux-able unlike the one in VF610.
>
Thanks!
Vladimir
> Regards
> afzal
>
> --->8---
>
> diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
> index e0565d73e49e..f8ac79b6136d 100644
> --- a/arch/arm/kernel/head-nommu.S
> +++ b/arch/arm/kernel/head-nommu.S
> @@ -249,20 +249,6 @@ ENTRY(__setup_mpu)
> setup_region r0, r5, r6, MPU_INSTR_SIDE @ 0x0, BG region, enabled
> 2: isb
>
> - /* Vectors region */
> - set_region_nr r0, #MPU_VECTORS_REGION
> - isb
> - /* Shared, inaccessible to PL0, rw PL1 */
> - mov r0, #CONFIG_VECTORS_BASE @ Cover from VECTORS_BASE
> - ldr r5,=(MPU_AP_PL1RW_PL0NA | MPU_RGN_NORMAL)
> - /* Writing N to bits 5:1 (RSR_SZ) --> region size 2^N+1 */
> - mov r6, #(((2 * PAGE_SHIFT - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN)
> -
> - setup_region r0, r5, r6, MPU_DATA_SIDE @ VECTORS_BASE, PL0 NA, enabled
> - beq 3f @ Memory-map not unified
> - setup_region r0, r5, r6, MPU_INSTR_SIDE @ VECTORS_BASE, PL0 NA, enabled
> -3: isb
> -
> /* Enable the MPU */
> mrc p15, 0, r0, c1, c0, 0 @ Read SCTLR
> bic r0, r0, #CR_BR @ Disable the 'default mem-map'
> diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
> index e82056df0635..7fe8906322d5 100644
> --- a/arch/arm/mm/nommu.c
> +++ b/arch/arm/mm/nommu.c
> @@ -269,12 +269,19 @@ void __init mpu_setup(void)
> ilog2(memblock.memory.regions[0].size),
> MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL);
> if (region_err) {
> - panic("MPU region initialization failure! %d", region_err);
> + panic("MPU RAM region initialization failure! %d", region_err);
> } else {
> - pr_info("Using ARMv7 PMSA Compliant MPU. "
> - "Region independence: %s, Max regions: %d\n",
> - mpu_iside_independent() ? "Yes" : "No",
> - mpu_max_regions());
> + region_err = mpu_setup_region(MPU_VECTORS_REGION, vectors_base,
> + ilog2(memblock.memory.regions[0].size),
> + MPU_AP_PL1RW_PL0NA | MPU_RGN_NORMAL);
> + if (region_err) {
> + panic("MPU VECTOR region initialization failure! %d",
> + region_err);
> + } else {
> + pr_info("Using ARMv7 PMSA Compliant MPU. "
> + "Region independence: %s, Max regions: %d\n",
> + mpu_iside_independent() ? "Yes" : "No",
> + mpu_max_regions());
> }
> }
> #else
>
^ permalink raw reply
* [PATCH 3/4] ARM64: dts: meson-gx-p23x-q20x: enable the Bluetooth module
From: Martin Blumenstingl @ 2017-01-16 9:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <042e2824-0772-cf27-ffa5-4c3b2af7c92b@suse.de>
On Mon, Jan 16, 2017 at 1:47 AM, Andreas F?rber <afaerber@suse.de> wrote:
> Am 15.01.2017 um 23:32 schrieb Martin Blumenstingl:
>> This takes the Bluetooth module out of reset (the reset line is
>> connected to GPIOX_17) and enables uart_A which is used to configure the
>> module.
>> This is identical for all boards which inherit meson-gx-p23x-q20x:
>> - GXL S905D P230
>> - GXL S905D P231
>> - GXM S912 Q200
>> - GXM S912 Q201
>>
>> To get the HCI interface up one has to install bluez-utils and run:
>> hciattach -s115200 /dev/ttyAML1 bcm43xx 2000000 flow -
>>
>> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
>> ---
>> arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 12 +++++++++++-
>> 1 file changed, 11 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
>> index 7a078bef04cd..7db779048091 100644
>> --- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
>> +++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
>> @@ -48,6 +48,7 @@
>> / {
>> aliases {
>> serial0 = &uart_AO;
>> + serial1 = &uart_A;
>> };
>>
>> chosen {
>> @@ -94,12 +95,21 @@
>>
>> sdio_pwrseq: sdio-pwrseq {
>> compatible = "mmc-pwrseq-simple";
>> - reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>;
>> + reset-gpios = <&gpio GPIOX_6 GPIO_ACTIVE_LOW>,
>> + <&gpio GPIOX_17 GPIO_ACTIVE_LOW>;
>> clocks = <&wifi32k>;
>> clock-names = "ext_clock";
>> };
>> };
>>
>> +/* This is connected to the Bluetooth module of the wifi/BT combo chip: */
>> +&uart_A {
>> + status = "okay";
>> + pinctrl-0 = <&uart_a_pins &uart_a_cts_rts_pins>;
>
> Nit: <&uart_a_pins>, <&uart_a_cts_rts_pins> please, like you've done for
> reset-gpios above.
indeed, not sure why I mixed it up. should I also send an update for
the pinctrl-documentation (as it seems to use the same pattern): [0]?
> Regards,
> Andreas
>
>> + pinctrl-names = "default";
>> + uart-has-rtscts;
>> +};
>> +
>> /* This UART is brought out to the DB9 connector */
>> &uart_AO {
>> status = "okay";
>>
>
>
> --
> SUSE Linux GmbH, Maxfeldstr. 5, 90409 N?rnberg, Germany
> GF: Felix Imend?rffer, Jane Smithard, Graham Norton
> HRB 21284 (AG N?rnberg)
[0] http://lxr.free-electrons.com/source/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt?v=4.9#L74
^ permalink raw reply
* [PATCH v2 0/2] phy: Replace the deprecated extcon API
From: Kishon Vijay Abraham I @ 2017-01-16 9:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <587C8DE8.5050106@samsung.com>
On Monday 16 January 2017 02:40 PM, Chanwoo Choi wrote:
> Hi Kishon,
>
> On 2017? 01? 10? 17:16, Chanwoo Choi wrote:
>> Hi Kishon,
>>
>> Could you review these patches or pick up them if there is no any comment?
>
> If there are no comments, could you apply these patches?
merged it already. You should see it phy -next before tomorrow.
Thanks
Kishon
>
>>
>> On 2016? 12? 30? 13:11, Chanwoo Choi wrote:
>>> This patches just replace the deprecated extcon API without any change
>>> of extcon operation and use the resource-managed function for
>>> extcon_register_notifier().
>>>
>>> The new extcon API instead of deprecated API.
>>> - extcon_set_cable_state_() -> extcon_set_state_sync();
>>> - extcon_get_cable_state_() -> extcon_get_state();
>>>
>>> Changes from v1:
>>> - Rebase these patches based on v4.10-rc1.
>>> - Drop the usb/power-supply/chipidea patches.
>>>
>>> Chanwoo Choi (2):
>>> phy: rcar-gen3-usb2: Replace the deprecated extcon API
>>> phy: sun4i-usb: Replace the deprecated extcon API
>>>
>>> drivers/phy/phy-rcar-gen3-usb2.c | 8 ++++----
>>> drivers/phy/phy-sun4i-usb.c | 4 ++--
>>> 2 files changed, 6 insertions(+), 6 deletions(-)
>>>
>>
>
>
^ permalink raw reply
* [PATCH 2/5] phy: meson: add USB2 and USB3 PHY support for Meson GXL
From: Kishon Vijay Abraham I @ 2017-01-16 9:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161126145635.24488-3-martin.blumenstingl@googlemail.com>
Hi,
On Saturday 26 November 2016 08:26 PM, Martin Blumenstingl wrote:
> This adds two new USB PHY drivers found on Meson GXL and GXM SoCs.
Please send them as separate drivers.
>
> The registers for the USB2 PHY block handle a maximum of 4 ports (newer
> SoCs may allow more ports, the driver handles this as long as the
> register length is adjusted in the .dts). The PHY block theoretically
> allows powering down each PHY port separately (by putting it into
> "reset" state). Unfortunately this does not work (my board has 2 USB
> ports, connected to port 1 and 2 of the dwc3's internal hub. When
> leaving the third USB PHY disabled then the hub sees that a device is
> plugged in, but it does not work: "usb usb1-port2: connect-debounce
> failed").
> The USB3 PHY will take care of enabling/disabling all available ports,
> because the USB3 PHY also manages the mode of the USB2 PHYs.
>
> The USB3 PHY actually has three purposes:
> - it provides the USB3 PHY
> - it handles the OTG device/host mode detection interrupt
> - it notifies the corresponding USB2 PHYs of the OTG mode changes
> On GXL and GXM SoCs one references all available USB2 PHY ports in the
> USB3 PHY because all are connected to the same USB controller (thus the
> mode will always match). This behavior is configurable via devicetree,
> by passing (or not passing) a list of other ("child") PHYs which should
> be configured by the USB3 PHY.
>
> Unfortunately there are no datasheets available for any of these PHYs.
> Both drivers were written by reading the reference drivers provided by
> Amlogic and analyzing the registers on the kernel that was shipped with
> my board.
>
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> ---
> drivers/phy/Kconfig | 13 ++
> drivers/phy/Makefile | 2 +
> drivers/phy/phy-meson-gxl-usb2.c | 374 ++++++++++++++++++++++++++++++++++++++
> drivers/phy/phy-meson-gxl-usb3.c | 377 +++++++++++++++++++++++++++++++++++++++
> 4 files changed, 766 insertions(+)
> create mode 100644 drivers/phy/phy-meson-gxl-usb2.c
> create mode 100644 drivers/phy/phy-meson-gxl-usb3.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 728e03f..ea74843 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -502,4 +502,17 @@ config PHY_MESON8B_USB2
> and GXBB SoCs.
> If unsure, say N.
>
> +config PHY_MESON_GXL_USB
> + tristate "Meson GXL USB2 and USB3 PHY drivers"
> + default ARCH_MESON
> + depends on OF && (ARCH_MESON || COMPILE_TEST)
> + depends on USB_SUPPORT
> + select USB_COMMON
> + select GENERIC_PHY
> + select REGMAP_MMIO
> + help
> + Enable this to support the Meson USB2 and USB3 PHYs found in
> + Meson GXL SoCs.
> + If unsure, say N.
> +
> endmenu
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 0c7fdae..960a96e 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -61,3 +61,5 @@ obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
> obj-$(CONFIG_ARCH_TEGRA) += tegra/
> obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
> obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
> +obj-$(CONFIG_PHY_MESON_GXL_USB) += phy-meson-gxl-usb2.o
> +obj-$(CONFIG_PHY_MESON_GXL_USB) += phy-meson-gxl-usb3.o
> diff --git a/drivers/phy/phy-meson-gxl-usb2.c b/drivers/phy/phy-meson-gxl-usb2.c
> new file mode 100644
> index 0000000..c081ce3
> --- /dev/null
> +++ b/drivers/phy/phy-meson-gxl-usb2.c
> @@ -0,0 +1,374 @@
> +/*
> + * Meson GXL USB2 PHY driver
> + *
> + * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/regmap.h>
> +#include <linux/reset.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/usb/of.h>
> +
> +/* bits [31:27] are read-only */
> +#define U2P_R0 0x0
> + #define U2P_R0_BYPASS_SEL BIT(0)
> + #define U2P_R0_BYPASS_DM_EN BIT(1)
> + #define U2P_R0_BYPASS_DP_EN BIT(2)
> + #define U2P_R0_TXBITSTUFF_ENH BIT(3)
> + #define U2P_R0_TXBITSTUFF_EN BIT(4)
> + #define U2P_R0_DM_PULLDOWN BIT(5)
> + #define U2P_R0_DP_PULLDOWN BIT(6)
> + #define U2P_R0_DP_VBUS_VLD_EXT_SEL BIT(7)
> + #define U2P_R0_DP_VBUS_VLD_EXT BIT(8)
> + #define U2P_R0_ADP_PRB_EN BIT(9)
> + #define U2P_R0_ADP_DISCHARGE BIT(10)
> + #define U2P_R0_ADP_CHARGE BIT(11)
> + #define U2P_R0_DRV_VBUS BIT(12)
> + #define U2P_R0_ID_PULLUP BIT(13)
> + #define U2P_R0_LOOPBACK_EN_B BIT(14)
> + #define U2P_R0_OTG_DISABLE BIT(15)
> + #define U2P_R0_COMMON_ONN BIT(16)
> + #define U2P_R0_FSEL_SHIFT 17
> + #define U2P_R0_FSEL_MASK GENMASK(19, 17)
> + #define U2P_R0_REF_CLK_SEL_SHIFT 20
> + #define U2P_R0_REF_CLK_SEL_MASK GENMASK(21, 20)
> + #define U2P_R0_POWER_ON_RESET BIT(22)
> + #define U2P_R0_V_ATE_TEST_EN_B_SHIFT 23
> + #define U2P_R0_V_ATE_TEST_EN_B_MASK GENMASK(24, 23)
> + #define U2P_R0_ID_SET_ID_DQ BIT(25)
> + #define U2P_R0_ATE_RESET BIT(26)
> + #define U2P_R0_FSV_MINUS BIT(27)
> + #define U2P_R0_FSV_PLUS BIT(28)
> + #define U2P_R0_BYPASS_DM_DATA BIT(29)
> + #define U2P_R0_BYPASS_DP_DATA BIT(30)
> +
> +#define U2P_R1 0x4
> + #define U2P_R1_BURN_IN_TEST BIT(0)
> + #define U2P_R1_ACA_ENABLE BIT(1)
> + #define U2P_R1_DCD_ENABLE BIT(2)
> + #define U2P_R1_VDAT_SRC_EN_B BIT(3)
> + #define U2P_R1_VDAT_DET_EN_B BIT(4)
> + #define U2P_R1_CHARGES_SEL BIT(5)
> + #define U2P_R1_TX_PREEMP_PULSE_TUNE BIT(6)
> + #define U2P_R1_TX_PREEMP_AMP_TUNE_SHIFT 7
> + #define U2P_R1_TX_PREEMP_AMP_TUNE_MASK GENMASK(8, 7)
> + #define U2P_R1_TX_RES_TUNE_SHIFT 9
> + #define U2P_R1_TX_RES_TUNE_MASK GENMASK(10, 9)
> + #define U2P_R1_TX_RISE_TUNE_SHIFT 11
> + #define U2P_R1_TX_RISE_TUNE_MASK GENMASK(12, 11)
> + #define U2P_R1_TX_VREF_TUNE_SHIFT 13
> + #define U2P_R1_TX_VREF_TUNE_MASK GENMASK(16, 13)
> + #define U2P_R1_TX_FSLS_TUNE_SHIFT 17
> + #define U2P_R1_TX_FSLS_TUNE_MASK GENMASK(20, 17)
> + #define U2P_R1_TX_HSXV_TUNE_SHIFT 21
> + #define U2P_R1_TX_HSXV_TUNE_MASK GENMASK(22, 21)
> + #define U2P_R1_OTG_TUNE_SHIFT 23
> + #define U2P_R1_OTG_TUNE_MASK GENMASK(25, 23)
> + #define U2P_R1_SQRX_TUNE_SHIFT 26
> + #define U2P_R1_SQRX_TUNE_MASK GENMASK(28, 26)
> + #define U2P_R1_COMP_DIS_TUNE_SHIFT 29
> + #define U2P_R1_COMP_DIS_TUNE_MASK GENMASK(31, 29)
> +
> +/* bits [31:14] are read-only */
> +#define U2P_R2 0x8
> + #define U2P_R2_DATA_IN_SHIFT 0
> + #define U2P_R2_DATA_IN_MASK GENMASK(3, 0)
> + #define U2P_R2_DATA_IN_EN_SHIFT 4
> + #define U2P_R2_DATA_IN_EN_MASK GENMASK(7, 4)
> + #define U2P_R2_ADDR_SHIFT 8
> + #define U2P_R2_ADDR_MASK GENMASK(11, 8)
> + #define U2P_R2_DATA_OUT_SEL BIT(12)
> + #define U2P_R2_CLK BIT(13)
> + #define U2P_R2_DATA_OUT_SHIFT 14
> + #define U2P_R2_DATA_OUT_MASK GENMASK(17, 14)
> + #define U2P_R2_ACA_PIN_RANGE_C BIT(18)
> + #define U2P_R2_ACA_PIN_RANGE_B BIT(19)
> + #define U2P_R2_ACA_PIN_RANGE_A BIT(20)
> + #define U2P_R2_ACA_PIN_GND BIT(21)
> + #define U2P_R2_ACA_PIN_FLOAT BIT(22)
> + #define U2P_R2_CHARGE_DETECT BIT(23)
> + #define U2P_R2_DEVICE_SESSION_VALID BIT(24)
> + #define U2P_R2_ADP_PROBE BIT(25)
> + #define U2P_R2_ADP_SENSE BIT(26)
> + #define U2P_R2_SESSION_END BIT(27)
> + #define U2P_R2_VBUS_VALID BIT(28)
> + #define U2P_R2_B_VALID BIT(29)
> + #define U2P_R2_A_VALID BIT(30)
> + #define U2P_R2_ID_DIG BIT(31)
> +
> +#define U2P_R3 0xc
> +
> +#define PHY_PORT_RESOURCE_SIZE 0x20
> +
> +#define RESET_COMPLETE_TIME 500
> +
> +struct phy_meson_gxl_usb2_priv {
> + struct regmap *regmap;
> + enum phy_mode mode;
> +};
> +
> +struct phy_meson_gxl_usb2_drv {
> + void __iomem *base;
> + int num_ports;
> + struct phy **ports;
> + struct clk *clk_usb;
> + struct clk *clk_usb_ddr;
> +};
> +
> +static const struct regmap_config phy_meson_gxl_usb2_regmap_conf = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = U2P_R3,
> +};
> +
> +static int phy_meson_gxl_usb2_set_mode(struct phy *phy, enum phy_mode mode)
> +{
> + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> +
> + switch (mode) {
> + case PHY_MODE_USB_HOST:
> + case PHY_MODE_USB_OTG:
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN,
> + U2P_R0_DM_PULLDOWN);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN,
> + U2P_R0_DP_PULLDOWN);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP, 0);
> + break;
> +
> + case PHY_MODE_USB_DEVICE:
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN,
> + 0);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN,
> + 0);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP,
> + U2P_R0_ID_PULLUP);
> + break;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + /* reset the PHY and wait until settings are stabilized */
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
> + U2P_R0_POWER_ON_RESET);
> + udelay(RESET_COMPLETE_TIME);
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, 0);
> + udelay(RESET_COMPLETE_TIME);
> +
> + priv->mode = mode;
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_power_off(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb2_drv *drv_priv =
> + dev_get_drvdata(phy->dev.parent);
> + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> +
> + /* power off the PHY by putting it into reset mode */
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET,
> + U2P_R0_POWER_ON_RESET);
> +
> + clk_disable_unprepare(drv_priv->clk_usb_ddr);
> + clk_disable_unprepare(drv_priv->clk_usb);
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_power_on(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb2_drv *drv_priv =
> + dev_get_drvdata(phy->dev.parent);
> + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
> + int ret;
> +
> + ret = clk_prepare_enable(drv_priv->clk_usb);
> + if (ret) {
> + dev_err(&phy->dev, "Failed to enable USB clock\n");
> + return ret;
> + }
> +
> + ret = clk_prepare_enable(drv_priv->clk_usb_ddr);
> + if (ret) {
> + clk_disable_unprepare(drv_priv->clk_usb);
> +
> + dev_err(&phy->dev, "Failed to enable USB DDR clock\n");
> + return ret;
> + }
> +
> + /* power on the PHY by taking it out of reset mode */
> + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, 0);
> +
> + ret = phy_meson_gxl_usb2_set_mode(phy, priv->mode);
> + if (ret) {
> + phy_meson_gxl_usb2_power_off(phy);
> +
> + dev_err(&phy->dev, "Failed to initialize PHY with mode %d\n",
> + priv->mode);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static const struct phy_ops phy_meson_gxl_usb2_ops = {
> + .power_on = phy_meson_gxl_usb2_power_on,
> + .power_off = phy_meson_gxl_usb2_power_off,
> + .set_mode = phy_meson_gxl_usb2_set_mode,
> + .owner = THIS_MODULE,
> +};
> +
> +static struct phy *phy_meson_gxl_usb2_of_xlate(struct device *dev,
> + struct of_phandle_args *args)
> +{
> + struct phy_meson_gxl_usb2_drv *priv = dev_get_drvdata(dev);
> + int port;
> +
> + if (args->args_count != 1) {
> + dev_err(dev, "Invalid number of cells in 'phy' property\n");
> + return ERR_PTR(-ENODEV);
> + }
> +
> + port = args->args[0];
> + if (WARN_ON(port >= priv->num_ports))
> + return ERR_PTR(-ENODEV);
> +
> + return priv->ports[port];
> +}
Please model every port as a sub-node and get rid of custom xlate implementation.
> +
> +static int phy_meson_gxl_usb2_probe_port(struct device *dev, int port)
> +{
> + struct phy_meson_gxl_usb2_drv *drv_priv = dev_get_drvdata(dev);
> + struct phy_meson_gxl_usb2_priv *phy_priv;
> + struct phy *phy;
> + void __iomem *port_base;
> +
> + phy_priv = devm_kzalloc(dev, sizeof(*phy_priv), GFP_KERNEL);
> + if (!phy_priv)
> + return -ENOMEM;
> +
> + switch (of_usb_get_dr_mode_by_phy(dev->of_node, port)) {
> + case USB_DR_MODE_PERIPHERAL:
> + phy_priv->mode = PHY_MODE_USB_DEVICE;
> + break;
> + case USB_DR_MODE_OTG:
> + phy_priv->mode = PHY_MODE_USB_OTG;
> + break;
> + case USB_DR_MODE_HOST:
> + default:
> + phy_priv->mode = PHY_MODE_USB_HOST;
> + break;
> + }
> +
> + phy = devm_phy_create(dev, NULL, &phy_meson_gxl_usb2_ops);
> + if (IS_ERR(phy)) {
> + dev_err(dev, "failed to create PHY port %d\n", port);
> + return PTR_ERR(phy);
> + }
> +
> + port_base = drv_priv->base + (port * PHY_PORT_RESOURCE_SIZE);
> + phy_priv->regmap = devm_regmap_init_mmio(&phy->dev, port_base,
> + &phy_meson_gxl_usb2_regmap_conf);
> + if (IS_ERR(phy_priv->regmap))
> + return PTR_ERR(phy_priv->regmap);
> +
> + phy_set_drvdata(phy, phy_priv);
> +
> + drv_priv->ports[port] = phy;
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb2_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct phy_meson_gxl_usb2_drv *priv;
> + struct phy_provider *phy_provider;
> + struct resource *res;
> + int i, ret;
> +
> + ret = device_reset(dev);
> + if (ret) {
> + dev_err(dev, "failed to reset device\n");
> + return ret;
> + }
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + platform_set_drvdata(pdev, priv);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + priv->base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(priv->base))
> + return PTR_ERR(priv->base);
> +
> + priv->num_ports = resource_size(res) / PHY_PORT_RESOURCE_SIZE;
> + if (priv->num_ports < 1) {
> + dev_err(dev, "specified memory range is too small\n");
> + return -EINVAL;
> + }
> +
> + priv->ports = devm_kcalloc(dev, priv->num_ports, sizeof(*priv->ports),
> + GFP_KERNEL);
> + if (!priv->ports)
> + return -ENOMEM;
> +
> + priv->clk_usb = devm_clk_get(dev, "usb");
> + if (IS_ERR(priv->clk_usb)) {
> + dev_err(dev, "failed to get USB clock\n");
> + return PTR_ERR(priv->clk_usb);
> + }
> +
> + priv->clk_usb_ddr = devm_clk_get(dev, "usb_ddr");
> + if (IS_ERR(priv->clk_usb_ddr)) {
> + dev_err(dev, "failed to get USB DDR clock\n");
> + return PTR_ERR(priv->clk_usb_ddr);
> + }
> +
> + for (i = 0; i < priv->num_ports; i++) {
> + ret = phy_meson_gxl_usb2_probe_port(dev, i);
> + if (ret)
> + return ret;
> + }
> +
> + phy_provider = devm_of_phy_provider_register(dev,
> + phy_meson_gxl_usb2_of_xlate);
> +
> + return PTR_ERR_OR_ZERO(phy_provider);
> +}
> +
> +static const struct of_device_id phy_meson_gxl_usb2_of_match[] = {
> + { .compatible = "amlogic,meson-gxl-usb2-phy", },
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb2_of_match);
> +
> +static struct platform_driver phy_meson_gxl_usb2_driver = {
> + .probe = phy_meson_gxl_usb2_probe,
> + .driver = {
> + .name = "phy-meson-gxl-usb2",
> + .of_match_table = phy_meson_gxl_usb2_of_match,
> + },
> +};
> +module_platform_driver(phy_meson_gxl_usb2_driver);
> +
> +MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
> +MODULE_DESCRIPTION("Meson GXL USB2 PHY driver");
> +MODULE_LICENSE("GPL");
GPL v2 to match with the file header.
> diff --git a/drivers/phy/phy-meson-gxl-usb3.c b/drivers/phy/phy-meson-gxl-usb3.c
> new file mode 100644
> index 0000000..90a4028
> --- /dev/null
> +++ b/drivers/phy/phy-meson-gxl-usb3.c
> @@ -0,0 +1,377 @@
> +/*
> + * Meson GXL USB3 PHY driver
> + *
> + * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/reset.h>
> +#include <linux/regmap.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/usb/of.h>
> +#include <linux/workqueue.h>
> +
> +#define USB_R0 0x00
> + #define USB_R0_P30_FSEL_SHIFT 0
> + #define USB_R0_P30_FSEL_MASK GENMASK(5, 0)
> + #define USB_R0_P30_PHY_RESET BIT(6)
> + #define USB_R0_P30_TEST_POWERDOWN_HSP BIT(7)
> + #define USB_R0_P30_TEST_POWERDOWN_SSP BIT(8)
> + #define USB_R0_P30_ACJT_LEVEL_SHIFT 9
> + #define USB_R0_P30_ACJT_LEVEL_MASK GENMASK(13, 9)
> + #define USB_R0_P30_TX_BOOST_LEVEL_SHIFT 14
> + #define USB_R0_P30_TX_BOOST_LEVEL_MASK GENMASK(16, 14)
> + #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17)
> + #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18)
> + #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_SHIFT 19
> + #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19)
> + #define USB_R0_U2D_SS_SCALEDOWN_MODE_SHIFT 29
> + #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29)
> + #define USB_R0_U2D_ACT BIT(31)
> +
> +#define USB_R1 0x04
> + #define USB_R1_U3H_BIGENDIAN_GS BIT(0)
> + #define USB_R1_U3H_PME_ENABLE BIT(1)
> + #define USB_R1_U3H_HUB_PORT_OVERCURRENT_SHIFT 2
> + #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(6, 2)
> + #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_SHIFT 7
> + #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(11, 7)
> + #define USB_R1_U3H_HOST_U2_PORT_DISABLE_SHIFT 12
> + #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(15, 12)
> + #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16)
> + #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17)
> + #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18)
> + #define USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT 19
> + #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19)
> + #define USB_R1_P30_PCS_TX_SWING_FULL_SHIFT 25
> + #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25)
> +
> +#define USB_R2 0x08
> + #define USB_R2_P30_CR_DATA_IN_SHIFT 0
> + #define USB_R2_P30_CR_DATA_IN_MASK GENMASK(15, 0)
> + #define USB_R2_P30_CR_READ BIT(16)
> + #define USB_R2_P30_CR_WRITE BIT(17)
> + #define USB_R2_P30_CR_CAP_ADDR BIT(18)
> + #define USB_R2_P30_CR_CAP_DATA BIT(19)
> + #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_SHIFT 20
> + #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20)
> + #define USB_R2_P30_PCS_TX_DEEMPH_6DB_SHIFT 26
> + #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26)
> +
> +#define USB_R3 0x0c
> + #define USB_R3_P30_SSC_ENABLE BIT(0)
> + #define USB_R3_P30_SSC_RANGE_SHIFT 1
> + #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1)
> + #define USB_R3_P30_SSC_REF_CLK_SEL_SHIFT 4
> + #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4)
> + #define USB_R3_P30_REF_SSP_EN BIT(13)
> + #define USB_R3_P30_LOS_BIAS_SHIFT 16
> + #define USB_R3_P30_LOS_BIAS_MASK GENMASK(18, 16)
> + #define USB_R3_P30_LOS_LEVEL_SHIFT 19
> + #define USB_R3_P30_LOS_LEVEL_MASK GENMASK(23, 19)
> + #define USB_R3_P30_MPLL_MULTIPLIER_SHIFT 24
> + #define USB_R3_P30_MPLL_MULTIPLIER_MASK GENMASK(30, 24)
> +
> +#define USB_R4 0x10
> + #define USB_R4_P21_PORT_RESET_0 BIT(0)
> + #define USB_R4_P21_SLEEP_M0 BIT(1)
> + #define USB_R4_MEM_PD_SHIFT 2
> + #define USB_R4_MEM_PD_MASK GENMASK(3, 2)
> + #define USB_R4_P21_ONLY BIT(4)
> +
> +#define USB_R5 0x14
> + #define USB_R5_ID_DIG_SYNC BIT(0)
> + #define USB_R5_ID_DIG_REG BIT(1)
> + #define USB_R5_ID_DIG_CFG_SHIFT 2
> + #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2)
> + #define USB_R5_ID_DIG_EN_0 BIT(4)
> + #define USB_R5_ID_DIG_EN_1 BIT(5)
> + #define USB_R5_ID_DIG_CURR BIT(6)
> + #define USB_R5_ID_DIG_IRQ BIT(7)
> + #define USB_R5_ID_DIG_TH_SHIFT 8
> + #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8)
> + #define USB_R5_ID_DIG_CNT_SHIFT 16
> + #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16)
> +
> +/* read-only register */
> +#define USB_R6 0x18
> + #define USB_R6_P30_CR_DATA_OUT_SHIFT 0
> + #define USB_R6_P30_CR_DATA_OUT_MASK GENMASK(15, 0)
> + #define USB_R6_P30_CR_ACK BIT(16)
> +
> +#define RESET_COMPLETE_TIME 500
> +
> +struct phy_meson_gxl_usb3_priv {
> + struct regmap *regmap;
> + struct delayed_work otg_work;
> + struct phy *this_phy;
> + int num_usb2_phys;
> + struct phy **usb2_phys;
> +};
> +
> +static const struct regmap_config phy_meson_gxl_usb3_regmap_conf = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> + .max_register = USB_R6,
> +};
> +
> +static int phy_meson_gxl_usb3_update_mode(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + u32 val;
> + enum phy_mode mode;
> + int i, ret;
> +
> + ret = regmap_read(priv->regmap, USB_R5, &val);
> + if (ret)
> + return ret;
> +
> + if (val & USB_R5_ID_DIG_CURR) {
> + mode = PHY_MODE_USB_DEVICE;
> +
> + regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT,
> + USB_R0_U2D_ACT);
> + regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
> + USB_R4_P21_SLEEP_M0);
> + } else {
> + mode = PHY_MODE_USB_HOST;
> +
> + regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT, 0);
> + regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
> + 0);
> + }
> +
> + /* inform the USB2 PHY that we have changed the mode */
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_set_mode(priv->usb2_phys[i], mode);
I'm finding it difficult to understand this. Why should the mode of one phy be
set from another phy? Maybe this part should be implemented using extcon?
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to update usb2-phy #%d mode to %d\n",
> + i, mode);
> + return ret;
> + }
> + }
> +
> + return ret;
> +}
> +
> +static void phy_meson_gxl_usb3_work(struct work_struct *data)
> +{
> + struct phy_meson_gxl_usb3_priv *priv =
> + container_of(data, struct phy_meson_gxl_usb3_priv,
> + otg_work.work);
> +
> + phy_meson_gxl_usb3_update_mode(priv->this_phy);
> +
> + /* unmask IRQs which may have arrived in the meantime */
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
> +}
> +
> +static int phy_meson_gxl_usb3_init(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + int i, ret;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_init(priv->usb2_phys[i]);
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to initialize related usb2-phy #%d\n",
> + i);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb3_exit(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + int i, ret;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_exit(priv->usb2_phys[i]);
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to exit related usb2-phy #%d\n", i);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int phy_meson_gxl_usb3_power_on(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + int i, ret;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_power_on(priv->usb2_phys[i]);
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to power on related usb2-phy #%d\n",
> + i);
> + return ret;
> + }
> + }
> +
> + regmap_update_bits(priv->regmap, USB_R1,
> + USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
> + 0x20 << USB_R1_U3H_FLADJ_30MHZ_REG_SHIFT);
> +
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0,
> + USB_R5_ID_DIG_EN_0);
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1,
> + USB_R5_ID_DIG_EN_1);
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_TH_MASK,
> + 0xff << USB_R5_ID_DIG_TH_SHIFT);
> +
> + return phy_meson_gxl_usb3_update_mode(phy);
> +}
> +
> +static int phy_meson_gxl_usb3_power_off(struct phy *phy)
> +{
> + struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
> + int i, ret;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + ret = phy_power_off(priv->usb2_phys[i]);
> + if (ret) {
> + dev_err(&phy->dev,
> + "Failed to power off related usb2-phy #%d\n",
> + i);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static irqreturn_t phy_meson_gxl_usb3_irq(int irq, void *data)
> +{
> + u32 val;
> + struct phy_meson_gxl_usb3_priv *priv = data;
> +
> + regmap_read(priv->regmap, USB_R5, &val);
> + if (!(val & USB_R5_ID_DIG_IRQ)) {
> + dev_err(&priv->this_phy->dev, "spurious interrupt\n");
> + return IRQ_NONE;
> + }
> +
> + schedule_delayed_work(&priv->otg_work, msecs_to_jiffies(10));
> +
> + /* acknowledge the IRQ */
> + regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_IRQ, 0);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static const struct phy_ops phy_meson_gxl_usb3_ops = {
> + .init = phy_meson_gxl_usb3_init,
> + .exit = phy_meson_gxl_usb3_exit,
> + .power_on = phy_meson_gxl_usb3_power_on,
> + .power_off = phy_meson_gxl_usb3_power_off,
> + .owner = THIS_MODULE,
> +};
> +
> +static int phy_meson_gxl_usb3_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct device_node *np = dev->of_node;
> + struct phy_meson_gxl_usb3_priv *priv;
> + struct resource *res;
> + struct phy *phy;
> + struct phy_provider *phy_provider;
> + void __iomem *base;
> + int i, irq;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + base = devm_ioremap_resource(dev, res);
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + priv->regmap = devm_regmap_init_mmio(dev, base,
> + &phy_meson_gxl_usb3_regmap_conf);
> + if (IS_ERR(priv->regmap))
> + return PTR_ERR(priv->regmap);
> +
> + irq = platform_get_irq(pdev, 0);
> + if (irq >= 0) {
> + INIT_DELAYED_WORK(&priv->otg_work, phy_meson_gxl_usb3_work);
> +
> + irq = devm_request_irq(dev, irq, phy_meson_gxl_usb3_irq,
> + IRQF_SHARED, dev_name(dev),
> + priv);
> + if (irq < 0) {
> + dev_err(dev, "could not register IRQ handler (%d)\n",
> + irq);
> + return -EINVAL;
> + }
> + }
> +
> + priv->num_usb2_phys = of_count_phandle_with_args(np, "phys",
> + "#phy-cells");
> +
> + priv->usb2_phys = devm_kcalloc(dev, priv->num_usb2_phys,
> + sizeof(*priv->usb2_phys), GFP_KERNEL);
> + if (!priv->usb2_phys)
> + return -ENOMEM;
> +
> + for (i = 0; i < priv->num_usb2_phys; i++) {
> + priv->usb2_phys[i] = devm_of_phy_get_by_index(dev, np, i);
I'm not sure if referencing usb2_phy from here is the right approach.
Thanks
Kishon
^ permalink raw reply
* [PATCH 2/2] spi: pca2xx-pci: Allow MSI
From: Andy Shevchenko @ 2017-01-16 9:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4061bba80ecc632b219b56d8a8cd25d62658d48a.1484557560.git.jan.kiszka@siemens.com>
On Mon, 2017-01-16 at 10:06 +0100, Jan Kiszka wrote:
> Now that the core is ready for edge-triggered interrupts, we can
> safely
> allow the PCI versions that provide this to enable the feature and,
> thus, have less shared interrupts.
>
My comments below.
> - ?if (IS_ERR(ssp->clk))
> + if (IS_ERR(ssp->clk))
> ? return PTR_ERR(ssp->clk);
This doesn't belong to the patch.
?
> + pci_set_master(dev);
> +
> + ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES);
> + if (ret < 0) {
> + clk_unregister(ssp->clk);
> + return ret;
> + }
> + ssp->irq = pci_irq_vector(dev, 0);
> +
This looks good, though I would put it closer to the initial place of
ssp->irq assignment, i.e. before clock registering.
> + pci_free_irq_vectors(dev);
> + pci_free_irq_vectors(dev);
You know my answer, right? So, please be sure that we are using
pcim_alloc_irq_vectors().
Yes, I know there is (was?) no such API, needs to be created. Currently
this might make a mess on ->remove().
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply
* [PATCH 1/2] spi: pxa2xx: Prepare for edge-triggered interrupts
From: Andy Shevchenko @ 2017-01-16 9:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6fe26505e67790b27eed28fd7451b51e70b7e8ba.1484557560.git.jan.kiszka@siemens.com>
On Mon, 2017-01-16 at 10:05 +0100, Jan Kiszka wrote:
> When using the a device with edge-triggered interrupts, such as MSIs,
> the interrupt handler has to ensure that there is a point in time
> during
> its execution where all interrupts sources are silent so that a new
> event can trigger a new interrupt again.
>
> This is achieved here by looping over SSSR evaluation. We need to take
> into account that SSCR1 may be changed by the transfer handler, thus
> we
> need to redo the mask calculation, at least regarding the volatile
> interrupt enable bit (TIE).
Could you split this to two patches, one just move the code under
question to a helper function (no functional change), the other does
what you state in commit message here?
>
> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
> ---
> ?drivers/spi/spi-pxa2xx.c | 50 +++++++++++++++++++++++++++----------
> -----------
> ?1 file changed, 28 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
> index dd7b5b4..24bf549 100644
> --- a/drivers/spi/spi-pxa2xx.c
> +++ b/drivers/spi/spi-pxa2xx.c
> @@ -737,6 +737,7 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
> ? struct driver_data *drv_data = dev_id;
> ? u32 sccr1_reg;
> ? u32 mask = drv_data->mask_sr;
> + irqreturn_t ret = IRQ_NONE;
> ? u32 status;
> ?
> ? /*
> @@ -760,37 +761,42 @@ static irqreturn_t ssp_int(int irq, void
> *dev_id)
> ?
> ? sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1);
> ?
> - /* Ignore possible writes if we don't need to write */
> - if (!(sccr1_reg & SSCR1_TIE))
> - mask &= ~SSSR_TFS;
> -
> ? /* Ignore RX timeout interrupt if it is disabled */
> ? if (!(sccr1_reg & SSCR1_TINTE))
> ? mask &= ~SSSR_TINT;
> ?
> - if (!(status & mask))
> - return IRQ_NONE;
> + while (1) {
> + /* Ignore possible writes if we don't need to write
> */
> + if (!(sccr1_reg & SSCR1_TIE))
> + mask &= ~SSSR_TFS;
> ?
> - if (!drv_data->master->cur_msg) {
> + if (!(status & mask))
> + return ret;
> ?
> - pxa2xx_spi_write(drv_data, SSCR0,
> - ?pxa2xx_spi_read(drv_data, SSCR0)
> - ?& ~SSCR0_SSE);
> - pxa2xx_spi_write(drv_data, SSCR1,
> - ?pxa2xx_spi_read(drv_data, SSCR1)
> - ?& ~drv_data->int_cr1);
> - if (!pxa25x_ssp_comp(drv_data))
> - pxa2xx_spi_write(drv_data, SSTO, 0);
> - write_SSSR_CS(drv_data, drv_data->clear_sr);
> + if (!drv_data->master->cur_msg) {
> ?
> - dev_err(&drv_data->pdev->dev,
> - "bad message state in interrupt handler\n");
> + pxa2xx_spi_write(drv_data, SSCR0,
> + ?pxa2xx_spi_read(drv_data,
> SSCR0)
> + ?& ~SSCR0_SSE);
> + pxa2xx_spi_write(drv_data, SSCR1,
> + ?pxa2xx_spi_read(drv_data,
> SSCR1)
> + ?& ~drv_data->int_cr1);
> + if (!pxa25x_ssp_comp(drv_data))
> + pxa2xx_spi_write(drv_data, SSTO, 0);
> + write_SSSR_CS(drv_data, drv_data->clear_sr);
> ?
> - /* Never fail */
> - return IRQ_HANDLED;
> - }
> + dev_err(&drv_data->pdev->dev,
> + "bad message state in interrupt
> handler\n");
> ?
> - return drv_data->transfer_handler(drv_data);
> + /* Never fail */
> + return IRQ_HANDLED;
> + }
> +
> + ret |= drv_data->transfer_handler(drv_data);
> +
> + status = pxa2xx_spi_read(drv_data, SSSR);
> + sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1);
> + }
> ?}
> ?
> ?/*
--
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy
^ permalink raw reply
* [PATCH 2/3] Broadcom USB DRD Phy driver for Northstar2
From: Kishon Vijay Abraham I @ 2017-01-16 9:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480485338-23451-3-git-send-email-raviteja.garimella@broadcom.com>
Hi,
On Wednesday 30 November 2016 11:25 AM, Raviteja Garimella wrote:
> This is driver for USB DRD Phy used in Broadcom's Northstar2
> SoC. The phy can be configured to be in Device mode or Host
> mode based on the type of cable connected to the port. The
> driver registers to extcon framework to get appropriate
> connect events for Host/Device cables connect/disconnect
> states based on VBUS and ID interrupts.
>
> Signed-off-by: Raviteja Garimella <raviteja.garimella@broadcom.com>
> ---
> drivers/phy/Kconfig | 13 +
> drivers/phy/Makefile | 1 +
> drivers/phy/phy-bcm-ns2-usbdrd.c | 587 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 601 insertions(+)
> create mode 100644 drivers/phy/phy-bcm-ns2-usbdrd.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index fe00f91..b3b6a73 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -479,6 +479,19 @@ config PHY_CYGNUS_PCIE
> Enable this to support the Broadcom Cygnus PCIe PHY.
> If unsure, say N.
>
> +config PHY_NS2_USB_DRD
> + tristate "Broadcom Northstar2 USB DRD PHY support"
> + depends on OF && (ARCH_BCM_IPROC || COMPILE_TEST)
> + select GENERIC_PHY
> + select EXTCON
> + default ARCH_BCM_IPROC
> + help
> + Enable this to support the Broadcom Northstar2 USB DRD PHY.
> + This driver initializes the PHY in either HOST or DEVICE mode.
> + The host or device configuration is read from device tree.
> +
> + If unsure, say N.
> +
> source "drivers/phy/tegra/Kconfig"
>
> config PHY_NS2_PCIE
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index a534cf5..b733ba2 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -58,5 +58,6 @@ obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
> obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o
> obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
> obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o
> +obj-$(CONFIG_PHY_NS2_USB_DRD) += phy-bcm-ns2-usbdrd.o
> obj-$(CONFIG_ARCH_TEGRA) += tegra/
> obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o
> diff --git a/drivers/phy/phy-bcm-ns2-usbdrd.c b/drivers/phy/phy-bcm-ns2-usbdrd.c
> new file mode 100644
> index 0000000..460040d
> --- /dev/null
> +++ b/drivers/phy/phy-bcm-ns2-usbdrd.c
> @@ -0,0 +1,587 @@
> +/*
> + * Copyright (C) 2016 Broadcom
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/extcon.h>
> +#include <linux/gpio.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +
> +#define ICFG_DRD_AFE 0x0
> +#define ICFG_MISC_STAT 0x18
> +#define ICFG_DRD_P0CTL 0x1C
> +#define ICFG_STRAP_CTRL 0x20
> +#define ICFG_FSM_CTRL 0x24
> +
> +#define IDM_RST_BIT BIT(0)
> +#define AFE_CORERDY_VDDC BIT(18)
> +#define PHY_PLL_RESETB BIT(15)
> +#define PHY_RESETB BIT(14)
> +#define PHY_PLL_LOCK BIT(0)
> +
> +#define DRD_DEV_MODE BIT(20)
> +#define OHCI_OVRCUR_POL BIT(11)
> +#define ICFG_OFF_MODE BIT(6)
> +#define PLL_LOCK_RETRY 1000
> +
> +#define EVT_DEVICE 0
> +#define EVT_HOST 1
> +#define EVT_IDLE 2
> +
> +#define DRD_HOST_MODE (BIT(2) | BIT(3))
> +#define DRD_DEVICE_MODE (BIT(4) | BIT(5))
> +#define DRD_HOST_VAL 0x803
> +#define DRD_DEV_VAL 0x807
> +#define GPIO_DELAY 20
> +#define PHY_WQ_DELAY msecs_to_jiffies(600)
> +
> +struct ns2_phy_data;
> +struct ns2_phy_driver {
> + void __iomem *icfgdrd_regs;
> + void __iomem *idmdrd_rst_ctrl;
> + void __iomem *crmu_usb2_ctrl;
> + void __iomem *usb2h_strap_reg;
> + spinlock_t lock; /* spin lock for phy driver */
> + bool host_mode;
> + struct ns2_phy_data *data;
> + struct extcon_specific_cable_nb extcon_dev;
> + struct extcon_specific_cable_nb extcon_host;
> + struct notifier_block host_nb;
> + struct notifier_block dev_nb;
> + struct delayed_work conn_work;
> + struct extcon_dev *edev;
> + struct gpio_desc *vbus_gpiod;
> + struct gpio_desc *id_gpiod;
> + int id_irq;
> + int vbus_irq;
> + unsigned long debounce_jiffies;
> + struct delayed_work wq_extcon;
> +};
> +
> +struct ns2_phy_data {
> + struct ns2_phy_driver *driver;
> + struct phy *phy;
> + int new_state;
> + bool poweron;
> +};
> +
> +static const unsigned int usb_extcon_cable[] = {
> + EXTCON_USB,
> + EXTCON_USB_HOST,
> + EXTCON_NONE,
> +};
> +
> +static inline int pll_lock_stat(u32 usb_reg, int reg_mask,
> + struct ns2_phy_driver *driver)
> +{
> + int retry = PLL_LOCK_RETRY;
> + u32 val;
> +
> + do {
> + udelay(1);
> + val = readl(driver->icfgdrd_regs + usb_reg);
> + if (val & reg_mask)
> + return 0;
> + } while (--retry > 0);
> +
> + return -EBUSY;
> +}
> +
> +static int ns2_drd_phy_init(struct phy *phy)
> +{
> + struct ns2_phy_data *data = phy_get_drvdata(phy);
> + struct ns2_phy_driver *driver = data->driver;
> + unsigned long flags;
> + u32 val;
> +
> + spin_lock_irqsave(&driver->lock, flags);
> +
> + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + if (data->new_state == EVT_HOST) {
> + val &= ~DRD_DEVICE_MODE;
> + val |= DRD_HOST_MODE;
> + } else {
> + val &= ~DRD_HOST_MODE;
> + val |= DRD_DEVICE_MODE;
> + }
> + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + spin_unlock_irqrestore(&driver->lock, flags);
> + return 0;
> +}
> +
> +static int ns2_drd_phy_shutdown(struct phy *phy)
> +{
> + struct ns2_phy_data *data = phy_get_drvdata(phy);
> + struct ns2_phy_driver *driver = data->driver;
> + unsigned long flags;
> + u32 val;
> +
> + spin_lock_irqsave(&driver->lock, flags);
> + if (!data->poweron)
> + goto exit;
> +
> + val = readl(driver->crmu_usb2_ctrl);
> + val &= ~AFE_CORERDY_VDDC;
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + driver->host_mode = 0;
> + val = readl(driver->crmu_usb2_ctrl);
> + val &= ~DRD_DEV_MODE;
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + /* Disable Host and Device Mode */
> + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL);
> + val &= ~(DRD_HOST_MODE | DRD_DEVICE_MODE | ICFG_OFF_MODE);
> + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + data->poweron = 0;
> +exit:
> + spin_unlock_irqrestore(&driver->lock, flags);
> + return 0;
> +}
> +
> +static int ns2_drd_phy_poweron(struct phy *phy)
> +{
> + struct ns2_phy_data *data = phy_get_drvdata(phy);
> + struct ns2_phy_driver *driver = data->driver;
> + u32 extcon_event = data->new_state;
> + unsigned long flags;
> + int ret;
> + u32 val;
> +
> + spin_lock_irqsave(&driver->lock, flags);
> + if (extcon_event == EVT_DEVICE) {
> + if (data->poweron)
> + goto exit;
> +
> + writel(DRD_DEV_VAL, driver->icfgdrd_regs + ICFG_DRD_P0CTL);
> +
> + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL);
> + val &= ~(DRD_HOST_MODE | ICFG_OFF_MODE);
> + val |= DRD_DEVICE_MODE;
> + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + val = readl(driver->idmdrd_rst_ctrl);
> + val &= ~IDM_RST_BIT;
> + writel(val, driver->idmdrd_rst_ctrl);
> +
> + val = readl(driver->crmu_usb2_ctrl);
> + val |= (AFE_CORERDY_VDDC | DRD_DEV_MODE);
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + /* Bring PHY and PHY_PLL out of Reset */
> + val = readl(driver->crmu_usb2_ctrl);
> + val |= (PHY_PLL_RESETB | PHY_RESETB);
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + ret = pll_lock_stat(ICFG_MISC_STAT, PHY_PLL_LOCK, driver);
> + if (ret < 0) {
> + dev_err(&phy->dev, "Phy PLL lock failed\n");
> + goto err_shutdown;
> + }
> + } else {
> + if (data->poweron && driver->host_mode)
> + goto exit;
> +
> + writel(DRD_HOST_VAL, driver->icfgdrd_regs + ICFG_DRD_P0CTL);
> +
> + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL);
> + val &= ~(DRD_DEVICE_MODE | ICFG_OFF_MODE);
> + val |= DRD_HOST_MODE;
> + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL);
> +
> + val = readl(driver->crmu_usb2_ctrl);
> + val |= AFE_CORERDY_VDDC;
> + writel(val, driver->crmu_usb2_ctrl);
> +
> + ret = pll_lock_stat(ICFG_MISC_STAT, PHY_PLL_LOCK, driver);
> + if (ret < 0) {
> + dev_err(&phy->dev, "Phy PLL lock failed\n");
> + goto err_shutdown;
> + }
> +
> + val = readl(driver->idmdrd_rst_ctrl);
> + val &= ~IDM_RST_BIT;
> + writel(val, driver->idmdrd_rst_ctrl);
> +
> + /* port over current Polarity */
> + val = readl(driver->usb2h_strap_reg);
> + val |= OHCI_OVRCUR_POL;
> + writel(val, driver->usb2h_strap_reg);
> +
> + driver->host_mode = 1;
> + }
> +
> + data->poweron = 1;
> +exit:
> + spin_unlock_irqrestore(&driver->lock, flags);
> + return 0;
> +
> +err_shutdown:
> + data->poweron = 1;
> + spin_unlock_irqrestore(&driver->lock, flags);
> + ns2_drd_phy_shutdown(phy);
> + return ret;
> +}
> +
> +static void connect_work(struct work_struct *work)
> +{
> + struct ns2_phy_driver *driver;
> + struct ns2_phy_data *data;
> + u32 extcon_event;
> +
> + driver = container_of(to_delayed_work(work),
> + struct ns2_phy_driver, conn_work);
> + data = driver->data;
> + extcon_event = data->new_state;
> +
> + if (extcon_event == EVT_DEVICE || extcon_event == EVT_HOST) {
> + ns2_drd_phy_init(data->phy);
> + ns2_drd_phy_poweron(data->phy);
> + } else if (extcon_event == EVT_IDLE) {
> + ns2_drd_phy_shutdown(data->phy);
> + }
> +}
> +
> +static int drd_device_notify(struct notifier_block *self,
> + unsigned long event, void *ptr)
> +{
> + struct ns2_phy_driver *driver = container_of(self,
> + struct ns2_phy_driver, dev_nb);
> +
> + if (event) {
> + pr_debug("Device connected\n");
> + driver->data->new_state = EVT_DEVICE;
> + schedule_delayed_work(&driver->conn_work, 0);
> + } else {
> + pr_debug("Device disconnected\n");
> + driver->data->new_state = EVT_IDLE;
> + schedule_delayed_work(&driver->conn_work, PHY_WQ_DELAY);
> + }
> +
> + return NOTIFY_DONE;
> +}
> +
> +static int drd_host_notify(struct notifier_block *self,
> + unsigned long event, void *ptr)
> +{
> + struct ns2_phy_driver *driver = container_of(self,
> + struct ns2_phy_driver, host_nb);
> +
> + if (event) {
> + pr_debug("Host connected\n");
> + driver->data->new_state = EVT_HOST;
> + schedule_delayed_work(&driver->conn_work, 0);
> + } else {
> + pr_debug("Host disconnected\n");
> + driver->data->new_state = EVT_IDLE;
> + schedule_delayed_work(&driver->conn_work, PHY_WQ_DELAY);
> + }
> +
> + return NOTIFY_DONE;
> +}
> +
> +static void extcon_work(struct work_struct *work)
> +{
> + struct ns2_phy_driver *driver;
> + int vbus;
> + int id;
> +
> + driver = container_of(to_delayed_work(work),
> + struct ns2_phy_driver, wq_extcon);
> +
> + id = gpiod_get_value_cansleep(driver->id_gpiod);
> + vbus = gpiod_get_value_cansleep(driver->vbus_gpiod);
> +
> + if (!id && vbus) {
> + extcon_set_cable_state_(driver->edev, EXTCON_USB_HOST, true);
> + } else if (id && !vbus) {
> + extcon_set_cable_state_(driver->edev, EXTCON_USB_HOST, false);
> + extcon_set_cable_state_(driver->edev, EXTCON_USB, false);
> + } else if (id && vbus) {
> + extcon_set_cable_state_(driver->edev, EXTCON_USB, true);
> + }
> +}
> +
> +static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
> +{
> + struct ns2_phy_driver *driver = dev_id;
> +
> + queue_delayed_work(system_power_efficient_wq, &driver->wq_extcon,
> + driver->debounce_jiffies);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int register_extcon_notifier(struct ns2_phy_driver *phy_driver,
> + struct device *dev)
> +{
> + struct extcon_dev *edev;
> + int ret;
> +
> + phy_driver->host_nb.notifier_call = drd_host_notify;
> + phy_driver->dev_nb.notifier_call = drd_device_notify;
> +
> + edev = phy_driver->edev;
> +
> + /* Register for device change notification */
> + ret = extcon_register_notifier(edev, EXTCON_USB,
> + &phy_driver->dev_nb);
> + if (ret < 0) {
> + dev_err(dev, "can't register extcon_dev for %s\n", edev->name);
> + return ret;
> + }
> +
> + /* Register for host change notification */
> + ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
> + &phy_driver->host_nb);
> + if (ret < 0) {
> + dev_err(dev, "can't register extcon_dev for %s\n", edev->name);
> + goto err_dev;
> + }
> +
> + /* Check the device cable connect state */
> + ret = extcon_get_cable_state_(edev, EXTCON_USB);
> + if (ret < 0) {
> + dev_err(dev, "can't get extcon_dev state for %s\n", edev->name);
> + goto err_host;
> + } else if (ret) {
> + phy_driver->data->new_state = EVT_DEVICE;
> + }
> +
> + /* Check the host cable connect state */
> + ret = extcon_get_cable_state_(edev, EXTCON_USB_HOST);
> + if (ret < 0) {
> + dev_err(dev, "can't get extcon_dev state for %s\n", edev->name);
> + goto err_host;
> + } else if (ret) {
> + phy_driver->data->new_state = EVT_HOST;
> + }
> +
> + return 0;
> +
> +err_host:
> + ret = extcon_unregister_notifier(edev, EXTCON_USB_HOST,
> + &phy_driver->host_nb);
> +err_dev:
> + ret = extcon_unregister_notifier(edev, EXTCON_USB,
> + &phy_driver->dev_nb);
> + return ret;
> +}
> +
> +static struct phy_ops ops = {
> + .init = ns2_drd_phy_init,
Is this really being used by any controller driver? Can you point me to the
controller driver that is using this driver?
> + .power_on = ns2_drd_phy_poweron,
> + .power_off = ns2_drd_phy_shutdown,
missing .owner.
Thanks
Kishon
^ permalink raw reply
* [PATCH 0/6] USB support for Broadcom NSP SoC
From: Kishon Vijay Abraham I @ 2017-01-16 9:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <79483fc3-5e91-a1f0-1dbf-1987682373e6@gmail.com>
On Tuesday 13 December 2016 07:50 AM, Florian Fainelli wrote:
> On 11/09/2016 01:33 AM, Yendapally Reddy Dhananjaya Reddy wrote:
>> This patch set contains the usb support for Broadcom NSP SoC.
>> The usb phy is connected through mdio interface. The mdio interface
>> can be used to access either internal phys or external phys using a
>> multiplexer.
>>
>> The first patch provides the documentation details for mdio-mux and
>> second patch provides the documentation details for usb3 phy. The third
>> patch contains the mdio-mux support and fourth patch contains the
>> changes to the mdio bus driver.
>>
>> The fifth patch provides the phy driver and sixth patch provides the
>> enable method for usb.
>>
>> This patch series has been tested on NSP bcm958625HR board.
>> This patch series is based on v4.9.0-rc1 and is available from github-
>> repo: https://github.com/Broadcom/cygnus-linux.git
>> branch:nsp-usb-v1
>
> Can you resubmit this patch series with the feedback from Andrew, Rob
> and Scott addressed?
can the phy patches be re-submitted based on latest mainline and addressing
those feedbacks?
Thanks
Kishon
^ permalink raw reply
* [PATCH] drivers: phy: constify phy_ops structures
From: Kishon Vijay Abraham I @ 2017-01-16 9:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483871756-19008-1-git-send-email-bhumirks@gmail.com>
On Sunday 08 January 2017 04:05 PM, Bhumika Goyal wrote:
> Declare phy_ops structures as const as they are only passed as an
> argument to the function devm_phy_create. This argument is of type const
> struct phy_ops *, so phy_ops structures having this property can be
> declared as const.
> Done using Coccinelle:
removed the rest of commit message and merged.
Thanks
Kishon
>
> @r1 disable optional_qualifier @
> identifier i;
> position p;
> @@
> static struct phy_ops i at p = {...};
>
> @ok1@
> identifier r1.i;
> position p;
> @@
> devm_phy_create(...,&i at p)
>
> @bad@
> position p!={r1.p,ok1.p};
> identifier r1.i;
> @@
> i at p
>
> @depends on !bad disable optional_qualifier@
> identifier r1.i;
> @@
> +const
> struct phy_ops i;
>
> File size details:
>
> text data bss dec hex filename
> 1504 264 0 1768 6e8 phy/phy-bcm-cygnus-pcie.o
> 1576 192 0 1768 6e8 phy/phy-bcm-cygnus-pcie.o
>
> 1083 264 0 1347 543 phy/phy-hi6220-usb.o
> 1155 192 0 1347 543 phy/phy-hi6220-usb.o
>
> 2767 264 0 3031 bd7 phy/phy-mt65xx-usb3.o
> 2829 192 0 3021 bcd phy/phy-mt65xx-usb3.o
>
> 2710 304 0 3014 bc6 phy/phy-rcar-gen3-usb2.o
> 2766 240 0 3006 bbe phy/phy-rcar-gen3-usb2.o
>
> Signed-off-by: Bhumika Goyal <bhumirks@gmail.com>
> ---
> drivers/phy/phy-bcm-cygnus-pcie.c | 2 +-
> drivers/phy/phy-hi6220-usb.c | 2 +-
> drivers/phy/phy-mt65xx-usb3.c | 2 +-
> drivers/phy/phy-rcar-gen3-usb2.c | 2 +-
> 4 files changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/phy/phy-bcm-cygnus-pcie.c b/drivers/phy/phy-bcm-cygnus-pcie.c
> index 082c03f..0f4ac5d 100644
> --- a/drivers/phy/phy-bcm-cygnus-pcie.c
> +++ b/drivers/phy/phy-bcm-cygnus-pcie.c
> @@ -114,7 +114,7 @@ static int cygnus_pcie_phy_power_off(struct phy *p)
> return cygnus_pcie_power_config(phy, false);
> }
>
> -static struct phy_ops cygnus_pcie_phy_ops = {
> +static const struct phy_ops cygnus_pcie_phy_ops = {
> .power_on = cygnus_pcie_phy_power_on,
> .power_off = cygnus_pcie_phy_power_off,
> .owner = THIS_MODULE,
> diff --git a/drivers/phy/phy-hi6220-usb.c b/drivers/phy/phy-hi6220-usb.c
> index b2141cb..398c102 100644
> --- a/drivers/phy/phy-hi6220-usb.c
> +++ b/drivers/phy/phy-hi6220-usb.c
> @@ -112,7 +112,7 @@ static int hi6220_phy_exit(struct phy *phy)
> return hi6220_phy_setup(priv, false);
> }
>
> -static struct phy_ops hi6220_phy_ops = {
> +static const struct phy_ops hi6220_phy_ops = {
> .init = hi6220_phy_start,
> .exit = hi6220_phy_exit,
> .owner = THIS_MODULE,
> diff --git a/drivers/phy/phy-mt65xx-usb3.c b/drivers/phy/phy-mt65xx-usb3.c
> index 4d85e73..d972067 100644
> --- a/drivers/phy/phy-mt65xx-usb3.c
> +++ b/drivers/phy/phy-mt65xx-usb3.c
> @@ -506,7 +506,7 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,
> return instance->phy;
> }
>
> -static struct phy_ops mt65xx_u3phy_ops = {
> +static const struct phy_ops mt65xx_u3phy_ops = {
> .init = mt65xx_phy_init,
> .exit = mt65xx_phy_exit,
> .power_on = mt65xx_phy_power_on,
> diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c
> index c63da1b..17be045 100644
> --- a/drivers/phy/phy-rcar-gen3-usb2.c
> +++ b/drivers/phy/phy-rcar-gen3-usb2.c
> @@ -350,7 +350,7 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p)
> return ret;
> }
>
> -static struct phy_ops rcar_gen3_phy_usb2_ops = {
> +static const struct phy_ops rcar_gen3_phy_usb2_ops = {
> .init = rcar_gen3_phy_usb2_init,
> .exit = rcar_gen3_phy_usb2_exit,
> .power_on = rcar_gen3_phy_usb2_power_on,
>
^ permalink raw reply
* [PATCH v2 0/2] phy: Replace the deprecated extcon API
From: Chanwoo Choi @ 2017-01-16 9:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <58749873.4070302@samsung.com>
Hi Kishon,
On 2017? 01? 10? 17:16, Chanwoo Choi wrote:
> Hi Kishon,
>
> Could you review these patches or pick up them if there is no any comment?
If there are no comments, could you apply these patches?
>
> On 2016? 12? 30? 13:11, Chanwoo Choi wrote:
>> This patches just replace the deprecated extcon API without any change
>> of extcon operation and use the resource-managed function for
>> extcon_register_notifier().
>>
>> The new extcon API instead of deprecated API.
>> - extcon_set_cable_state_() -> extcon_set_state_sync();
>> - extcon_get_cable_state_() -> extcon_get_state();
>>
>> Changes from v1:
>> - Rebase these patches based on v4.10-rc1.
>> - Drop the usb/power-supply/chipidea patches.
>>
>> Chanwoo Choi (2):
>> phy: rcar-gen3-usb2: Replace the deprecated extcon API
>> phy: sun4i-usb: Replace the deprecated extcon API
>>
>> drivers/phy/phy-rcar-gen3-usb2.c | 8 ++++----
>> drivers/phy/phy-sun4i-usb.c | 4 ++--
>> 2 files changed, 6 insertions(+), 6 deletions(-)
>>
>
--
Best Regards,
Chanwoo Choi
S/W Center, Samsung Electronics
^ permalink raw reply
* [PATCH v2 2/2] phy: sun4i-usb: Replace the deprecated extcon API
From: Kishon Vijay Abraham I @ 2017-01-16 9:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1483071089-8362-3-git-send-email-cw00.choi@samsung.com>
On Friday 30 December 2016 09:41 AM, Chanwoo Choi wrote:
> This patch replaces the deprecated extcon API as following:
> - extcon_set_cable_state_() -> extcon_set_state_sync()
>
> Cc: Kishon Vijay Abraham I <kishon@ti.com>
> Cc: Maxime Ripard <maxime.ripard@free-electrons.com>
> Cc: Chen-Yu Tsai <wens@csie.org>
> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
merged both the patches in this series.
Thanks
Kishon
> ---
> drivers/phy/phy-sun4i-usb.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
> index bf28a0fdd569..eae171e18043 100644
> --- a/drivers/phy/phy-sun4i-usb.c
> +++ b/drivers/phy/phy-sun4i-usb.c
> @@ -534,7 +534,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
> mutex_unlock(&phy0->mutex);
>
> if (id_notify) {
> - extcon_set_cable_state_(data->extcon, EXTCON_USB_HOST,
> + extcon_set_state_sync(data->extcon, EXTCON_USB_HOST,
> !id_det);
> /* When leaving host mode force end the session here */
> if (force_session_end && id_det == 1) {
> @@ -547,7 +547,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
> }
>
> if (vbus_notify)
> - extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det);
> + extcon_set_state_sync(data->extcon, EXTCON_USB, vbus_det);
>
> if (sun4i_usb_phy0_poll(data))
> queue_delayed_work(system_wq, &data->detect, POLL_TIME);
>
^ permalink raw reply
* [PATCH v8 00/18] KVM PCIe/MSI passthrough on ARM/ARM64 and IOVA reserved regions
From: Auger Eric @ 2017-01-16 9:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <e1e6d9cf-5fb8-e118-3a47-4c6be77c21a3@semihalf.com>
Hi Tomasz,
On 13/01/2017 14:59, Tomasz Nowicki wrote:
> Hello Eric,
>
> On 11.01.2017 10:41, Eric Auger wrote:
>> Following LPC discussions, we now report reserved regions through
>> the iommu-group sysfs reserved_regions attribute file.
>>
>> Reserved regions are populated through the IOMMU get_resv_region
>> callback (former get_dm_regions), now implemented by amd-iommu,
>> intel-iommu and arm-smmu:
>> - the intel-iommu reports the [0xfee00000 - 0xfeefffff] MSI window
>> as a reserved region and RMRR regions as direct-mapped regions.
>> - the amd-iommu reports device direct mapped regions, the MSI region
>> and HT regions.
>> - the arm-smmu reports the MSI window (arbitrarily located at
>> 0x8000000 and 1MB large).
>>
>> Unsafe interrupt assignment is tested by enumerating all MSI irq
>> domains and checking MSI remapping is supported in the above hierarchy.
>> This check is done in case we detect the iommu translates MSI
>> (an IOMMU_RESV_MSI window exists). Otherwise the IRQ remapping
>> capability is checked at IOMMU level. Obviously this is a defensive
>> IRQ safety assessment: Assuming there are several MSI controllers
>> in the system and at least one does not implement IRQ remapping,
>> the assignment will be considered as unsafe (even if this controller
>> is not acessible from the assigned devices).
>>
>> The series first patch stems from Robin's branch:
>> http://linux-arm.org/git?p=linux-rm.git;a=shortlog;h=refs/heads/iommu/misc
>>
>>
>> Best Regards
>>
>> Eric
>>
>> Git: complete series available at
>> https://github.com/eauger/linux/tree/v4.10-rc3-reserved-v8
>
> I tested the series on ThunderX with internal 10G VNIC and Intel IXGBE
> NIC. Please feel free to add my:
> Tested-by: Tomasz Nowicki <tomasz.nowicki@caviumnetworks.com>
Many thanks!
Eric
>
> Thanks,
> Tomasz
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 1/4] phy: sun4i-usb: add support for V3s USB PHY
From: Kishon Vijay Abraham I @ 2017-01-16 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170106135624.kbjdvb3wtytfj6ob@lukather>
On Friday 06 January 2017 07:26 PM, Maxime Ripard wrote:
> On Tue, Jan 03, 2017 at 11:25:31PM +0800, Icenowy Zheng wrote:
>> Allwinner V3s come with a USB PHY controller slightly different to other
>> SoCs, with only one PHY.
>>
>> Add support for it.
>>
>> Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
>
> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
merged, thanks!
-Kishon
>
> Thanks,
> Maxime
>
^ permalink raw reply
* [RFC PATCH v2 05/10] genirq: export irq_get_percpu_devid_partition to modules
From: Thomas Gleixner @ 2017-01-16 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484323429-15231-6-git-send-email-will.deacon@arm.com>
On Fri, 13 Jan 2017, Will Deacon wrote:
> Any modular driver using cluster-affine PPIs needs to be able to call
> irq_get_percpu_devid_partition so that it can enable the IRQ on the
> correct subset of CPUs.
>
> This patch exports the symbol so that it can be called from within a
> module.
>
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Signed-off-by: Will Deacon <will.deacon@arm.com>
> ---
> kernel/irq/irqdesc.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
> index 00bb0aeea1d0..1e6ae73eae59 100644
> --- a/kernel/irq/irqdesc.c
> +++ b/kernel/irq/irqdesc.c
> @@ -856,6 +856,7 @@ int irq_get_percpu_devid_partition(unsigned int irq, struct cpumask *affinity)
>
> return 0;
> }
> +EXPORT_SYMBOL_GPL(irq_get_percpu_devid_partition);
Acked-by: Thomas Gleixner <tglx@linutronix.de>
^ permalink raw reply
* [PATCH v2 3/3] phy: rockchip-inno-usb2: Set EXTCON_USB when EXTCON_CHG_USB_SDP was set
From: Kishon Vijay Abraham I @ 2017-01-16 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <23666cc1a5ff123ece5bdbb9821d1eab280d0927.1482307697.git.baolin.wang@linaro.org>
On Wednesday 21 December 2016 01:42 PM, Baolin Wang wrote:
> According to the documentation, we should set the EXTCON_USB when
> one SDP charger connector was reported.
>
> Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
> Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
merged, thanks!
-Kishon
> ---
> Changes since v1:
> - Change extcon_set_cable_state_() to extcon_set_state_sync().
> - Add reviewed tag by Chanwoo Choi.
> ---
> drivers/phy/phy-rockchip-inno-usb2.c | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c
> index 2f99ec9..4ea95c2 100644
> --- a/drivers/phy/phy-rockchip-inno-usb2.c
> +++ b/drivers/phy/phy-rockchip-inno-usb2.c
> @@ -595,9 +595,14 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
> if (rport->vbus_attached != vbus_attach) {
> rport->vbus_attached = vbus_attach;
>
> - if (notify_charger && rphy->edev)
> + if (notify_charger && rphy->edev) {
> extcon_set_cable_state_(rphy->edev,
> cable, vbus_attach);
> + if (cable == EXTCON_CHG_USB_SDP)
> + extcon_set_state_sync(rphy->edev,
> + EXTCON_USB,
> + vbus_attach);
> + }
> }
> break;
> case OTG_STATE_B_PERIPHERAL:
>
^ permalink raw reply
* [PATCH 2/2] spi: pca2xx-pci: Allow MSI
From: Jan Kiszka @ 2017-01-16 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1484557560.git.jan.kiszka@siemens.com>
Now that the core is ready for edge-triggered interrupts, we can safely
allow the PCI versions that provide this to enable the feature and,
thus, have less shared interrupts.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
drivers/spi/spi-pxa2xx-pci.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
index 58d2d48..e7e5b08 100644
--- a/drivers/spi/spi-pxa2xx-pci.c
+++ b/drivers/spi/spi-pxa2xx-pci.c
@@ -203,16 +203,24 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
ssp = &spi_pdata.ssp;
ssp->phys_base = pci_resource_start(dev, 0);
ssp->mmio_base = pcim_iomap_table(dev)[0];
- ssp->irq = dev->irq;
ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn;
ssp->type = c->type;
snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id);
ssp->clk = clk_register_fixed_rate(&dev->dev, buf , NULL, 0,
c->max_clk_rate);
- if (IS_ERR(ssp->clk))
+ if (IS_ERR(ssp->clk))
return PTR_ERR(ssp->clk);
+ pci_set_master(dev);
+
+ ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES);
+ if (ret < 0) {
+ clk_unregister(ssp->clk);
+ return ret;
+ }
+ ssp->irq = pci_irq_vector(dev, 0);
+
memset(&pi, 0, sizeof(pi));
pi.fwnode = dev->dev.fwnode;
pi.parent = &dev->dev;
@@ -224,6 +232,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
pdev = platform_device_register_full(&pi);
if (IS_ERR(pdev)) {
clk_unregister(ssp->clk);
+ pci_free_irq_vectors(dev);
return PTR_ERR(pdev);
}
@@ -241,6 +250,7 @@ static void pxa2xx_spi_pci_remove(struct pci_dev *dev)
platform_device_unregister(pdev);
clk_unregister(spi_pdata->ssp.clk);
+ pci_free_irq_vectors(dev);
}
static const struct pci_device_id pxa2xx_spi_pci_devices[] = {
--
2.1.4
^ permalink raw reply related
* [PATCH 1/2] spi: pxa2xx: Prepare for edge-triggered interrupts
From: Jan Kiszka @ 2017-01-16 9:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1484557560.git.jan.kiszka@siemens.com>
When using the a device with edge-triggered interrupts, such as MSIs,
the interrupt handler has to ensure that there is a point in time during
its execution where all interrupts sources are silent so that a new
event can trigger a new interrupt again.
This is achieved here by looping over SSSR evaluation. We need to take
into account that SSCR1 may be changed by the transfer handler, thus we
need to redo the mask calculation, at least regarding the volatile
interrupt enable bit (TIE).
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
drivers/spi/spi-pxa2xx.c | 50 +++++++++++++++++++++++++++---------------------
1 file changed, 28 insertions(+), 22 deletions(-)
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index dd7b5b4..24bf549 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -737,6 +737,7 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
struct driver_data *drv_data = dev_id;
u32 sccr1_reg;
u32 mask = drv_data->mask_sr;
+ irqreturn_t ret = IRQ_NONE;
u32 status;
/*
@@ -760,37 +761,42 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1);
- /* Ignore possible writes if we don't need to write */
- if (!(sccr1_reg & SSCR1_TIE))
- mask &= ~SSSR_TFS;
-
/* Ignore RX timeout interrupt if it is disabled */
if (!(sccr1_reg & SSCR1_TINTE))
mask &= ~SSSR_TINT;
- if (!(status & mask))
- return IRQ_NONE;
+ while (1) {
+ /* Ignore possible writes if we don't need to write */
+ if (!(sccr1_reg & SSCR1_TIE))
+ mask &= ~SSSR_TFS;
- if (!drv_data->master->cur_msg) {
+ if (!(status & mask))
+ return ret;
- pxa2xx_spi_write(drv_data, SSCR0,
- pxa2xx_spi_read(drv_data, SSCR0)
- & ~SSCR0_SSE);
- pxa2xx_spi_write(drv_data, SSCR1,
- pxa2xx_spi_read(drv_data, SSCR1)
- & ~drv_data->int_cr1);
- if (!pxa25x_ssp_comp(drv_data))
- pxa2xx_spi_write(drv_data, SSTO, 0);
- write_SSSR_CS(drv_data, drv_data->clear_sr);
+ if (!drv_data->master->cur_msg) {
- dev_err(&drv_data->pdev->dev,
- "bad message state in interrupt handler\n");
+ pxa2xx_spi_write(drv_data, SSCR0,
+ pxa2xx_spi_read(drv_data, SSCR0)
+ & ~SSCR0_SSE);
+ pxa2xx_spi_write(drv_data, SSCR1,
+ pxa2xx_spi_read(drv_data, SSCR1)
+ & ~drv_data->int_cr1);
+ if (!pxa25x_ssp_comp(drv_data))
+ pxa2xx_spi_write(drv_data, SSTO, 0);
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
- /* Never fail */
- return IRQ_HANDLED;
- }
+ dev_err(&drv_data->pdev->dev,
+ "bad message state in interrupt handler\n");
- return drv_data->transfer_handler(drv_data);
+ /* Never fail */
+ return IRQ_HANDLED;
+ }
+
+ ret |= drv_data->transfer_handler(drv_data);
+
+ status = pxa2xx_spi_read(drv_data, SSSR);
+ sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1);
+ }
}
/*
--
2.1.4
^ permalink raw reply related
* [PATCH 0/2] spi: pca2xx: Prepare for and enable MSI support
From: Jan Kiszka @ 2017-01-16 9:05 UTC (permalink / raw)
To: linux-arm-kernel
This enhances the pca2xx driver's interrupt handler with support for
edge-triggered interrupts and makes use of that for PCI-hosted variants,
like the Intel Quark SoC.
Jan
Jan Kiszka (2):
spi: pxa2xx: Prepare for edge-triggered interrupts
spi: pca2xx-pci: Allow MSI
drivers/spi/spi-pxa2xx-pci.c | 14 +++++++++++--
drivers/spi/spi-pxa2xx.c | 50 +++++++++++++++++++++++++-------------------
2 files changed, 40 insertions(+), 24 deletions(-)
--
2.1.4
^ permalink raw reply
* [PATCH v1 1/3] dt: bindings: add documentation for zx2967 family watchdog controller
From: Shawn Guo @ 2017-01-16 9:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1484540395-3335-1-git-send-email-baoyou.xie@linaro.org>
On Mon, Jan 16, 2017 at 12:19:53PM +0800, Baoyou Xie wrote:
> This patch adds dt-binding documentation for zx2967 family
> watchdog controller.
>
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
> ---
> .../bindings/watchdog/zte,zx2967-wdt.txt | 29 ++++++++++++++++++++++
> 1 file changed, 29 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt
>
> diff --git a/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt b/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt
> new file mode 100644
> index 0000000..0fe0d40
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt
> @@ -0,0 +1,29 @@
> +ZTE zx2967 Watchdog timer
> +
> +Required properties:
> +
> +- compatible : should be one of the following.
> + * zte,zx296718-wdt
> +- reg : Specifies base physical address and size of the registers.
> +- clocks : Pairs of phandle and specifier referencing the controller's clocks.
> +- clock-names: "wdtclk" for the watchdog clock.
clock-names only makes sense when there are multiple clock phandles in
'clocks' property. When clock-names is not present, the driver code
calls devm_clk_get() with the second parameter being NULL.
> +- resets : Reference to the reset controller controlling the watchdog
> + controller.
> +- reset-names : Must include the following entries:
> + * wdtrst
Same as clock-names.
> +
> +Optional properties:
> +
> +- reset-mask-config : Mask and configuare value that be wrote to aon-sysctrl.
First of all, for vendor specific properties, we should have a vendor
prefix, something like "zte,reset-mask-config".
Secondly, we should really have more comments to explain why this
property is optional, i.e. in which cases it should be present, and in
which cases it can be missing. Also, the relationship between this
reset and 'resets = <&toprst 35>' should be explained a bit as well.
Shawn
> +
> +Example:
> +
> +wdt_ares: watchdog at 1465000 {
> + compatible = "zte,zx296718-wdt";
> + reg = <0x1465000 0x1000>;
> + clocks = <&topcrm WDT_WCLK>;
> + clock-names = "wdtclk";
> + resets = <&toprst 35>;
> + reset-names = "wdtrst";
> + reset-mask-config = <1 0x115>;
> +};
> --
> 2.7.4
>
^ permalink raw reply
* USB: OHCI: high softirq load
From: Boris Brezillon @ 2017-01-16 9:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <bd83e3b2-b329-3635-2917-0ffe61d3535f@overkiz.com>
Hi Antoine,
On Mon, 16 Jan 2017 08:45:58 +0100
Antoine Aubert <a.aubert@overkiz.com> wrote:
> Hi,
>
> Im working on a AT91SAM9G25cu board
> (arch/arm/boot/dts/at91-kizboxmini.dts). We use linux-4.1.31, and when
> OHCI is enabled, I got some wired effects.
Can you test on a more recent kernel (4.9 or 4.10-rc4)?
>
> eg with 3 FTDI pluged, interrupts: more than 3.5k/s, cpu softirq > 24%,
> loadavg > 0.5
Can you check which interrupt is triggered (cat /proc/interrupts), and
enable debug messages in drivers/usb/host/ohci-at91.c?
Thanks,
Boris
>
> This issue disappear when disabling OHCI and use EHCI only.
>
> What are the usual causes, and where to begin with ?
>
> Thanks in advance,
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox