Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [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 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

* [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 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 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] 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 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 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 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/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 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 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 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 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 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 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 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 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 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 02/11] drm/rockchip/dsi: dw-mipi: support RK3399 mipi dsi
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 vopb/vopl switch register of RK3399 mipi is different from RK3288,
the default setting for mipi dsi mode is different too, so add a
of_device_id structure to distinguish them, and make sure set the
correct mode before mipi phy init.

Signed-off-by: Chris Zhong <zyw@rock-chips.com>
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
---

 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 101 ++++++++++++++++++++++++---------
 1 file changed, 74 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index d9aa382..04fd595 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -28,9 +28,17 @@
 
 #define DRIVER_NAME    "dw-mipi-dsi"
 
-#define GRF_SOC_CON6                    0x025c
-#define DSI0_SEL_VOP_LIT                (1 << 6)
-#define DSI1_SEL_VOP_LIT                (1 << 9)
+#define RK3288_GRF_SOC_CON6		0x025c
+#define RK3288_DSI0_SEL_VOP_LIT		BIT(6)
+#define RK3288_DSI1_SEL_VOP_LIT		BIT(9)
+
+#define RK3399_GRF_SOC_CON19		0x6250
+#define RK3399_DSI0_SEL_VOP_LIT		BIT(0)
+#define RK3399_DSI1_SEL_VOP_LIT		BIT(4)
+
+/* disable turnrequest, turndisable, forcetxstopmode, forcerxmode */
+#define RK3399_GRF_SOC_CON22		0x6258
+#define RK3399_GRF_DSI_MODE		0xffff0000
 
 #define DSI_VERSION			0x00
 #define DSI_PWR_UP			0x04
@@ -147,7 +155,6 @@
 #define LPRX_TO_CNT(p)			((p) & 0xffff)
 
 #define DSI_BTA_TO_CNT			0x8c
-
 #define DSI_LPCLK_CTRL			0x94
 #define AUTO_CLKLANE_CTRL		BIT(1)
 #define PHY_TXREQUESTCLKHS		BIT(0)
@@ -213,11 +220,11 @@
 
 #define HSFREQRANGE_SEL(val)	(((val) & 0x3f) << 1)
 
-#define INPUT_DIVIDER(val)	((val - 1) & 0x7f)
+#define INPUT_DIVIDER(val)	(((val) - 1) & 0x7f)
 #define LOW_PROGRAM_EN		0
 #define HIGH_PROGRAM_EN		BIT(7)
-#define LOOP_DIV_LOW_SEL(val)	((val - 1) & 0x1f)
-#define LOOP_DIV_HIGH_SEL(val)	(((val - 1) >> 5) & 0x1f)
+#define LOOP_DIV_LOW_SEL(val)	(((val) - 1) & 0x1f)
+#define LOOP_DIV_HIGH_SEL(val)	((((val) - 1) >> 5) & 0x1f)
 #define PLL_LOOP_DIV_EN		BIT(5)
 #define PLL_INPUT_DIV_EN	BIT(4)
 
@@ -263,6 +270,11 @@ enum {
 };
 
 struct dw_mipi_dsi_plat_data {
+	u32 dsi0_en_bit;
+	u32 dsi1_en_bit;
+	u32 grf_switch_reg;
+	u32 grf_dsi0_mode;
+	u32 grf_dsi0_mode_reg;
 	unsigned int max_data_lanes;
 	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
 					   struct drm_display_mode *mode);
@@ -279,6 +291,7 @@ struct dw_mipi_dsi {
 
 	struct clk *pllref_clk;
 	struct clk *pclk;
+	struct clk *phy_cfg_clk;
 
 	unsigned int lane_mbps; /* per lane */
 	u32 channel;
@@ -353,6 +366,7 @@ static inline struct dw_mipi_dsi *encoder_to_dsi(struct drm_encoder *encoder)
 {
 	return container_of(encoder, struct dw_mipi_dsi, encoder);
 }
+
 static inline void dsi_write(struct dw_mipi_dsi *dsi, u32 reg, u32 val)
 {
 	writel(val, dsi->base + reg);
@@ -364,7 +378,7 @@ static inline u32 dsi_read(struct dw_mipi_dsi *dsi, u32 reg)
 }
 
 static void dw_mipi_dsi_phy_write(struct dw_mipi_dsi *dsi, u8 test_code,
-				 u8 test_data)
+				  u8 test_data)
 {
 	/*
 	 * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
@@ -400,6 +414,14 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
 
 	dsi_write(dsi, DSI_PWR_UP, POWERUP);
 
+	if (!IS_ERR(dsi->phy_cfg_clk)) {
+		ret = clk_prepare_enable(dsi->phy_cfg_clk);
+		if (ret) {
+			dev_err(dsi->dev, "Failed to enable phy_cfg_clk\n");
+			return ret;
+		}
+	}
+
 	dw_mipi_dsi_phy_write(dsi, 0x10, BYPASS_VCO_RANGE |
 					 VCO_RANGE_CON_SEL(vco) |
 					 VCO_IN_CAP_CON_LOW |
@@ -439,22 +461,23 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
 	dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK |
 				     PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
 
-
 	ret = readx_poll_timeout(readl, dsi->base + DSI_PHY_STATUS,
 				 val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US);
 	if (ret < 0) {
 		dev_err(dsi->dev, "failed to wait for phy lock state\n");
-		return ret;
+		goto phy_init_end;
 	}
 
 	ret = readx_poll_timeout(readl, dsi->base + DSI_PHY_STATUS,
 				 val, val & STOP_STATE_CLK_LANE, 1000,
 				 PHY_STATUS_TIMEOUT_US);
-	if (ret < 0) {
+	if (ret < 0)
 		dev_err(dsi->dev,
 			"failed to wait for phy clk lane stop state\n");
-		return ret;
-	}
+
+phy_init_end:
+	if (!IS_ERR(dsi->phy_cfg_clk))
+		clk_disable_unprepare(dsi->phy_cfg_clk);
 
 	return ret;
 }
@@ -512,7 +535,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
 
 	if (device->lanes > dsi->pdata->max_data_lanes) {
 		dev_err(dsi->dev, "the number of data lanes(%u) is too many\n",
-				device->lanes);
+			device->lanes);
 		return -EINVAL;
 	}
 
@@ -815,8 +838,8 @@ static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi)
 }
 
 static void dw_mipi_dsi_encoder_mode_set(struct drm_encoder *encoder,
-					struct drm_display_mode *mode,
-					struct drm_display_mode *adjusted_mode)
+					 struct drm_display_mode *mode,
+					 struct drm_display_mode *adjusted_mode)
 {
 	struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
 	int ret;
@@ -878,6 +901,7 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
 static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
 {
 	struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
+	const struct dw_mipi_dsi_plat_data *pdata = dsi->pdata;
 	int mux = drm_of_encoder_active_endpoint_id(dsi->dev->of_node, encoder);
 	u32 val;
 
@@ -886,6 +910,10 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
 		return;
 	}
 
+	if (pdata->grf_dsi0_mode_reg)
+		regmap_write(dsi->grf_regmap, pdata->grf_dsi0_mode_reg,
+			     pdata->grf_dsi0_mode);
+
 	dw_mipi_dsi_phy_init(dsi);
 	dw_mipi_dsi_wait_for_two_frames(dsi);
 
@@ -895,11 +923,11 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
 	clk_disable_unprepare(dsi->pclk);
 
 	if (mux)
-		val = DSI0_SEL_VOP_LIT | (DSI0_SEL_VOP_LIT << 16);
+		val = pdata->dsi0_en_bit | (pdata->dsi0_en_bit << 16);
 	else
-		val = DSI0_SEL_VOP_LIT << 16;
+		val = pdata->dsi0_en_bit << 16;
 
-	regmap_write(dsi->grf_regmap, GRF_SOC_CON6, val);
+	regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
 	dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
 }
 
@@ -931,7 +959,7 @@ dw_mipi_dsi_encoder_atomic_check(struct drm_encoder *encoder,
 	return 0;
 }
 
-static struct drm_encoder_helper_funcs
+static const struct drm_encoder_helper_funcs
 dw_mipi_dsi_encoder_helper_funcs = {
 	.commit = dw_mipi_dsi_encoder_commit,
 	.mode_set = dw_mipi_dsi_encoder_mode_set,
@@ -939,7 +967,7 @@ dw_mipi_dsi_encoder_helper_funcs = {
 	.atomic_check = dw_mipi_dsi_encoder_atomic_check,
 };
 
-static struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
+static const struct drm_encoder_funcs dw_mipi_dsi_encoder_funcs = {
 	.destroy = drm_encoder_cleanup,
 };
 
@@ -975,7 +1003,7 @@ static void dw_mipi_dsi_drm_connector_destroy(struct drm_connector *connector)
 	drm_connector_cleanup(connector);
 }
 
-static struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
+static const struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
 	.dpms = drm_atomic_helper_connector_dpms,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.destroy = dw_mipi_dsi_drm_connector_destroy,
@@ -985,7 +1013,7 @@ static struct drm_connector_funcs dw_mipi_dsi_atomic_connector_funcs = {
 };
 
 static int dw_mipi_dsi_register(struct drm_device *drm,
-				      struct dw_mipi_dsi *dsi)
+				struct dw_mipi_dsi *dsi)
 {
 	struct drm_encoder *encoder = &dsi->encoder;
 	struct drm_connector *connector = &dsi->connector;
@@ -1006,14 +1034,14 @@ static int dw_mipi_dsi_register(struct drm_device *drm,
 	drm_encoder_helper_add(&dsi->encoder,
 			       &dw_mipi_dsi_encoder_helper_funcs);
 	ret = drm_encoder_init(drm, &dsi->encoder, &dw_mipi_dsi_encoder_funcs,
-			 DRM_MODE_ENCODER_DSI, NULL);
+			       DRM_MODE_ENCODER_DSI, NULL);
 	if (ret) {
 		dev_err(dev, "Failed to initialize encoder with drm\n");
 		return ret;
 	}
 
 	drm_connector_helper_add(connector,
-			&dw_mipi_dsi_connector_helper_funcs);
+				 &dw_mipi_dsi_connector_helper_funcs);
 
 	drm_connector_init(drm, &dsi->connector,
 			   &dw_mipi_dsi_atomic_connector_funcs,
@@ -1059,21 +1087,36 @@ static enum drm_mode_status rk3288_mipi_dsi_mode_valid(
 }
 
 static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = {
+	.dsi0_en_bit = RK3288_DSI0_SEL_VOP_LIT,
+	.dsi1_en_bit = RK3288_DSI1_SEL_VOP_LIT,
+	.grf_switch_reg = RK3288_GRF_SOC_CON6,
 	.max_data_lanes = 4,
 	.mode_valid = rk3288_mipi_dsi_mode_valid,
 };
 
+static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = {
+	.dsi0_en_bit = RK3399_DSI0_SEL_VOP_LIT,
+	.dsi1_en_bit = RK3399_DSI1_SEL_VOP_LIT,
+	.grf_switch_reg = RK3399_GRF_SOC_CON19,
+	.grf_dsi0_mode = RK3399_GRF_DSI_MODE,
+	.grf_dsi0_mode_reg = RK3399_GRF_SOC_CON22,
+	.max_data_lanes = 4,
+};
+
 static const struct of_device_id dw_mipi_dsi_dt_ids[] = {
 	{
 	 .compatible = "rockchip,rk3288-mipi-dsi",
 	 .data = &rk3288_mipi_dsi_drv_data,
+	}, {
+	 .compatible = "rockchip,rk3399-mipi-dsi",
+	 .data = &rk3399_mipi_dsi_drv_data,
 	},
 	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
 
 static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
-			     void *data)
+			    void *data)
 {
 	const struct of_device_id *of_id =
 			of_match_device(dw_mipi_dsi_dt_ids, dev);
@@ -1117,6 +1160,10 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 		return ret;
 	}
 
+	dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
+	if (IS_ERR(dsi->phy_cfg_clk))
+		dev_dbg(dev, "have not phy_cfg_clk\n");
+
 	ret = clk_prepare_enable(dsi->pllref_clk);
 	if (ret) {
 		dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__);
@@ -1141,7 +1188,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 }
 
 static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
-	void *data)
+			       void *data)
 {
 	struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
 
-- 
2.6.3

^ permalink raw reply related

* [PATCH v2 03/11] drm/rockchip/dsi: remove mode_valid function
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 MIPI DSI do not need check the validity of resolution, the max
resolution should depend VOP. Hence, remove rk3288_mipi_dsi_mode_valid
here.

Signed-off-by: Chris Zhong <zyw@rock-chips.com>
---

 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 39 ----------------------------------
 1 file changed, 39 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index 04fd595..8f8d48a 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -276,8 +276,6 @@ struct dw_mipi_dsi_plat_data {
 	u32 grf_dsi0_mode;
 	u32 grf_dsi0_mode_reg;
 	unsigned int max_data_lanes;
-	enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
-					   struct drm_display_mode *mode);
 };
 
 struct dw_mipi_dsi {
@@ -978,23 +976,8 @@ static int dw_mipi_dsi_connector_get_modes(struct drm_connector *connector)
 	return drm_panel_get_modes(dsi->panel);
 }
 
-static enum drm_mode_status dw_mipi_dsi_mode_valid(
-					struct drm_connector *connector,
-					struct drm_display_mode *mode)
-{
-	struct dw_mipi_dsi *dsi = con_to_dsi(connector);
-
-	enum drm_mode_status mode_status = MODE_OK;
-
-	if (dsi->pdata->mode_valid)
-		mode_status = dsi->pdata->mode_valid(connector, mode);
-
-	return mode_status;
-}
-
 static struct drm_connector_helper_funcs dw_mipi_dsi_connector_helper_funcs = {
 	.get_modes = dw_mipi_dsi_connector_get_modes,
-	.mode_valid = dw_mipi_dsi_mode_valid,
 };
 
 static void dw_mipi_dsi_drm_connector_destroy(struct drm_connector *connector)
@@ -1065,33 +1048,11 @@ static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi)
 	return 0;
 }
 
-static enum drm_mode_status rk3288_mipi_dsi_mode_valid(
-					struct drm_connector *connector,
-					struct drm_display_mode *mode)
-{
-	/*
-	 * The VID_PKT_SIZE field in the DSI_VID_PKT_CFG
-	 * register is 11-bit.
-	 */
-	if (mode->hdisplay > 0x7ff)
-		return MODE_BAD_HVALUE;
-
-	/*
-	 * The V_ACTIVE_LINES field in the DSI_VTIMING_CFG
-	 * register is 11-bit.
-	 */
-	if (mode->vdisplay > 0x7ff)
-		return MODE_BAD_VVALUE;
-
-	return MODE_OK;
-}
-
 static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = {
 	.dsi0_en_bit = RK3288_DSI0_SEL_VOP_LIT,
 	.dsi1_en_bit = RK3288_DSI1_SEL_VOP_LIT,
 	.grf_switch_reg = RK3288_GRF_SOC_CON6,
 	.max_data_lanes = 4,
-	.mode_valid = rk3288_mipi_dsi_mode_valid,
 };
 
 static struct dw_mipi_dsi_plat_data rk3399_mipi_dsi_drv_data = {
-- 
2.6.3

^ permalink raw reply related

* [PATCH v2 04/11] dt-bindings: add power domain node 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>

Signed-off-by: Chris Zhong <zyw@rock-chips.com>
Acked-by: Rob Herring <robh@kernel.org>
---

 .../devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt      | 3 +++
 1 file changed, 3 insertions(+)

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 0f82568..188f6f7 100644
--- a/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
+++ b/Documentation/devicetree/bindings/display/rockchip/dw_mipi_dsi_rockchip.txt
@@ -15,6 +15,9 @@ Required properties:
 - 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.
 
+Optional properties:
+- power-domains: a phandle to mipi dsi power domain node.
+
 [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
 [2] Documentation/devicetree/bindings/media/video-interfaces.txt
 
-- 
2.6.3

^ permalink raw reply related

* [PATCH v2 05/11] drm/rockchip/dsi: add dw-mipi power domain support
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>

Reference the power domain incase dw-mipi power down when
in use.

Signed-off-by: Chris Zhong <zyw@rock-chips.com>
---

 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index 8f8d48a..d2a3efb 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -12,6 +12,7 @@
 #include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
 #include <drm/drm_atomic_helper.h>
@@ -291,6 +292,7 @@ struct dw_mipi_dsi {
 	struct clk *pclk;
 	struct clk *phy_cfg_clk;
 
+	int dpms_mode;
 	unsigned int lane_mbps; /* per lane */
 	u32 channel;
 	u32 lanes;
@@ -842,6 +844,9 @@ static void dw_mipi_dsi_encoder_mode_set(struct drm_encoder *encoder,
 	struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
 	int ret;
 
+	if (dsi->dpms_mode == DRM_MODE_DPMS_ON)
+		return;
+
 	dsi->mode = adjusted_mode;
 
 	ret = dw_mipi_dsi_get_lane_bps(dsi);
@@ -853,6 +858,8 @@ static void dw_mipi_dsi_encoder_mode_set(struct drm_encoder *encoder,
 		return;
 	}
 
+	pm_runtime_get_sync(dsi->dev);
+
 	dw_mipi_dsi_init(dsi);
 	dw_mipi_dsi_dpi_config(dsi, mode);
 	dw_mipi_dsi_packet_handler_config(dsi);
@@ -874,6 +881,9 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
 {
 	struct dw_mipi_dsi *dsi = encoder_to_dsi(encoder);
 
+	if (dsi->dpms_mode != DRM_MODE_DPMS_ON)
+		return;
+
 	drm_panel_disable(dsi->panel);
 
 	if (clk_prepare_enable(dsi->pclk)) {
@@ -893,7 +903,9 @@ static void dw_mipi_dsi_encoder_disable(struct drm_encoder *encoder)
 
 	dw_mipi_dsi_set_mode(dsi, DW_MIPI_DSI_CMD_MODE);
 	dw_mipi_dsi_disable(dsi);
+	pm_runtime_put(dsi->dev);
 	clk_disable_unprepare(dsi->pclk);
+	dsi->dpms_mode = DRM_MODE_DPMS_OFF;
 }
 
 static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
@@ -927,6 +939,7 @@ static void dw_mipi_dsi_encoder_commit(struct drm_encoder *encoder)
 
 	regmap_write(dsi->grf_regmap, pdata->grf_switch_reg, val);
 	dev_dbg(dsi->dev, "vop %s output to dsi0\n", (mux) ? "LIT" : "BIG");
+	dsi->dpms_mode = DRM_MODE_DPMS_ON;
 }
 
 static int
@@ -1094,6 +1107,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 
 	dsi->dev = dev;
 	dsi->pdata = pdata;
+	dsi->dpms_mode = DRM_MODE_DPMS_OFF;
 
 	ret = rockchip_mipi_parse_dt(dsi);
 	if (ret)
@@ -1139,6 +1153,8 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 
 	dev_set_drvdata(dev, dsi);
 
+	pm_runtime_enable(dev);
+
 	dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
 	dsi->dsi_host.dev = dev;
 	return mipi_dsi_host_register(&dsi->dsi_host);
@@ -1154,6 +1170,7 @@ static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
 	struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
 
 	mipi_dsi_host_unregister(&dsi->dsi_host);
+	pm_runtime_disable(dev);
 	clk_disable_unprepare(dsi->pllref_clk);
 }
 
-- 
2.6.3

^ permalink raw reply related

* [PATCH v2 06/11] drm/rockchip/dsi: return probe defer if attach panel failed
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>

From: Mark Yao <mark.yao@rock-chips.com>

Return -EINVAL would cause mipi dsi bad behavior, probe defer
to ensure mipi find the correct mode,

Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
---

 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index d2a3efb..5e3f031 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -549,10 +549,14 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
 	dsi->channel = device->channel;
 	dsi->format = device->format;
 	dsi->panel = of_drm_find_panel(device->dev.of_node);
-	if (dsi->panel)
-		return drm_panel_attach(dsi->panel, &dsi->connector);
+	if (!dsi->panel) {
+		DRM_ERROR("failed to find panel\n");
+		return -EPROBE_DEFER;
+	}
 
-	return -EINVAL;
+	drm_panel_attach(dsi->panel, &dsi->connector);
+
+	return 0;
 }
 
 static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
@@ -560,7 +564,8 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
 {
 	struct dw_mipi_dsi *dsi = host_to_dsi(host);
 
-	drm_panel_detach(dsi->panel);
+	if (dsi->panel)
+		drm_panel_detach(dsi->panel);
 
 	return 0;
 }
-- 
2.6.3

^ permalink raw reply related

* [PATCH v2 07/11] drm/rockchip/dsi: fix mipi display can't found at init time
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>

From: Mark Yao <mark.yao@rock-chips.com>

The problem is that:
  mipi panel probe request mipi_dsi_host_register.
  mipi host attach is call from panel device, so the defer function
always can't works.

So at the first bind time, always can't found mipi panel.

Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
---

 drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 57 +++++++++++++++++++++++-----------
 1 file changed, 39 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index 5e3f031..4ec82f6 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -551,11 +551,9 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
 	dsi->panel = of_drm_find_panel(device->dev.of_node);
 	if (!dsi->panel) {
 		DRM_ERROR("failed to find panel\n");
-		return -EPROBE_DEFER;
+		return -ENODEV;
 	}
 
-	drm_panel_attach(dsi->panel, &dsi->connector);
-
 	return 0;
 }
 
@@ -567,6 +565,7 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
 	if (dsi->panel)
 		drm_panel_detach(dsi->panel);
 
+	dsi->panel = NULL;
 	return 0;
 }
 
@@ -1048,6 +1047,8 @@ static int dw_mipi_dsi_register(struct drm_device *drm,
 			   &dw_mipi_dsi_atomic_connector_funcs,
 			   DRM_MODE_CONNECTOR_DSI);
 
+	drm_panel_attach(dsi->panel, &dsi->connector);
+
 	drm_mode_connector_attach_encoder(connector, encoder);
 
 	return 0;
@@ -1097,23 +1098,17 @@ MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids);
 static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 			    void *data)
 {
-	const struct of_device_id *of_id =
-			of_match_device(dw_mipi_dsi_dt_ids, dev);
-	const struct dw_mipi_dsi_plat_data *pdata = of_id->data;
 	struct platform_device *pdev = to_platform_device(dev);
 	struct drm_device *drm = data;
-	struct dw_mipi_dsi *dsi;
+	struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
 	struct resource *res;
 	int ret;
 
-	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
-	if (!dsi)
-		return -ENOMEM;
-
-	dsi->dev = dev;
-	dsi->pdata = pdata;
 	dsi->dpms_mode = DRM_MODE_DPMS_OFF;
 
+	if (!dsi->panel)
+		return -EPROBE_DEFER;
+
 	ret = rockchip_mipi_parse_dt(dsi);
 	if (ret)
 		return ret;
@@ -1160,9 +1155,7 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master,
 
 	pm_runtime_enable(dev);
 
-	dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
-	dsi->dsi_host.dev = dev;
-	return mipi_dsi_host_register(&dsi->dsi_host);
+	return 0;
 
 err_pllref:
 	clk_disable_unprepare(dsi->pllref_clk);
@@ -1174,7 +1167,6 @@ static void dw_mipi_dsi_unbind(struct device *dev, struct device *master,
 {
 	struct dw_mipi_dsi *dsi = dev_get_drvdata(dev);
 
-	mipi_dsi_host_unregister(&dsi->dsi_host);
 	pm_runtime_disable(dev);
 	clk_disable_unprepare(dsi->pllref_clk);
 }
@@ -1186,11 +1178,40 @@ static const struct component_ops dw_mipi_dsi_ops = {
 
 static int dw_mipi_dsi_probe(struct platform_device *pdev)
 {
-	return component_add(&pdev->dev, &dw_mipi_dsi_ops);
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *of_id =
+			of_match_device(dw_mipi_dsi_dt_ids, dev);
+	const struct dw_mipi_dsi_plat_data *pdata = of_id->data;
+	struct dw_mipi_dsi *dsi;
+	int ret;
+
+	dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
+	if (!dsi)
+		return -ENOMEM;
+
+	dsi->dev = dev;
+	dsi->pdata = pdata;
+	dsi->dsi_host.ops = &dw_mipi_dsi_host_ops;
+	dsi->dsi_host.dev = &pdev->dev;
+
+	ret = mipi_dsi_host_register(&dsi->dsi_host);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, dsi);
+	ret = component_add(&pdev->dev, &dw_mipi_dsi_ops);
+	if (ret)
+		mipi_dsi_host_unregister(&dsi->dsi_host);
+
+	return ret;
 }
 
 static int dw_mipi_dsi_remove(struct platform_device *pdev)
 {
+	struct dw_mipi_dsi *dsi = dev_get_drvdata(&pdev->dev);
+
+	if (dsi)
+		mipi_dsi_host_unregister(&dsi->dsi_host);
 	component_del(&pdev->dev, &dw_mipi_dsi_ops);
 	return 0;
 }
-- 
2.6.3

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox