* Re: [PATCH v4 3/4] dt-bindings: phy: Add support for QMP phy
From: Kishon Vijay Abraham I @ 2017-01-16 8:49 UTC (permalink / raw)
To: Vivek Gautam, robh+dt, linux-kernel, devicetree
Cc: mark.rutland, sboyd, bjorn.andersson, srinivas.kandagatla,
linux-arm-msm
In-Reply-To: <1484045519-19030-4-git-send-email-vivek.gautam@codeaurora.org>
Hi,
On Tuesday 10 January 2017 04:21 PM, Vivek Gautam wrote:
> Qualcomm chipsets have QMP phy controller that provides
> support to a number of controller, viz. PCIe, UFS, and USB.
> Adding dt binding information for the same.
>
> Signed-off-by: Vivek Gautam <vivek.gautam@codeaurora.org>
> Acked-by: Rob Herring <robh@kernel.org>
> ---
>
> Changes since v3:
> - Added #clock-cells = <1>, indicating that phy is a clock provider.
>
> Changes since v2:
> - Removed binding for "ref_clk_src" since we don't request this
> clock in the driver.
> - Addressed s/ref_clk/ref. Don't need to add '_clk' suffix to clock names.
> - Using 'phy' for the node name.
>
> Changes since v1:
> - New patch, forked out of the original driver patch:
> "phy: qcom-qmp: new qmp phy driver for qcom-chipsets"
> - Added 'Acked-by' from Rob.
> - Updated bindings to include mem resource as a list of
> offset - length pair for serdes block and for each lane.
> - Added a new binding for 'lane-offsets' that contains offsets
> to tx, rx and pcs blocks from each lane base address.
>
> .../devicetree/bindings/phy/qcom-qmp-phy.txt | 76 ++++++++++++++++++++++
> 1 file changed, 76 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
>
> diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
> new file mode 100644
> index 000000000000..6f510fe48f46
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
> @@ -0,0 +1,76 @@
> +Qualcomm QMP PHY controller
> +===========================
> +
> +QMP phy controller supports physical layer functionality for a number of
> +controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB.
> +
> +Required properties:
> + - compatible: compatible list, contains:
> + "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
> + "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996.
> + - reg: list of offset and length pair of the PHY register sets.
> + at index 0: offset and length of register set for PHY common
> + serdes block.
> + from index 1 - N: offset and length of register set for each lane,
> + for N number of phy lanes (ports).
> + - lane-offsets: array of offsets to tx, rx and pcs blocks for phy lanes.
> + - #phy-cells: must be 1
> + - Cell after phy phandle should be the port (lane) number.
> + - #clock-cells: must be 1
> + - Phy pll outputs a bunch of clocks for Tx, Rx and Pipe
> + interface (for pipe based PHYs). These clock are then gate-controlled
> + by gcc.
> + - clocks: a list of phandles and clock-specifier pairs,
> + one for each entry in clock-names.
> + - clock-names: must be "cfg_ahb" for phy config clock,
> + "aux" for phy aux clock,
> + "ref" for 19.2 MHz ref clk,
> + "pipe<port-number>" for pipe clock specific to
> + each port/lane (Optional).
> + - resets: a list of phandles and reset controller specifier pairs,
> + one for each entry in reset-names.
> + - reset-names: must be "phy" for reset of phy block,
> + "common" for phy common block reset,
> + "cfg" for phy's ahb cfg block reset (Optional).
> + "port<port-number>" for reset specific to
> + each port/lane (Optional).
> + - vdda-phy-supply: Phandle to a regulator supply to PHY core block.
> + - vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block.
> +
> +Optional properties:
> + - vddp-ref-clk-supply: Phandle to a regulator supply to any specific refclk
> + pll block.
> +
> +Example:
> + pcie_phy: phy@34000 {
> + compatible = "qcom,msm8996-qmp-pcie-phy";
> + reg = <0x034000 0x48f>,
> + <0x035000 0x5bf>,
> + <0x036000 0x5bf>,
> + <0x037000 0x5bf>;
> + /* tx, rx, pcs */
> + lane-offsets = <0x0 0x200 0x400>;
> + #phy-cells = <1>;
> + #clock-cells = <1>;
> +
> + clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>,
> + <&gcc GCC_PCIE_PHY_CFG_AHB_CLK>,
> + <&gcc GCC_PCIE_CLKREF_CLK>,
> + <&gcc GCC_PCIE_0_PIPE_CLK>,
> + <&gcc GCC_PCIE_1_PIPE_CLK>,
> + <&gcc GCC_PCIE_2_PIPE_CLK>;
> + clock-names = "aux", "cfg_ahb", "ref",
> + "pipe0", "pipe1", "pipe2";
> +
> + vdda-phy-supply = <&pm8994_l28>;
> + vdda-pll-supply = <&pm8994_l12>;
> +
> + resets = <&gcc GCC_PCIE_PHY_BCR>,
> + <&gcc GCC_PCIE_PHY_COM_BCR>,
> + <&gcc GCC_PCIE_PHY_COM_NOCSR_BCR>,
> + <&gcc GCC_PCIE_0_PHY_BCR>,
> + <&gcc GCC_PCIE_1_PHY_BCR>,
> + <&gcc GCC_PCIE_2_PHY_BCR>;
> + reset-names = "phy", "common", "cfg",
> + "lane0", "lane1", "lane2";
Each lane has a separate clock, separate reset.. why not create sub-nodes for
each lane?
Thanks
Kishon
^ permalink raw reply
* RE: [PATCH v3 2/3] USB3/DWC3: Add property "snps, incr-burst-type-adjustment" for INCR burst type
From: Felipe Balbi @ 2017-01-16 8:50 UTC (permalink / raw)
To: Jerry Huang, Rob Herring
Cc: mark.rutland@arm.com, catalin.marinas@arm.com,
will.deacon@arm.com, linux@armlinux.org.uk,
devicetree@vger.kernel.org, linux-usb@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <DB5PR0401MB18132BB4CDE32EEA8F479E55FE7D0@DB5PR0401MB1813.eurprd04.prod.outlook.com>
[-- Attachment #1: Type: text/plain, Size: 4776 bytes --]
Hi,
Jerry Huang <jerry.huang@nxp.com> writes:
>> > On Thu, Dec 22, 2016 at 8:52 PM, Jerry Huang <jerry.huang@nxp.com>
>> wrote:
>> > > Hi, Rob,
>> > >> -----Original Message-----
>> > >> From: Rob Herring [mailto:robh@kernel.org]
>> > >> Sent: Friday, December 23, 2016 2:45 AM
>> > >> To: Jerry Huang <jerry.huang@nxp.com>
>> > >> Cc: balbi@kernel.org; mark.rutland@arm.com;
>> > >> catalin.marinas@arm.com; will.deacon@arm.com;
>> > >> linux@armlinux.org.uk; devicetree@vger.kernel.org;
>> > >> linux-usb@vger.kernel.org; linux-kernel@vger.kernel.org; linux-arm-
>> > >> kernel@lists.infradead.org
>> > >> Subject: Re: [PATCH v3 2/3] USB3/DWC3: Add property "snps,
>> > >> incr-burst- type-adjustment" for INCR burst type
>> > >>
>> > >> On Mon, Dec 19, 2016 at 05:25:53PM +0800, Changming Huang wrote:
>> > >> > New property "snps,incr-burst-type-adjustment = <x>, <y>" for
>> > >> > USB3.0
>> > >> DWC3.
>> > >> > Field "x": 1/0 - undefined length INCR burst type enable or not;
>> > >> > Field
>> > >> > "y": INCR4/INCR8/INCR16/INCR32/INCR64/INCR128/INCR256 burst
>> type.
>> > >> >
>> > >> > While enabling undefined length INCR burst type and INCR16 burst
>> > >> > type, get better write performance on NXP Layerscape platform:
>> > >> > around 3% improvement (from 364MB/s to 375MB/s).
>> > >> >
>> > >> > Signed-off-by: Changming Huang <jerry.huang@nxp.com>
>> > >> > ---
>> > >> > Changes in v3:
>> > >> > - add new property for INCR burst in usb node.
>> > >> >
>> > >> > Documentation/devicetree/bindings/usb/dwc3.txt | 5 +++++
>> > >> > arch/arm/boot/dts/ls1021a.dtsi | 1 +
>> > >> > arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 3 +++
>> > >> > arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi | 2 ++
>> > >> > 4 files changed, 11 insertions(+)
>> > >> >
>> > >> > diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt
>> > >> > b/Documentation/devicetree/bindings/usb/dwc3.txt
>> > >> > index e3e6983..8c405a3 100644
>> > >> > --- a/Documentation/devicetree/bindings/usb/dwc3.txt
>> > >> > +++ b/Documentation/devicetree/bindings/usb/dwc3.txt
>> > >> > @@ -55,6 +55,10 @@ Optional properties:
>> > >> > fladj_30mhz_sdbnd signal is invalid or incorrect.
>> > >> >
>> > >> > - <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to
>> > >> > be
>> > >> reallocated.
>> > >> > + - snps,incr-burst-type-adjustment: Value for INCR burst type of
>> > >> GSBUSCFG0
>> > >> > + register, undefined length INCR burst type enable and INCRx type.
>> > >> > + First field is for undefined length INCR burst type enable or not.
>> > >> > + Second field is for largest INCRx type enabled.
>> > >>
>> > >> Why do you need the first field? Is the 2nd field used if the 1st is 0?
>> > >> If not, then just use the presence of the property to enable or not.
>> > > The first field is one switch.
>> > > When it is 1, means undefined length INCR burst type enabled, we can
>> > > use
>> > any length less than or equal to the largest-enabled burst length of
>> > INCR4/8/16/32/64/128/256.
>> > > When it is zero, means INCRx burst mode enabled, we can use one
>> > > fixed
>> > burst length of 1/4/8/16/32/64/128/256 byte.
>> > > So, the 2nd field is used if the 1st is 0, we need to select one
>> > > largest burst
>> > length the USB controller can support.
>> > > If we don't want to change the value of this register (use the
>> > > default value),
>> > we don't need to add this property to usb node.
>> >
>> > Just make this a single value with 0 meaning INCR and 4/8/16/etc being
>> INCRx.
>> Maybe, I didn't describe it clearly.
>> According to DWC3 spec, the value "0" of field INCRBrstEna means INCRx
>> burst mode, 1 means INCR burst mode.
>> Regardless of the value of INCRBrstEna [bit0], we need to modify the other
>> field bit[1,2,3,4,5,6,7] to one INCR burst type for the platform supported.
>> Ad you mentioned, if we just use a single value with 0 meaning INCR and
>> 4/8/16/etc being INCRx.
>> I understand totally that when it is none-zero, we can use it for INCR burst
>> mode.
>> Then, when it is 0, how to select the INCRx value?
>>
>> So, I think we still need two vaue to specify INCRBrstEna and INCRx burst
>> type.
> Hi, Balbi,
> It seems there is no feedback for my comment, so these patches can be accepted?
probably not, we need to really understand what information we need so
it can be described properly. The last thing we want is unnecessary DT
properties.
It seems to me that we can extrapolate INCRBrstEna based on which burst
modes are enabled. If only 0 is passed, then that bit should be 1, if 0
and any other size is passed, then that bit should be 0, no?
--
balbi
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]
^ permalink raw reply
* Re: [v2 2/3] ARM: dts: STM32 Add USB FS host mode support
From: Alexandre Torgue @ 2017-01-16 8:57 UTC (permalink / raw)
To: Bruno Herrera, Rob Herring, Mark Rutland, Maxime Coquelin
Cc: devicetree, Russell King, linux-arm-kernel, linux-kernel
In-Reply-To: <20170116020958.62767-2-bruherrera@gmail.com>
Hi Bruno,
On 01/16/2017 03:09 AM, Bruno Herrera wrote:
> This patch adds the USB pins and nodes for USB HS/FS cores working at FS speed,
> using embedded PHY.
>
> Signed-off-by: Bruno Herrera <bruherrera@gmail.com>
Sorry, but what is patch 1 & pacth 3 status ?
For this one, can split it in 3 patches (one patch for SOC and one for
each board) please.
> ---
> arch/arm/boot/dts/stm32f429-disco.dts | 30 ++++++++++++++++++++++++++++++
> arch/arm/boot/dts/stm32f429.dtsi | 35 ++++++++++++++++++++++++++++++++++-
> arch/arm/boot/dts/stm32f469-disco.dts | 30 ++++++++++++++++++++++++++++++
> 3 files changed, 94 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/boot/dts/stm32f429-disco.dts b/arch/arm/boot/dts/stm32f429-disco.dts
> index 7d0415e..374c5ed 100644
> --- a/arch/arm/boot/dts/stm32f429-disco.dts
> +++ b/arch/arm/boot/dts/stm32f429-disco.dts
> @@ -88,6 +88,16 @@
> gpios = <&gpioa 0 0>;
> };
> };
> +
> + /* This turns on vbus for otg for host mode (dwc2) */
> + vcc5v_otg: vcc5v-otg-regulator {
> + compatible = "regulator-fixed";
> + gpio = <&gpioc 4 0>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&usbotg_pwren_h>;
> + regulator-name = "vcc5_host1";
> + regulator-always-on;
> + };
> };
>
> &clk_hse {
> @@ -99,3 +109,23 @@
> pinctrl-names = "default";
> status = "okay";
> };
> +
> +&usbotg_hs {
> + compatible = "st,stm32-fsotg", "snps,dwc2";
> + dr_mode = "host";
> + pinctrl-0 = <&usbotg_fs_pins_b>;
> + pinctrl-names = "default";
> + status = "okay";
> +};
> +
> +&pinctrl {
> + usb-host {
> + usbotg_pwren_h: usbotg-pwren-h {
> + pins {
> + pinmux = <STM32F429_PC4_FUNC_GPIO>;
> + bias-disable;
> + drive-push-pull;
> + };
> + };
> + };
> +};
Pinctrl muxing has to be defined/declared in stm32f429.dtsi
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> index e4dae0e..bc07aa8 100644
> --- a/arch/arm/boot/dts/stm32f429.dtsi
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -206,7 +206,7 @@
> reg = <0x40007000 0x400>;
> };
>
> - pin-controller {
> + pinctrl: pin-controller {
> #address-cells = <1>;
> #size-cells = <1>;
> compatible = "st,stm32f429-pinctrl";
> @@ -316,6 +316,30 @@
> };
> };
>
> + usbotg_fs_pins_a: usbotg_fs@0 {
> + pins {
> + pinmux = <STM32F429_PA10_FUNC_OTG_FS_ID>,
> + <STM32F429_PA11_FUNC_OTG_FS_DM>,
> + <STM32F429_PA12_FUNC_OTG_FS_DP>;
> + bias-disable;
> + drive-push-pull;
> + slew-rate = <2>;
> + };
> + };
> +
> + usbotg_fs_pins_b: usbotg_fs@1 {
> + pins {
> + pinmux = <STM32F429_PB12_FUNC_OTG_HS_ID>,
> + <STM32F429_PB14_FUNC_OTG_HS_DM>,
> + <STM32F429_PB15_FUNC_OTG_HS_DP>;
> + bias-disable;
> + drive-push-pull;
> + slew-rate = <2>;
> + };
> + };
> +
> +
> +
> usbotg_hs_pins_a: usbotg_hs@0 {
> pins {
> pinmux = <STM32F429_PH4_FUNC_OTG_HS_ULPI_NXT>,
> @@ -420,6 +444,15 @@
> status = "disabled";
> };
>
> + usbotg_fs: usb@50000000 {
> + compatible = "st,stm32f4xx-fsotg", "snps,dwc2";
> + reg = <0x50000000 0x40000>;
> + interrupts = <67>;
> + clocks = <&rcc 0 39>;
> + clock-names = "otg";
> + status = "disabled";
> + };
> +
> rng: rng@50060800 {
> compatible = "st,stm32-rng";
> reg = <0x50060800 0x400>;
> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
> index 8877c00..8ae6763 100644
> --- a/arch/arm/boot/dts/stm32f469-disco.dts
> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
> @@ -68,6 +68,17 @@
> soc {
> dma-ranges = <0xc0000000 0x0 0x10000000>;
> };
> +
> + /* This turns on vbus for otg for host mode (dwc2) */
> + vcc5v_otg: vcc5v-otg-regulator {
> + compatible = "regulator-fixed";
> + enable-active-high;
> + gpio = <&gpiob 2 0>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&usbotg_pwren_h>;
> + regulator-name = "vcc5_host1";
> + regulator-always-on;
> + };
> };
>
> &rcc {
> @@ -81,3 +92,22 @@
> &usart3 {
> status = "okay";
> };
> +
> +&usbotg_fs {
> + dr_mode = "host";
> + pinctrl-0 = <&usbotg_fs_pins_a>;
> + pinctrl-names = "default";
> + status = "okay";
> +};
> +
> +&pinctrl {
> + usb-host {
> + usbotg_pwren_h: usbotg-pwren-h {
> + pins {
> + pinmux = <STM32F429_PB2_FUNC_GPIO>;
> + bias-disable;
> + drive-push-pull;
> + };
> + };
> + };
> +};
Same. Note that if you have 2 configuration for one feature (like it is
here for "usbotg_pwren_h"), you could index it. Not that I'm adding a
dedidacted pinctroller for stm32f469.
Br
Alex
>
^ permalink raw reply
* [PATCH] rtc: stm32: use 0 instead of ~PWR_CR_DBP in regmap_update_bits
From: Amelie Delaunay @ 2017-01-16 8:57 UTC (permalink / raw)
To: Alessandro Zummo, Alexandre Belloni, Rob Herring, Mark Rutland,
Maxime Coquelin, Alexandre Torgue, Russell King
Cc: rtc-linux-/JYPxA39Uh5TLH3MbocFFw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Gabriel Fernandez,
Amelie Delaunay
Using the ~ operator on a BIT() constant results in a large 'unsigned long'
constant that won't fit into an 'unsigned int' function argument on 64-bit
architectures, resulting in a harmless build warning in x86 allmodconfig:
drivers/rtc/rtc-stm32.c: In function 'stm32_rtc_probe':
drivers/rtc/rtc-stm32.c:651:51: error: large integer implicitly truncated to unsigned type [-Werror=overflow]
regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
As PWR_CR_DBP mask prevents other bits to be cleared, replace all
~PWR_CR_DBP by 0.
Fixes: 4e64350f42e2 ("rtc: add STM32 RTC driver")
Signed-off-by: Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>
Signed-off-by: Amelie Delaunay <amelie.delaunay-qxv4g6HH51o@public.gmane.org>
---
drivers/rtc/rtc-stm32.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
index 8c599f5..03c97c1 100644
--- a/drivers/rtc/rtc-stm32.c
+++ b/drivers/rtc/rtc-stm32.c
@@ -648,7 +648,7 @@ static int stm32_rtc_probe(struct platform_device *pdev)
err:
clk_disable_unprepare(rtc->ck_rtc);
- regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
+ regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0);
device_init_wakeup(&pdev->dev, false);
@@ -670,7 +670,7 @@ static int stm32_rtc_remove(struct platform_device *pdev)
clk_disable_unprepare(rtc->ck_rtc);
/* Enable backup domain write protection */
- regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
+ regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0);
device_init_wakeup(&pdev->dev, false);
--
1.9.1
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply related
* Re: [PATCH v1 1/3] dt: bindings: add documentation for zx2967 family watchdog controller
From: Shawn Guo @ 2017-01-16 9:04 UTC (permalink / raw)
To: Baoyou Xie
Cc: jun.nie-QSEj5FYQhm4dnm+yROfE0A, wim-IQzOog9fTRqzQB+pC5nmwQ,
linux-0h96xk9xTtrk1uMJSBkQmQ, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-watchdog-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
xie.baoyou-Th6q7B73Y6EnDS1+zs4M5A,
chen.chaokai-Th6q7B73Y6EnDS1+zs4M5A,
wang.qiang01-Th6q7B73Y6EnDS1+zs4M5A
In-Reply-To: <1484540395-3335-1-git-send-email-baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
On Mon, Jan 16, 2017 at 12:19:53PM +0800, Baoyou Xie wrote:
> This patch adds dt-binding documentation for zx2967 family
> watchdog controller.
>
> Signed-off-by: Baoyou Xie <baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
> .../bindings/watchdog/zte,zx2967-wdt.txt | 29 ++++++++++++++++++++++
> 1 file changed, 29 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt
>
> diff --git a/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt b/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt
> new file mode 100644
> index 0000000..0fe0d40
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt
> @@ -0,0 +1,29 @@
> +ZTE zx2967 Watchdog timer
> +
> +Required properties:
> +
> +- compatible : should be one of the following.
> + * zte,zx296718-wdt
> +- reg : Specifies base physical address and size of the registers.
> +- clocks : Pairs of phandle and specifier referencing the controller's clocks.
> +- clock-names: "wdtclk" for the watchdog clock.
clock-names only makes sense when there are multiple clock phandles in
'clocks' property. When clock-names is not present, the driver code
calls devm_clk_get() with the second parameter being NULL.
> +- resets : Reference to the reset controller controlling the watchdog
> + controller.
> +- reset-names : Must include the following entries:
> + * wdtrst
Same as clock-names.
> +
> +Optional properties:
> +
> +- reset-mask-config : Mask and configuare value that be wrote to aon-sysctrl.
First of all, for vendor specific properties, we should have a vendor
prefix, something like "zte,reset-mask-config".
Secondly, we should really have more comments to explain why this
property is optional, i.e. in which cases it should be present, and in
which cases it can be missing. Also, the relationship between this
reset and 'resets = <&toprst 35>' should be explained a bit as well.
Shawn
> +
> +Example:
> +
> +wdt_ares: watchdog@1465000 {
> + compatible = "zte,zx296718-wdt";
> + reg = <0x1465000 0x1000>;
> + clocks = <&topcrm WDT_WCLK>;
> + clock-names = "wdtclk";
> + resets = <&toprst 35>;
> + reset-names = "wdtrst";
> + reset-mask-config = <1 0x115>;
> +};
> --
> 2.7.4
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [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: Maxime Ripard, Icenowy Zheng
Cc: Chen-Yu Tsai, Bin Liu, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA
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-ymACFijhrKM@public.gmane.org>
>
> Acked-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
merged, thanks!
-Kishon
>
> Thanks,
> Maxime
>
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 0/6] USB support for Broadcom NSP SoC
From: Kishon Vijay Abraham I @ 2017-01-16 9:17 UTC (permalink / raw)
To: Florian Fainelli, Yendapally Reddy Dhananjaya Reddy, Rob Herring,
Mark Rutland, Russell King, Ray Jui, Scott Branden, Jon Mason
Cc: netdev, bcm-kernel-feedback-list, linux-kernel, linux-arm-kernel,
devicetree
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
* Re: [PATCH 2/3] Broadcom USB DRD Phy driver for Northstar2
From: Kishon Vijay Abraham I @ 2017-01-16 9:22 UTC (permalink / raw)
To: Raviteja Garimella, Rob Herring, Mark Rutland, Ray Jui,
Scott Branden, Jon Mason, Catalin Marinas, Will Deacon
Cc: devicetree, bcm-kernel-feedback-list, linux-kernel,
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
* Re: [PATCH] pcie: ti: Provide patch to force GEN1 PCIe operation
From: Lukasz Majewski @ 2017-01-16 9:31 UTC (permalink / raw)
To: Kishon Vijay Abraham I
Cc: Bjorn Helgaas, Rob Herring, Mark Rutland, Jingoo Han, Joao Pinto,
linux-omap, linux-pci, devicetree, linux-kernel
In-Reply-To: <587C8088.80905@ti.com>
Hi Kishon,
> Hi Łukasz,
>
> On Monday 16 January 2017 12:19 PM, Lukasz Majewski wrote:
> > Hi Kishon,
> >
> >> Hi,
> >>
> >> On Sunday 15 January 2017 06:49 PM, Lukasz Majewski wrote:
> >>> Some devices (due to e.g. bad PCIe signal integrity) require to
> >>> run with forced GEN1 speed on PCIe bus.
> >>>
> >>> This patch changes the speed explicitly on dra7 based devices when
> >>> proper device tree attribute is defined for the PCIe controller.
> >>>
> >>> Signed-off-by: Lukasz Majewski <lukma@denx.de>
> >>
> >> Bjorn has already queued a patch to do the same thing
> >> https://git.kernel.org/cgit/linux/kernel/git/helgaas/pci.git/log/?h=pci/host-dra7xx
> >
> > It seems like Bjorn only modifies CAP registers.
>
> The patch also modifies the LNKCTL2 register.
> >
> > He also needs to change register with 0x080C offset to actually
> > ( PCIECTRL_PL_WIDTH_SPEED_CTL )
>
> This bit is used to initiate speed change (after the link is
> initialized in GEN1). Resetting the bit (like what you have done
> here) prevents speed change.
This is strange, but e2e advised me to do things as I did in the patch
to _force_ GEN1 operation on PCIe2 port [1] (AM5728)
Link:
[1] https://e2e.ti.com/support/arm/sitara_arm/f/791/t/566421
Both patches modify 0x5180 007C register to set GEN1 capability
(PCI_EXP_LNKCAP_SLS_2_5GB)
The problem is with second register (in your patch):
>From SPRUHZ6G TRM:
PCIECTRL_EP_DBICS_LNK_CAS_2 (0x5180 00A0)
- TRGT_LINK_SPEED (Reset 0x1) - "Target Link Speed" - no more
description in TRM
It is set to PCI_EXP_LNKCAP_SLS_2_5GB = 0x1, which is the same as
default /reset value.
Could you clarify which way to _force_ PCIe GEN1 operation is correct?
Mine shows differences in lspci output (as posted in [1]).
>
> IMO the better way is to set the LNKCTL2 to GEN1 instead of hacking
> the IP register.
>From the original patch description:
"Add support to force Root Complex to work in GEN1 mode if so desired,
but don't force GEN1 mode on any board just yet."
Are there any (floating around) patches allowing forcing GEN1 operation
on any board (I would like to reuse/port them to my current solution)?
Thanks in advance,
Łukasz Majewski
>
> Thanks
> Kishon
>
> >
> > Best regards,
> > Łukasz
> >
> >>
> >> Thanks
> >> Kishon
> >>
> >>> ---
> >>>
> >>> Patch applies on newest origin/master
> >>> SHA1: f4d3935e4f4884ba80561db5549394afb8eef8f7
> >>>
> >>> Tested at AM5728
> >>>
> >>> ---
> >>> Documentation/devicetree/bindings/pci/ti-pci.txt | 1 +
> >>> drivers/pci/host/pci-dra7xx.c | 23
> >>> +++++++++++++++++++++++
> >>> drivers/pci/host/pcie-designware.h | 1 + 3 files
> >>> changed, 25 insertions(+)
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/pci/ti-pci.txt
> >>> b/Documentation/devicetree/bindings/pci/ti-pci.txt index
> >>> 60e2516..9f97409 100644 ---
> >>> a/Documentation/devicetree/bindings/pci/ti-pci.txt +++
> >>> b/Documentation/devicetree/bindings/pci/ti-pci.txt @@ -25,6 +25,7
> >>> @@ PCIe Designware Controller
> >>> Optional Property:
> >>> - gpios : Should be added if a gpio line is required to drive
> >>> PERST# line
> >>> + - to,pcie-is-gen1: Indicates that forced gen1 port operation is
> >>> needed.
> >>> Example:
> >>> axi {
> >>> diff --git a/drivers/pci/host/pci-dra7xx.c
> >>> b/drivers/pci/host/pci-dra7xx.c index 9595fad..eec5fae 100644
> >>> --- a/drivers/pci/host/pci-dra7xx.c
> >>> +++
> >>> b/drivers/pci/host/pci-https://git.kernel.org/cgit/linux/kernel/git/helgaas/pci.git/log/?h=pci/host-dra7xxdra7xx.c
> >>> @@ -63,6 +63,13 @@ #define
> >>> LINK_UP BIT(16)
> >>> #define
> >>> DRA7XX_CPU_TO_BUS_ADDR 0x0FFFFFFF
> >>> +#define PCIECTRL_EP_DBICS_LNK_CAP
> >>> 0x007C +#define
> >>> MAX_LINK_SPEEDS_MASK GENMASK(3, 0)
> >>> +#define MAX_LINK_SPEEDS_GEN1
> >>> BIT(0) + +#define
> >>> PCIECTRL_PL_WIDTH_SPEED_CTL 0x080C
> >>> +#define CFG_DIRECTED_SPEED_CHANGE
> >>> BIT(17) + struct dra7xx_pcie { struct pcie_port pp;
> >>> void __iomem *base; /* DT
> >>> ti_conf */ @@ -270,6 +277,7 @@ static int __init
> >>> dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx, struct pcie_port
> >>> *pp = &dra7xx->pp; struct device *dev = pp->dev;
> >>> struct resource *res;
> >>> + u32 val;
> >>>
> >>> pp->irq = platform_get_irq(pdev, 1);
> >>> if (pp->irq < 0) {
> >>> @@ -296,6 +304,18 @@ static int __init dra7xx_add_pcie_port(struct
> >>> dra7xx_pcie *dra7xx, if (!pp->dbi_base)
> >>> return -ENOMEM;
> >>>
> >>> + if (pp->is_gen1) {
> >>> + dev_info(dev, "GEN1 forced\n");
> >>> +
> >>> + val = readl(pp->dbi_base +
> >>> PCIECTRL_EP_DBICS_LNK_CAP);
> >>> + set_mask_bits(&val, MAX_LINK_SPEEDS_MASK,
> >>> MAX_LINK_SPEEDS_GEN1);
> >>> + writel(val, pp->dbi_base +
> >>> PCIECTRL_EP_DBICS_LNK_CAP); +
> >>> + val = readl(pp->dbi_base +
> >>> PCIECTRL_PL_WIDTH_SPEED_CTL);
> >>> + val &= ~CFG_DIRECTED_SPEED_CHANGE;
> >>> + writel(val, pp->dbi_base +
> >>> PCIECTRL_PL_WIDTH_SPEED_CTL);
> >>> + }
> >>> +
> >>> ret = dw_pcie_host_init(pp);
> >>> if (ret) {
> >>> dev_err(dev, "failed to initialize host\n");
> >>> @@ -404,6 +424,9 @@ static int __init dra7xx_pcie_probe(struct
> >>> platform_device *pdev) goto err_gpio;
> >>> }
> >>>
> >>> + if (of_property_read_bool(np, "ti,pcie-is-gen1"))
> >>> + pp->is_gen1 = true;
> >>> +
> >>> reg = dra7xx_pcie_readl(dra7xx,
> >>> PCIECTRL_DRA7XX_CONF_DEVICE_CMD); reg &= ~LTSSM_EN;
> >>> dra7xx_pcie_writel(dra7xx,
> >>> PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg); diff --git
> >>> a/drivers/pci/host/pcie-designware.h
> >>> b/drivers/pci/host/pcie-designware.h index a567ea2..2fb0b18 100644
> >>> --- a/drivers/pci/host/pcie-designware.h +++
> >>> b/drivers/pci/host/pcie-designware.h @@ -50,6 +50,7 @@ struct
> >>> pcie_port { struct irq_domain *irq_domain;
> >>> unsigned long msi_data;
> >>> u8 iatu_unroll_enabled;
> >>> + u8 is_gen1;
> >>> DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
> >>> };
> >>>
> >>>
> >
> >
> >
> >
> > Best regards,
> >
> > Lukasz Majewski
> >
> > --
> >
> > DENX Software Engineering GmbH, Managing Director: Wolfgang
> > Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell,
> > Germany Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email:
> > wd@denx.de
> >
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
^ permalink raw reply
* Re: [PATCH v2 0/3] Adding DT support for TI HECC module
From: Yegor Yefremov @ 2017-01-16 9:34 UTC (permalink / raw)
To: Tony Lindgren
Cc: linux-can@vger.kernel.org, linux-omap@vger.kernel.org, devicetree,
robh+dt, Andrey Skvortsov, hs, Marc Kleine-Budde
In-Reply-To: <20170112154155.GA2630@atomide.com>
On Thu, Jan 12, 2017 at 4:41 PM, Tony Lindgren <tony@atomide.com> wrote:
> * Yegor Yefremov <yegorslists@googlemail.com> [170112 00:00]:
>> On Thu, Jan 12, 2017 at 1:47 AM, Tony Lindgren <tony@atomide.com> wrote:
>> > * Yegor Yefremov <yegorslists@googlemail.com> [170111 13:52]:
>> >> On Wed, Jan 11, 2017 at 3:05 PM, <yegorslists@googlemail.com> wrote:
>> >> > From: Yegor Yefremov <yegorslists@googlemail.com>
>> >> >
>> >> > This is an attempt to revive DT support for TI HECC that was started in 2015.
>> >> >
>> >> > I haven't changed much because not all questions could be fully answered:
>> >> >
>> >> > * Should HECC use "am3505" as compatible?
>> >>
>> >> I mean "ti,am3505-hecc"
>> >
>> > Yeah it should use the device name for the driver.
>> >
>> >> > * What should be done to the offsets (ti,scc-ram-offset, ti,hecc-ram-offset, ti,mbx-offset)?
>> >
>> > The devicetree maintainers need to ack the binding doc. Maybe
>> > send that as a first patch?
>>
>> The question is whether to place these settings into dtsi (as it was
>> done in the original patch) or in the driver itself.
>
> Well where are they on the SoC? Each driver should only access registers
> that belong to the driver module.
>
> If the ti,scc-ram-offset and ti,hecc-ram-offset are not within the ECC
> driver module, probably you should use a separate driver for them
> such as drivers/misc/sram.c.
>
> Also, sounds like the ti,mbx-offset should just be using the mailbox
> framework like remoteproc is doing with include/linux/omap-mailbox.h?
AFAIK all offsets are in RAM and belong to ioremapped space:
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(&pdev->dev, "No mem resources\n");
goto probe_exit;
}
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq) {
dev_err(&pdev->dev, "No irq resource\n");
goto probe_exit;
}
if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
dev_err(&pdev->dev, "HECC region already claimed\n");
err = -EBUSY;
goto probe_exit;
}
addr = ioremap(mem->start, resource_size(mem));
if (!addr) {
dev_err(&pdev->dev, "ioremap failed\n");
err = -ENOMEM;
goto probe_exit_free_region;
}
hecc_ram_offset usage:
static inline void hecc_write_lam(struct ti_hecc_priv *priv, u32 mbxno, u32 val)
{
__raw_writel(val, priv->base + priv->hecc_ram_offset + mbxno * 4);
}
mbx_offset usage:
static inline void hecc_write_mbx(struct ti_hecc_priv *priv, u32 mbxno,
u32 reg, u32 val)
{
__raw_writel(val, priv->base + priv->mbx_offset + mbxno * 0x10 +
reg);
}
static inline u32 hecc_read_mbx(struct ti_hecc_priv *priv, u32 mbxno, u32 reg)
{
return __raw_readl(priv->base + priv->mbx_offset + mbxno * 0x10 +
reg);
}
scc_ram_offset won't be used at all. CAN controller will be used in
HECC mode only:
/* SCC compat mode NOT supported (and not needed too) */
hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_SCM);
@Marc is mailbox infra applicable here?
Yegor
^ permalink raw reply
* Re: [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: Martin Blumenstingl, linux-amlogic, linux-arm-kernel, devicetree,
khilman, carlo, mark.rutland, robh+dt
Cc: catalin.marinas, will.deacon, narmstrong
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
* Re: [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: Andreas Färber
Cc: linux-serial-u79uwXL29TY76Z2rM5mHXA,
linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
jslaby-IBi9RG/b67k, gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
khilman-rdvid1DuHRBWk0Htik3J/w, carlo-KA+7E9HrN00dnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
catalin.marinas-5wv7dgnIgG8, will.deacon-5wv7dgnIgG8,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <042e2824-0772-cf27-ffa5-4c3b2af7c92b-l3A5Bk7waGM@public.gmane.org>
On Mon, Jan 16, 2017 at 1:47 AM, Andreas Färber <afaerber-l3A5Bk7waGM@public.gmane.org> 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-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org>
>> ---
>> 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
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] fbdev: ssd1307fb: allow reset-gpios is missing
From: Icenowy Zheng @ 2017-01-16 9:50 UTC (permalink / raw)
To: Maxime Ripard
Cc: David Airlie, linux-fbdev, Rob Herring, linux-kernel, devicetree
2017年1月16日 16:02于 Maxime Ripard <maxime.ripard@free-electrons.com>写道:
>
> On Sun, Jan 15, 2017 at 07:21:46PM +0800, Icenowy Zheng wrote:
> > Currently some SSD1306 OLED modules are sold without a reset pin (only
> > VCC, GND, SCK, SDA four pins).
> >
> > Add support for missing reset-gpios property.
> >
> > Signed-off-by: Icenowy Zheng <icenowy@aosc.xyz>
>
> Unfortunately, a similar patch has been sent a couple of times
> already:
> https://www.spinics.net/lists/devicetree/msg158330.html
Why is it never merged?
There are really boards that needs this function.
>
> Maxime
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
^ permalink raw reply
* Re: [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: Baoyou Xie
Cc: jun.nie-QSEj5FYQhm4dnm+yROfE0A, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mark.rutland-5wv7dgnIgG8,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
shawnguo-DgEjT+Ai2ygdnm+yROfE0A,
xie.baoyou-Th6q7B73Y6EnDS1+zs4M5A,
chen.chaokai-Th6q7B73Y6EnDS1+zs4M5A,
wang.qiang01-Th6q7B73Y6EnDS1+zs4M5A
In-Reply-To: <1484377530-30635-1-git-send-email-baoyou.xie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.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-QSEj5FYQhm4dnm+yROfE0A@public.gmane.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@1461060 {
That node should be named reset-controller.
> + compatible = "zte,zx296718-reset";
> + reg = <0x01461060 0x8>;
> + #reset-cells = <1>;
> + };
regards
Philipp
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [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: Baoyou Xie
Cc: jun.nie, robh+dt, mark.rutland, linux-arm-kernel, devicetree,
linux-kernel, shawnguo, xie.baoyou, chen.chaokai, wang.qiang01
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
* Re: [PATCH 09/10] ARM: dts: da850: add the SATA node
From: Bartosz Golaszewski @ 2017-01-16 10:03 UTC (permalink / raw)
To: David Lechner
Cc: Kevin Hilman, Sekhar Nori, Patrick Titiano, Michael Turquette,
Tejun Heo, Rob Herring, Mark Rutland, Russell King,
linux-ide-u79uwXL29TY76Z2rM5mHXA, linux-devicetree, LKML, arm-soc
In-Reply-To: <4eb4ada8-1d2d-2fa1-7961-21da56ea0082-nq/r/kbU++upp/zk7JDF2g@public.gmane.org>
2017-01-13 20:36 GMT+01:00 David Lechner <david-nq/r/kbU++upp/zk7JDF2g@public.gmane.org>:
> 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-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
>> ---
>> 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@0x218000 {
>
>
> 0x needs to be omitted.
>
> sata: ahci@218000 {
>
Will fix in v2.
Thanks,
Bartosz Golaszewski
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2 0/11] Rockchip dw-mipi-dsi driver
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: dianders, tfiga, heiko, yzq, mark.rutland, devicetree, robh+dt,
galak, pawel.moll, seanpaul
Cc: linux-kernel, dri-devel, linux-rockchip, Chris Zhong,
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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ 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: dianders, tfiga, heiko, yzq, mark.rutland, devicetree, robh+dt,
galak, pawel.moll, seanpaul
Cc: linux-kernel, dri-devel, linux-rockchip, Chris Zhong,
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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ 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: dianders, tfiga, heiko, yzq, mark.rutland, devicetree, robh+dt,
galak, pawel.moll, seanpaul
Cc: linux-kernel, dri-devel, linux-rockchip, Chris Zhong,
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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ 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: dianders, tfiga, heiko, yzq, mark.rutland, devicetree, robh+dt,
galak, pawel.moll, seanpaul
Cc: linux-kernel, dri-devel, linux-rockchip, Chris Zhong,
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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ 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: dianders, tfiga, heiko, yzq, mark.rutland, devicetree, robh+dt,
galak, pawel.moll, seanpaul
Cc: linux-kernel, dri-devel, linux-rockchip, Chris Zhong,
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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ 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: dianders, tfiga, heiko, yzq, mark.rutland, devicetree, robh+dt,
galak, pawel.moll, seanpaul
Cc: linux-kernel, dri-devel, linux-rockchip, Chris Zhong,
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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ 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: dianders, tfiga, heiko, yzq, mark.rutland, devicetree, robh+dt,
galak, pawel.moll, seanpaul
Cc: linux-kernel, dri-devel, linux-rockchip, Chris Zhong,
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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ 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: dianders, tfiga, heiko, yzq, mark.rutland, devicetree, robh+dt,
galak, pawel.moll, seanpaul
Cc: linux-kernel, dri-devel, linux-rockchip, Chris Zhong,
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
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related
* [PATCH v2 08/11] drm/rockchip/dsi: fix the issue can not send commands
From: Chris Zhong @ 2017-01-16 10:08 UTC (permalink / raw)
To: dianders, tfiga, heiko, yzq, mark.rutland, devicetree, robh+dt,
galak, pawel.moll, seanpaul
Cc: linux-rockchip, xubilv, Chris Zhong, Mark Yao, David Airlie,
dri-devel, linux-arm-kernel, linux-kernel
In-Reply-To: <1484561311-494-1-git-send-email-zyw@rock-chips.com>
From: xubilv <xbl@rock-chips.com>
There is a bug in hdr_write function, the value from the caller will be
overwritten, it cause the mipi can not send the correct command. And the
MIPI_DSI_GENERIC_SHORT_WRITE_n_PARAM message type should be supported.
Signed-off-by: xubilv <xbl@rock-chips.com>
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
---
drivers/gpu/drm/rockchip/dw-mipi-dsi.c | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
index 4ec82f6..4a2691c 100644
--- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c
@@ -572,10 +572,12 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host,
static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 val)
{
int ret;
+ u32 sts;
ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS,
- val, !(val & GEN_CMD_FULL), 1000,
+ sts, !(sts & GEN_CMD_FULL), 1000,
CMD_PKT_STATUS_TIMEOUT_US);
+
if (ret < 0) {
dev_err(dsi->dev, "failed to get available command FIFO\n");
return ret;
@@ -584,8 +586,9 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 val)
dsi_write(dsi, DSI_GEN_HDR, val);
ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS,
- val, val & (GEN_CMD_EMPTY | GEN_PLD_W_EMPTY),
+ sts, sts & (GEN_CMD_EMPTY | GEN_PLD_W_EMPTY),
1000, CMD_PKT_STATUS_TIMEOUT_US);
+
if (ret < 0) {
dev_err(dsi->dev, "failed to write command FIFO\n");
return ret;
@@ -594,8 +597,8 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 val)
return 0;
}
-static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi,
- const struct mipi_dsi_msg *msg)
+static int dw_mipi_dsi_short_write(struct dw_mipi_dsi *dsi,
+ const struct mipi_dsi_msg *msg)
{
const u16 *tx_buf = msg->tx_buf;
u32 val = GEN_HDATA(*tx_buf) | GEN_HTYPE(msg->type);
@@ -609,13 +612,14 @@ static int dw_mipi_dsi_dcs_short_write(struct dw_mipi_dsi *dsi,
return dw_mipi_dsi_gen_pkt_hdr_write(dsi, val);
}
-static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi,
- const struct mipi_dsi_msg *msg)
+static int dw_mipi_dsi_long_write(struct dw_mipi_dsi *dsi,
+ const struct mipi_dsi_msg *msg)
{
const u32 *tx_buf = msg->tx_buf;
int len = msg->tx_len, pld_data_bytes = sizeof(*tx_buf), ret;
u32 val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type);
u32 remainder = 0;
+ u32 sts = 0;
if (msg->tx_len < 3) {
dev_err(dsi->dev, "wrong tx buf length %zu for long write\n",
@@ -635,7 +639,7 @@ static int dw_mipi_dsi_dcs_long_write(struct dw_mipi_dsi *dsi,
}
ret = readx_poll_timeout(readl, dsi->base + DSI_CMD_PKT_STATUS,
- val, !(val & GEN_PLD_W_FULL), 1000,
+ sts, !(sts & GEN_PLD_W_FULL), 1000,
CMD_PKT_STATUS_TIMEOUT_US);
if (ret < 0) {
dev_err(dsi->dev,
@@ -656,11 +660,15 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
switch (msg->type) {
case MIPI_DSI_DCS_SHORT_WRITE:
case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+ case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
+ case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
+ case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
- ret = dw_mipi_dsi_dcs_short_write(dsi, msg);
+ ret = dw_mipi_dsi_short_write(dsi, msg);
break;
case MIPI_DSI_DCS_LONG_WRITE:
- ret = dw_mipi_dsi_dcs_long_write(dsi, msg);
+ case MIPI_DSI_GENERIC_LONG_WRITE:
+ ret = dw_mipi_dsi_long_write(dsi, msg);
break;
default:
dev_err(dsi->dev, "unsupported message type\n");
--
2.6.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox