Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 18/33] pcmcia: sa1100: provide generic CF support
From: Linus Walleij @ 2016-09-14 11:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20160914090602.GB1041@n2100.armlinux.org.uk>

On Wed, Sep 14, 2016 at 11:06 AM, Russell King - ARM Linux
<linux@armlinux.org.uk> wrote:

> Thanks, I've included a change there, should be part of the branch by
> the time you get this email - sa1100 head should be 9ad0f8181616.  If
> not, it's probably still being pushed out over my slow 'net link.

Thanks, fetched it and tested, this fix is there things work so far.

>> (It revealed another bug in fetching GPIOs but it is an orthogobal
>> problem altogether, looking into it.)
>
> If you're referring to the generic sa1100 pcmcia code, there's a fix
> for that already in my branch.

Unfortunately not, the bug is still there, I'll point it out in the relevant
patch, just need to do a boot test.

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH V2 4/4] ARM64 LPC: support earlycon for UART connected to LPC
From: zhichang @ 2016-09-14 11:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <7585762.SZVHZyJdka@wuerfel>



On 2016?09?08? 19:04, Arnd Bergmann wrote:
> On Thursday, September 8, 2016 6:04:31 PM CEST zhichang wrote:
>> Hi, Arnd,
>>
>> On 2016?09?07? 22:52, Arnd Bergmann wrote:
>>> On Wednesday, September 7, 2016 9:33:53 PM CEST Zhichang Yuan wrote:
>>>> From: "zhichang.yuan" <yuanzhichang@hisilicon.com>
>>>>
>>>> This patch support the earlycon for UART connected to LPC on Hip06.
>>>> This patch is depended on the LPC driver.
>>>>
>>>> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
>>>>
>>>
>>> I'm skeptical about this too. Is this just needed because the 8250
>>> earlycon support comes before the lpc bus initialization?
>> I think you wonder why early_serial8250_setup can not be used direclty for this earlycon of LPC uart.
>>
>> 1. the earlycon kernel parameter format of LPC uart is different from 8250. something like that
>> "earlycon=hisilpcuart,mmio,0xa01b0000,0,0x2f8". You see, there is one more parameter after the baudrate.
> 
> We should never need to specify the addresses manually like this,
> it's actually supposed to work if you just list "earlycon" here.

Do you mean flat-tree earlycon?
Ok, will support this in V3.

> 
> The first membase is apparently only used during setup:
> 
> +       writel(LPC_IRQ_CLEAR, device->port.membase + LPC_REG_IRQ_ST);
> +       /* ensure the LPC is available */
> +       while (!(readl(device->port.membase + LPC_REG_OP_STATUS) &
> +                       LPC_STATUS_IDLE))
> 
> Why doesn't the firmware do this before handing off control of
> the kernel to the console?
This is a checking on the LPC controller status.
I think we can keep this here.

> 
>> Hip06 LPC uart need two base addresses for earlycon.
>> 2. the IO type is mmio to introduce a memory base address to access LPC register file. But the real uart
>> IO type is UPIO_PORT. This is spcial...
> 
> This sounds like a deficiency in the of_setup_earlycon() function,
> which can only handle MMIO addresses, and won't actually
> be able to understand nodes without a "ranges" property like
> you have here.
> 
Yes.
The current of_setup_earlycon only support MMIO and the first reg property must be memory.

We can not support our LPC uart without any new code.
But we can implement a private earlycon setup function and register it to the __earlycon_table, things will be ok.
I will do it in V3.

Best,
Zhichang

> I think we need to add a special case for port ranges here.
> 
> 	Arnd
> 

^ permalink raw reply

* [PATCH 10/33] pcmcia: soc_common: switch to using gpio_descs
From: Linus Walleij @ 2016-09-14 11:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <E1beJkO-0000mg-Lu@rmk-PC.armlinux.org.uk>

On Mon, Aug 29, 2016 at 12:24 PM, Russell King
<rmk+kernel@armlinux.org.uk> wrote:

> Switch to using the gpiod_* consumer API rather than the legacy API.
>
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
(...)

> +int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt)
> +{
> +       int i;
> +
> +       for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
> +               struct gpio_desc *desc;
> +

Here I inserted:

        /* Skip over unnamed GPIOs, assume unused */
        if (!skt->stat[i].name)
            continue;

to get it working again on h3600.

> +               desc = gpiod_get(skt->socket.dev.parent,
> +                                skt->stat[i].name, GPIOD_IN);
> +               if (IS_ERR(desc)) {
> +                       dev_err(skt->socket.dev.parent,
> +                               "Failed to get GPIO for %s: %ld\n",
> +                               skt->stat[i].name, PTR_ERR(desc));
> +                       __soc_pcmcia_hw_shutdown(skt, i);
> +                       return PTR_ERR(desc);
> +               }


It bugs out for me on the legacy h3600, since it only defines
two of these pins not all of the ARRAY_SIZE(skt->stat) pins
will succeed and we get an error message like this:

sa11x0-pcmcia sa11x0-pcmcia: Failed to get GPIO for (null): -2
sa11x0-pcmcia: probe of sa11x0-pcmcia failed with error -2

With the patch above it goes away and the log is silent.
The debugfs gpio file looks like this:

cat gpio
gpiochip0: GPIOs 0-27, gpio:
 gpio-0   (                    |Power Button        ) in  hi
 gpio-10  (                    |pcmcia1-detect      ) in  hi
 gpio-11  (                    |pcmcia1-ready       ) in  hi
 gpio-17  (                    |pcmcia0-detect      ) in  hi
 gpio-18  (                    |Action button       ) in  hi
 gpio-21  (                    |pcmcia0-ready       ) in  hi
 gpio-23  (                    |dcd                 ) in  hi
 gpio-25  (                    |cts                 ) in  lo
 gpio-26  (                    |rts                 ) out lo

gpiochip1: GPIOs 28-43, parent: platform/htc-egpio, htc-egpio:
 gpio-28  (                    |Flash Vpp           ) out lo
 gpio-29  (                    |PCMCIA CARD RESET   ) out lo
 gpio-30  (                    |OPT RESET           ) out lo
 gpio-32  (                    |OPT NVRAM ON        ) out lo
 gpio-33  (                    |OPT ON              ) out lo
 gpio-34  (                    |LCD power           ) out lo
 gpio-36  (                    |LCD control         ) out lo
 gpio-42  (                    |LCD 5v              ) out lo
 gpio-43  (                    |LCD 9v/-6.5v        ) out lo

Which seems like before the patch series.

I still suspect the PCMCIA is not really working but I have
limited experience of the bus so I don't really know how
to test it deeply or have my PCMCIA ethernet or harddrive
probe properly.

There are no regressions however, so with something like
the above patch applied:
Tested-by: Linus Walleij <linus.walleij@linaro.org>

For the whole patch series on H3600.

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH v5 02/16] dt/bindings: Update binding for PM domain idle states
From: Ulf Hansson @ 2016-09-14 11:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <87h99i6b5d.fsf@arm.com>

>>>
>> Yes, you are right, I disagree with the definition of a domain around a
>> device.

To fill in, I agree with Lina (and Kevin).

>From my point of view, a domain is per definition containing resources
which are shared among devices. Having one device per domain, does in
general not make sense.

> OK, great.
>> However, as long as you don't force SoC's to define devices in
>> the CPU PM domain to have their own virtual domains, I have no problem.
>> You are welcome to define it the way you want for Juno or any other
>> platform.
> I don't think that's true; the bindings have to work the same way for
> all platforms. If for Juno we put CPU idle state phandles in a
> domain-idle-states property for per-CPU domains then, with the current
> implementation, the CPU-level idle states would be duplicated between
> cpuidle and the CPU PM domains.
>> I don't want that to be the forced and expected out of all
>> SoCs. All I am saying here is that the current implementation would
>> handle your case as well.
>
> The current implementation certainly does cover the work I want to
> do. The suggestion of per-device power domains for devices/CPUs with
> their own idle states is simply intended to minimise the binding design,
> since we'd no longer need cpu-idle-states or device-idle-states
> (the latter was proposed elsewhere).

I see your point, but IMHO that would be to simplify the description
of the hardware. And I don't think it's sufficient to cover all
existing cases.

>
> I am fine with the bindings as they are implemented currently so long
> as:
>
> - The binding doc makes clear how idle state phandles should be split
>   between cpu-idle-states and domain-idle-states. It should make it
>   obvious that no phandle should ever appear in both properties. It
>   would even be worth briefly going over the backward-compatibility
>   implications (e.g. what happens with old-kernel/new-DT and
>   new-kernel/old-DT combos if a platform has OSI and PC support and we
>   move cluster-level idle state phandles out of cpu-idle-states and into
>   domai-idle-states).
>
> - We have a reason against the definition of power domains as "a set of
>   devices bound by a common power (including idle) state", since that
>   definition would simplify the bindings. In my view, "nobody thinks
>   that's what a power domain is" _is_ a compelling reason, so if others
>   on the list get involved I'm convinced. I think I speak for Sudeep
>   here too.
>

>From a CPU point of view, I think it may very well be considered as
any other device. Yes, we have treated them in a specific manner
regarding the idle state definitions we currently have - and we can
continue to do that.

Although, in the long run, I think we needs something more flexible
that can be used for domains and devices.

Kind regards
Uffe

^ permalink raw reply

* [PATCH V2 3/4] ARM64 LPC: support serial based on low-pin-count
From: zhichang.yuan @ 2016-09-14 11:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <2531252.L41vzyMSKX@wuerfel>



On 2016/9/8 17:58, Arnd Bergmann wrote:
> On Thursday, September 8, 2016 5:51:25 PM CEST zhichang wrote:
>> On 2016?09?07? 22:50, Arnd Bergmann wrote:
>>> On Wednesday, September 7, 2016 9:33:52 PM CEST Zhichang Yuan wrote:
>>>> From: "zhichang.yuan" <yuanzhichang@hisilicon.com>
>>>>
>>>> On Hip06 platform, a 16550 compatible UART is connected to low-pin-count and
>>>> controlled through the LPC I/O cycles. This patch drives the UART port with
>>>> the specific serial in/out function pair based on the indirect-IO mechanism
>>>> introduced by Hip06 LPC driver.
>>>>
>>>> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
>>>
>>> Any reason this cannot just use the regular drivers/tty/serial/8250/8250_of.c
>>> driver?
>> I think two reasons for that:
>> 1. 8250_of.c is only for devicetree, but we need to support ACPI device too;
> 
> ACPI has its own way of describing serial ports, use that instead.
Could you give me some info about ACPI serial ports?
I found there is _CRS specific for serial, but it seems no serial driver use that.

Thanks!
Zhichang

> 
>> 2. It seems UPIO_PORT is not supported there.
> 
> Should be easy enough to add.
> 
> 	Arnd
> 
> .
> 

^ permalink raw reply

* [PATCH v9 06/19] ARM: STi: DT: STiH407: Add FDMA driver dt nodes.
From: Patrice Chotard @ 2016-09-14 11:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473081421-16555-7-git-send-email-peter.griffin@linaro.org>

Hi Peter

On 09/05/2016 03:16 PM, Peter Griffin wrote:
> These nodes are required to get the fdma driver working
> on STiH407 based silicon.
> 
> Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
> Acked-by: Lee Jones <lee.jones@linaro.org>
> ---
>  arch/arm/boot/dts/stih407-family.dtsi | 52 +++++++++++++++++++++++++++++++++++
>  1 file changed, 52 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/stih407-family.dtsi b/arch/arm/boot/dts/stih407-family.dtsi
> index d294e82..45cab30 100644
> --- a/arch/arm/boot/dts/stih407-family.dtsi
> +++ b/arch/arm/boot/dts/stih407-family.dtsi
> @@ -821,5 +821,57 @@
>  			clock-frequency	= <600000000>;
>  			st,syscfg	= <&syscfg_core 0x224>;
>  		};
> +
> +		/* fdma audio */
> +		fdma0: dma-controller at 8e20000 {
> +			compatible = "st,stih407-fdma-mpe31-11", "st,slim-rproc";
> +			reg = <0x8e20000 0x8000>,
> +			      <0x8e30000 0x3000>,
> +			      <0x8e37000 0x1000>,
> +			      <0x8e38000 0x8000>;
> +			reg-names = "slimcore", "dmem", "peripherals", "imem";
> +			clocks = <&clk_s_c0_flexgen CLK_FDMA>,
> +				 <&clk_s_c0_flexgen CLK_EXT2F_A9>,
> +				 <&clk_s_c0_flexgen CLK_EXT2F_A9>,
> +				 <&clk_s_c0_flexgen CLK_EXT2F_A9>;
> +			interrupts = <GIC_SPI 5 IRQ_TYPE_NONE>;
> +			dma-channels = <16>;
> +			#dma-cells = <3>;
> +		};
> +
> +		/* fdma app */
> +		fdma1: dma-controller at 8e40000 {
> +			compatible = "st,stih407-fdma-mpe31-12", "st,slim-rproc";
> +			reg = <0x8e40000 0x8000>,
> +			      <0x8e50000 0x3000>,
> +			      <0x8e57000 0x1000>,
> +			      <0x8e58000 0x8000>;
> +			reg-names = "slimcore", "dmem", "peripherals", "imem";
> +			clocks = <&clk_s_c0_flexgen CLK_FDMA>,
> +				<&clk_s_c0_flexgen CLK_TX_ICN_DMU>,
> +				<&clk_s_c0_flexgen CLK_TX_ICN_DMU>,
> +				<&clk_s_c0_flexgen CLK_EXT2F_A9>;
> +
> +			interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>;
> +			dma-channels = <16>;
> +			#dma-cells = <3>;
> +		};
> +
> +		/* fdma free running */
> +		fdma2: dma-controller at 8e60000 {
> +			compatible = "st,stih407-fdma-mpe31-13", "st,slim-rproc";
> +			reg = <0x8e60000 0x8000>,
> +			      <0x8e70000 0x3000>,
> +			      <0x8e77000 0x1000>,
> +			      <0x8e78000 0x8000>;
> +			reg-names = "slimcore", "dmem", "peripherals", "imem";
> +			interrupts = <GIC_SPI 9 IRQ_TYPE_NONE>;
> +			dma-channels = <16>;
> +			#dma-cells = <3>;
> +			clocks = <&clk_s_c0_flexgen CLK_FDMA>,
> +				<&clk_s_c0_flexgen CLK_EXT2F_A9>,
> +				<&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>,
> +				<&clk_s_c0_flexgen CLK_EXT2F_A9>;
> +		};
>  	};
>  };
> 

Applied for STi next

Thanks

^ permalink raw reply

* [PATCH v9 10/19] ARM: DT: STiH407: Add i2s_out pinctrl configuration
From: Patrice Chotard @ 2016-09-14 12:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473081421-16555-11-git-send-email-peter.griffin@linaro.org>

Hi Peter

On 09/05/2016 03:16 PM, Peter Griffin wrote:
> This patch adds the pinctrl config for the i2s_out pins
> used by the uniperif player IP.
> 
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
> Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
> Acked-by: Lee Jones <lee.jones@linaro.org>
> ---
>  arch/arm/boot/dts/stih407-pinctrl.dtsi | 23 +++++++++++++++++++++++
>  1 file changed, 23 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/stih407-pinctrl.dtsi b/arch/arm/boot/dts/stih407-pinctrl.dtsi
> index a538ae5..0fb5c8a 100644
> --- a/arch/arm/boot/dts/stih407-pinctrl.dtsi
> +++ b/arch/arm/boot/dts/stih407-pinctrl.dtsi
> @@ -1067,6 +1067,29 @@
>  				};
>  			};
>  
> +			i2s_out {
> +				pinctrl_i2s_8ch_out: i2s_8ch_out{
> +					st,pins {
> +						mclk = <&pio33 5 ALT1 OUT>;
> +						lrclk = <&pio33 7 ALT1 OUT>;
> +						sclk = <&pio33 6 ALT1 OUT>;
> +						data0 = <&pio33 4 ALT1 OUT>;
> +						data1 = <&pio34 0 ALT1 OUT>;
> +						data2 = <&pio34 1 ALT1 OUT>;
> +						data3 = <&pio34 2 ALT1 OUT>;
> +					};
> +				};
> +
> +				pinctrl_i2s_2ch_out: i2s_2ch_out{
> +					st,pins {
> +						mclk = <&pio33 5 ALT1 OUT>;
> +						lrclk = <&pio33 7 ALT1 OUT>;
> +						sclk = <&pio33 6 ALT1 OUT>;
> +						data0 = <&pio33 4 ALT1 OUT>;
> +					};
> +				};
> +			};
> +
>  			serial3 {
>  				pinctrl_serial3: serial3-0 {
>  					st,pins {
> 


Applied for STi next

Thanks

^ permalink raw reply

* [PATCH v9 11/19] ARM: DT: STiH407: Add i2s_in pinctrl configuration
From: Patrice Chotard @ 2016-09-14 12:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473081421-16555-12-git-send-email-peter.griffin@linaro.org>

Hi Peter

On 09/05/2016 03:16 PM, Peter Griffin wrote:
> This patch adds the pinctrl config for the i2s_in pins
> used by the uniperif reader IP.
> 
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
> Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
> Acked-by: Lee Jones <lee.jones@linaro.org>
> ---
>  arch/arm/boot/dts/stih407-pinctrl.dtsi | 24 ++++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/stih407-pinctrl.dtsi b/arch/arm/boot/dts/stih407-pinctrl.dtsi
> index 0fb5c8a..537db7e 100644
> --- a/arch/arm/boot/dts/stih407-pinctrl.dtsi
> +++ b/arch/arm/boot/dts/stih407-pinctrl.dtsi
> @@ -1090,6 +1090,30 @@
>  				};
>  			};
>  
> +			i2s_in {
> +				pinctrl_i2s_8ch_in: i2s_8ch_in{
> +					st,pins {
> +						mclk = <&pio32 5 ALT1 IN>;
> +						lrclk = <&pio32 7 ALT1 IN>;
> +						sclk = <&pio32 6 ALT1 IN>;
> +						data0 = <&pio32 4 ALT1 IN>;
> +						data1 = <&pio33 0 ALT1 IN>;
> +						data2 = <&pio33 1 ALT1 IN>;
> +						data3 = <&pio33 2 ALT1 IN>;
> +						data4 = <&pio33 3 ALT1 IN>;
> +					};
> +				};
> +
> +				pinctrl_i2s_2ch_in: i2s_2ch_in{
> +					st,pins {
> +						mclk = <&pio32 5 ALT1 IN>;
> +						lrclk = <&pio32 7 ALT1 IN>;
> +						sclk = <&pio32 6 ALT1 IN>;
> +						data0 = <&pio32 4 ALT1 IN>;
> +					};
> +				};
> +			};
> +
>  			serial3 {
>  				pinctrl_serial3: serial3-0 {
>  					st,pins {
> 



Applied for STi next

Thanks

^ permalink raw reply

* [PATCH v9 12/19] ARM: DT: STiH407: Add spdif_out pinctrl config
From: Patrice Chotard @ 2016-09-14 12:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473081421-16555-13-git-send-email-peter.griffin@linaro.org>

Hi Peter

On 09/05/2016 03:16 PM, Peter Griffin wrote:
> This patch adds the pinctrl config for the spidf out
> pins used by the sasg codec IP.
> 
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
> Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
> Acked-by: Lee Jones <lee.jones@linaro.org>
> ---
>  arch/arm/boot/dts/stih407-pinctrl.dtsi | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/stih407-pinctrl.dtsi b/arch/arm/boot/dts/stih407-pinctrl.dtsi
> index 537db7e..598dbab 100644
> --- a/arch/arm/boot/dts/stih407-pinctrl.dtsi
> +++ b/arch/arm/boot/dts/stih407-pinctrl.dtsi
> @@ -1114,6 +1114,14 @@
>  				};
>  			};
>  
> +			spdif_out {
> +				pinctrl_spdif_out: spdif_out{
> +					st,pins {
> +						spdif_out = <&pio34 7 ALT1 OUT>;
> +					};
> +				};
> +			};
> +
>  			serial3 {
>  				pinctrl_serial3: serial3-0 {
>  					st,pins {
> 



Applied for STi next

Thanks

^ permalink raw reply

* [PATCH v9 13/19] ARM: STi: DT: STiH407: Add sti-sasg-codec dt node
From: Patrice Chotard @ 2016-09-14 12:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473081421-16555-14-git-send-email-peter.griffin@linaro.org>

Hi Peter

On 09/05/2016 03:16 PM, Peter Griffin wrote:
> This patch adds the dt node for the internal audio
> codec IP.
> 
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
> Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
> ---
>  arch/arm/boot/dts/stih407-family.dtsi | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/stih407-family.dtsi b/arch/arm/boot/dts/stih407-family.dtsi
> index 45cab30..d1258d5 100644
> --- a/arch/arm/boot/dts/stih407-family.dtsi
> +++ b/arch/arm/boot/dts/stih407-family.dtsi
> @@ -873,5 +873,12 @@
>  				<&clk_s_c0_flexgen CLK_TX_ICN_DISP_0>,
>  				<&clk_s_c0_flexgen CLK_EXT2F_A9>;
>  		};
> +
> +		sti_sasg_codec: sti-sasg-codec {
> +			compatible = "st,stih407-sas-codec";
> +			#sound-dai-cells = <1>;
> +			status = "disabled";
> +			st,syscfg = <&syscfg_core>;
> +		};
>  	};
>  };
> 


Applied for STi next

Thanks

^ permalink raw reply

* [PATCH v9 14/19] ARM: STi: DT: STiH407: Add uniperif player dt nodes
From: Patrice Chotard @ 2016-09-14 12:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473081421-16555-15-git-send-email-peter.griffin@linaro.org>

Hi Peter

On 09/05/2016 03:16 PM, Peter Griffin wrote:
> This patch adds the DT nodes for the uniperif player
> IP blocks found on STiH407 family silicon.
> 
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
> Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
> ---
>  arch/arm/boot/dts/stih407-family.dtsi | 80 +++++++++++++++++++++++++++++++++++
>  1 file changed, 80 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/stih407-family.dtsi b/arch/arm/boot/dts/stih407-family.dtsi
> index d1258d5..1edc36c 100644
> --- a/arch/arm/boot/dts/stih407-family.dtsi
> +++ b/arch/arm/boot/dts/stih407-family.dtsi
> @@ -880,5 +880,85 @@
>  			status = "disabled";
>  			st,syscfg = <&syscfg_core>;
>  		};
> +
> +		sti_uni_player0: sti-uni-player at 8d80000 {
> +			compatible = "st,sti-uni-player";
> +			#sound-dai-cells = <0>;
> +			st,syscfg = <&syscfg_core>;
> +			clocks = <&clk_s_d0_flexgen CLK_PCM_0>;
> +			assigned-clocks = <&clk_s_d0_quadfs 0>, <&clk_s_d0_flexgen CLK_PCM_0>;
> +			assigned-clock-parents = <0>, <&clk_s_d0_quadfs 0>;
> +			assigned-clock-rates = <50000000>;
> +			reg = <0x8d80000 0x158>;
> +			interrupts = <GIC_SPI 84 IRQ_TYPE_NONE>;
> +			dmas = <&fdma0 2 0 1>;
> +			dai-name = "Uni Player #0 (HDMI)";
> +			dma-names = "tx";
> +			st,uniperiph-id = <0>;
> +			st,version = <5>;
> +			st,mode = "HDMI";
> +
> +			status		= "disabled";
> +		};
> +
> +		sti_uni_player1: sti-uni-player at 8d81000 {
> +			compatible = "st,sti-uni-player";
> +			#sound-dai-cells = <0>;
> +			st,syscfg = <&syscfg_core>;
> +			clocks = <&clk_s_d0_flexgen CLK_PCM_1>;
> +			assigned-clocks = <&clk_s_d0_quadfs 1>, <&clk_s_d0_flexgen CLK_PCM_1>;
> +			assigned-clock-parents = <0>, <&clk_s_d0_quadfs 1>;
> +			assigned-clock-rates = <50000000>;
> +			reg = <0x8d81000 0x158>;
> +			interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>;
> +			dmas = <&fdma0 3 0 1>;
> +			dai-name = "Uni Player #1 (PIO)";
> +			dma-names = "tx";
> +			st,uniperiph-id = <1>;
> +			st,version = <5>;
> +			st,mode = "PCM";
> +
> +			status = "disabled";
> +		};
> +
> +		sti_uni_player2: sti-uni-player at 8d82000 {
> +			compatible = "st,sti-uni-player";
> +			#sound-dai-cells = <0>;
> +			st,syscfg = <&syscfg_core>;
> +			clocks = <&clk_s_d0_flexgen CLK_PCM_2>;
> +			assigned-clocks = <&clk_s_d0_quadfs 2>, <&clk_s_d0_flexgen CLK_PCM_2>;
> +			assigned-clock-parents = <0>, <&clk_s_d0_quadfs 2>;
> +			assigned-clock-rates = <50000000>;
> +			reg = <0x8d82000 0x158>;
> +			interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>;
> +			dmas = <&fdma0 4 0 1>;
> +			dai-name = "Uni Player #1 (DAC)";
> +			dma-names = "tx";
> +			st,uniperiph-id = <2>;
> +			st,version = <5>;
> +			st,mode = "PCM";
> +
> +			status = "disabled";
> +		};
> +
> +		sti_uni_player3: sti-uni-player at 8d85000 {
> +			compatible = "st,sti-uni-player";
> +			#sound-dai-cells = <0>;
> +			st,syscfg = <&syscfg_core>;
> +			clocks = <&clk_s_d0_flexgen CLK_SPDIFF>;
> +			assigned-clocks = <&clk_s_d0_quadfs 3>, <&clk_s_d0_flexgen CLK_SPDIFF>;
> +			assigned-clock-parents = <0>, <&clk_s_d0_quadfs 3>;
> +			assigned-clock-rates = <50000000>;
> +			reg = <0x8d85000 0x158>;
> +			interrupts = <GIC_SPI 89 IRQ_TYPE_NONE>;
> +			dmas = <&fdma0 7 0 1>;
> +			dma-names = "tx";
> +			dai-name = "Uni Player #1 (PIO)";
> +			st,uniperiph-id = <3>;
> +			st,version = <5>;
> +			st,mode = "SPDIF";
> +
> +			status = "disabled";
> +		};
>  	};
>  };
> 


Applied for STi next

Thanks

^ permalink raw reply

* [PATCH v9 15/19] ARM: STi: DT: STiH407: Add uniperif reader dt nodes
From: Patrice Chotard @ 2016-09-14 12:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473081421-16555-16-git-send-email-peter.griffin@linaro.org>

Hi Peter

On 09/05/2016 03:16 PM, Peter Griffin wrote:
> This patch adds the DT node for the uniperif reader
> IP block found on STiH407 family silicon.
> 
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
> Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
> ---
>  arch/arm/boot/dts/stih407-family.dtsi | 28 ++++++++++++++++++++++++++++
>  1 file changed, 28 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/stih407-family.dtsi b/arch/arm/boot/dts/stih407-family.dtsi
> index 1edc36c..883019a 100644
> --- a/arch/arm/boot/dts/stih407-family.dtsi
> +++ b/arch/arm/boot/dts/stih407-family.dtsi
> @@ -960,5 +960,33 @@
>  
>  			status = "disabled";
>  		};
> +
> +		sti_uni_reader0: sti-uni-reader at 8d83000 {
> +			compatible = "st,sti-uni-reader";
> +			#sound-dai-cells = <0>;
> +			st,syscfg = <&syscfg_core>;
> +			reg = <0x8d83000 0x158>;
> +			interrupts = <GIC_SPI 87 IRQ_TYPE_NONE>;
> +			dmas = <&fdma0 5 0 1>;
> +			dma-names = "rx";
> +			dai-name = "Uni Reader #0 (PCM IN)";
> +			st,version = <3>;
> +
> +			status = "disabled";
> +		};
> +
> +		sti_uni_reader1: sti-uni-reader at 8d84000 {
> +			compatible = "st,sti-uni-reader";
> +			#sound-dai-cells = <0>;
> +			st,syscfg = <&syscfg_core>;
> +			reg = <0x8d84000 0x158>;
> +			interrupts = <GIC_SPI 88 IRQ_TYPE_NONE>;
> +			dmas = <&fdma0 6 0 1>;
> +			dma-names = "rx";
> +			dai-name = "Uni Reader #1 (HDMI RX)";
> +			st,version = <3>;
> +
> +			status = "disabled";
> +		};
>  	};
>  };
> 



Applied for STi next

Thanks

^ permalink raw reply

* [PATCH v9 16/19] ARM: DT: STi: stihxxx-b2120: Add DT nodes for STi audio card
From: Patrice Chotard @ 2016-09-14 12:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473081421-16555-17-git-send-email-peter.griffin@linaro.org>

Hi Peter

On 09/05/2016 03:16 PM, Peter Griffin wrote:
> This patch enables the uniperif players 2 & 3 for b2120 boards
> and also adds the "simple-audio-card" device node to interconnect
> the SoC sound device and the codec.
> 
> Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
> Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
> ---
>  arch/arm/boot/dts/stihxxx-b2120.dtsi | 45 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 45 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/stihxxx-b2120.dtsi b/arch/arm/boot/dts/stihxxx-b2120.dtsi
> index 722c63f..4939501 100644
> --- a/arch/arm/boot/dts/stihxxx-b2120.dtsi
> +++ b/arch/arm/boot/dts/stihxxx-b2120.dtsi
> @@ -131,5 +131,50 @@
>  				dvb-card	= <STV0367_TDA18212_NIMA_1>;
>  			};
>  		};
> +
> +		sti_uni_player2: sti-uni-player at 8d82000 {
> +			status = "okay";
> +		};
> +
> +		sti_uni_player3: sti-uni-player at 8d85000 {
> +			status = "okay";
> +		};
> +
> +		sti_sasg_codec: sti-sasg-codec {
> +			status = "okay";
> +			pinctrl-names = "default";
> +			pinctrl-0 = <&pinctrl_spdif_out>;
> +		};
> +
> +		sound {
> +			compatible = "simple-audio-card";
> +			simple-audio-card,name = "sti audio card";
> +			status = "okay";
> +
> +			simple-audio-card,dai-link at 0 {
> +				/* DAC */
> +				format = "i2s";
> +				mclk-fs = <256>;
> +				cpu {
> +					sound-dai = <&sti_uni_player2>;
> +				};
> +
> +				codec {
> +					sound-dai = <&sti_sasg_codec 1>;
> +				};
> +			};
> +			simple-audio-card,dai-link at 1 {
> +				/* SPDIF */
> +				format = "left_j";
> +				mclk-fs = <128>;
> +				cpu {
> +					sound-dai = <&sti_uni_player3>;
> +				};
> +
> +				codec {
> +					sound-dai = <&sti_sasg_codec 0>;
> +				};
> +			};
> +		};
>  	};
>  };
> 


Applied for STi next

Thanks

^ permalink raw reply

* [PATCH V2 3/4] ARM64 LPC: support serial based on low-pin-count
From: Arnd Bergmann @ 2016-09-14 12:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <57D93921.50303@hisilicon.com>

On Wednesday, September 14, 2016 7:48:49 PM CEST zhichang.yuan wrote:
> On 2016/9/8 17:58, Arnd Bergmann wrote:
> > On Thursday, September 8, 2016 5:51:25 PM CEST zhichang wrote:
> >> On 2016?09?07? 22:50, Arnd Bergmann wrote:
> >>> On Wednesday, September 7, 2016 9:33:52 PM CEST Zhichang Yuan wrote:
> >>>> From: "zhichang.yuan" <yuanzhichang@hisilicon.com>
> >>>>
> >>>> On Hip06 platform, a 16550 compatible UART is connected to low-pin-count and
> >>>> controlled through the LPC I/O cycles. This patch drives the UART port with
> >>>> the specific serial in/out function pair based on the indirect-IO mechanism
> >>>> introduced by Hip06 LPC driver.
> >>>>
> >>>> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
> >>>
> >>> Any reason this cannot just use the regular drivers/tty/serial/8250/8250_of.c
> >>> driver?
> >> I think two reasons for that:
> >> 1. 8250_of.c is only for devicetree, but we need to support ACPI device too;
> > 
> > ACPI has its own way of describing serial ports, use that instead.
> Could you give me some info about ACPI serial ports?
> I found there is _CRS specific for serial, but it seems no serial driver use that.

drivers/tty/serial/8250/8250_dw.c is a driver that uses ACPI matching,
and possibly drivers/tty/serial/8250/8250_pnp.c could work as well.

	Arnd

^ permalink raw reply

* [PATCH 10/33] pcmcia: soc_common: switch to using gpio_descs
From: Russell King - ARM Linux @ 2016-09-14 12:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CACRpkdZvNnVG5U3XQPm5KJDLci76xFP7JOO78AZ3a8QVBs0ZQg@mail.gmail.com>

On Wed, Sep 14, 2016 at 01:29:04PM +0200, Linus Walleij wrote:
> On Mon, Aug 29, 2016 at 12:24 PM, Russell King
> <rmk+kernel@armlinux.org.uk> wrote:
> 
> > Switch to using the gpiod_* consumer API rather than the legacy API.
> >
> > Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
> (...)
> 
> > +int soc_pcmcia_request_gpiods(struct soc_pcmcia_socket *skt)
> > +{
> > +       int i;
> > +
> > +       for (i = 0; i < ARRAY_SIZE(skt->stat); i++) {
> > +               struct gpio_desc *desc;
> > +
> 
> Here I inserted:
> 
>         /* Skip over unnamed GPIOs, assume unused */
>         if (!skt->stat[i].name)
>             continue;
> 
> to get it working again on h3600.

Thanks, I'll add that.

> > +               desc = gpiod_get(skt->socket.dev.parent,
> > +                                skt->stat[i].name, GPIOD_IN);
> > +               if (IS_ERR(desc)) {
> > +                       dev_err(skt->socket.dev.parent,
> > +                               "Failed to get GPIO for %s: %ld\n",
> > +                               skt->stat[i].name, PTR_ERR(desc));
> > +                       __soc_pcmcia_hw_shutdown(skt, i);
> > +                       return PTR_ERR(desc);
> > +               }
> 
> 
> It bugs out for me on the legacy h3600, since it only defines
> two of these pins not all of the ARRAY_SIZE(skt->stat) pins
> will succeed and we get an error message like this:
> 
> sa11x0-pcmcia sa11x0-pcmcia: Failed to get GPIO for (null): -2
> sa11x0-pcmcia: probe of sa11x0-pcmcia failed with error -2
> 
> With the patch above it goes away and the log is silent.
> The debugfs gpio file looks like this:
> 
> cat gpio
> gpiochip0: GPIOs 0-27, gpio:
>  gpio-0   (                    |Power Button        ) in  hi
>  gpio-10  (                    |pcmcia1-detect      ) in  hi
>  gpio-11  (                    |pcmcia1-ready       ) in  hi
>  gpio-17  (                    |pcmcia0-detect      ) in  hi
>  gpio-18  (                    |Action button       ) in  hi
>  gpio-21  (                    |pcmcia0-ready       ) in  hi
>  gpio-23  (                    |dcd                 ) in  hi
>  gpio-25  (                    |cts                 ) in  lo
>  gpio-26  (                    |rts                 ) out lo
> 
> gpiochip1: GPIOs 28-43, parent: platform/htc-egpio, htc-egpio:
>  gpio-28  (                    |Flash Vpp           ) out lo
>  gpio-29  (                    |PCMCIA CARD RESET   ) out lo
>  gpio-30  (                    |OPT RESET           ) out lo
>  gpio-32  (                    |OPT NVRAM ON        ) out lo
>  gpio-33  (                    |OPT ON              ) out lo
>  gpio-34  (                    |LCD power           ) out lo
>  gpio-36  (                    |LCD control         ) out lo
>  gpio-42  (                    |LCD 5v              ) out lo
>  gpio-43  (                    |LCD 9v/-6.5v        ) out lo
> 
> Which seems like before the patch series.

Yay.

> I still suspect the PCMCIA is not really working but I have
> limited experience of the bus so I don't really know how
> to test it deeply or have my PCMCIA ethernet or harddrive
> probe properly.

Yes, to me the H3600 code looks really really really weird - the way
H3XXX_EGPIO_CARD_RESET is "shared" (badly) between both sockets is
certainly racy.  I've no idea what the semantics there are supposed
to be - I suspect that H3600 PCMCIA hasn't worked for a very long
time, or if it has, it's probably not been reliable.

> There are no regressions however, so with something like
> the above patch applied:
> Tested-by: Linus Walleij <linus.walleij@linaro.org>
> 
> For the whole patch series on H3600.

Thanks!

-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply

* [PATCH V3 0/4] ARM64 LPC: legacy ISA I/O support
From: Zhichang Yuan @ 2016-09-14 12:15 UTC (permalink / raw)
  To: linux-arm-kernel

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

This patch supports the 16550 compatible UART attached to the Low-Pin-Count
interface mplemented on Hisilicon Hip06 SoC. The periperals attached this LPC
include UART, BT, KCS, and so on.
	                -----------
			| LPC host|
	                |         |
	                -----------
	                     |
 	        _____________V_______________LPC
                  |			  |
                  V	                  V
             -----------             ------------
             |  UART   |             |  BT(ipmi)|
             -----------             ------------

When master accesses those periperals beneath the Hip06 LPC, a specific LPC
driver is needed to make LPC host generate the standard LPC I/O cycles with
the target periperals'I/O port addresses. But on curent arm64 world, there is
no real I/O accesses. All the I/O operations through in/out pair are based on
MMIO which is not satisfied the I/O mechanism on Hip06 LPC.
To solve this issue and keep the relevant existing peripherals' driver
unchanged, this patch set redefines the in/out pair to support both the IO
operations for Hip06 LPC and the original MMIO. The way specific to Hip06 is
named as indirect-IO in this patchset.

This patch set is built based on mainline v4.8-rc6;

Changes from V2:
  - Support the PIO retrieval from the linux PIO generated by
  pci_address_to_pio. This method replace the 4K PIO reservation in V2;
  - Support the flat-tree earlycon;
  - Some revises based on Arnd's remarks;
  - Make sure the linux PIO range allocated to Hip06 LPC peripherals starts
  from non-ZERO;

Changes from V1:
  - Support the ACPI LPC device;
  - Optimize the dts LPC driver in ISA compatible mode;
  - Reserve the IO range below 4K in avoid the possible conflict with PCI host
  IO ranges;
  - Support the LPC uart and relevant earlycon;

Signed-off-by: Zhichang Yuan <yuanzhichang@hisilicon.com>

zhichang.yuan (4):
  ARM64 LPC: Indirect ISA port IO introduced
  ARM64 LPC: LPC driver implementation on Hip06
  ARM64 LPC: support serial based on low-pin-count
  ARM64 LPC: support earlycon for UART connected to LPC

 .../arm/hisilicon/hisilicon-low-pin-count.txt      |  35 +
 .../devicetree/bindings/serial/hisi-lpc-uart.txt   |  60 ++
 arch/arm64/Kconfig                                 |   6 +
 arch/arm64/include/asm/io.h                        |  90 +++
 drivers/bus/Kconfig                                |   8 +
 drivers/bus/Makefile                               |   2 +
 drivers/bus/extio.c                                |  66 ++
 drivers/bus/hisi_lpc.c                             | 766 +++++++++++++++++++++
 drivers/of/address.c                               |   9 +
 drivers/tty/serial/8250/8250_early.c               |  26 +-
 drivers/tty/serial/8250/8250_hisi_lpc.c            | 171 +++++
 drivers/tty/serial/8250/Kconfig                    |   9 +
 drivers/tty/serial/8250/Makefile                   |   1 +
 include/linux/extio.h                              |  49 ++
 14 files changed, 1296 insertions(+), 2 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
 create mode 100644 Documentation/devicetree/bindings/serial/hisi-lpc-uart.txt
 create mode 100644 drivers/bus/extio.c
 create mode 100644 drivers/bus/hisi_lpc.c
 create mode 100644 drivers/tty/serial/8250/8250_hisi_lpc.c
 create mode 100644 include/linux/extio.h

-- 
1.9.1

^ permalink raw reply

* [PATCH V3 1/4] ARM64 LPC: Indirect ISA port IO introduced
From: Zhichang Yuan @ 2016-09-14 12:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473855354-150093-1-git-send-email-yuanzhichang@hisilicon.com>

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

For arm64, there is no I/O space as other architectural platforms, such as
X86. Most I/O accesses are achieved based on MMIO. But for some arm64 SoCs,
such as Hip06, when accessing some legacy ISA devices connected to LPC, those
known port addresses are used to control the corresponding target devices, for
example, 0x2f8 is for UART, 0xe4 is for ipmi-bt. It is different from the
normal MMIO mode in using.

To drive these devices, this patch introduces a method named indirect-IO.
In this method the in/out pair in arch/arm64/include/asm/io.h will be
redefined. When upper layer drivers call in/out with those known legacy port
addresses to access the peripherals, the hooking functions corrresponding to
those target peripherals will be called. Through this way, those upper layer
drivers which depend on in/out can run on Hip06 without any changes.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
---
 arch/arm64/Kconfig          |  6 +++
 arch/arm64/include/asm/io.h | 90 +++++++++++++++++++++++++++++++++++++++++++++
 drivers/bus/extio.c         | 66 +++++++++++++++++++++++++++++++++
 include/linux/extio.h       | 49 ++++++++++++++++++++++++
 4 files changed, 211 insertions(+)
 create mode 100644 drivers/bus/extio.c
 create mode 100644 include/linux/extio.h

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index bc3f00f..9579479 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -161,6 +161,12 @@ config ARCH_MMAP_RND_COMPAT_BITS_MIN
 config ARCH_MMAP_RND_COMPAT_BITS_MAX
        default 16
 
+config ARM64_INDIRECT_PIO
+	def_bool n
+	help
+	  Support to access the ISA I/O devices with the legacy X86 I/O port
+	  addresses in some SoCs, such as Hisilicon Hip06.
+
 config NO_IOPORT_MAP
 	def_bool y if !PCI
 
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 9b6e408..d3acf1f 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -34,6 +34,10 @@
 
 #include <xen/xen.h>
 
+#ifdef CONFIG_ARM64_INDIRECT_PIO
+#include <linux/extio.h>
+#endif
+
 /*
  * Generic IO read/write.  These perform native-endian accesses.
  */
@@ -142,6 +146,38 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
 #define writel(v,c)		({ __iowmb(); writel_relaxed((v),(c)); })
 #define writeq(v,c)		({ __iowmb(); writeq_relaxed((v),(c)); })
 
+
+#define BUILDS_RW(bwl, type)						\
+static inline void reads##bwl(const volatile void __iomem *addr,	\
+				void *buffer, unsigned int count)	\
+{									\
+	if (count) {							\
+		type *buf = buffer;					\
+									\
+		do {							\
+			type x = __raw_read##bwl(addr);			\
+			*buf++ = x;					\
+		} while (--count);					\
+	}								\
+}									\
+									\
+static inline void writes##bwl(volatile void __iomem *addr,		\
+				const void *buffer, unsigned int count)	\
+{									\
+	if (count) {							\
+		const type *buf = buffer;				\
+									\
+		do {							\
+			__raw_write##bwl(*buf++, addr);			\
+		} while (--count);					\
+	}								\
+}
+
+BUILDS_RW(b, u8)
+#define readsb readsb
+#define writesb writesb
+
+
 /*
  *  I/O port access primitives.
  */
@@ -149,6 +185,60 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
 #define IO_SPACE_LIMIT		(PCI_IO_SIZE - 1)
 #define PCI_IOBASE		((void __iomem *)PCI_IO_START)
 
+
+/*
+ * redefine the in(s)b/out(s)b for indirect-IO.
+ */
+#define inb inb
+static inline u8 inb(unsigned long addr)
+{
+#ifdef CONFIG_ARM64_INDIRECT_PIO
+	if (arm64_extio_ops && arm64_extio_ops->start <= addr &&
+			addr <= arm64_extio_ops->end)
+		return extio_inb(addr);
+#endif
+	return readb(PCI_IOBASE + addr);
+}
+
+
+#define outb outb
+static inline void outb(u8 value, unsigned long addr)
+{
+#ifdef CONFIG_ARM64_INDIRECT_PIO
+	if (arm64_extio_ops && arm64_extio_ops->start <= addr &&
+			addr <= arm64_extio_ops->end)
+		extio_outb(value, addr);
+	else
+#endif
+		writeb(value, PCI_IOBASE + addr);
+}
+
+#define insb insb
+static inline void insb(unsigned long addr, void *buffer, unsigned int count)
+{
+#ifdef CONFIG_ARM64_INDIRECT_PIO
+	if (arm64_extio_ops && arm64_extio_ops->start <= addr &&
+			addr <= arm64_extio_ops->end)
+		extio_insb(addr, buffer, count);
+	else
+#endif
+		readsb(PCI_IOBASE + addr, buffer, count);
+}
+
+#define outsb outsb
+static inline void outsb(unsigned long addr, const void *buffer,
+			 unsigned int count)
+{
+#ifdef CONFIG_ARM64_INDIRECT_PIO
+	if (arm64_extio_ops && arm64_extio_ops->start <= addr &&
+			addr <= arm64_extio_ops->end)
+		extio_outsb(addr, buffer, count);
+	else
+#endif
+		writesb(PCI_IOBASE + addr, buffer, count);
+}
+
+
 /*
  * String version of I/O memory access operations.
  */
diff --git a/drivers/bus/extio.c b/drivers/bus/extio.c
new file mode 100644
index 0000000..1e7a9c5
--- /dev/null
+++ b/drivers/bus/extio.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ * Author: Zou Rongrong <@huawei.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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/io.h>
+
+
+struct extio_ops *arm64_extio_ops;
+
+
+u8 __weak extio_inb(unsigned long addr)
+{
+	return arm64_extio_ops->pfin ?
+		arm64_extio_ops->pfin(arm64_extio_ops->devpara,
+			addr + arm64_extio_ops->ptoffset, NULL,
+			sizeof(u8), 1) : -1;
+}
+
+void __weak extio_outb(u8 value, unsigned long addr)
+{
+	if (!arm64_extio_ops->pfout)
+		return;
+
+	arm64_extio_ops->pfout(arm64_extio_ops->devpara,
+			addr + arm64_extio_ops->ptoffset, &value,
+			sizeof(u8), 1);
+}
+
+
+void __weak extio_insb(unsigned long addr, void *buffer,
+				unsigned int count)
+{
+	if (!arm64_extio_ops->pfin)
+		return;
+
+	arm64_extio_ops->pfin(arm64_extio_ops->devpara,
+			addr + arm64_extio_ops->ptoffset, buffer,
+			sizeof(u8), count);
+}
+
+void __weak extio_outsb(unsigned long addr, const void *buffer,
+			 unsigned int count)
+{
+	if (!arm64_extio_ops->pfout)
+		return;
+
+	arm64_extio_ops->pfout(arm64_extio_ops->devpara,
+			addr + arm64_extio_ops->ptoffset, buffer,
+			sizeof(u8), count);
+}
+
+
diff --git a/include/linux/extio.h b/include/linux/extio.h
new file mode 100644
index 0000000..08d1fca
--- /dev/null
+++ b/include/linux/extio.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ * Author: Zou Rongrong <@huawei.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LINUX_EXTIO_H
+#define __LINUX_EXTIO_H
+
+
+typedef u64 (*inhook)(void *devobj, unsigned long ptaddr, void *inbuf,
+				size_t dlen, unsigned int count);
+typedef void (*outhook)(void *devobj, unsigned long ptaddr,
+				const void *outbuf, size_t dlen,
+				unsigned int count);
+
+struct extio_ops {
+	unsigned long start;/* inclusive, sys io addr */
+	unsigned long end;/* inclusive, sys io addr */
+	unsigned long ptoffset;/* port Io - system Io */
+
+	inhook	pfin;
+	outhook	pfout;
+	void *devpara;
+};
+
+
+extern struct extio_ops *arm64_extio_ops;
+
+extern u8 extio_inb(unsigned long addr);
+extern void extio_outb(u8 value, unsigned long addr);
+extern void extio_insb(unsigned long addr, void *buffer, unsigned int count);
+extern void extio_outsb(unsigned long addr, const void *buffer,
+				unsigned int count);
+
+
+#endif /* __LINUX_EXTIO_H*/
-- 
1.9.1

^ permalink raw reply related

* [PATCH V3 2/4] ARM64 LPC: LPC driver implementation on Hip06
From: Zhichang Yuan @ 2016-09-14 12:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473855354-150093-1-git-send-email-yuanzhichang@hisilicon.com>

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

On Hip06, the accesses to LPC peripherals work in an indirect way. A
corresponding LPC driver configure some registers in LPC master at first, then
the real accesses on LPC slave devices are finished by the LPC master, which
is transparent to LPC driver.
This patch implement the relevant driver for Hip06 LPC. Cooperating with
indirect-IO, ipmi messages is in service without any changes on ipmi driver.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
---
 .../arm/hisilicon/hisilicon-low-pin-count.txt      |  35 ++
 drivers/bus/Kconfig                                |   8 +
 drivers/bus/Makefile                               |   2 +
 drivers/bus/hisi_lpc.c                             | 653 +++++++++++++++++++++
 drivers/of/address.c                               |   9 +
 5 files changed, 707 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
 create mode 100644 drivers/bus/hisi_lpc.c

diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
new file mode 100644
index 0000000..820e26d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon-low-pin-count.txt
@@ -0,0 +1,35 @@
+Hisilicon Hip06 low-pin-count device
+  Usually LPC controller is part of PCI host bridge, so the legacy ISA ports
+  locate on LPC bus can be accessed direclty. But some SoCs have independent
+  LPC controller, and access the legacy ports by triggering LPC I/O cycles.
+  Hisilicon Hip06 implements this LPC device.
+
+Required properties:
+- compatible: should be "hisilicon,low-pin-count"
+- #address-cells: must be 2 which stick to the ISA/EISA binding doc.
+- #size-cells: must be 1 which stick to the ISA/EISA binding doc.
+- reg: base address and length of the register set for the device.
+- ranges: define a 1:1 mapping between the I/O space of the child device and
+	  the parent.
+
+Note:
+  The node name before '@' must be "isa" to represent the binding stick to the
+  ISA/EISA binding specification.
+
+Example:
+
+isa at a01b0000 {
+	compatible = "hisilicom,low-pin-count";
+	#address-cells = <2>;
+	#size-cells = <1>;
+	reg = <0x0 0xa01b0000 0x0 0x1000>;
+	ranges = <0x01 0xe4 0x0 0xe4 0x1000>;
+
+
+	ipmi0: bt at e4 {
+		compatible = "ipmi-bt";
+		device_type = "ipmi";
+		reg = <0x01 0xe4 0x04>;
+		status = "disabled";
+	};
+};
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 3b205e2..fdb232b 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -64,6 +64,14 @@ config BRCMSTB_GISB_ARB
 	  arbiter. This driver provides timeout and target abort error handling
 	  and internal bus master decoding.
 
+config HISILICON_LPC
+	bool "Workaround for nonstandard ISA I/O space on Hisilicon Hip0X"
+	depends on (ARCH_HISI || COMPILE_TEST) && ARM64
+	select ARM64_INDIRECT_PIO
+	help
+	  Driver needed for some legacy ISA devices attached to Low-Pin-Count
+	  on Hisilicon Hip0X Soc.
+
 config IMX_WEIM
 	bool "Freescale EIM DRIVER"
 	depends on ARCH_MXC
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index ac84cc4..6ffbb27 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -7,6 +7,8 @@ obj-$(CONFIG_ARM_CCI)		+= arm-cci.o
 obj-$(CONFIG_ARM_CCN)		+= arm-ccn.o
 
 obj-$(CONFIG_BRCMSTB_GISB_ARB)	+= brcmstb_gisb.o
+obj-$(CONFIG_ARM64_INDIRECT_PIO)	+= extio.o
+obj-$(CONFIG_HISILICON_LPC)	+= hisi_lpc.o
 obj-$(CONFIG_IMX_WEIM)		+= imx-weim.o
 obj-$(CONFIG_MIPS_CDMM)		+= mips_cdmm.o
 obj-$(CONFIG_MVEBU_MBUS) 	+= mvebu-mbus.o
diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
new file mode 100644
index 0000000..9b364d0
--- /dev/null
+++ b/drivers/bus/hisi_lpc.c
@@ -0,0 +1,653 @@
+/*
+ * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ * Author: Zou Rongrong <@huawei.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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/acpi.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/serial_8250.h>
+#include <linux/slab.h>
+
+
+struct hisilpc_dev;
+
+/* This flag is specific to differentiate earlycon operations and the others */
+#define FG_EARLYCON_LPC		0x0001
+/*
+ * this bit set means each IO operation will target to different port address;
+ * 0 means repeatly IO operations will be sticked on the same port, such as BT;
+ */
+#define FG_INCRADDR_LPC		0x0002
+
+struct lpc_cycle_para {
+	unsigned int opflags;
+	unsigned int csize;/*the data length of each operation*/
+};
+
+struct hisilpc_dev {
+	spinlock_t cycle_lock;
+	void __iomem  *membase;
+	struct platform_device *pltdev;
+};
+
+
+/* The maximum continous operations*/
+#define LPC_MAX_OPCNT	16
+
+#define LPC_REG_START		(0x00)/*start a new LPC cycle*/
+#define LPC_REG_OP_STATUS	(0x04)/*the current LPC status*/
+#define LPC_REG_IRQ_ST		(0x08)/*interrupt enable&status*/
+#define LPC_REG_OP_LEN		(0x10)/*how many LPC cycles each start*/
+#define LPC_REG_CMD		(0x14)/*command for the required LPC cycle*/
+#define LPC_REG_ADDR		(0x20)/*LPC target address*/
+#define LPC_REG_WDATA		(0x24)/*data to be written*/
+#define LPC_REG_RDATA		(0x28)/*data coming from peer*/
+
+
+/* The command register fields*/
+#define LPC_CMD_SAMEADDR_SING	(0x00000008)
+#define LPC_CMD_SAMEADDR_INC	(0x00000000)
+#define LPC_CMD_TYPE_IO		(0x00000000)
+#define LPC_CMD_TYPE_MEM	(0x00000002)
+#define LPC_CMD_TYPE_FWH	(0x00000004)
+#define LPC_CMD_WRITE		(0x00000001)
+#define LPC_CMD_READ		(0x00000000)
+
+#define LPC_IRQ_CLEAR		(0x02)
+#define LPC_IRQ_OCCURRED	(0x02)
+
+#define LPC_STATUS_IDLE		(0x01)
+#define LPC_OP_FINISHED		(0x02)
+
+#define START_WORK		(0x01)
+
+/*
+ * The minimal waiting interval... Suggest it is not less than 10.
+ * Bigger value probably will lower the performance.
+ */
+#define LPC_NSEC_PERWAIT	100
+/*
+ * The maximum waiting time is about 128us.
+ * The fastest IO cycle time is about 390ns, but the worst case will wait
+ * for extra 256 lpc clocks, so (256 + 13) * 30ns = 8 us. The maximum
+ * burst cycles is 16. So, the maximum waiting time is about 128us under
+ * worst case.
+ * choose 1300 as the maximum.
+ */
+#define LPC_MAX_WAITCNT		1300
+/* About 10us. This is specfic for single IO operation, such as inb. */
+#define LPC_PEROP_WAITCNT	100
+
+
+static inline int wait_lpc_idle(unsigned char *mbase,
+				unsigned int waitcnt) {
+	u32 opstatus = 0;
+
+	while (waitcnt--) {
+		ndelay(LPC_NSEC_PERWAIT);
+		opstatus = readl(mbase + LPC_REG_OP_STATUS);
+		if (opstatus & LPC_STATUS_IDLE)
+			return (opstatus & LPC_OP_FINISHED) ? 0 : (-EIO);
+	}
+	return -ETIME;
+}
+
+
+/**
+ * hisilpc_target_in - trigger a series of lpc cycles to read required data
+ *		  from target periperal.
+ * @pdev: pointer to hisi lpc device
+ * @para: some paramerters used to control the lpc I/O operations
+ * @ptaddr: the lpc I/O target port address
+ * @buf: where the read back data is stored
+ * @opcnt: how many I/O operations required in this calling
+ *
+ * only one byte data is read each I/O operation.
+ *
+ * Returns 0 on success, non-zero on fail.
+ *
+ */
+static int hisilpc_target_in(struct hisilpc_dev *pdev,
+				struct lpc_cycle_para *para,
+				unsigned long ptaddr, unsigned char *buf,
+				unsigned long opcnt)
+{
+	unsigned int cmd_word;
+	unsigned int waitcnt;
+	int retval;
+	/*initialized as 0 to remove compile warning */
+	unsigned long flags = 0;
+
+	if (!buf || !opcnt || !para || !pdev)
+		return -EINVAL;
+
+	if (para->csize != 1 || opcnt  > LPC_MAX_OPCNT)
+		return -EINVAL;
+
+	cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_READ;
+	waitcnt = (LPC_PEROP_WAITCNT);
+	if (!(para->opflags & FG_INCRADDR_LPC)) {
+		cmd_word |= LPC_CMD_SAMEADDR_SING;
+		waitcnt = LPC_MAX_WAITCNT;
+	}
+
+	/* whole operation must be atomic */
+	if (!(para->opflags & FG_EARLYCON_LPC))
+		spin_lock_irqsave(&pdev->cycle_lock, flags);
+
+	writel(opcnt, pdev->membase + LPC_REG_OP_LEN);
+
+	writel(cmd_word, pdev->membase + LPC_REG_CMD);
+
+	writel(ptaddr, pdev->membase + LPC_REG_ADDR);
+
+	writel(START_WORK, pdev->membase + LPC_REG_START);
+
+	/* whether the operation is finished */
+	retval = wait_lpc_idle(pdev->membase, waitcnt);
+	if (!retval) {
+		for (; opcnt--; buf++)
+			*buf = readl(pdev->membase + LPC_REG_RDATA);
+	}
+
+	if (!(para->opflags & FG_EARLYCON_LPC))
+		spin_unlock_irqrestore(&pdev->cycle_lock, flags);
+
+	return retval;
+}
+
+/**
+ * hisilpc_target_out - trigger a series of lpc cycles to write required data
+ *		  to target periperal.
+ * @pdev: pointer to hisi lpc device
+ * @para: some paramerters used to control the lpc I/O operations
+ * @ptaddr: the lpc I/O target port address
+ * @buf: where the data to be written is stored
+ * @opcnt: how many I/O operations required
+ *
+ * only one byte data is read each I/O operation.
+ *
+ * Returns 0 on success, non-zero on fail.
+ *
+ */
+static int hisilpc_target_out(struct hisilpc_dev *pdev,
+				struct lpc_cycle_para *para,
+				unsigned long ptaddr,
+				const unsigned char *buf,
+				unsigned long opcnt)
+{
+	unsigned int cmd_word;
+	unsigned int waitcnt;
+	int retval;
+	/* initialized as 0 to remove compile warning */
+	unsigned long flags = 0;
+
+
+	if (!buf || !opcnt || !para || !pdev)
+		return -EINVAL;
+
+	if (para->csize != 1 || opcnt  > LPC_MAX_OPCNT)
+		return -EINVAL;
+
+	cmd_word = LPC_CMD_TYPE_IO | LPC_CMD_WRITE;
+	waitcnt = (LPC_PEROP_WAITCNT);
+	if (!(para->opflags & FG_INCRADDR_LPC)) {
+		cmd_word |= LPC_CMD_SAMEADDR_SING;
+		waitcnt = LPC_MAX_WAITCNT;
+	}
+
+	/* whole operation must be atomic */
+	if (!(para->opflags & FG_EARLYCON_LPC))
+		spin_lock_irqsave(&pdev->cycle_lock, flags);
+
+	writel(opcnt, pdev->membase + LPC_REG_OP_LEN);
+	for (; opcnt--; buf++)
+		writel(*buf, pdev->membase + LPC_REG_WDATA);
+
+	writel(cmd_word, pdev->membase + LPC_REG_CMD);
+
+	writel(ptaddr, pdev->membase + LPC_REG_ADDR);
+
+	writel(START_WORK, pdev->membase + LPC_REG_START);
+
+	/* whether the operation is finished */
+	retval = wait_lpc_idle(pdev->membase, waitcnt);
+
+	if (!(para->opflags & FG_EARLYCON_LPC))
+		spin_unlock_irqrestore(&pdev->cycle_lock, flags);
+
+	return retval;
+}
+
+/**
+ * hisilpc_comm_inb - read/input the data from the I/O peripheral through LPC.
+ * @devobj: pointer to the device information relevant to LPC controller.
+ * @outbuf: a buffer where the data read is stored at.
+ * @ptaddr: the target I/O port address.
+ * @dlen: the data length required to read from the target I/O port.
+ * @count: how many I/O operations required in this calling.  >1 is for ins.
+ *
+ * For this lpc, only support inb/insb now.
+ *
+ * For inbs, returns 0 on success, -1 on fail.
+ * when succeed, the data read back is stored in buffer pointed by inbuf.
+ * For inb, return the data read from I/O or -1 when error occur.
+ */
+u64 hisilpc_comm_inb(void *devobj, unsigned long ptaddr,
+				void *inbuf, size_t dlen,
+				unsigned int count)
+{
+	struct hisilpc_dev *lpcdev;
+	struct lpc_cycle_para iopara;
+	unsigned int loopcnt, cntleft;
+	unsigned int rd_data;
+	unsigned char *newbuf;
+	int ret = 0;
+	/* only support data unit length is 1 now... */
+	if (!count || (!inbuf && count != 1) || !devobj || dlen != 1)
+		return -1;
+
+	newbuf = (unsigned char *)inbuf;
+	/*
+	 * the operation data len is 4 bytes, need to ensure the buffer
+	 * is big enough.
+	 */
+	if (!inbuf || count < sizeof(u32))
+		newbuf = (unsigned char *)&rd_data;
+
+	lpcdev = (struct hisilpc_dev *)devobj;
+	dev_dbg(&lpcdev->pltdev->dev, "In-IO(0x%lx), count=%u\n", ptaddr,
+			count);
+
+	iopara.opflags = FG_INCRADDR_LPC;
+	/*
+	 * to improve performance, support repeatly rd at same target
+	 * address.
+	 */
+	if (count > 1)
+		iopara.opflags &= ~FG_INCRADDR_LPC;
+
+	iopara.csize = dlen;
+
+	cntleft = count;
+	do {
+		loopcnt = (cntleft > LPC_MAX_OPCNT) ? LPC_MAX_OPCNT : cntleft;
+		ret = hisilpc_target_in(lpcdev,
+				&iopara, ptaddr, newbuf, loopcnt);
+		if (ret)
+			return -1;
+		newbuf += loopcnt;
+		cntleft -= loopcnt;
+	} while (cntleft);
+
+	/* for inb */
+	if (!inbuf)
+		return rd_data;
+	/* for insb, copy the data to the return variable */
+	if (inbuf != newbuf)
+		memcpy(inbuf, &rd_data, count);
+
+	return 0;
+}
+
+/**
+ * hisilpc_comm_outb - write/output the data in out buffer to the I/O peripheral
+ *		    through LPC.
+ * @devobj: pointer to the device information relevant to LPC controller.
+ * @outbuf: a buffer where the data to be written is stored.
+ * @ptaddr: the target I/O port address.
+ * @dlen: the data length required writing to the target I/O port .
+ * @count: how many I/O operations required in this calling. >1 is for outs.
+ *
+ * For this lpc, only support outb/outsb now.
+ *
+ */
+void hisilpc_comm_outb(void *devobj, unsigned long ptaddr,
+				const void *outbuf, size_t dlen,
+				unsigned int count)
+{
+	struct hisilpc_dev *lpcdev;
+	struct lpc_cycle_para iopara;
+	unsigned int loopcnt;
+	const unsigned char *newbuf;
+	int ret = 0;
+
+	if (!count || !outbuf || !devobj)
+		return;
+
+	newbuf = (const unsigned char *)outbuf;
+	lpcdev = (struct hisilpc_dev *)devobj;
+
+	dev_dbg(&lpcdev->pltdev->dev, "Out-IO(0x%lx), cnt=%u\n", ptaddr, count);
+
+	iopara.opflags = FG_INCRADDR_LPC;
+	/* to improve performance,  support repeatly wr same target address */
+	if (count > 1)
+		iopara.opflags &= ~FG_INCRADDR_LPC;
+
+	iopara.csize = 1;
+
+	do {
+		loopcnt = (count > LPC_MAX_OPCNT) ? LPC_MAX_OPCNT : count;
+		ret = hisilpc_target_out(lpcdev,
+				&iopara, ptaddr, newbuf, loopcnt);
+		if (ret)
+			return;
+		newbuf += loopcnt;
+		count -= loopcnt;
+	} while (count);
+}
+
+
+/**
+ * hisilpc_ischild_ipmi - check whether the designated device is ipmi
+ * @dev: the device to be checked.
+ * @data: the value used to match the acpi device in checking.
+ *
+ * Returns 1 means the device to be checked is matched.
+ * 0 means some failures.
+ *
+ */
+static int  hisilpc_ischild_ipmi(struct device *dev)
+{
+	struct acpi_device *adev;
+	struct acpi_hardware_id *hwid;
+	/* only support dts and acpi */
+	if (IS_ERR_OR_NULL(dev->fwnode) && !dev->of_node) {
+		dev_err(dev, "Not valid child device!\n");
+		return -EINVAL;
+	}
+
+	adev = ACPI_COMPANION(dev);
+	if (adev) {
+		list_for_each_entry(hwid, &adev->pnp.ids, list) {
+			dev_info(dev, "hwid is %s\n", hwid->id);
+			if (!strcmp("IPI0001", hwid->id))
+				return 1;
+		}
+	} else {
+		if (!strcmp(dev->of_node->type, "ipmi"))
+			return 1;
+	}
+
+	dev_info(dev, "not ipmi child device!\n");
+	return 0;
+}
+
+
+/**
+ * hisilpc_children_map_sysio - setup the mapping between system Io and
+ *			physical IO
+ *
+ * @child: the device whose IO is handling
+ * @data: some device specific data. For ACPI device, should be NULL.
+ *
+ * Returns >=0 means the mapping is successfully created;
+ * others mean some failures.
+ */
+static int hisilpc_children_map_sysio(struct device * child, void * data)
+{
+	struct resource *iores;
+	unsigned long cpuio;
+	struct extio_ops *opsnode;
+	int ret;
+	struct hisilpc_dev *lpcdev;
+
+	if (!child || !child->parent)
+		return -EINVAL;
+
+	iores = platform_get_resource_byname(to_platform_device(child),
+					IORESOURCE_IO, "dev_io");
+	if (!iores)
+		return -ENODEV;
+
+	/*
+	 * can not use devm_kzalloc to allocate slab for child before its driver
+	 * start probing. Here allocate the slab with the name of parent.
+	 */
+	opsnode = devm_kzalloc(child->parent, sizeof(*opsnode), GFP_KERNEL);
+	if (!opsnode)
+		return -ENOMEM;
+
+	cpuio = data ? *((unsigned long *)data) : 0;
+
+	opsnode->start = iores->start;
+	opsnode->end = iores->end;
+	opsnode->ptoffset = cpuio ? (cpuio - iores->start) : 0;
+
+	dev_info(child, "map sys port[%lx - %lx] offset=0x%lx",
+				(unsigned long)iores->start,
+				(unsigned long)iores->end,
+				opsnode->ptoffset);
+
+	opsnode->pfin = hisilpc_comm_inb;
+	opsnode->pfout = hisilpc_comm_outb;
+
+	lpcdev = platform_get_drvdata(to_platform_device(child->parent));
+	opsnode->devpara = lpcdev;
+
+	/* only apply indirect-IO to ipmi child device */
+	ret = hisilpc_ischild_ipmi(child);
+	if (ret < 0)
+		return ret;
+
+	if (ret > 0) {
+		WRITE_ONCE(arm64_extio_ops, opsnode);
+		/* update ret as successful */
+		ret = 0;
+	} else {
+		ret = platform_device_add_data(to_platform_device(child),
+						opsnode,
+						sizeof(*opsnode));
+		devm_kfree(child->parent, opsnode);
+	}
+
+	if (!ret)
+		dev_info(child, "to phy [%lx-%lx]\n", cpuio,
+			(unsigned long)(iores->end - iores->start) + cpuio);
+	else
+		dev_info(child, "FAIL(0x%x)!!\n", ret);
+
+	return ret;
+}
+
+/**
+ * of_hisilpc_register_pio - register the deivce physical IO address into
+ *			io_range_list
+ *
+ * Returns >=0 means ok.
+ * others mean some failures.
+ */
+static int of_hisilpc_register_pio(struct device_node *dev,
+					unsigned long *phyport)
+{
+	static int isfirst = 0;
+	const __be32	*addrp;
+	u64		size;
+	unsigned int	flags;
+	u64	taddr;
+	int residx = 0;
+
+
+	if (!dev || !phyport)
+		return -EINVAL;
+	/* only one IO reg exists */
+	do {
+		addrp = of_get_address(dev, residx, &size, &flags);
+		if (addrp == NULL) {
+			pr_err("%s:: get OF address(%d) FAIL!\n",
+				dev->name, residx);
+			return -EINVAL;
+		}
+		residx++;
+	} while(!(flags & IORESOURCE_IO));
+
+
+	taddr = of_translate_address(dev, addrp);
+	if (taddr == OF_BAD_ADDR) {
+		pr_err("%s:: translate IO address fail\n", dev->name);
+		return -EINVAL;
+	}
+
+	/* register one more IO byte for the first register */
+	if (!isfirst) {
+		size += 1;
+		isfirst = 1;
+	}
+
+	if (pci_register_io_range(taddr, size)) {
+		pr_err("%s::register physical range[%llx, %llx) FAIL!\n",
+			dev->name, taddr, size);
+		return -ENXIO;
+	}
+
+	pr_info("%s:: register physical range[%llx, %llx) OK\n",
+			dev->name, taddr, size);
+
+	*phyport = taddr;
+
+	return 0;
+}
+
+/**
+ * hisilpc_probe_child_dev - setup the mapping between linux IO and
+ *			physical IO for all children under hisilpc
+ *
+ * @ppdev: point to the hisilpc device
+ *
+ * Returns =0 means ok.
+ * others mean some failures.
+ */
+static int hisilpc_probe_child_dev(struct device *ppdev)
+{
+	int ret;
+
+	if (!ppdev)
+		return -EINVAL;
+
+	ret = 0;
+	/* for device tree, scan the child devices now */
+	if (!has_acpi_companion(ppdev)) {
+		struct device_node *root, *child;
+
+		root = ppdev->of_node;
+		for_each_available_child_of_node(root, child) {
+			struct platform_device *ptdev;
+			unsigned long cpuio;
+
+			/* register the IO range configured in dt */
+			ret = of_hisilpc_register_pio(child, &cpuio);
+			if (ret) {
+				dev_err(ppdev, "fail to register raw IO for %s\n",
+						child->name);
+				return ret;
+			}
+
+			ptdev = of_platform_device_create(child, NULL, ppdev);
+			if (!ptdev) {
+				dev_err(ppdev, "create platform device fail for %s\n",
+					child->name);
+				return -EFAULT;
+			}
+
+			ret = hisilpc_children_map_sysio(&ptdev->dev, &cpuio);
+			if (ret)
+				dev_err(&ptdev->dev, "Mapping sysio for dts child devices FAIL\n");
+		}
+	} else {
+		ret = device_for_each_child(ppdev, NULL,
+					hisilpc_children_map_sysio);
+		if (ret)
+			dev_err(ppdev, "Mapping sysio for ACPI child devices FAIL\n");
+	}
+
+	return ret;
+}
+
+
+/**
+ * hisilpc_probe - the probe callback function for hisi lpc device,
+ *		will finish all the intialization.
+ * @pdev: the platform device corresponding to hisi lpc
+ *
+ * Returns 0 on success, non-zero on fail.
+ *
+ */
+static int hisilpc_probe(struct platform_device *pdev)
+{
+	struct resource *iores;
+	struct hisilpc_dev *lpcdev;
+	int ret;
+
+	dev_info(&pdev->dev, "hslpc start probing...\n");
+
+	lpcdev = devm_kzalloc(&pdev->dev,
+				sizeof(struct hisilpc_dev), GFP_KERNEL);
+	if (!lpcdev)
+		return -ENOMEM;
+
+	spin_lock_init(&lpcdev->cycle_lock);
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	lpcdev->membase = devm_ioremap_resource(&pdev->dev, iores);
+	if (IS_ERR(lpcdev->membase)) {
+		dev_err(&pdev->dev, "No mem resource\n");
+		return PTR_ERR(lpcdev->membase);
+	}
+
+	lpcdev->pltdev = pdev;
+	platform_set_drvdata(pdev, lpcdev);
+
+	ret = hisilpc_probe_child_dev(&pdev->dev);
+	if (!ret)
+		dev_info(&pdev->dev, "hslpc finish probing...\n");
+	else
+		dev_err(&pdev->dev, "hslpc probe got fail(%d)!\n", -ret);
+
+	return ret;
+}
+
+
+static const struct of_device_id hisilpc_of_match[] = {
+	{
+		.compatible = "hisilicon,low-pin-count",
+	},
+	{},
+};
+
+static const struct acpi_device_id hisilpc_acpi_match[] = {
+	{"HISI0191", },
+	{},
+};
+
+static struct platform_driver hisilpc_driver = {
+	.driver = {
+		.name           = "hisi_lpc",
+		.of_match_table = hisilpc_of_match,
+		.acpi_match_table = hisilpc_acpi_match,
+	},
+	.probe = hisilpc_probe,
+};
+
+
+builtin_platform_driver(hisilpc_driver);
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 02b2903..ba4a330 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -690,9 +690,18 @@ static int __of_address_to_resource(struct device_node *dev,
 	memset(r, 0, sizeof(struct resource));
 	if (flags & IORESOURCE_IO) {
 		unsigned long port;
+
 		port = pci_address_to_pio(taddr);
 		if (port == (unsigned long)-1)
 			return -EINVAL;
+		/*
+		 * special processing for non-pci device gurantee the linux start pio
+		 * is not ZERO. Otherwise, some drivers' initialization will fail.
+		 */
+		if (!port && (!IS_ENABLED(CONFIG_OF_ADDRESS_PCI) ||
+				!of_bus_pci_match(dev)))
+			port += 1;
+
 		r->start = port;
 		r->end = port + size - 1;
 	} else {
-- 
1.9.1

^ permalink raw reply related

* [PATCH V3 3/4] ARM64 LPC: support serial based on low-pin-count
From: Zhichang Yuan @ 2016-09-14 12:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473855354-150093-1-git-send-email-yuanzhichang@hisilicon.com>

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

On Hip06 platform, a 16550 compatible UART is connected to low-pin-count and
controlled through the LPC I/O cycles. After registering the LPC uart specific
serial_in/serial_out to 8250 core driver, serial data can be read/written
through the LPC.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
---
 .../devicetree/bindings/serial/hisi-lpc-uart.txt   |  60 ++++++++
 drivers/tty/serial/8250/8250_hisi_lpc.c            | 171 +++++++++++++++++++++
 drivers/tty/serial/8250/Kconfig                    |   9 ++
 drivers/tty/serial/8250/Makefile                   |   1 +
 4 files changed, 241 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/hisi-lpc-uart.txt
 create mode 100644 drivers/tty/serial/8250/8250_hisi_lpc.c

diff --git a/Documentation/devicetree/bindings/serial/hisi-lpc-uart.txt b/Documentation/devicetree/bindings/serial/hisi-lpc-uart.txt
new file mode 100644
index 0000000..0f8ec2a
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/hisi-lpc-uart.txt
@@ -0,0 +1,60 @@
+* Hisilicon hip06 UART through low-pin-count
+
+Required properties:
+- compatible : "hisilicon,lpc-uart"
+- reg : offset and length of the I/O port set for the device.
+- reg-names : name the uart resources.
+		"lpc_mem" represents memory resource of the LPC parent. When
+		flat-tree earlycon is needed, this memory resource and
+		resource name are mandatory. Otherwise they are optional;
+		"dev_io" represents I/O resource of this device. It is
+		mandatory to access this device;
+
+Clock handling:
+  The clock rate of this device is same as the 8250 default clock rate, that
+  is 1843200. No need to define the clock rate in device tree.
+
+Note:
+  This device depends on its parent device whose compatible string is
+  "hisilicon,low-pin-count".
+
+  The format of "reg" property follows the I/O space definition in ISA/EISA
+  binding specification linked to:
+  http://www.firmware.org/1275/bindings/isa/isa0_4d.ps
+
+Example:
+
+	uart0: lpc-uart at 2f8 {
+		compatible = "hisilicon,lpc-uart";
+		reg = <0x01 0x2f8 0x08>;
+		status = "disabled";
+	};
+
+
+Example with low-pin-count parent device:
+
+	isa at a01b0000 {
+		compatible = "hisilicon,low-pin-count";
+		#address-cells = <2>;
+		#size-cells = <1>;
+		reg = <0x0 0xa01b0000 0x0 0x1000>;
+		ranges = <0x00 0xa01b0000 0x00 0xa01b0000 0x1000>,
+			<0x01 0xe4 0x0 0xe4 0x04>,
+			<0x01 0x2f8 0x0 0x2f8 0x08>;
+
+		ipmi0: bt at e4 {
+			compatible = "ipmi-bt";
+			device_type = "ipmi";
+			reg = <0x01 0xe4 0x04>;
+			reg-names = "dev_io";
+			status = "disabled";
+		};
+
+		uart0: lpc-uart at 2f8 {
+			compatible = "hisilicon,lpc-uart";
+			reg =  <0x00 0xa01b0000 0x1000>,
+				<0x01 0x2f8 0x08>;
+			ret-names = "lpc_mem", "dev_io";
+			status = "disabled";
+		};
+	};
diff --git a/drivers/tty/serial/8250/8250_hisi_lpc.c b/drivers/tty/serial/8250/8250_hisi_lpc.c
new file mode 100644
index 0000000..a8ba1ca
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_hisi_lpc.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
+ * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
+ * Author: Zou Rongrong <@huawei.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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/module.h>
+#include <linux/acpi.h>
+#include <linux/serial_8250.h>
+#include <asm-generic/serial.h>
+#include <linux/of_address.h>
+
+
+/**
+ * hisilpc_serial_inb - read/input data from the designated serial port.
+ * @p: the serial port where the data read from
+ * @offset:  the target I/O port address where the read is from
+ *
+ * Returns the byte data from this serial port.
+ * -1 means some failures.
+ *
+ */
+static unsigned int hisilpc_serial_inb(struct uart_port *p, int offset)
+{
+	struct extio_ops *parentops;
+
+	parentops = p->private_data;
+	if (!parentops || !parentops->pfin)
+		return -1;
+
+	return parentops->pfin(parentops->devpara,
+				p->iobase + (offset << p->regshift),
+				NULL, sizeof(u8), 1);
+}
+
+/**
+ * hisilpc_serial_outb - write/output data from the designated serial port.
+ * @p: the serial port where the data is written to
+ * @offset:  the target I/O port address where the write is from
+ *
+ */
+static void hisilpc_serial_outb(struct uart_port *p, int offset, int value)
+{
+	struct extio_ops *parentops;
+
+	parentops = p->private_data;
+	if (!parentops || !parentops->pfout)
+		return;
+
+	parentops->pfout(parentops->devpara,
+				p->iobase + (offset << p->regshift),
+				&value, sizeof(u8), 1);
+}
+
+
+static int hisilpc8250_probe(struct platform_device *pdev)
+{
+	struct uart_8250_port uart = {};
+	struct uart_port *port = &uart.port;
+	int err = 0;
+	struct resource *iores;
+	struct extio_ops *platdata;
+
+	if (!pdev->dev.parent)
+		return -ENODEV;
+	dev_info(&pdev->dev, "##probe entering\n");
+
+	/* To support the earlycon in bootargs, the first reg must be MEM */
+	iores = platform_get_resource_byname(pdev, IORESOURCE_IO,
+						"dev_io");
+	if (!iores) {
+		dev_err(&pdev->dev, "can not find the IO0\n");
+		return -ENXIO;
+	}
+
+	/*
+	 * save the platform data from parent in uart_port for serial_in,
+	 * serial_out
+	 */
+	platdata = dev_get_platdata(&pdev->dev);
+	port->private_data = (void *)platdata;
+	if (!port->private_data) {
+		dev_err(&pdev->dev, "no platform data!\n");
+		return -ENODEV;
+	}
+
+	if (platdata->start != iores->start || platdata->end != iores->end) {
+		dev_err(&pdev->dev, "PIO range[0x%lx - %lx] isn't fit!\n",
+			(unsigned long)iores->start,
+			(unsigned long)iores->end);
+		return -ENXIO;
+	}
+	port->iobase = (unsigned long)iores->start + platdata->ptoffset;
+	dev_info(&pdev->dev, "real port start is 0x%lx\n", port->iobase);
+
+	port->irq	= 0;
+	port->flags	= UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
+	port->dev	= &pdev->dev;
+	port->iotype	= UPIO_PORT;
+	port->regshift	= 0;
+	port->uartclk	= BASE_BAUD * 16;
+
+	spin_lock_init(&port->lock);
+
+	port->serial_in = hisilpc_serial_inb;
+	port->serial_out = hisilpc_serial_outb;
+
+	err = serial8250_register_8250_port(&uart);
+	if (err < 0) {
+		dev_err(&pdev->dev, "register uart FAIL(%d)!\n", -err);
+		return err;
+	}
+
+	platform_set_drvdata(pdev, (void *)&err);
+	dev_info(&pdev->dev, "##probing OK(%d)\n", err);
+	return 0;
+}
+
+static int hisilpc8250_remove(struct platform_device *pdev)
+{
+	int line = *((int *)platform_get_drvdata(pdev));
+
+	serial8250_unregister_port(line);
+
+	return 0;
+}
+
+
+static const struct of_device_id hs8250_of_match[] = {
+	{ .compatible = "hisilicon,lpc-uart" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, hs8250_of_match);
+
+static const struct acpi_device_id hs8250_acpi_match[] = {
+	/*{ "PNP0501", 0 },*/
+	{ "HISI1031", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(acpi, hs8250_acpi_match);
+
+static struct platform_driver hs_lpc8250_driver = {
+	.driver = {
+		.name		= "hisi-lpc-uart",
+		.of_match_table	= hs8250_of_match,
+		.acpi_match_table = ACPI_PTR(hs8250_acpi_match),
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+	},
+	.probe			= hisilpc8250_probe,
+	.remove			= hisilpc8250_remove,
+};
+
+module_platform_driver(hs_lpc8250_driver);
+
+
+MODULE_AUTHOR("Rongrong Zou");
+MODULE_DESCRIPTION("8250 serial probe module for Hisilicon LPC UART");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("v1.0");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 7c6f7af..c2e42f7 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -246,6 +246,15 @@ config SERIAL_8250_HUB6
 	  To compile this driver as a module, choose M here: the module
 	  will be called 8250_hub6.
 
+config SERIAL_8250_HISI_LPC
+	tristate "Support Hisilicon Hip0X UART through LPC"
+	depends on SERIAL_8250 !=n && HISILICON_LPC
+	help
+	  Say Y here if you have a hip06 board.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called 8250_hisi_lpc.
+
 #
 # Misc. options/drivers.
 #
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 367d403..1f2915b 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_SERIAL_8250_BOCA)		+= 8250_boca.o
 obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554)	+= 8250_exar_st16c554.o
 obj-$(CONFIG_SERIAL_8250_HUB6)		+= 8250_hub6.o
 obj-$(CONFIG_SERIAL_8250_FSL)		+= 8250_fsl.o
+obj-$(CONFIG_SERIAL_8250_HISI_LPC)	+= 8250_hisi_lpc.o
 obj-$(CONFIG_SERIAL_8250_DW)		+= 8250_dw.o
 obj-$(CONFIG_SERIAL_8250_EM)		+= 8250_em.o
 obj-$(CONFIG_SERIAL_8250_OMAP)		+= 8250_omap.o
-- 
1.9.1

^ permalink raw reply related

* [PATCH V3 4/4] ARM64 LPC: support earlycon for UART connected to LPC
From: Zhichang Yuan @ 2016-09-14 12:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473855354-150093-1-git-send-email-yuanzhichang@hisilicon.com>

From: "zhichang.yuan" <yuanzhichang@hisilicon.com>

This patch support the earlycon for UART connected to LPC on Hip06.
This patch is depended on the LPC driver.

Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
---
 drivers/bus/hisi_lpc.c               | 113 +++++++++++++++++++++++++++++++++++
 drivers/tty/serial/8250/8250_early.c |  26 +++++++-
 2 files changed, 137 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/hisi_lpc.c b/drivers/bus/hisi_lpc.c
index 9b364d0..2269828 100644
--- a/drivers/bus/hisi_lpc.c
+++ b/drivers/bus/hisi_lpc.c
@@ -360,6 +360,119 @@ void hisilpc_comm_outb(void *devobj, unsigned long ptaddr,
 
 
 /**
+ * hisilpc_early_in - read/input operation specific for hisi LPC earlycon.
+ * @devobj: pointer to device relevant information of the caller.
+ * @inbuf: the buffer where the read back data is populated.
+ *
+ * for earlycon, dlen and count should be one.
+ *
+ * Return the data read from earlycon on success, error ID on fail.
+ *
+ */
+static unsigned int __init hisilpc_early_in(struct uart_port *port, int offset)
+{
+	unsigned int backval = 0;
+	unsigned int ret = 0;
+	struct lpc_cycle_para para;
+	struct hisilpc_dev lpcdev;
+
+	if (!port->mapbase || !port->iobase || !port->membase)
+		return -EINVAL;
+
+	para.opflags = FG_EARLYCON_LPC;
+	para.csize = 1;
+	lpcdev.membase = port->membase;
+
+	ret = hisilpc_target_in(&lpcdev, &para,
+				port->iobase + (offset << port->regshift),
+				(unsigned char *)&backval, 1);
+	return (ret) ? : backval;
+}
+
+/**
+ * hisilpc_early_out - write/output operation specific for hisi LPC earlycon.
+ * @port: pointer to uart_port of eralycon
+ *
+ * for earlycon, dlen and count should be one.
+ *
+ */
+static void __init hisilpc_early_out(struct uart_port *port, int offset,
+					int value)
+{
+	struct lpc_cycle_para para;
+	struct hisilpc_dev lpcdev;
+
+	if (!port->mapbase || !port->iobase || !port->membase)
+		return;
+
+	para.opflags = FG_EARLYCON_LPC;
+	para.csize = 1;
+	lpcdev.membase = port->membase;
+
+	(void)hisilpc_target_out(&lpcdev, &para,
+				port->iobase + (offset << port->regshift),
+				(unsigned char *)&value, 1);
+}
+
+
+/**
+ * early_hisilpc8250_setup - initilize the lpc earlycon
+ * @device: pointer to the elarycon device
+ * @options: a option string from earlycon kernel-parameter
+ *
+ * Returns 0 on success, non-zero on fail.
+ *
+ */
+static int __init early_hisilpc8250_setup(struct earlycon_device *device,
+						const char *options)
+{
+	char *p;
+	int ret;
+
+	if (!device->port.membase)
+		return -ENODEV;
+
+	if (device->port.iotype != UPIO_MEM)
+		return -EINVAL;
+
+	if (device->options) {
+		p = strchr(device->options, ',');
+		if (p && (p + 1) != '\0') {
+			ret = kstrtoul(++p, 0,
+				(unsigned long *)&device->port.iobase);
+			if (ret || device->port.iobase == 0)
+				return ret ?: -EFAULT;
+		} else
+			device->port.iobase = 0x2f8;
+	} else {
+		device->port.iobase = 0x2f8;
+		device->baud = 0;
+	}
+
+	device->port.serial_in = hisilpc_early_in;
+	device->port.serial_out = hisilpc_early_out;
+	/* must convert iotype to UPIO_PORT for Hip06 indirect-io */
+	device->port.iotype = UPIO_PORT;
+
+	/* disable interrupts from LPC */
+	writel(LPC_IRQ_CLEAR, device->port.membase + LPC_REG_IRQ_ST);
+	/* ensure the LPC is available */
+	while (!(readl(device->port.membase + LPC_REG_OP_STATUS) &
+			LPC_STATUS_IDLE))
+		cpu_relax();
+
+	return early_serial8250_setup(device, options);
+}
+
+
+
+EARLYCON_DECLARE(hisilpcuart, early_hisilpc8250_setup);
+OF_EARLYCON_DECLARE(hisilpcuart, "hisilicon,lpc-uart",
+					early_hisilpc8250_setup);
+
+
+
+/**
  * hisilpc_ischild_ipmi - check whether the designated device is ipmi
  * @dev: the device to be checked.
  * @data: the value used to match the acpi device in checking.
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 85a12f0..3b5d0a8 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -37,7 +37,7 @@
 #include <asm/io.h>
 #include <asm/serial.h>
 
-static unsigned int __init serial8250_early_in(struct uart_port *port, int offset)
+static unsigned int __init serial8250_early_in_raw(struct uart_port *port, int offset)
 {
 	offset <<= port->regshift;
 
@@ -57,7 +57,7 @@ static unsigned int __init serial8250_early_in(struct uart_port *port, int offse
 	}
 }
 
-static void __init serial8250_early_out(struct uart_port *port, int offset, int value)
+static void __init serial8250_early_out_raw(struct uart_port *port, int offset, int value)
 {
 	offset <<= port->regshift;
 
@@ -80,6 +80,28 @@ static void __init serial8250_early_out(struct uart_port *port, int offset, int
 	}
 }
 
+static inline void __init serial8250_early_out(struct uart_port *port,
+					int offset, int value)
+{
+	if (port->serial_out)
+		port->serial_out(port, offset, value);
+	else {
+		port->serial_out = serial8250_early_out_raw;
+		serial8250_early_out_raw(port, offset, value);
+	}
+}
+
+static inline unsigned int __init serial8250_early_in(struct uart_port *port,
+					int offset)
+{
+	if (port->serial_in)
+		return port->serial_in(port, offset);
+
+	port->serial_in = serial8250_early_in_raw;
+	return serial8250_early_in_raw(port, offset);
+}
+
+
 #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
 
 static void __init serial_putc(struct uart_port *port, int c)
-- 
1.9.1

^ permalink raw reply related

* [PATCH V3 1/4] ARM64 LPC: Indirect ISA port IO introduced
From: Arnd Bergmann @ 2016-09-14 12:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473855354-150093-2-git-send-email-yuanzhichang@hisilicon.com>

On Wednesday, September 14, 2016 8:15:51 PM CEST Zhichang Yuan wrote:
> From: "zhichang.yuan" <yuanzhichang@hisilicon.com>
> 
> For arm64, there is no I/O space as other architectural platforms, such as
> X86. Most I/O accesses are achieved based on MMIO. But for some arm64 SoCs,
> such as Hip06, when accessing some legacy ISA devices connected to LPC, those
> known port addresses are used to control the corresponding target devices, for
> example, 0x2f8 is for UART, 0xe4 is for ipmi-bt. It is different from the
> normal MMIO mode in using.
> 
> To drive these devices, this patch introduces a method named indirect-IO.
> In this method the in/out pair in arch/arm64/include/asm/io.h will be
> redefined. When upper layer drivers call in/out with those known legacy port
> addresses to access the peripherals, the hooking functions corrresponding to
> those target peripherals will be called. Through this way, those upper layer
> drivers which depend on in/out can run on Hip06 without any changes.
> 
> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>

Looks ok overall, but I have a couple of comments for details.

> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index bc3f00f..9579479 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -161,6 +161,12 @@ config ARCH_MMAP_RND_COMPAT_BITS_MIN
>  config ARCH_MMAP_RND_COMPAT_BITS_MAX
>         default 16
>  
> +config ARM64_INDIRECT_PIO
> +	def_bool n

'def_bool n' is the same as the shorter and more common 'bool'.

> diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
> index 9b6e408..d3acf1f 100644
> --- a/arch/arm64/include/asm/io.h
> +++ b/arch/arm64/include/asm/io.h
> @@ -34,6 +34,10 @@
>  
>  #include <xen/xen.h>
>  
> +#ifdef CONFIG_ARM64_INDIRECT_PIO
> +#include <linux/extio.h>
> +#endif

No need to guard includes with an #ifdef.

> +#define BUILDS_RW(bwl, type)						\
> +static inline void reads##bwl(const volatile void __iomem *addr,	\
> +				void *buffer, unsigned int count)	\
> +{									\
> +	if (count) {							\
> +		type *buf = buffer;					\
> +									\
> +		do {							\
> +			type x = __raw_read##bwl(addr);			\
> +			*buf++ = x;					\
> +		} while (--count);					\
> +	}								\
> +}									\
> +									\
> +static inline void writes##bwl(volatile void __iomem *addr,		\
> +				const void *buffer, unsigned int count)	\
> +{									\
> +	if (count) {							\
> +		const type *buf = buffer;				\
> +									\
> +		do {							\
> +			__raw_write##bwl(*buf++, addr);			\
> +		} while (--count);					\
> +	}								\
> +}
> +
> +BUILDS_RW(b, u8)

Why is this in here?

> @@ -149,6 +185,60 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
>  #define IO_SPACE_LIMIT		(PCI_IO_SIZE - 1)
>  #define PCI_IOBASE		((void __iomem *)PCI_IO_START)
>  
> +
> +/*
> + * redefine the in(s)b/out(s)b for indirect-IO.
> + */
> +#define inb inb
> +static inline u8 inb(unsigned long addr)
> +{
> +#ifdef CONFIG_ARM64_INDIRECT_PIO
> +	if (arm64_extio_ops && arm64_extio_ops->start <= addr &&
> +			addr <= arm64_extio_ops->end)
> +		return extio_inb(addr);
> +#endif
> +	return readb(PCI_IOBASE + addr);
> +}
> +

Looks ok, but you only seem to do this for the 8-bit
accessors, when it should be done for 16-bit and 32-bit
ones as well for consistency.

> diff --git a/drivers/bus/extio.c b/drivers/bus/extio.c
> new file mode 100644
> index 0000000..1e7a9c5
> --- /dev/null
> +++ b/drivers/bus/extio.c
> @@ -0,0 +1,66 @@

This is in a globally visible directory

> +
> +struct extio_ops *arm64_extio_ops;

But the identifier uses an architecture specific prefix. Either
move the whole file into arch/arm64, or make the naming so that
it can be used for everything.

> +u8 __weak extio_inb(unsigned long addr)
> +{
> +	return arm64_extio_ops->pfin ?
> +		arm64_extio_ops->pfin(arm64_extio_ops->devpara,
> +			addr + arm64_extio_ops->ptoffset, NULL,
> +			sizeof(u8), 1) : -1;
> +}

No need for the __weak attribute, just make sure that the
code is always built-in when needed.

Also, it doesn't seem necessary to have an extern function if
all it does is call the one callback that you have already 
checked earlier. Either put it all into the inline
definition in asm/io.h, or put it all into the extern
version like this.

#ifdef CONFIG_ARM64_INDIRECT_PIO /* otherwise use default from asm-generic */
#define inb inb
extern u8 inb(unsigned long addr);
#endif

u8 inb(unsigned long addr)
{
	if (arm64_extio_ops && arm64_extio_ops->start <= addr &&
			addr <= arm64_extio_ops->end)
		arm64_extio_ops->pfin(arm64_extio_ops->devpara,addr + arm64_extio_ops->ptoffset, NULL,sizeof(u8), 1) : -1;
	return extio_inb(addr);
}

> +#define inb inb
> +static inline u8 inb(unsigned long addr)
> +{
> +#ifdef CONFIG_ARM64_INDIRECT_PIO
> +	if (arm64_extio_ops && arm64_extio_ops->start <= addr &&
> +			addr <= arm64_extio_ops->end)
> +		return extio_inb(addr);
> +#endif
> +	return readb(PCI_IOBASE + addr);
> +}

> diff --git a/include/linux/extio.h b/include/linux/extio.h
> new file mode 100644
> index 0000000..08d1fca
> --- /dev/null
> +++ b/include/linux/extio.h
> @@ -0,0 +1,49 @@
> +/*
> + * Copyright (C) 2016 Hisilicon Limited, All Rights Reserved.
> + * Author: Zhichang Yuan <yuanzhichang@hisilicon.com>
> + * Author: Zou Rongrong <@huawei.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.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef __LINUX_EXTIO_H
> +#define __LINUX_EXTIO_H
> +
> +
> +typedef u64 (*inhook)(void *devobj, unsigned long ptaddr, void *inbuf,
> +				size_t dlen, unsigned int count);
> +typedef void (*outhook)(void *devobj, unsigned long ptaddr,
> +				const void *outbuf, size_t dlen,
> +				unsigned int count);

I would drop the typedef and just declare the types directly in the
only place that references them.

	Arnd

^ permalink raw reply

* [PATCH V3 3/4] ARM64 LPC: support serial based on low-pin-count
From: Arnd Bergmann @ 2016-09-14 12:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473855354-150093-4-git-send-email-yuanzhichang@hisilicon.com>

On Wednesday, September 14, 2016 8:15:53 PM CEST Zhichang Yuan wrote:
> From: "zhichang.yuan" <yuanzhichang@hisilicon.com>
> 
> On Hip06 platform, a 16550 compatible UART is connected to low-pin-count and
> controlled through the LPC I/O cycles. After registering the LPC uart specific
> serial_in/serial_out to 8250 core driver, serial data can be read/written
> through the LPC.
> 
> Signed-off-by: zhichang.yuan <yuanzhichang@hisilicon.com>
> 

I still think this should be handled by 8250_of.c after the addition of
support for IORESOURCE_IO.

	Arnd

^ permalink raw reply

* [PATCH] coresight: tmc: fix for trace collection bug in sysFS mode
From: Suzuki K Poulose @ 2016-09-14 12:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAGhh56GQmKnk5UaYYW-X1YpsPdb7SwCy1b5ANd3tmdAXBTBbZA@mail.gmail.com>

On 14/09/16 12:30, Venkatesh Vivekanandan wrote:
>
>
> On Wed, Sep 14, 2016 at 3:26 PM, Suzuki K Poulose <Suzuki.Poulose at arm.com <mailto:Suzuki.Poulose@arm.com>> wrote:
>
>     On 13/09/16 16:41, Mathieu Poirier wrote:
>
>         On 13 September 2016 at 06:20, Venkatesh Vivekanandan
>         <venkatesh.vivekanandan at broadcom.com <mailto:venkatesh.vivekanandan@broadcom.com>> wrote:
>
>             tmc_etb_dump_hw is never called in sysFS mode to collect trace from
>             hardware, because drvdata->mode is set to CS_MODE_DISABLED at
>             tmc_disable_etf/etr_sink
>
>             static void tmc_etb_disable_hw(struct tmc_drvdata *drvdata)
>             {
>                     .
>                     .
>                     if (local_read(&drvdata->mode) == CS_MODE_SYSFS)
>                             tmc_etb_dump_hw(drvdata);
>                     .
>                     .
>             }
>
>             static void tmc_disable_etf_sink(struct coresight_device *csdev)
>             {
>                    .
>                    .
>                     val = local_xchg(&drvdata->mode, CS_MODE_DISABLED);
>                     /* Disable the TMC only if it needs to */
>                     if (val != CS_MODE_DISABLED)
>                             tmc_etb_disable_hw(drvdata);
>
>
>         You are correct.
>
>                    .
>                    .
>             }
>
  
>     I think we should :
>
>     1) First switch the drvdata->mode to a normal type from local_t. Using an
>     atomic type for mode is completely unnecessary and comes with the overhead
>     of barriers/synchronisation instructions, while all accesses, including read/write
>     are performed under the drvdata->spinlock. I have a patch already for this, which
>     I plan to send it soon.
>
>     and
>
>     2) Do something like :
>
>     void  tmc_disable_etX_sink()
>     {
>             if (drvdata->mode != CS_MODE_DISABLED) {
>                     tmc_etX_disable_hw(drvdata);
>                     drvdata->mode = CS_MODE_DISABLED;
>             }
>     }
>
> You will fix this along with above changes?

Yes.

nit: Please fix your mail client. Do not use HTML formatted emails on mailing list

Cheers
Suzuki

^ permalink raw reply

* [PATCH v7 00/22] Generic DT bindings for PCI IOMMUs and ARM SMMU
From: Auger Eric @ 2016-09-14 12:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <d03ea5e7-59f1-8b49-4ba2-d05fc2030ebc@arm.com>

Hi,
On 14/09/2016 12:35, Robin Murphy wrote:
> On 14/09/16 09:41, Auger Eric wrote:
>> Hi,
>>
>> On 12/09/2016 18:13, Robin Murphy wrote:
>>> Hi all,
>>>
>>> To any more confusing fixups and crazily numbered extra patches, here's
>>> a quick v7 with everything rebased into the right order. The significant
>>> change this time is to implement iommu_fwspec properly from the start,
>>> which ends up being far simpler and more robust than faffing about
>>> introducing it somewhere 'less intrusive' to move toward core code later.
>>>
>>> New branch in the logical place:
>>>
>>> git://linux-arm.org/linux-rm iommu/generic-v7
>>
>> For information, as discussed privately with Robin I experience some
>> regressions with the former and now deprecated dt description.
>>
>> on my AMD Overdrive board and my old dt description I now only see a
>> single group:
>>
>> /sys/kernel/iommu_groups/
>> /sys/kernel/iommu_groups/0
>> /sys/kernel/iommu_groups/0/devices
>> /sys/kernel/iommu_groups/0/devices/e0700000.xgmac
>>
>> whereas I formerly see
>>
>> /sys/kernel/iommu_groups/
>> /sys/kernel/iommu_groups/3
>> /sys/kernel/iommu_groups/3/devices
>> /sys/kernel/iommu_groups/3/devices/0000:00:00.0
>> /sys/kernel/iommu_groups/1
>> /sys/kernel/iommu_groups/1/devices
>> /sys/kernel/iommu_groups/1/devices/e0700000.xgmac
>> /sys/kernel/iommu_groups/4
>> /sys/kernel/iommu_groups/4/devices
>> /sys/kernel/iommu_groups/4/devices/0000:00:02.2
>> /sys/kernel/iommu_groups/4/devices/0000:01:00.1
>> /sys/kernel/iommu_groups/4/devices/0000:00:02.0
>> /sys/kernel/iommu_groups/4/devices/0000:01:00.0
>> /sys/kernel/iommu_groups/2
>> /sys/kernel/iommu_groups/2/devices
>> /sys/kernel/iommu_groups/2/devices/e0900000.xgmac
>> /sys/kernel/iommu_groups/0
>> /sys/kernel/iommu_groups/0/devices
>> /sys/kernel/iommu_groups/0/devices/f0000000.pcie
>>
>> This is the group topology without ACS override. Applying the non
>> upstreamed "pci: Enable overrides for missing ACS capabilities" I used
>> to see separate groups for each PCIe components. Now I don't see any
>> difference with and without ACS override.
> 
> OK, having reproduced on my Juno, the problem looks to be that
> of_for_each_phandle() leaves err set to -ENOENT after successfully
> walking a phandle list, which makes __find_legacy_master_phandle()
> always bail out after the first SMMU.
> 
> Can you confirm that the following diff fixes things for you?

Well it improves but there are still differences in the group topology.
The PFs now are in group 0.

root at trusty:~# lspci -nk
00:00.0 0600: 1022:1a00
        Subsystem: 1022:1a00
00:02.0 0600: 1022:1a01
00:02.2 0604: 1022:1a02
        Kernel driver in use: pcieport
01:00.0 0200: 8086:1521 (rev 01)
        Subsystem: 8086:0002
        Kernel driver in use: igb
01:00.1 0200: 8086:1521 (rev 01)
        Subsystem: 8086:0002
        Kernel driver in use: igb


with your series + fix:
/sys/kernel/iommu_groups/
/sys/kernel/iommu_groups/3
/sys/kernel/iommu_groups/3/devices
/sys/kernel/iommu_groups/3/devices/0000:00:00.0
/sys/kernel/iommu_groups/1
/sys/kernel/iommu_groups/1/devices
/sys/kernel/iommu_groups/1/devices/e0700000.xgmac
/sys/kernel/iommu_groups/4
/sys/kernel/iommu_groups/4/devices
/sys/kernel/iommu_groups/4/devices/0000:00:02.2
/sys/kernel/iommu_groups/4/devices/0000:00:02.0
/sys/kernel/iommu_groups/2
/sys/kernel/iommu_groups/2/devices
/sys/kernel/iommu_groups/2/devices/e0900000.xgmac
/sys/kernel/iommu_groups/0
/sys/kernel/iommu_groups/0/devices
/sys/kernel/iommu_groups/0/devices/0000:01:00.1
/sys/kernel/iommu_groups/0/devices/f0000000.pcie
/sys/kernel/iommu_groups/0/devices/0000:01:00.0

Before (4.8-rc5):

/sys/kernel/iommu_groups/
/sys/kernel/iommu_groups/3
/sys/kernel/iommu_groups/3/devices
/sys/kernel/iommu_groups/3/devices/0000:00:00.0
/sys/kernel/iommu_groups/1
/sys/kernel/iommu_groups/1/devices
/sys/kernel/iommu_groups/1/devices/e0700000.xgmac
/sys/kernel/iommu_groups/4
/sys/kernel/iommu_groups/4/devices
/sys/kernel/iommu_groups/4/devices/0000:00:02.2
/sys/kernel/iommu_groups/4/devices/0000:01:00.1
/sys/kernel/iommu_groups/4/devices/0000:00:02.0
/sys/kernel/iommu_groups/4/devices/0000:01:00.0
/sys/kernel/iommu_groups/2
/sys/kernel/iommu_groups/2/devices
/sys/kernel/iommu_groups/2/devices/e0900000.xgmac
/sys/kernel/iommu_groups/0
/sys/kernel/iommu_groups/0/devices
/sys/kernel/iommu_groups/0/devices/f0000000.pcie

Thanks

Eric

> 
> Robin
> 
> --->8---
> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> index fa892d25004d..ac4aab97c93a 100644
> --- a/drivers/iommu/arm-smmu.c
> +++ b/drivers/iommu/arm-smmu.c
> @@ -477,7 +477,7 @@ static int __find_legacy_master_phandle(struct
> device *dev, void *data)
>  			return 1;
>  		}
>  	it->node = np;
> -	return err;
> +	return err == -ENOENT ? 0 : err;
>  }
> 
>  static struct platform_driver arm_smmu_driver;
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

^ permalink raw reply

* [PATCH V3 2/4] ARM64 LPC: LPC driver implementation on Hip06
From: Arnd Bergmann @ 2016-09-14 12:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1473855354-150093-3-git-send-email-yuanzhichang@hisilicon.com>

On Wednesday, September 14, 2016 8:15:52 PM CEST Zhichang Yuan wrote:

> +Required properties:
> +- compatible: should be "hisilicon,low-pin-count"
> +- #address-cells: must be 2 which stick to the ISA/EISA binding doc.
> +- #size-cells: must be 1 which stick to the ISA/EISA binding doc.
> +- reg: base address and length of the register set for the device.
> +- ranges: define a 1:1 mapping between the I/O space of the child device and
> +	  the parent.

Do we still need the "ranges" here? The property in your example seems
wrong.

> +	ranges = <0x01 0xe4 0x0 0xe4 0x1000>;

You translate I/O port 0x00e4 through 0x10e4 to CPU address 0x0e4?

> +/**
> + * hisilpc_children_map_sysio - setup the mapping between system Io and
> + *			physical IO
> + *
> + * @child: the device whose IO is handling
> + * @data: some device specific data. For ACPI device, should be NULL.
> + *
> + * Returns >=0 means the mapping is successfully created;
> + * others mean some failures.
> + */
> +static int hisilpc_children_map_sysio(struct device * child, void * data)
> +{
> +	struct resource *iores;
> +	unsigned long cpuio;
> +	struct extio_ops *opsnode;
> +	int ret;
> +	struct hisilpc_dev *lpcdev;
> +
> +	if (!child || !child->parent)
> +		return -EINVAL;
> +
> +	iores = platform_get_resource_byname(to_platform_device(child),
> +					IORESOURCE_IO, "dev_io");
> +	if (!iores)
> +		return -ENODEV;
> +
> +	/*
> +	 * can not use devm_kzalloc to allocate slab for child before its driver
> +	 * start probing. Here allocate the slab with the name of parent.
> +	 */
> +	opsnode = devm_kzalloc(child->parent, sizeof(*opsnode), GFP_KERNEL);
> +	if (!opsnode)
> +		return -ENOMEM;
> +
> +	cpuio = data ? *((unsigned long *)data) : 0;
> +
> +	opsnode->start = iores->start;
> +	opsnode->end = iores->end;
> +	opsnode->ptoffset = cpuio ? (cpuio - iores->start) : 0;
> +
> +	dev_info(child, "map sys port[%lx - %lx] offset=0x%lx",
> +				(unsigned long)iores->start,
> +				(unsigned long)iores->end,
> +				opsnode->ptoffset);
> +
> +	opsnode->pfin = hisilpc_comm_inb;
> +	opsnode->pfout = hisilpc_comm_outb;
> +
> +	lpcdev = platform_get_drvdata(to_platform_device(child->parent));
> +	opsnode->devpara = lpcdev;
> +
> +	/* only apply indirect-IO to ipmi child device */

I don't get this part. The bus driver should not care what its
children are, just register and PIO ranges that the bus can handle
in theory, i.e. from 0x000 to 0xfff.

	Arnd

^ permalink raw reply


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