Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 5/5] ARM: dts: imx28-cfa10049: Move i2cmux out of bus node
From: Maxime Ripard @ 2018-01-04 12:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1514383478-32544-5-git-send-email-festevam@gmail.com>

On Wed, Dec 27, 2017 at 12:04:38PM -0200, Fabio Estevam wrote:
> From: Fabio Estevam <fabio.estevam@nxp.com>
> 
> Move i2cmux node from soc node to root node.
> 
> i2cmux node does not have any register properties and thus shouldn't be
> placed on the bus.
> 
> This fixes the following build warnings with W=1:
> 
> arch/arm/boot/dts/imx28-cfa10049.dtb: Warning (simple_bus_reg): Node /apb at 80000000/apbx at 80040000/i2cmux missing or empty reg/ranges property
> 
> Cc: Maxime Ripard <maxime.ripard@free-electrons.com>
> Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/6213d373/attachment-0001.sig>

^ permalink raw reply

* [RFC PATCH 09/12] mmc: sdhci: Use software timer when timeout greater than hardware capablility
From: Kishon Vijay Abraham I @ 2018-01-04 12:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <74170f0a-329a-2c66-7ad4-a1fedb9747df@intel.com>

Hi Adrian,

On Wednesday 20 December 2017 07:41 PM, Adrian Hunter wrote:
> On 14/12/17 15:09, Kishon Vijay Abraham I wrote:
>> Errata i834 in AM572x Sitara Processors Silicon Revision 2.0, 1.1
>> (SPRZ429K July 2014?Revised March 2017 [1]) mentions
>> Under high speed HS200 and SDR104 modes, the functional clock for MMC
>> modules will reach up to 192 MHz. At this frequency, the maximum obtainable
>> timeout (DTO = 0xE) through MMC host controller is (1/192MHz)*2^27 = 700ms.
>> Commands taking longer than 700ms may be affected by this small window
>> frame. Workaround for this errata is use a software timer instead of
>> hardware timer to provide the delay requested by the upper layer.
>>
>> While this errata is specific to AM572x, it is applicable to all sdhci
>> based controllers when a particular request require timeout greater
>> than hardware capability.
> 
> It doesn't work for our controllers.  Even if the data timeout interrupt is
> disabled, it seems like the timeout still "happens" in some fashion - after
> which the host controller starts misbehaving.

even if the data timeout doesn't get disabled, count = 0xE is still present. So
ideally this shouldn't break any existing platforms no?
> 
> So you will need to add a quirk.
> 
>>
>> Re-use the software timer already implemented in sdhci to program the
>> correct timeout value and also disable the hardware timeout when
>> the required timeout is greater than hardware capabiltiy in order to
>> avoid spurious timeout interrupts.
>>
>> This patch is based on the earlier patch implemented for omap_hsmmc [2]
>>
>> [1] -> http://www.ti.com/lit/er/sprz429k/sprz429k.pdf
>> [2] -> https://patchwork.kernel.org/patch/9791449/
>>
>> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
>> ---
>>  drivers/mmc/host/sdhci.c | 41 +++++++++++++++++++++++++++++++++++++++--
>>  drivers/mmc/host/sdhci.h | 11 +++++++++++
>>  2 files changed, 50 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>> index e9290a3439d5..d0655e1d2cc7 100644
>> --- a/drivers/mmc/host/sdhci.c
>> +++ b/drivers/mmc/host/sdhci.c
>> @@ -673,6 +673,27 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
>>  	}
>>  }
>>  
>> +static void sdhci_calc_sw_timeout(struct sdhci_host *host,
>> +				  struct mmc_command *cmd,
>> +				  unsigned int target_timeout)
>> +{
>> +	struct mmc_host *mmc = host->mmc;
>> +	struct mmc_ios *ios = &mmc->ios;
>> +	struct mmc_data *data = cmd->data;
>> +	unsigned long long transfer_time;
>> +
>> +	if (data) {
>> +		transfer_time = MMC_BLOCK_TRANSFER_TIME_MS(data->blksz,
>> +							   ios->bus_width,
>> +							   ios->clock);
> 
> If it has a value, actual_clock is better than ios->clock.

okay.
> 
>> +		/* calculate timeout for the entire data */
>> +		host->data_timeout = (data->blocks * (target_timeout +
>> +						      transfer_time));
>> +	} else if (cmd->flags & MMC_RSP_BUSY) {
>> +		host->data_timeout = cmd->busy_timeout * MSEC_PER_SEC;
> 
> Doesn't need MSEC_PER_SEC multiplier.

right.
> 
>> +	}
>> +}
>> +
>>  static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>  {
>>  	u8 count;
>> @@ -732,8 +753,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
>>  	}
>>  
>>  	if (count >= 0xF) {
>> -		DBG("Too large timeout 0x%x requested for CMD%d!\n",
>> -		    count, cmd->opcode);
>> +		DBG("Too large timeout.. using SW timeout for CMD%d!\n",
>> +		    cmd->opcode);
>> +		sdhci_calc_sw_timeout(host, cmd, target_timeout);
>> +		host->ier &= ~SDHCI_INT_DATA_TIMEOUT;
>> +		sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
>> +		sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
>>  		count = 0xE;
>>  	}
>>  
>> @@ -1198,6 +1223,14 @@ static void sdhci_finish_command(struct sdhci_host *host)
>>  {
>>  	struct mmc_command *cmd = host->cmd;
>>  
>> +	if (host->data_timeout) {
>> +		unsigned long timeout;
>> +
>> +		timeout = jiffies +
>> +			  msecs_to_jiffies(host->data_timeout);
>> +		sdhci_mod_timer(host, host->cmd->mrq, timeout);
> 
> cmd could be the sbc or a stop cmd or a command during transfer, so this
> needs more logic.

host->data_timeout gets set only for data commands or commands with busy
timeout. But I guess for commands during data transfer, host->data_timeout
might still be set?

Checking sdhci_data_line_cmd(mrq->cmd) in addition to host->data_timeout should
take care of all cases right?
> 
>> +	}
>> +
>>  	host->cmd = NULL;
>>  
>>  	if (cmd->flags & MMC_RSP_PRESENT) {
>> @@ -2341,6 +2374,10 @@ static bool sdhci_request_done(struct sdhci_host *host)
>>  		return true;
>>  	}
>>  
>> +	host->data_timeout = 0;
>> +	host->ier |= SDHCI_INT_DATA_TIMEOUT;
>> +	sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
>> +	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
> 
> sdhci can have 2 requests in progress to allow for commands to be sent while
> a data transfer is in progress, so this is not necessarily the data transfer
> request that is done.  Also we want to avoid unnecessary register writes.
> 

okay.. got it.
>>  	sdhci_del_timer(host, mrq);
>>  
>>  	/*
>> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
>> index 54bc444c317f..e6e0278bea1a 100644
>> --- a/drivers/mmc/host/sdhci.h
>> +++ b/drivers/mmc/host/sdhci.h
>> @@ -332,6 +332,15 @@ struct sdhci_adma2_64_desc {
>>  /* Allow for a a command request and a data request at the same time */
>>  #define SDHCI_MAX_MRQS		2
>>  
>> +/*
>> + * Time taken for transferring one block. It is multiplied by a constant
>> + * factor '2' to account for any errors
>> + */
>> +#define MMC_BLOCK_TRANSFER_TIME_MS(blksz, bus_width, freq)		\
>> +				   ((unsigned long long)		\
>> +				   (2 * (((blksz) * MSEC_PER_SEC *	\
>> +				   (8 / (bus_width))) / (freq))))
> 
> I don't think the macro helps make the code more readable.  Might just as
> well write a nice function to calculate the entire data request timeout.

okay.
> 
>> +
>>  enum sdhci_cookie {
>>  	COOKIE_UNMAPPED,
>>  	COOKIE_PRE_MAPPED,	/* mapped by sdhci_pre_req() */
>> @@ -546,6 +555,8 @@ struct sdhci_host {
>>  	/* Host SDMA buffer boundary. */
>>  	u32			sdma_boundary;
>>  
>> +	unsigned long long	data_timeout;
> 
> msecs_to_jiffies() will truncate to 'unsigned int' anyway, so this might as
> well be 'unsigned int'.
> 

okay.

Thanks
Kishon

^ permalink raw reply

* [PATCH] clk: imx: imx7d: correct video pll clock tree
From: Fabio Estevam @ 2018-01-04 12:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1514999361-2723-1-git-send-email-Anson.Huang@nxp.com>

On Wed, Jan 3, 2018 at 3:09 PM, Anson Huang <Anson.Huang@nxp.com> wrote:
> There is a test divider and post divider in video PLL,
> test divider is placed before post divider, all clocks
> that can select parent from video PLL should be from
> post divider, NOT from pll_video_main, below are
> clock tree dump before and after this patch:
>
> Before:
> pll_video_main
>    pll_video_main_bypass
>       pll_video_main_clk
>          lcdif_pixel_src
>             lcdif_pixel_cg
>                lcdif_pixel_pre_div
>                   lcdif_pixel_post_div
>                      lcdif_pixel_root_clk
> After:
> pll_video_main
>    pll_video_main_bypass
>       pll_video_main_clk
>          pll_video_test_div
>             pll_video_post_div
>                lcdif_pixel_src
>                   lcdif_pixel_cg
>                      lcdif_pixel_pre_div
>                         lcdif_pixel_post_div
>                            lcdif_pixel_root_clk
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>

Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>

^ permalink raw reply

* [PATCH] ARM: dts: imx6ul: remove unnecessary clocks for cpu-freq
From: Fabio Estevam @ 2018-01-04 13:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1514978534-27416-1-git-send-email-Anson.Huang@nxp.com>

On Wed, Jan 3, 2018 at 9:22 AM, Anson Huang <Anson.Huang@nxp.com> wrote:
> Remove unnecessary clocks for cpu-freq driver to
> avoid confusion.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>

Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>

^ permalink raw reply

* [PATCH 1/2] clk: imx: imx7d: add the snvs clock
From: Fabio Estevam @ 2018-01-04 13:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515078402-22135-1-git-send-email-Anson.Huang@nxp.com>

On Thu, Jan 4, 2018 at 1:06 PM, Anson Huang <Anson.Huang@nxp.com> wrote:
> According to the i.MX7D Reference Manual,
> SNVS block has a clock gate, accessing SNVS block
> would need this clock gate to be enabled, add it
> into clock tree so that SNVS module driver can
> operate this clock gate.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>

Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>

^ permalink raw reply

* [PATCH 2/2] ARM: dts: imx7s: add snvs rtc clock
From: Fabio Estevam @ 2018-01-04 13:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1515078402-22135-2-git-send-email-Anson.Huang@nxp.com>

On Thu, Jan 4, 2018 at 1:06 PM, Anson Huang <Anson.Huang@nxp.com> wrote:
> Add i.MX7 SNVS RTC clock.
>
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>

Reviewed-by: Fabio Estevam <fabio.estevam@nxp.com>

^ permalink raw reply

* [PATCH v2] dt: psci: Update DT bindings to support hierarchical PSCI states
From: Ulf Hansson @ 2018-01-04 13:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180104123132.GA28646@e107155-lin>

Hi Sudeep,

On 4 January 2018 at 13:31, Sudeep Holla <sudeep.holla@arm.com> wrote:
> Hi Ulf,
>
> I will suggest some wording changes not of which are not compulsory and
> left to you to pick up or drop.

Thanks for reviewing!

>
> On 28/12/17 14:40, Ulf Hansson wrote:
>> From: Lina Iyer <lina.iyer@linaro.org>
>>
>> Update DT bindings to represent hierarchical CPU and CPU domain idle states
>> for PSCI. Also update the PSCI examples to clearly show how flattened and
>> hierarchical idle states can be represented in DT.
>>
>> Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
>> ---
>>
>> Changes in v2:
>>       - Addressed comments from Rob.
>>       - Updated some labels in the examples to get more consistency.
>>
>> For your information, I have picked up the work from Lina Iyer around the so
>> called CPU cluster idling series [1,2] and I working on new versions. However,
>> I decided to post the updates to the PSCI DT bindings first, as they will be
>> needed to be agreed upon before further changes can be done to the PSCI firmware
>> driver.
>>
>> Note, these bindings have been discussed over and over again, at LKML, but
>> especially also at various Linux conferences, like LPC and Linaro Connect. We
>> finally came to a conclusion and the changes we agreed upon, should be reflected
>> in this update.
>>
>> Of course, it's a while ago since the latest discussions, but hopefully people
>> don't have too hard time to remember.
>>
>> Kind regards
>> Uffe
>>
>> [1]
>> https://www.spinics.net/lists/arm-kernel/msg566200.html
>>
>> [2]
>> https://lwn.net/Articles/716300/
>>
>> ---
>>  Documentation/devicetree/bindings/arm/psci.txt | 152 +++++++++++++++++++++++++
>>  1 file changed, 152 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/psci.txt b/Documentation/devicetree/bindings/arm/psci.txt
>> index a2c4f1d..8a09bd2 100644
>> --- a/Documentation/devicetree/bindings/arm/psci.txt
>> +++ b/Documentation/devicetree/bindings/arm/psci.txt
>> @@ -105,7 +105,159 @@ Case 3: PSCI v0.2 and PSCI v0.1.
>>               ...
>>       };
>>
>> +PSCI v1.0 onwards, supports OS-Initiated mode for powering off CPUs and CPU
>> +clusters from the firmware.
>
> Since we are trying to avoid usage of "clusters"(as it's not architecturally
> defined, but I know it's too late as it widely used everywhere). Also this
> binding is not just OSI specific, it can be used for Platform Co-ordinated
> also so let's not specify them at all.
>
> How about:
> "ARM systems can have multiple cores sometimes in hierarchical arrangement.
> This often, but not always, maps directly to the processor power topology
> of the system. Individual nodes in a topology have their own specific power
> states and can be better represented in DT hierarchically"

Sounds great! Let me change to this!

>
>> For such topologies the PSCI firmware driver acts
>
> PSCI firmware can be represented as a pseudo power controller ?

Yeah, this isn't very clear. I figure out something better or perhaps
just drop this.

>
>> +as pseudo-controller, which may be specified in the psci DT node. The
>> +definitions of the CPU and the CPU cluster topology, must conform to the domain
>> +idle state specification [3].
>
> I assume it should be  "..definitions of the idle states for CPU and the CPU
> topology" above, otherwise they should conform to topology binding :) rather
> than domain idle state bindings.

Yep.

>
>> The domain idle states themselves, must be
>> +compatible with the defined 'domain-idle-state' binding [1], and also need to
>> +specify the arm,psci-suspend-param property for each idle state.
>> +
>> +DT allows representing CPU and CPU cluster idle states in two different ways -
>> +
>> +The flattened model as given in Example 1, lists CPU's idle states followed by
>> +the domain idle state that the CPUs may choose. This is the general practice
>> +followed in PSCI firmwares that support Platform Coordinated mode.
>
> I would rather drop the above statement or specify in Example 2 that it can be
> used for both OSI and PC.

Yeah, I fully agree, this needs to be more clear in the doc.

>
>> Note that
>> +the idle states are all compatible with "arm,idle-state".
>> +
>> +Example 2 represents the hierarchical model of CPU and domain idle states.
>> +CPUs define their domain provider in their DT node. The domain controls the
>> +power to the CPU and possibly other h/w blocks that would be powered off when
>> +the CPU is powered off. The CPU's idle states may therefore be considered as
>> +the domain's idle states and have the compatible "arm,idle-state". Such domains
>> +may be embedded within another domain that represents common h/w blocks between
>> +these CPUs viz. the cluster. The idle states of the cluster would be
>> +represented as the domain's idle states. In order to use OS-Initiated mode of
>> +PSCI in the firmware, the hierarchical representation must be used.
>> +
>
> Can we avoid using poweroff as it's one of the idle states and not the only
> one ?

Yeah, I guess "low power state" or "idle state" is better?

Additionally we mentioning "clusters" here again. I may be difficult
to avoid using that terminology, when describing how things work. I
can try, but perhaps it's just easier to make a statement early on to
describe what "clusters" means in this context? Or what do you think?

>
> Other than that, the examples look good to me.

Great, thanks!

Kind regards
Uffe

^ permalink raw reply

* [PATCH] ARM: dts: sun[47]i: Fix display backend 1 output to TCON0 remote endpoint
From: Maxime Ripard @ 2018-01-04 13:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180103163155.13975-1-wens@csie.org>

On Thu, Jan 04, 2018 at 12:31:55AM +0800, Chen-Yu Tsai wrote:
> There is a copy-paste error in the display pipeline device tree graph.
> The remote endpoint of the display backend 1's output to TCON0 points
> to the wrong endpoint. This will result in the driver incorrectly
> parsing the relationship of the components.
> 
> Reported-by: Andrea Venturi <ennesimamail.av@gmail.com>
> Fixes: 0df4cf33a594 ("ARM: dts: sun4i: Add device nodes for display
> 		      pipelines")
> Fixes: 5b92b29bed45 ("ARM: dts: sun7i: Add device nodes for display
> 		      pipelines")
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/f70c36ad/attachment.sig>

^ permalink raw reply

* [PATCH v3 05/11] ARM: sun8i: h3/h5: add DE2 CCU device node for H3
From: maxime.ripard at free-electrons.com @ 2018-01-04 13:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171222122243.25735-6-icenowy@aosc.io>

On Fri, Dec 22, 2017 at 08:22:37PM +0800, Icenowy Zheng wrote:
> The DE2 in H3/H5 has a clock control unit in it, and the behavior is
> slightly different between H3 and H5.
> 
> Add the common parts in H3/H5 DTSI, and add the compatible string in H3
> DTSI.
> 
> The compatible string of H5 DE2 CCU will be added in a separated patch.
> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
> Changes in v2:
> - Use H3 DE2 CCU compatible as it's discovered that H3 and A83T DE2 CCU are
>   not equal.
> 
>  arch/arm/boot/dts/sun8i-h3.dtsi    |  4 ++++
>  arch/arm/boot/dts/sunxi-h3-h5.dtsi | 14 ++++++++++++++

Could you split that patch in half, with the common part in one patch,
and the H3 part in a second one?

This is a nightmare to merge otherwise.

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/59c0ba21/attachment.sig>

^ permalink raw reply

* [PATCH v3 09/11] clk: sunxi-ng: add support for Allwinner A64 DE2 CCU
From: Maxime Ripard @ 2018-01-04 13:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171222122243.25735-10-icenowy@aosc.io>

On Fri, Dec 22, 2017 at 08:22:41PM +0800, Icenowy Zheng wrote:
> Allwinner A64's DE2 needs to claim a section of SRAM (SRAM C) to work.
> 
> Add support for it.

That's highly suspicious that the clocks need an SRAM to operate
properly.

Can you elaborate?

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/be08db2b/attachment.sig>

^ permalink raw reply

* [RESEND PATCH v2 14/15] ASoC: qcom: apq8096: Add db820c machine driver
From: Srinivas Kandagatla @ 2018-01-04 13:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180104120244.GE10774@sirena.org.uk>



On 04/01/18 12:02, Mark Brown wrote:
> On Wed, Jan 03, 2018 at 09:20:45AM -0800, Stephen Boyd wrote:
>> On 12/14/2017 09:34 AM, srinivas.kandagatla at linaro.org wrote:
> 
>>> uThis patch adds support to DB820c machine driver.
> 
>>> +	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
> 
>> Why do we need to do this? Can you add some sort of comment in the code
>> about why?
> 
> And why are we applying DMA restrictions in a machine driver?

Initially I had this in pcm driver, but looking at example usage of 
snd_dma_alloc_pages, most of them use card->dev and some of them use pcm 
device for allocating dma memory.

Also, as I moved most dsp static services and dais out of DT, except 
codec and sound card, sound card device was the only choice I had for 
binding with iommu and enforcing iova range restrictions.

This call will be replaced by dma-ranges property in DT either way.


--srini
> 

^ permalink raw reply

* [PATCH v3] PCI: imx6: Add PHY reference clock source support
From: Ilya Ledvich @ 2018-01-04 13:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOMZO5AFC9dxhsQjmRrDA7Z3KMkEemryKOBmQhXm19NXKxHkKQ@mail.gmail.com>

i.MX7D variant of the IP can use either Crystal Oscillator input
or internal clock input as a Reference Clock input for PCIe PHY.
Add support for an optional property 'fsl,pcie-phy-refclk-internal'.
If present then an internal clock input is used as PCIe PHY
reference clock source. By default an external oscillator input
is still used.

Verified on Compulab SBC-iMX7 Single Board Computer.

Signed-off-by: Ilya Ledvich <ilya@compulab.co.il>
---
changes since V2:
	add a vendor prefix 'fsl' to a new property

 Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt | 5 +++++
 drivers/pci/dwc/pci-imx6.c                               | 8 +++++++-
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt
index 7b1e48b..1591a6a 100644
--- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt
+++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt
@@ -50,6 +50,11 @@ Additional required properties for imx7d-pcie:
 	       - "pciephy"
 	       - "apps"
 
+Additional optional properties for imx7d-pcie:
+- fsl,pcie-phy-refclk-internal: If present then an internal PLL input is used
+  as PCIe PHY reference clock source. By default an external oscillator input
+  is used.
+
 Example:
 
 	pcie at 0x01000000 {
diff --git a/drivers/pci/dwc/pci-imx6.c b/drivers/pci/dwc/pci-imx6.c
index b734835..36812d3 100644
--- a/drivers/pci/dwc/pci-imx6.c
+++ b/drivers/pci/dwc/pci-imx6.c
@@ -61,6 +61,7 @@ struct imx6_pcie {
 	u32			tx_swing_low;
 	int			link_gen;
 	struct regulator	*vpcie;
+	bool			pciephy_refclk_sel;
 };
 
 /* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */
@@ -474,7 +475,9 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
 	switch (imx6_pcie->variant) {
 	case IMX7D:
 		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
-				   IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, 0);
+				   IMX7D_GPR12_PCIE_PHY_REFCLK_SEL,
+				   imx6_pcie->pciephy_refclk_sel ?
+				   IMX7D_GPR12_PCIE_PHY_REFCLK_SEL : 0);
 		break;
 	case IMX6SX:
 		regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
@@ -840,6 +843,9 @@ static int imx6_pcie_probe(struct platform_device *pdev)
 		imx6_pcie->vpcie = NULL;
 	}
 
+	imx6_pcie->pciephy_refclk_sel =
+		of_property_read_bool(node, "fsl,pcie-phy-refclk-internal");
+
 	platform_set_drvdata(pdev, imx6_pcie);
 
 	ret = imx6_add_pcie_port(imx6_pcie, pdev);
-- 
1.9.1

^ permalink raw reply related

* [PATCH v2] ARM: dts: sunxi: Add sid for a83t
From: Maxime Ripard @ 2018-01-04 14:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAGb2v64mf-ihyOs-WJZuVa4Yib3Szp90RZu_a1EeQ1LJXnoXEQ@mail.gmail.com>

On Fri, Dec 22, 2017 at 06:11:52PM +0800, Chen-Yu Tsai wrote:
> On Fri, Dec 22, 2017 at 6:07 PM, Emmanuel Vadot <manu@bidouilliste.com> wrote:
> > On Fri, 22 Dec 2017 09:35:08 +0100
> > Maxime Ripard <maxime.ripard@free-electrons.com> wrote:
> >
> >> On Thu, Dec 21, 2017 at 07:09:03PM +0100, Emmanuel Vadot wrote:
> >> >
> >> >  Hi Maxime,
> >> >
> >> > On Thu, 21 Dec 2017 16:26:30 +0100
> >> > Maxime Ripard <maxime.ripard@free-electrons.com> wrote:
> >> >
> >> > > Hi,
> >> > >
> >> > > On Thu, Dec 21, 2017 at 09:19:24AM -0600, Kyle Evans wrote:
> >> > > > On Thu, Dec 21, 2017 at 8:55 AM, Maxime Ripard
> >> > > > <maxime.ripard@free-electrons.com> wrote:
> >> > > > > Hi Kyle,
> >> > > > >
> >> > > > > On Tue, Dec 19, 2017 at 03:05:23PM -0600, kevans91 at ksu.edu wrote:
> >> > > > >> Allwinner a83t has a 1 KB sid block with efuse for security rootkey and
> >> > > > >> thermal calibration data, add node to describe it.
> >> > > > >>
> >> > > > >> a83t-sid is not currently supported by nvmem/sunxi-sid, but it is
> >> > > > >> supported in an external driver for FreeBSD.
> >> > > > >>
> >> > > > >> Signed-off-by: Kyle Evans <kevans91@ksu.edu>
> >> > > > >
> >> > > > > The patch looks fine in itself, but we've had a number of issues with
> >> > > > > the register layout (and access patterns) in the past, so I'd rather
> >> > > > > have something that works in Linux too if possible.
> >> > > >
> >> > > > I have a patch that I think should make it work fine on Linux [1], but
> >> > > > I'm afraid I have little to no capability to test it myself and so I
> >> > > > did not add it as well.
> >> > > >
> >> > > > I do know that the rootkey is offset 0x200 into the given space [2],
> >> > > > as is the case with the H3, and that the readout quirk is not needed.
> >> > > > I wasn't 100% sure that the a83t has 2Kbit worth of efuse space as the
> >> > > > H3, but I do know that thermal data can be found at 0x34 and 0x38 in
> >> > > > this space.
> >> > >
> >> > > Then maybe we should leave it aside until someone takes some time on
> >> > > the A83t.
> >> >
> >> >  Take some time on the Linux driver and do not apply this patch for
> >> > now you mean ?
> >>
> >> Yep.
> >>
> >> Maxime
> >
> >  Since linux doesn't have the compatible in it's driver what would
> > be the harm to add the node in the DTS ? If a quirks is needed because
> > some region is weird this would go in the driver right ? I don't see a
> > technical problem for adding this node right now.
> >  If Kyle confirm the lenght of the region and that no quirk is needed
> > will it be enough ?
> 
> I guess I wasn't very clear. I'm OK with the patch going in. The device
> node currently says nothing about how much efuse space there is. The
> memory region covers that and the control section, and the size matches
> what the memory map says.
> 
> The size and offset of the efuse space would be dealt with in the driver.

Let's merge it then.

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/d04730a1/attachment.sig>

^ permalink raw reply

* [RESEND PATCH v2 14/15] ASoC: qcom: apq8096: Add db820c machine driver
From: Mark Brown @ 2018-01-04 14:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <418b531d-9d51-80c5-85aa-8ab8ef27bebb@linaro.org>

On Thu, Jan 04, 2018 at 01:44:30PM +0000, Srinivas Kandagatla wrote:

> Initially I had this in pcm driver, but looking at example usage of
> snd_dma_alloc_pages, most of them use card->dev and some of them use pcm
> device for allocating dma memory.

If they're using card->dev for DMA they're messing up, they need to use
the device associated with the DMA controller.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/4d88de45/attachment.sig>

^ permalink raw reply

* [linux-sunxi] [PATCH v4 0/2] Initial Allwinner V3s CSI Support
From: Maxime Ripard @ 2018-01-04 14:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171225111526.4663f997f5d6bfc6cf157f10@magewell.com>

On Mon, Dec 25, 2017 at 11:15:26AM +0800, Yong wrote:
> Hi,
> 
> On Fri, 22 Dec 2017 14:46:48 +0100
> Ond?ej Jirman <megous@megous.com> wrote:
> 
> > Hello,
> > 
> > Yong Deng p??e v P? 22. 12. 2017 v 17:32 +0800:
> > > This patchset add initial support for Allwinner V3s CSI.
> > > 
> > > Allwinner V3s SoC have two CSI module. CSI0 is used for MIPI interface
> > > and CSI1 is used for parallel interface. This is not documented in
> > > datasheet but by testing and guess.
> > > 
> > > This patchset implement a v4l2 framework driver and add a binding 
> > > documentation for it. 
> > > 
> > > Currently, the driver only support the parallel interface. And has been
> > > tested with a BT1120 signal which generating from FPGA. The following
> > > fetures are not support with this patchset:
> > >   - ISP 
> > >   - MIPI-CSI2
> > >   - Master clock for camera sensor
> > >   - Power regulator for the front end IC
> > > 
> > > Thanks for Ond?ej Jirman's help.
> > > 
> > > Changes in v4:
> > >   * Deal with the CSI 'INNER QUEUE'.
> > >     CSI will lookup the next dma buffer for next frame before the
> > >     the current frame done IRQ triggered. This is not documented
> > >     but reported by Ond?ej Jirman.
> > >     The BSP code has workaround for this too. It skip to mark the
> > >     first buffer as frame done for VB2 and pass the second buffer
> > >     to CSI in the first frame done ISR call. Then in second frame
> > >     done ISR call, it mark the first buffer as frame done for VB2
> > >     and pass the third buffer to CSI. And so on. The bad thing is
> > >     that the first buffer will be written twice and the first frame
> > >     is dropped even the queued buffer is sufficient.
> > >     So, I make some improvement here. Pass the next buffer to CSI
> > >     just follow starting the CSI. In this case, the first frame
> > >     will be stored in first buffer, second frame in second buffer.
> > >     This mothed is used to avoid dropping the first frame, it
> > >     would also drop frame when lacking of queued buffer.
> > >   * Fix: using a wrong mbus_code when getting the supported formats
> > >   * Change all fourcc to pixformat
> > >   * Change some function names
> > > 
> > > Changes in v3:
> > >   * Get rid of struct sun6i_csi_ops
> > >   * Move sun6i-csi to new directory drivers/media/platform/sunxi
> > >   * Merge sun6i_csi.c and sun6i_csi_v3s.c into sun6i_csi.c
> > >   * Use generic fwnode endpoints parser
> > >   * Only support a single subdev to make things simple
> > >   * Many complaintion fix
> > > 
> > > Changes in v2: 
> > >   * Change sunxi-csi to sun6i-csi
> > >   * Rebase to media_tree master branch 
> > > 
> > > Following is the 'v4l2-compliance -s -f' output, I have test this
> > > with both interlaced and progressive signal:
> > > 
> > > # ./v4l2-compliance -s -f
> > > v4l2-compliance SHA   : 6049ea8bd64f9d78ef87ef0c2b3dc9b5de1ca4a1
> > > 
> > > Driver Info:
> > >         Driver name   : sun6i-video
> > >         Card type     : sun6i-csi
> > >         Bus info      : platform:csi
> > >         Driver version: 4.15.0
> > >         Capabilities  : 0x84200001
> > >                 Video Capture
> > >                 Streaming
> > >                 Extended Pix Format
> > >                 Device Capabilities
> > >         Device Caps   : 0x04200001
> > >                 Video Capture
> > >                 Streaming
> > >                 Extended Pix Format
> > > 
> > > Compliance test for device /dev/video0 (not using libv4l2):
> > > 
> > > Required ioctls:
> > >         test VIDIOC_QUERYCAP: OK
> > > 
> > > Allow for multiple opens:
> > >         test second video open: OK
> > >         test VIDIOC_QUERYCAP: OK
> > >         test VIDIOC_G/S_PRIORITY: OK
> > >         test for unlimited opens: OK
> > > 
> > > Debug ioctls:
> > >         test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
> > >         test VIDIOC_LOG_STATUS: OK (Not Supported)
> > > 
> > > Input ioctls:
> > >         test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
> > >         test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> > >         test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
> > >         test VIDIOC_ENUMAUDIO: OK (Not Supported)
> > >         test VIDIOC_G/S/ENUMINPUT: OK
> > >         test VIDIOC_G/S_AUDIO: OK (Not Supported)
> > >         Inputs: 1 Audio Inputs: 0 Tuners: 0
> > > 
> > > Output ioctls:
> > >         test VIDIOC_G/S_MODULATOR: OK (Not Supported)
> > >         test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
> > >         test VIDIOC_ENUMAUDOUT: OK (Not Supported)
> > >         test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
> > >         test VIDIOC_G/S_AUDOUT: OK (Not Supported)
> > >         Outputs: 0 Audio Outputs: 0 Modulators: 0
> > > 
> > > Input/Output configuration ioctls:
> > >         test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
> > >         test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
> > >         test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
> > >         test VIDIOC_G/S_EDID: OK (Not Supported)
> > > 
> > > Test input 0:
> > > 
> > >         Control ioctls:
> > >                 test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
> > >                 test VIDIOC_QUERYCTRL: OK (Not Supported)
> > >                 test VIDIOC_G/S_CTRL: OK (Not Supported)
> > >                 test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
> > >                 test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
> > >                 test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
> > >                 Standard Controls: 0 Private Controls: 0
> > 
> > I'm not sure if your driver passes control queries to the subdev. It
> > did not originally, and I'm not sure you picked up the change from my
> > version of the driver. "Not supported" here seems to indicate that it
> > does not.
> > 
> > I'd be interested what's the recommended practice here. It sure helps
> > with some apps that expect to be able to modify various input controls
> > directly on the /dev/video# device. These are then supported out of the
> > box.
> > 
> > It's a one-line change. See:
> > 
> > https://www.kernel.org/doc/html/latest/media/kapi/v4l2-controls.html#in
> > heriting-controls
> 
> I think this is a feature and not affect the driver's main function.
> I just focused on making the CSI main function to work properly in 
> the initial version. Is this feature mandatory or most commonly used?

I agree here. Adding more and more features along the iterations is
just the best way to never get something merged.

Let's focus on a good basis that this driver provides, merge that, and
then build on top of it.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/25330596/attachment.sig>

^ permalink raw reply

* [linux-sunxi] [PATCH v4 0/2] Initial Allwinner V3s CSI Support
From: Maxime Ripard @ 2018-01-04 14:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171225085802.lfyk4blmbqxq6r2m@core.my.home>

On Mon, Dec 25, 2017 at 09:58:02AM +0100, Ond?ej Jirman wrote:
> Hello,
> 
> On Mon, Dec 25, 2017 at 11:15:26AM +0800, Yong wrote:
> > Hi,
> > 
> > On Fri, 22 Dec 2017 14:46:48 +0100
> > Ond?ej Jirman <megous@megous.com> wrote:
> > 
> > > Hello,
> > > 
> > > Yong Deng p??e v P? 22. 12. 2017 v 17:32 +0800:
> > > > 
> > > > Test input 0:
> > > > 
> > > >         Control ioctls:
> > > >                 test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
> > > >                 test VIDIOC_QUERYCTRL: OK (Not Supported)
> > > >                 test VIDIOC_G/S_CTRL: OK (Not Supported)
> > > >                 test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
> > > >                 test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
> > > >                 test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
> > > >                 Standard Controls: 0 Private Controls: 0
> > > 
> > > I'm not sure if your driver passes control queries to the subdev. It
> > > did not originally, and I'm not sure you picked up the change from my
> > > version of the driver. "Not supported" here seems to indicate that it
> > > does not.
> > > 
> > > I'd be interested what's the recommended practice here. It sure helps
> > > with some apps that expect to be able to modify various input controls
> > > directly on the /dev/video# device. These are then supported out of the
> > > box.
> > > 
> > > It's a one-line change. See:
> > > 
> > > https://www.kernel.org/doc/html/latest/media/kapi/v4l2-controls.html#in
> > > heriting-controls
> > 
> > I think this is a feature and not affect the driver's main function.
> > I just focused on making the CSI main function to work properly in 
> > the initial version. Is this feature mandatory or most commonly used?
> 
> I grepped the platform/ code and it seems, that inheriting controls
> from subdevs is pretty common for input drivers. (there are varying
> approaches though, some inherit by hand in the link function, some
> just register and empty ctrl_handler on the v4l2_dev and leave the
> rest to the core).
> 
> Practically, I haven't found a common app that would allow me to enter
> both /dev/video0 and /dev/v4l-subdevX. I'm sure anyone can write one
> themselves, but it would be better if current controls were available
> at the /dev/video0 device automatically.
> 
> It's much simpler for the userspace apps than the alternative, which
> is trying to identify the correct subdev that is currently
> associated with the CSI driver at runtime, which is not exactly
> straightforward and requires much more code, than a few lines in
> the kernel, that are required to inherit controls:

And it becomes much more complicated once you have the same controls
on the v4l2 device and subdevice, which is not that uncommon.

Maxime



-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/6715e4cd/attachment-0001.sig>

^ permalink raw reply

* [PATCH] ARM: dts: sun8i: a83t: bananapi-m3: Add LED device nodes
From: Maxime Ripard @ 2018-01-04 14:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180103062844.30315-1-wens@csie.org>

On Wed, Jan 03, 2018 at 02:28:44PM +0800, Chen-Yu Tsai wrote:
> The Bananapi M3 has two controllable LEDs, blue and green, that are tied
> to the PMIC's two GPIO pins.
> 
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>

Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/6df6ab79/attachment.sig>

^ permalink raw reply

* [PATCH] arm64: asid: Do not replace active_asids if already 0
From: Catalin Marinas @ 2018-01-04 14:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180104114028.GA10756@arm.com>

On Thu, Jan 04, 2018 at 11:40:28AM +0000, Will Deacon wrote:
> On Thu, Jan 04, 2018 at 11:17:21AM +0000, Catalin Marinas wrote:
> > (and we now have a formally verified ASID allocator ;))
> 
> It would be cool to mention the verifier in the commit message; potentially
> even including the code somewhere so that it can be used to test future
> changes.

Good idea. I pushed it here:

https://git.kernel.org/pub/scm/linux/kernel/git/cmarinas/kernel-tla.git/

(keeping the repository name generic as I may push other specs)

> Acked-by: Will Deacon <will.deacon@arm.com>
> Reviewed-by: Will Deacon <will.deacon@arm.com>

Thanks.

-- 
Catalin

^ permalink raw reply

* [PATCH 01/11] clk: sunxi-ng: Don't set k if width is 0 for nkmp plls
From: maxime.ripard at free-electrons.com @ 2018-01-04 14:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171230210203.24115-2-jernej.skrabec@siol.net>

Hi,

On Sat, Dec 30, 2017 at 10:01:53PM +0100, Jernej Skrabec wrote:
> For example, A83T have nmp plls which are modelled as nkmp plls. Since k
> is not specified, it has offset 0, shift 0 and lowest value 1. This
> means that LSB bit is always set to 1, which may change clock rate.
> 
> Fix that by applying k factor only if k width is greater than 0.
> 
> Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>

This looks fine...

> ---
>  drivers/clk/sunxi-ng/ccu_nkmp.c | 21 +++++++++++++--------
>  1 file changed, 13 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c
> index e58c95787f94..709f528af2b3 100644
> --- a/drivers/clk/sunxi-ng/ccu_nkmp.c
> +++ b/drivers/clk/sunxi-ng/ccu_nkmp.c
> @@ -81,7 +81,7 @@ static unsigned long ccu_nkmp_recalc_rate(struct clk_hw *hw,
>  					unsigned long parent_rate)
>  {
>  	struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw);
> -	unsigned long n, m, k, p;
> +	unsigned long n, m, k = 1, p;
>  	u32 reg;
>  
>  	reg = readl(nkmp->common.base + nkmp->common.reg);
> @@ -92,11 +92,13 @@ static unsigned long ccu_nkmp_recalc_rate(struct clk_hw *hw,
>  	if (!n)
>  		n++;
>  
> -	k = reg >> nkmp->k.shift;
> -	k &= (1 << nkmp->k.width) - 1;
> -	k += nkmp->k.offset;
> -	if (!k)
> -		k++;
> +	if (nkmp->k.width) {
> +		k = reg >> nkmp->k.shift;
> +		k &= (1 << nkmp->k.width) - 1;
> +		k += nkmp->k.offset;
> +		if (!k)
> +			k++;
> +	}

... but could you add a comment there to explain why you're using a
different construct than the one used for the other factors?

Thanks!
Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180104/d66be374/attachment.sig>

^ permalink raw reply

* [PATCH v2 0/8] ARM: sun9i: SMP support with Multi-Cluster Power Management
From: Chen-Yu Tsai @ 2018-01-04 14:37 UTC (permalink / raw)
  To: linux-arm-kernel

This is v2 of my sun9i SMP support with MCPM series which was started
over two years ago [1]. We've tried to implement PSCI for both the A80
and A83T. Results were not promising. The issue is that these two chips
have a broken security extensions implementation. If a specific bit is
not burned in its e-fuse, most if not all security protections don't
work [2]. Even worse, non-secure access to the GIC become secure. This
requires a crazy workaround in the GIC driver which probably doesn't work
in all cases [3].

Nicolas mentioned that the MCPM framework is likely overkill in our
case [4]. However the framework does provide cluster/core state tracking
and proper sequencing of cache related operations. We could rework
the code to use standard smp_ops, but I would like to actually get
a working version in first.

Much of the sunxi-specific MCPM code is derived from Allwinner code and
documentation, with some references to the other MCPM implementations,
as well as the Cortex's Technical Reference Manuals for the power
sequencing info.

One major difference compared to other platforms is we currently do not
have a standalone PMU or other embedded firmware to do the actually power
sequencing. All power/reset control is done by the kernel. Nicolas
mentioned that a new optional callback should be added in cases where the
kernel has to do the actual power down [5]. For now however I'm using a
dedicated single thread workqueue. CPU and cluster power off work is
queued from the .{cpu,cluster}_powerdown_prepare callbacks. This solution
is somewhat heavy, as I have a total of 10 static work structs. It might
also be a bit racy, as nothing prevents the system from bringing a core
back before the asynchronous work shuts it down. This would likely
happen under a heavily loaded system with a scheduler that brings cores
in and out of the system frequently. In simple use-cases it performs OK.

Changes since v1:

  - Leading zeroes for device node addresses removed
  - Added device tree binding for SMP SRAM
  - Simplified Kconfig options
  - Switched to SPDX license identifier
  - Map CPU to device tree node and check compatible to see if it's
    Cortex-A15 or Cortex-A7
  - Fix incorrect CPUCFG cluster status macro that prevented cluster
    0 L2 cache WFI detection
  - Fixed reversed bit for turning off cluster
  - Put cluster in reset before turning off power (or it hangs)
  - Added dedicated workqueue for turning off power to cpus and clusters
  - Request CPUCFG and SRAM MMIO ranges
  - Some comments fixed or added
  - Some debug messages added

[1] http://www.spinics.net/lists/arm-kernel/msg418350.html
[2] https://lists.denx.de/pipermail/u-boot/2017-June/294637.html
[3] https://github.com/wens/linux/commit/c48654c1f737116e7a7660183c8c74fa91970528
[4] http://www.spinics.net/lists/arm-kernel/msg434160.html
[5] http://www.spinics.net/lists/arm-kernel/msg434408.html

Chen-Yu Tsai (8):
  ARM: sun9i: Support SMP on A80 with Multi-Cluster Power Management
    (MCPM)
  ARM: dts: sun9i: Add CCI-400 device nodes for A80
  ARM: dts: sun9i: Add CPUCFG device node for A80 dtsi
  ARM: dts: sun9i: Add PRCM device node for the A80 dtsi
  ARM: sun9i: mcpm: Support CPU/cluster power down and hotplugging for
    cpu1~7
  dt-bindings: ARM: sunxi: Document A80 SoC secure SRAM usage by SMP
    hotplug
  ARM: sun9i: mcpm: Support cpu0 hotplug
  ARM: dts: sun9i: Add secure SRAM node used for MCPM SMP hotplug

 .../devicetree/bindings/arm/sunxi/smp-sram.txt     |  44 ++
 arch/arm/boot/dts/sun9i-a80.dtsi                   |  75 +++
 arch/arm/mach-sunxi/Kconfig                        |   2 +
 arch/arm/mach-sunxi/Makefile                       |   1 +
 arch/arm/mach-sunxi/mcpm.c                         | 633 +++++++++++++++++++++
 5 files changed, 755 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/sunxi/smp-sram.txt
 create mode 100644 arch/arm/mach-sunxi/mcpm.c

-- 
2.15.1

^ permalink raw reply

* [PATCH v2 1/8] ARM: sun9i: Support SMP on A80 with Multi-Cluster Power Management (MCPM)
From: Chen-Yu Tsai @ 2018-01-04 14:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180104143754.2425-1-wens@csie.org>

The A80 is a big.LITTLE SoC with 1 cluster of 4 Cortex-A7s and
1 cluster of 4 Cortex-A15s.

This patch adds support to bring up the second cluster and thus all
cores using the common MCPM code. Core/cluster power down has not
been implemented, thus CPU hotplugging and big.LITTLE switcher is
not supported.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 arch/arm/mach-sunxi/Kconfig  |   2 +
 arch/arm/mach-sunxi/Makefile |   1 +
 arch/arm/mach-sunxi/mcpm.c   | 425 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 428 insertions(+)
 create mode 100644 arch/arm/mach-sunxi/mcpm.c

diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 58153cdf025b..53c4e7420cfb 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -47,5 +47,7 @@ config MACH_SUN9I
 	bool "Allwinner (sun9i) SoCs support"
 	default ARCH_SUNXI
 	select ARM_GIC
+	select MCPM if SMP
+	select ARM_CCI400_PORT_CTRL if SMP
 
 endif
diff --git a/arch/arm/mach-sunxi/Makefile b/arch/arm/mach-sunxi/Makefile
index 27b168f121a1..cd25d9d81257 100644
--- a/arch/arm/mach-sunxi/Makefile
+++ b/arch/arm/mach-sunxi/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_ARCH_SUNXI) += sunxi.o
+obj-$(CONFIG_MCPM) += mcpm.o
 obj-$(CONFIG_SMP) += platsmp.o
diff --git a/arch/arm/mach-sunxi/mcpm.c b/arch/arm/mach-sunxi/mcpm.c
new file mode 100644
index 000000000000..30719998f3f0
--- /dev/null
+++ b/arch/arm/mach-sunxi/mcpm.c
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2015 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * arch/arm/mach-sunxi/mcpm.c
+ *
+ * Based on arch/arm/mach-exynos/mcpm-exynos.c and Allwinner code
+ */
+
+#include <linux/arm-cci.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+#include <asm/cputype.h>
+#include <asm/cp15.h>
+#include <asm/mcpm.h>
+
+#define SUNXI_CPUS_PER_CLUSTER		4
+#define SUNXI_NR_CLUSTERS		2
+
+#define CPUCFG_CX_CTRL_REG0(c)		(0x10 * (c))
+#define CPUCFG_CX_CTRL_REG0_L1_RST_DISABLE(n)	BIT(n)
+#define CPUCFG_CX_CTRL_REG0_L1_RST_DISABLE_ALL	0xf
+#define CPUCFG_CX_CTRL_REG0_L2_RST_DISABLE_A7	BIT(4)
+#define CPUCFG_CX_CTRL_REG0_L2_RST_DISABLE_A15	BIT(0)
+#define CPUCFG_CX_CTRL_REG1(c)		(0x10 * (c) + 0x4)
+#define CPUCFG_CX_CTRL_REG1_ACINACTM	BIT(0)
+#define CPUCFG_CX_RST_CTRL(c)		(0x80 + 0x4 * (c))
+#define CPUCFG_CX_RST_CTRL_DBG_SOC_RST	BIT(24)
+#define CPUCFG_CX_RST_CTRL_ETM_RST(n)	BIT(20 + (n))
+#define CPUCFG_CX_RST_CTRL_ETM_RST_ALL	(0xf << 20)
+#define CPUCFG_CX_RST_CTRL_DBG_RST(n)	BIT(16 + (n))
+#define CPUCFG_CX_RST_CTRL_DBG_RST_ALL	(0xf << 16)
+#define CPUCFG_CX_RST_CTRL_H_RST	BIT(12)
+#define CPUCFG_CX_RST_CTRL_L2_RST	BIT(8)
+#define CPUCFG_CX_RST_CTRL_CX_RST(n)	BIT(4 + (n))
+#define CPUCFG_CX_RST_CTRL_CORE_RST(n)	BIT(n)
+
+#define PRCM_CPU_PO_RST_CTRL(c)		(0x4 + 0x4 * (c))
+#define PRCM_CPU_PO_RST_CTRL_CORE(n)	BIT(n)
+#define PRCM_CPU_PO_RST_CTRL_CORE_ALL	0xf
+#define PRCM_PWROFF_GATING_REG(c)	(0x100 + 0x4 * (c))
+#define PRCM_PWROFF_GATING_REG_CLUSTER	BIT(4)
+#define PRCM_PWROFF_GATING_REG_CORE(n)	BIT(n)
+#define PRCM_PWR_SWITCH_REG(c, cpu)	(0x140 + 0x10 * (c) + 0x4 * (cpu))
+#define PRCM_CPU_SOFT_ENTRY_REG		0x164
+
+static void __iomem *cpucfg_base;
+static void __iomem *prcm_base;
+
+static bool sunxi_core_is_cortex_a15(unsigned int core, unsigned int cluster)
+{
+	struct device_node *node;
+	int cpu = cluster * SUNXI_CPUS_PER_CLUSTER + core;
+
+	node = of_cpu_device_node_get(cpu);
+
+	/* In case of_cpu_device_node_get fails */
+	if (!node)
+		node = of_get_cpu_node(cpu, NULL);
+
+	if (!node) {
+		/*
+		 * There's no point in returning an error, since we
+		 * would be mid way in a core or cluster power sequence.
+		 */
+		pr_err("%s: Couldn't get CPU cluster %u core %u device node\n",
+		       __func__, cluster, core);
+
+		return false;
+	}
+
+	return of_device_is_compatible(node, "arm,cortex-a15");
+}
+
+static int sunxi_cpu_power_switch_set(unsigned int cpu, unsigned int cluster,
+				      bool enable)
+{
+	u32 reg;
+
+	/* control sequence from Allwinner A80 user manual v1.2 PRCM section */
+	reg = readl(prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu));
+	if (enable) {
+		if (reg == 0x00) {
+			pr_debug("power clamp for cluster %u cpu %u already open\n",
+				 cluster, cpu);
+			return 0;
+		}
+
+		writel(0xff, prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu));
+		udelay(10);
+		writel(0xfe, prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu));
+		udelay(10);
+		writel(0xf8, prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu));
+		udelay(10);
+		writel(0xf0, prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu));
+		udelay(10);
+		writel(0x00, prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu));
+		udelay(10);
+	} else {
+		writel(0xff, prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu));
+		udelay(10);
+	}
+
+	return 0;
+}
+
+static int sunxi_cpu_powerup(unsigned int cpu, unsigned int cluster)
+{
+	u32 reg;
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	if (cpu >= SUNXI_CPUS_PER_CLUSTER || cluster >= SUNXI_NR_CLUSTERS)
+		return -EINVAL;
+
+	/* assert processor power-on reset */
+	reg = readl(prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
+	reg &= ~PRCM_CPU_PO_RST_CTRL_CORE(cpu);
+	writel(reg, prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
+
+	/* Cortex-A7: hold L1 reset disable signal low */
+	if (!sunxi_core_is_cortex_a15(cpu, cluster)) {
+		reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG0(cluster));
+		reg &= ~CPUCFG_CX_CTRL_REG0_L1_RST_DISABLE(cpu);
+		writel(reg, cpucfg_base + CPUCFG_CX_CTRL_REG0(cluster));
+	}
+
+	/* assert processor related resets */
+	reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+	reg &= ~CPUCFG_CX_RST_CTRL_DBG_RST(cpu);
+
+	/*
+	 * Allwinner code also asserts resets for NEON on A15. According
+	 * to ARM manuals, asserting power-on reset is sufficient.
+	 */
+	if (!sunxi_core_is_cortex_a15(cpu, cluster))
+		reg &= ~CPUCFG_CX_RST_CTRL_ETM_RST(cpu);
+
+	writel(reg, cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+
+	/* open power switch */
+	sunxi_cpu_power_switch_set(cpu, cluster, true);
+
+	/* clear processor power gate */
+	reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	reg &= ~PRCM_PWROFF_GATING_REG_CORE(cpu);
+	writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	udelay(20);
+
+	/* de-assert processor power-on reset */
+	reg = readl(prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
+	reg |= PRCM_CPU_PO_RST_CTRL_CORE(cpu);
+	writel(reg, prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
+
+	/* de-assert all processor resets */
+	reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+	reg |= CPUCFG_CX_RST_CTRL_DBG_RST(cpu);
+	reg |= CPUCFG_CX_RST_CTRL_CORE_RST(cpu);
+	if (!sunxi_core_is_cortex_a15(cpu, cluster))
+		reg |= CPUCFG_CX_RST_CTRL_ETM_RST(cpu);
+	else
+		reg |= CPUCFG_CX_RST_CTRL_CX_RST(cpu); /* NEON */
+	writel(reg, cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+
+	return 0;
+}
+
+static int sunxi_cluster_powerup(unsigned int cluster)
+{
+	u32 reg;
+
+	pr_debug("%s: cluster %u\n", __func__, cluster);
+	if (cluster >= SUNXI_NR_CLUSTERS)
+		return -EINVAL;
+
+	/* assert ACINACTM */
+	reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster));
+	reg |= CPUCFG_CX_CTRL_REG1_ACINACTM;
+	writel(reg, cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster));
+
+	/* assert cluster processor power-on resets */
+	reg = readl(prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
+	reg &= ~PRCM_CPU_PO_RST_CTRL_CORE_ALL;
+	writel(reg, prcm_base + PRCM_CPU_PO_RST_CTRL(cluster));
+
+	/* assert cluster resets */
+	reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+	reg &= ~CPUCFG_CX_RST_CTRL_DBG_SOC_RST;
+	reg &= ~CPUCFG_CX_RST_CTRL_DBG_RST_ALL;
+	reg &= ~CPUCFG_CX_RST_CTRL_H_RST;
+	reg &= ~CPUCFG_CX_RST_CTRL_L2_RST;
+
+	/*
+	 * Allwinner code also asserts resets for NEON on A15. According
+	 * to ARM manuals, asserting power-on reset is sufficient.
+	 */
+	if (!sunxi_core_is_cortex_a15(0, cluster))
+		reg &= ~CPUCFG_CX_RST_CTRL_ETM_RST_ALL;
+
+	writel(reg, cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+
+	/* hold L1/L2 reset disable signals low */
+	reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG0(cluster));
+	if (sunxi_core_is_cortex_a15(0, cluster)) {
+		/* Cortex-A15: hold L2RSTDISABLE low */
+		reg &= ~CPUCFG_CX_CTRL_REG0_L2_RST_DISABLE_A15;
+	} else {
+		/* Cortex-A7: hold L1RSTDISABLE and L2RSTDISABLE low */
+		reg &= ~CPUCFG_CX_CTRL_REG0_L1_RST_DISABLE_ALL;
+		reg &= ~CPUCFG_CX_CTRL_REG0_L2_RST_DISABLE_A7;
+	}
+	writel(reg, cpucfg_base + CPUCFG_CX_CTRL_REG0(cluster));
+
+	/* clear cluster power gate */
+	reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	reg &= ~PRCM_PWROFF_GATING_REG_CLUSTER;
+	writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	udelay(20);
+
+	/* de-assert cluster resets */
+	reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+	reg |= CPUCFG_CX_RST_CTRL_DBG_SOC_RST;
+	reg |= CPUCFG_CX_RST_CTRL_H_RST;
+	reg |= CPUCFG_CX_RST_CTRL_L2_RST;
+	writel(reg, cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+
+	/* de-assert ACINACTM */
+	reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster));
+	reg &= ~CPUCFG_CX_CTRL_REG1_ACINACTM;
+	writel(reg, cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster));
+
+	return 0;
+}
+
+static void sunxi_cpu_cache_disable(void)
+{
+	/* Disable and flush the local CPU cache. */
+	v7_exit_coherency_flush(louis);
+}
+
+/*
+ * This bit is shared between the initial mcpm_sync_init call to enable
+ * CCI-400 and proper cluster cache disable before power down.
+ */
+static void sunxi_cluster_cache_disable_without_axi(void)
+{
+	if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A15) {
+		/*
+		 * On the Cortex-A15 we need to disable
+		 * L2 prefetching before flushing the cache.
+		 */
+		asm volatile(
+		"mcr	p15, 1, %0, c15, c0, 3\n"
+		"isb\n"
+		"dsb"
+		: : "r" (0x400));
+	}
+
+	/* Flush all cache levels for this cluster. */
+	v7_exit_coherency_flush(all);
+
+	/*
+	 * Disable cluster-level coherency by masking
+	 * incoming snoops and DVM messages:
+	 */
+	cci_disable_port_by_cpu(read_cpuid_mpidr());
+}
+
+static void sunxi_cluster_cache_disable(void)
+{
+	unsigned int cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
+	u32 reg;
+
+	pr_debug("%s: cluster %u\n", __func__, cluster);
+
+	sunxi_cluster_cache_disable_without_axi();
+
+	/* last man standing, assert ACINACTM */
+	reg = readl(cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster));
+	reg |= CPUCFG_CX_CTRL_REG1_ACINACTM;
+	writel(reg, cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster));
+}
+
+static const struct mcpm_platform_ops sunxi_power_ops = {
+	.cpu_powerup		= sunxi_cpu_powerup,
+	.cluster_powerup	= sunxi_cluster_powerup,
+	.cpu_cache_disable	= sunxi_cpu_cache_disable,
+	.cluster_cache_disable	= sunxi_cluster_cache_disable,
+};
+
+/*
+ * Enable cluster-level coherency, in preparation for turning on the MMU.
+ *
+ * Also enable regional clock gating and L2 data latency settings for
+ * Cortex-A15. These settings are from the vendor kernel.
+ */
+static void __naked sunxi_power_up_setup(unsigned int affinity_level)
+{
+	asm volatile (
+		"mrc	p15, 0, r1, c0, c0, 0\n"
+		"movw	r2, #" __stringify(ARM_CPU_PART_MASK & 0xffff) "\n"
+		"movt	r2, #" __stringify(ARM_CPU_PART_MASK >> 16) "\n"
+		"and	r1, r1, r2\n"
+		"movw	r2, #" __stringify(ARM_CPU_PART_CORTEX_A15 & 0xffff) "\n"
+		"movt	r2, #" __stringify(ARM_CPU_PART_CORTEX_A15 >> 16) "\n"
+		"cmp	r1, r2\n"
+		"bne	not_a15\n"
+
+		/* The following is Cortex-A15 specific */
+
+		/* ACTLR2: Enable CPU regional clock gates */
+		"mrc p15, 1, r1, c15, c0, 4\n"
+		"orr r1, r1, #(0x1<<31)\n"
+		"mcr p15, 1, r1, c15, c0, 4\n"
+
+		/* L2ACTLR */
+		"mrc p15, 1, r1, c15, c0, 0\n"
+		/* Enable L2, GIC, and Timer regional clock gates */
+		"orr r1, r1, #(0x1<<26)\n"
+		/* Disable clean/evict from being pushed to external */
+		"orr r1, r1, #(0x1<<3)\n"
+		"mcr p15, 1, r1, c15, c0, 0\n"
+
+		/* L2CTRL: L2 data RAM latency */
+		"mrc p15, 1, r1, c9, c0, 2\n"
+		"bic r1, r1, #(0x7<<0)\n"
+		"orr r1, r1, #(0x3<<0)\n"
+		"mcr p15, 1, r1, c9, c0, 2\n"
+
+		/* End of Cortex-A15 specific setup */
+		"not_a15:\n"
+
+		"cmp	r0, #1\n"
+		"bxne	lr\n"
+		"b	cci_enable_port_for_self"
+	);
+}
+
+static void sunxi_mcpm_setup_entry_point(void)
+{
+	__raw_writel(virt_to_phys(mcpm_entry_point),
+		     prcm_base + PRCM_CPU_SOFT_ENTRY_REG);
+}
+
+static int __init sunxi_mcpm_init(void)
+{
+	struct device_node *cpucfg_node, *node;
+	struct resource res;
+	int ret;
+
+	if (!of_machine_is_compatible("allwinner,sun9i-a80"))
+		return -ENODEV;
+
+	if (!cci_probed())
+		return -ENODEV;
+
+	node = of_find_compatible_node(NULL, NULL, "allwinner,sun9i-a80-prcm");
+	if (!node)
+		return -ENODEV;
+
+	/*
+	 * Unfortunately we can not request the I/O region for the PRCM.
+	 * It is shared with the PRCM clock.
+	 */
+	prcm_base = of_iomap(node, 0);
+	of_node_put(node);
+	if (!prcm_base) {
+		pr_err("%s: failed to map PRCM registers\n", __func__);
+		return -ENOMEM;
+	}
+
+	cpucfg_node = of_find_compatible_node(NULL, NULL,
+					      "allwinner,sun9i-a80-cpucfg");
+	if (!cpucfg_node) {
+		ret = -ENODEV;
+		goto err_unmap_prcm;
+	}
+
+	cpucfg_base = of_io_request_and_map(cpucfg_node, 0, "sunxi-mcpm");
+	if (IS_ERR(cpucfg_base)) {
+		ret = PTR_ERR(cpucfg_base);
+		pr_err("%s: failed to map CPUCFG registers: %d\n",
+		       __func__, ret);
+		goto err_put_cpucfg_node;
+	}
+
+	ret = mcpm_platform_register(&sunxi_power_ops);
+	if (!ret)
+		ret = mcpm_sync_init(sunxi_power_up_setup);
+	if (!ret)
+		/* do not disable AXI master as no one will re-enable it */
+		ret = mcpm_loopback(sunxi_cluster_cache_disable_without_axi);
+	if (ret)
+		goto err_unmap_release_cpucfg;
+
+	/* We don't need the CPUCFG device node anymore */
+	of_node_put(cpucfg_node);
+
+	/* Set the hardware entry point address */
+	sunxi_mcpm_setup_entry_point();
+
+	/* Actually enable MCPM */
+	mcpm_smp_set_ops();
+
+	pr_info("sunxi MCPM support installed\n");
+
+	return ret;
+
+err_unmap_release_cpucfg:
+	iounmap(cpucfg_base);
+	of_address_to_resource(cpucfg_node, 0, &res);
+	release_mem_region(res.start, resource_size(&res));
+err_put_cpucfg_node:
+	of_node_put(cpucfg_node);
+err_unmap_prcm:
+	iounmap(prcm_base);
+	return ret;
+}
+
+early_initcall(sunxi_mcpm_init);
-- 
2.15.1

^ permalink raw reply related

* [PATCH v2 2/8] ARM: dts: sun9i: Add CCI-400 device nodes for A80
From: Chen-Yu Tsai @ 2018-01-04 14:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180104143754.2425-1-wens@csie.org>

The A80 includes an ARM CCI-400 interconnect to support multi-cluster
CPU caches.

Also add the maximum clock frequency for the CPUs, as listed in the
A80 Optimus Board FEX file.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 arch/arm/boot/dts/sun9i-a80.dtsi | 46 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index 90eac0b2a193..85fb800af8ab 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -63,48 +63,64 @@
 		cpu0: cpu at 0 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
+			cci-control-port = <&cci_control0>;
+			clock-frequency = <12000000>;
 			reg = <0x0>;
 		};
 
 		cpu1: cpu at 1 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
+			cci-control-port = <&cci_control0>;
+			clock-frequency = <12000000>;
 			reg = <0x1>;
 		};
 
 		cpu2: cpu at 2 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
+			cci-control-port = <&cci_control0>;
+			clock-frequency = <12000000>;
 			reg = <0x2>;
 		};
 
 		cpu3: cpu at 3 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
+			cci-control-port = <&cci_control0>;
+			clock-frequency = <12000000>;
 			reg = <0x3>;
 		};
 
 		cpu4: cpu at 100 {
 			compatible = "arm,cortex-a15";
 			device_type = "cpu";
+			cci-control-port = <&cci_control1>;
+			clock-frequency = <18000000>;
 			reg = <0x100>;
 		};
 
 		cpu5: cpu at 101 {
 			compatible = "arm,cortex-a15";
 			device_type = "cpu";
+			cci-control-port = <&cci_control1>;
+			clock-frequency = <18000000>;
 			reg = <0x101>;
 		};
 
 		cpu6: cpu at 102 {
 			compatible = "arm,cortex-a15";
 			device_type = "cpu";
+			cci-control-port = <&cci_control1>;
+			clock-frequency = <18000000>;
 			reg = <0x102>;
 		};
 
 		cpu7: cpu at 103 {
 			compatible = "arm,cortex-a15";
 			device_type = "cpu";
+			cci-control-port = <&cci_control1>;
+			clock-frequency = <18000000>;
 			reg = <0x103>;
 		};
 	};
@@ -431,6 +447,36 @@
 			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
 		};
 
+		cci: cci at 1c90000 {
+			compatible = "arm,cci-400";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x01c90000 0x1000>;
+			ranges = <0x0 0x01c90000 0x10000>;
+
+			cci_control0: slave-if at 4000 {
+				compatible = "arm,cci-400-ctrl-if";
+				interface-type = "ace";
+				reg = <0x4000 0x1000>;
+			};
+
+			cci_control1: slave-if at 5000 {
+				compatible = "arm,cci-400-ctrl-if";
+				interface-type = "ace";
+				reg = <0x5000 0x1000>;
+			};
+
+			pmu at 9000 {
+				 compatible = "arm,cci-400-pmu,r1";
+				 reg = <0x9000 0x5000>;
+				 interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+					      <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+					      <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+					      <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
+					      <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
+			};
+		};
+
 		de_clocks: clock at 3000000 {
 			compatible = "allwinner,sun9i-a80-de-clks";
 			reg = <0x03000000 0x30>;
-- 
2.15.1

^ permalink raw reply related

* [PATCH v2 3/8] ARM: dts: sun9i: Add CPUCFG device node for A80 dtsi
From: Chen-Yu Tsai @ 2018-01-04 14:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180104143754.2425-1-wens@csie.org>

CPUCFG is a collection of registers that are mapped to the SoC's signals
from each individual processor core and associated peripherals, such as
resets for processors, L1/L2 cache and other things.

These registers are used for SMP bringup and CPU hotplugging.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 arch/arm/boot/dts/sun9i-a80.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index 85fb800af8ab..85ecb4d64cfd 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -363,6 +363,11 @@
 			#reset-cells = <1>;
 		};
 
+		cpucfg at 1700000 {
+			compatible = "allwinner,sun9i-a80-cpucfg";
+			reg = <0x01700000 0x100>;
+		};
+
 		mmc0: mmc at 1c0f000 {
 			compatible = "allwinner,sun9i-a80-mmc";
 			reg = <0x01c0f000 0x1000>;
-- 
2.15.1

^ permalink raw reply related

* [PATCH v2 4/8] ARM: dts: sun9i: Add PRCM device node for the A80 dtsi
From: Chen-Yu Tsai @ 2018-01-04 14:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180104143754.2425-1-wens@csie.org>

The PRCM is a collection of clock controls, reset controls, and various
power switches/gates. Some of these can be independently listed and
supported, while a number of CPU related ones are used in tandem with
CPUCFG for SMP bringup and CPU hotplugging.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 arch/arm/boot/dts/sun9i-a80.dtsi | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index 85ecb4d64cfd..bf4d40e8359f 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -709,6 +709,11 @@
 			interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
 		};
 
+		prcm at 8001400 {
+			compatible = "allwinner,sun9i-a80-prcm";
+			reg = <0x08001400 0x200>;
+		};
+
 		apbs_rst: reset at 80014b0 {
 			reg = <0x080014b0 0x4>;
 			compatible = "allwinner,sun6i-a31-clock-reset";
-- 
2.15.1

^ permalink raw reply related

* [PATCH v2 5/8] ARM: sun9i: mcpm: Support CPU/cluster power down and hotplugging for cpu1~7
From: Chen-Yu Tsai @ 2018-01-04 14:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180104143754.2425-1-wens@csie.org>

This patch adds common code used to power down all cores and clusters.
The code is quite long. The common MCPM library does not provide a
callback for doing the actual power down sequence. Instead it assumes
some other part (maybe a power management coprocessor) will handle it.
Since our platform does not have this, we resort to using a single thread
workqueue, based on how our work should be done in the order they were
queued, so the cluster power down code does not execute before the core
power down code. Though the scenario is not catastrophic, it will leave
the cluster on and using power.

This might be a bit racy, as nothing prevents the system from bringing a
core or cluster back before the asynchronous work shuts it down. This would
likely happen under a heavily loaded system with a scheduler that brings
cores in and out of the system frequently. It would either result in a
stall on a single core, or worse, hang the system if a cluster is abruptly
turned off. In simple use-cases it performs OK.

The primary core (cpu0) requires setting flags to have the BROM bounce
execution to the SMP software entry code. This is done in a subsequent
patch to keep the changes cleanly separated.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
 arch/arm/mach-sunxi/mcpm.c | 170 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 165 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-sunxi/mcpm.c b/arch/arm/mach-sunxi/mcpm.c
index 30719998f3f0..ddc26b5fec48 100644
--- a/arch/arm/mach-sunxi/mcpm.c
+++ b/arch/arm/mach-sunxi/mcpm.c
@@ -12,9 +12,12 @@
 #include <linux/arm-cci.h>
 #include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/irqchip/arm-gic.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/workqueue.h>
 
 #include <asm/cputype.h>
 #include <asm/cp15.h>
@@ -30,6 +33,9 @@
 #define CPUCFG_CX_CTRL_REG0_L2_RST_DISABLE_A15	BIT(0)
 #define CPUCFG_CX_CTRL_REG1(c)		(0x10 * (c) + 0x4)
 #define CPUCFG_CX_CTRL_REG1_ACINACTM	BIT(0)
+#define CPUCFG_CX_STATUS(c)		(0x30 + 0x4 * (c))
+#define CPUCFG_CX_STATUS_STANDBYWFI(n)	BIT(16 + (n))
+#define CPUCFG_CX_STATUS_STANDBYWFIL2	BIT(0)
 #define CPUCFG_CX_RST_CTRL(c)		(0x80 + 0x4 * (c))
 #define CPUCFG_CX_RST_CTRL_DBG_SOC_RST	BIT(24)
 #define CPUCFG_CX_RST_CTRL_ETM_RST(n)	BIT(20 + (n))
@@ -237,6 +243,30 @@ static int sunxi_cluster_powerup(unsigned int cluster)
 	return 0;
 }
 
+struct sunxi_mcpm_work {
+	struct work_struct work;
+	unsigned int cpu;
+	unsigned int cluster;
+};
+
+static struct workqueue_struct *sunxi_mcpm_wq;
+static struct sunxi_mcpm_work sunxi_mcpm_cpu_down_work[2][4];
+static struct sunxi_mcpm_work sunxi_mcpm_cluster_down_work[2];
+
+static void sunxi_cpu_powerdown_prepare(unsigned int cpu, unsigned int cluster)
+{
+	gic_cpu_if_down(0);
+
+	queue_work(sunxi_mcpm_wq,
+		   &sunxi_mcpm_cpu_down_work[cluster][cpu].work);
+}
+
+static void sunxi_cluster_powerdown_prepare(unsigned int cluster)
+{
+	queue_work(sunxi_mcpm_wq,
+		   &sunxi_mcpm_cluster_down_work[cluster].work);
+}
+
 static void sunxi_cpu_cache_disable(void)
 {
 	/* Disable and flush the local CPU cache. */
@@ -286,11 +316,116 @@ static void sunxi_cluster_cache_disable(void)
 	writel(reg, cpucfg_base + CPUCFG_CX_CTRL_REG1(cluster));
 }
 
+static int sunxi_do_cpu_powerdown(unsigned int cpu, unsigned int cluster)
+{
+	u32 reg;
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	if (cpu >= SUNXI_CPUS_PER_CLUSTER || cluster >= SUNXI_NR_CLUSTERS)
+		return -EINVAL;
+
+	/* gate processor power */
+	reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	reg |= PRCM_PWROFF_GATING_REG_CORE(cpu);
+	writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	udelay(20);
+
+	/* close power switch */
+	sunxi_cpu_power_switch_set(cpu, cluster, false);
+
+	return 0;
+}
+
+static int sunxi_do_cluster_powerdown(unsigned int cluster)
+{
+	u32 reg;
+
+	pr_debug("%s: cluster %u\n", __func__, cluster);
+	if (cluster >= SUNXI_NR_CLUSTERS)
+		return -EINVAL;
+
+	/* assert cluster resets */
+	pr_debug("%s: assert cluster reset\n", __func__);
+	reg = readl(cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+	reg &= ~CPUCFG_CX_RST_CTRL_DBG_SOC_RST;
+	reg &= ~CPUCFG_CX_RST_CTRL_H_RST;
+	reg &= ~CPUCFG_CX_RST_CTRL_L2_RST;
+	writel(reg, cpucfg_base + CPUCFG_CX_RST_CTRL(cluster));
+
+	/* gate cluster power */
+	pr_debug("%s: gate cluster power\n", __func__);
+	reg = readl(prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	reg |= PRCM_PWROFF_GATING_REG_CLUSTER;
+	writel(reg, prcm_base + PRCM_PWROFF_GATING_REG(cluster));
+	udelay(20);
+
+	return 0;
+}
+
+static struct sunxi_mcpm_work *to_sunxi_mcpm_work(struct work_struct *work)
+{
+	return container_of(work, struct sunxi_mcpm_work, work);
+}
+
+/* async. work functions to bring down cpus and clusters */
+static void sunxi_cpu_powerdown(struct work_struct *_work)
+{
+	struct sunxi_mcpm_work *work = to_sunxi_mcpm_work(_work);
+	unsigned int cluster = work->cluster, cpu = work->cpu;
+	int ret;
+	u32 reg;
+
+	/* wait for CPU core to enter WFI */
+	ret = readl_poll_timeout(cpucfg_base + CPUCFG_CX_STATUS(cluster), reg,
+				 reg & CPUCFG_CX_STATUS_STANDBYWFI(cpu),
+				 1000, 100000);
+
+	if (ret)
+		return;
+
+	/* power down CPU core */
+	sunxi_do_cpu_powerdown(cpu, cluster);
+}
+
+static void sunxi_cluster_powerdown(struct work_struct *_work)
+{
+	struct sunxi_mcpm_work *work = to_sunxi_mcpm_work(_work);
+	unsigned int cluster = work->cluster;
+	int ret;
+	u32 reg;
+
+	pr_debug("%s: cluster %u\n", __func__, cluster);
+
+	/* wait for cluster L2 WFI */
+	ret = readl_poll_timeout(cpucfg_base + CPUCFG_CX_STATUS(cluster), reg,
+				 reg & CPUCFG_CX_STATUS_STANDBYWFIL2,
+				 1000, 100000);
+	if (ret)
+		return;
+
+	sunxi_do_cluster_powerdown(cluster);
+}
+
+static int sunxi_wait_for_powerdown(unsigned int cpu, unsigned int cluster)
+{
+	int ret;
+	u32 reg;
+
+	ret = readl_poll_timeout(prcm_base + PRCM_PWR_SWITCH_REG(cluster, cpu),
+				 reg, reg == 0xff, 1000, 100000);
+	pr_debug("%s: cpu %u cluster %u powerdown: %s\n", __func__,
+		 cpu, cluster, ret ? "timed out" : "done");
+	return ret;
+}
+
 static const struct mcpm_platform_ops sunxi_power_ops = {
-	.cpu_powerup		= sunxi_cpu_powerup,
-	.cluster_powerup	= sunxi_cluster_powerup,
-	.cpu_cache_disable	= sunxi_cpu_cache_disable,
-	.cluster_cache_disable	= sunxi_cluster_cache_disable,
+	.cpu_powerup		   = sunxi_cpu_powerup,
+	.cpu_powerdown_prepare	   = sunxi_cpu_powerdown_prepare,
+	.cluster_powerup	   = sunxi_cluster_powerup,
+	.cluster_powerdown_prepare = sunxi_cluster_powerdown_prepare,
+	.cpu_cache_disable	   = sunxi_cpu_cache_disable,
+	.cluster_cache_disable	   = sunxi_cluster_cache_disable,
+	.wait_for_powerdown	   = sunxi_wait_for_powerdown,
 };
 
 /*
@@ -352,6 +487,7 @@ static int __init sunxi_mcpm_init(void)
 	struct device_node *cpucfg_node, *node;
 	struct resource res;
 	int ret;
+	int i, j;
 
 	if (!of_machine_is_compatible("allwinner,sun9i-a80"))
 		return -ENODEV;
@@ -389,6 +525,28 @@ static int __init sunxi_mcpm_init(void)
 		goto err_put_cpucfg_node;
 	}
 
+	/* Initialize our strictly ordered workqueue */
+	sunxi_mcpm_wq = alloc_ordered_workqueue("%s", 0, "sunxi-mcpm");
+	if (!sunxi_mcpm_wq) {
+		ret = -ENOMEM;
+		pr_err("%s: failed to create our workqueue\n", __func__);
+		goto err_unmap_release_cpucfg;
+	}
+
+	/* Initialize power down work */
+	for (i = 0; i < SUNXI_NR_CLUSTERS; i++) {
+		for (j = 0; j < SUNXI_CPUS_PER_CLUSTER; j++) {
+			sunxi_mcpm_cpu_down_work[i][j].cluster = i;
+			sunxi_mcpm_cpu_down_work[i][j].cpu = j;
+			INIT_WORK(&sunxi_mcpm_cpu_down_work[i][j].work,
+				  sunxi_cpu_powerdown);
+		}
+
+		sunxi_mcpm_cluster_down_work[i].cluster = i;
+		INIT_WORK(&sunxi_mcpm_cluster_down_work[i].work,
+			  sunxi_cluster_powerdown);
+	}
+
 	ret = mcpm_platform_register(&sunxi_power_ops);
 	if (!ret)
 		ret = mcpm_sync_init(sunxi_power_up_setup);
@@ -396,7 +554,7 @@ static int __init sunxi_mcpm_init(void)
 		/* do not disable AXI master as no one will re-enable it */
 		ret = mcpm_loopback(sunxi_cluster_cache_disable_without_axi);
 	if (ret)
-		goto err_unmap_release_cpucfg;
+		goto err_destroy_workqueue;
 
 	/* We don't need the CPUCFG device node anymore */
 	of_node_put(cpucfg_node);
@@ -411,6 +569,8 @@ static int __init sunxi_mcpm_init(void)
 
 	return ret;
 
+err_destroy_workqueue:
+	destroy_workqueue(sunxi_mcpm_wq);
 err_unmap_release_cpucfg:
 	iounmap(cpucfg_base);
 	of_address_to_resource(cpucfg_node, 0, &res);
-- 
2.15.1

^ permalink raw reply related


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