Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ARM: Versatile Express: extend the MPIDR range used for pen release check
From: Nicolas Pitre @ 2013-01-22 20:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130122185833.GE3959@e102568-lin.cambridge.arm.com>

On Tue, 22 Jan 2013, Lorenzo Pieralisi wrote:

> On Tue, Jan 22, 2013 at 06:25:20PM +0000, Nicolas Pitre wrote:
> > On Tue, 22 Jan 2013, Lorenzo Pieralisi wrote:
> > 
> > > In ARM multi-cluster systems the MPIDR affinity level 0 cannot be used as a
> > > single cpu identifier, affinity levels 1 and 2 must be taken into account as
> > > well.
> > > This patch extends the MPIDR usage to affinity levels 1 and 2 in versatile
> > > secondary cores start up code in order to compare the passed pen_release
> > > value with the full-blown affinity mask.
> > > 
> > > Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> > > Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> > 
> > Note that my b.L series makes this patch obsolete.
> 
> This is needed to boot TC2 in the mainline. Agreed, when the power API
> BSP support for TC2 is merged this can be removed, but waiting for that to
> happen we should fix the current code to enable TC2 in its current state.

Sensible.

Acked-by: Nicolas Pitre <nico@linaro.org>


Nicolas

^ permalink raw reply

* Compilation problem with drivers/staging/zsmalloc when !SMP on ARM
From: Konrad Rzeszutek Wilk @ 2013-01-22 20:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130121152440.GJ23505@n2100.arm.linux.org.uk>

On Mon, Jan 21, 2013 at 03:24:40PM +0000, Russell King - ARM Linux wrote:
> On Fri, Jan 18, 2013 at 11:37:25PM -0500, Konrad Rzeszutek Wilk wrote:
> > On Fri, Jan 18, 2013 at 01:45:27PM -0800, Greg Kroah-Hartman wrote:
> > > On Fri, Jan 18, 2013 at 09:08:59PM +0000, Russell King - ARM Linux wrote:
> > > > On Fri, Jan 18, 2013 at 02:24:15PM -0600, Matt Sealey wrote:
> > > > > Hello all,
> > > > > 
> > > > > I wonder if anyone can shed some light on this linking problem I have
> > > > > right now. If I configure my kernel without SMP support (it is a very
> > > > > lean config for i.MX51 with device tree support only) I hit this error
> > > > > on linking:
> > > > 
> > > > Yes, I looked at this, and I've decided that I will _not_ fix this export,
> > > > neither will I accept a patch to add an export.
> > > > 
> > > > As far as I can see, this code is buggy in a SMP environment.  There's
> > > > apparantly no guarantee that:
> > > > 
> > > > 1. the mapping will be created on a particular CPU.
> > > > 2. the mapping will then be used only on this specific CPU.
> > > > 3. no guarantee that another CPU won't speculatively prefetch from this
> > > >    region.
> > 
> > I thought the code had per_cpu for it - so that you wouldn't do that unless
> > you really went out the way to do it.
> 
> Actually, yes, you're right - that negates point (4) and possibly (2),
> but (3) is still a concern.  (3) shouldn't be that much of an issue
> _provided_ that the virtual addresses aren't explicitly made use of by
> other CPUs.  Is that guaranteed by the zsmalloc code?  (IOW, does it
> own the virtual region it places these mappings in?)

It does own them but it does also hand them off. So the users of it
might be put on a different CPU. I think, I need to trace the call-chain.
> 
> What is the performance difference between having and not having this
> optimization?  Can you provide some measurements please?

Oh boy, there were somewhere.
> 
> Lastly, as you hold per_cpu stuff across this, that means preemption
> is disabled - and any kind of scheduling is also a bug.  Is there
> any reason the kmap stuff can't be used?  Has this been tried?  How
> does it compare numerically with the existing solutions?

It was really dependent on the architecture. On x86 the copying
was superior, but on ARM it was sllow.

^ permalink raw reply

* Compilation problem with drivers/staging/zsmalloc when !SMP on ARM
From: Konrad Rzeszutek Wilk @ 2013-01-22 20:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130121055541.GD3666@blaptop>

> > The initial patch were done on x86. Then Seth did the work to make sure
> > it worked on PPC. Munchin looked on ARM and that is it.
> 
> s/Munchin/Minchan

Thank you. I am sorry for butchering your name.
> 
> > 
> > If you have an ARM server that you would be willing to part with I would
> > be thrilled to look at it.
> > 
> > > 
> > > diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c
> > > b/drivers/staging/zsmalloc/zsmalloc-main.c
> > > index 09a9d35..ecf75fb 100644
> > 	> --- a/drivers/staging/zsmalloc/zsmalloc-main.c
> > > +++ b/drivers/staging/zsmalloc/zsmalloc-main.c
> > > @@ -228,7 +228,7 @@ struct zs_pool {
> > >   * mapping rather than copying
> > >   * for object mapping.
> > >  */
> > > -#if defined(CONFIG_ARM)
> > > +#if defined(CONFIG_ARM) && defined(CONFIG_SMP)
> > >  #define USE_PGTABLE_MAPPING
> 
> I don't get it. How to prevent the problem Russel described?
> The problem is that other CPU can prefetch _speculatively_ under us.

<nods> Not sure either.
> 
> > >  #endif
> > > 
> > > .. such that it even compiles in both "guess" configurations, the
> > > slower Cortex-A8 600MHz single core system gets to use the slow copy
> > > path and the dual-core 1GHz+ Cortex-A9 (with twice the RAM..) gets to
> > > use the fast mapping path. Essentially all the patch does is "improve
> > > performance" on the fastest, best-configured, large-amounts-of-RAM,
> > > lots-of-CPU-performance ARM systems (OMAP4+, Snapdragon, Exynos4+,
> > > marvell armada, i.MX6..) while introducing the problems Russell
> > > describes, and leave performance exactly the same and potentially far
> > > more stable on the slower, memory-limited ARM machines.
> > 
> > Any ideas on how to detect that?
> > > 
> > > Given the purpose of zsmalloc, zram, zcache etc. this somewhat defies
> > > logic. If it's not making the memory-limited, slow ARM systems run
> > > better, what's the point?
> > > 
> > > So in summary I suggest "we" (Greg? or is it Seth's responsibility?)
> > > should just back out that whole USE_PGTABLE_MAPPING chunk of code
> > > introduced with f553646. Then Russell can carry on randconfiging and I
> > > can build for SMP and UP and get the same code.. with less bugs.
> > 
> > I get that you want to have this fixed right now. I think having it
> > fixed the right way is a better choice. Lets discuss that first
> > before we start tossing patches to disable parts of it.
> 
> If I don't miss something, we could have 2 choice.
> 
> 1) use flush_tlb_kernel_range instead of local_flush_tlb_kernel_range
> Or
> 2) use only memory copy
> 
> I guess everybody want 2 because it makes code very simple and maintainable.
> Even, rencently Joonsoo sent optimize patch.
> Look at https://lkml.org/lkml/2013/1/16/68 so zram/zcache effect caused by 2
> would be minimized.
> 
> But please give me the time and I will borrow quad-core embedded target board
> and test 1 on the phone with Seth's benchmark.
> 
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo at vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> 
> -- 
> Kind regards,
> Minchan Kim

^ permalink raw reply

* arm: Kernel failures when several memory banks are used with starting address above 128MB
From: Nicolas Pitre @ 2013-01-22 20:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAHTX3dJZxuoz_0Eaa7QcoK9bF4LdLuWcDcwK3OUKc6qY_0PeuQ@mail.gmail.com>

On Tue, 22 Jan 2013, Michal Simek wrote:

> Hi,
> 
> I have a question regarding to the case where DTS specify one memory bank
> for example <0x0 0x40000000> with CONFIG_ARM_PATCH_PHYS_VIRT=y
> where the kernel can be loaded at a 16MB boundary.
> I was testing it on the 3.8-rc4 on arm zynq.
> 
> 1. If the kernel is loaded within 0 - 127MB memory then the kernel can
> work with the whole
> 1GB memory. It shows that the memory in front of the kernel is also
> available for the kernel.
> 
> 2. If the kernel is loaded on the higher addresses then it fails by
> these error messages.
> "Ignoring RAM at 00000000-3fffffff (vmalloc region overlap).
> Memory policy: ECC disabled, Data cache writeback
> Kernel panic - not syncing: ERROR: Failed to allocate 0x1000 bytes below 0x0."
> 
> 3. If I use several memory banks solution
> for example
> reg = <0 0x10000000 0x10000000 0x30000000>;
> and the kernel is loaded to 0x10008000 then the first memory bank is
> ignored and kernel will boot.
> "Ignoring RAM at 00000000-0fffffff (vmalloc region overlap)." with
> 768MB of memory.
> 
> 4. The next interesting example is description with 3 memory banks.
> reg = <0 0x10000000 0x10000000 0x20000000 0x30000000 0x10000000>;
> which behaves as point 3. It means the first 128MB is ignored and only
> 768MB of ram is available.
> 
> 
> The real question is how the kernel should behave for these situations.
> I would expect that if the kernel is within one memory bank
> then it will use this whole bank
> Or
> I would expect that the memory which is in front of the kernel start address
> will be simple ignored and the kernel will find out which memory bank
> is used and will use it.
> Not just caused kernel panic.
> Or
> Is there any expectation that you have to run the relocatable kernel
> in the first 128MB of the memory
> or changing DTS depending on the kernel position where it is loaded?

There are two kernel config symbols influencing this:

config AUTO_ZRELADDR
        bool "Auto calculation of the decompressed kernel image address"
        depends on !ZBOOT_ROM && !ARCH_U300
        help
          ZRELADDR is the physical address where the decompressed kernel
          image will be placed. If AUTO_ZRELADDR is selected, the address
          will be determined at run-time by masking the current IP with
          0xf8000000. This assumes the zImage being placed in the first 128MB
          from start of memory.

config ARM_PATCH_PHYS_VIRT
        bool "Patch physical to virtual translations at runtime" if EMBEDDED
        default y
        depends on !XIP_KERNEL && MMU
        depends on !ARCH_REALVIEW || !SPARSEMEM
        help
          Patch phys-to-virt and virt-to-phys translation functions at
          boot and module load time according to the position of the
          kernel in system memory.

          This can only be used with non-XIP MMU kernels where the base
          of physical memory is at a 16MB boundary.

          Only disable this option if you know that you do not require
          this feature (eg, building a kernel for a single machine) and
          you need to shrink the kernel to the minimal size.

Of course, the kernel must be loaded at some address within the provided 
RAM information in DT as well.  If you cannot meet those restrictions 
then the corresponding features have to be disabled in your build.


Nicolas

^ permalink raw reply

* [PATCH v2 3/3] arm: omap2: gpmc: add DT bindings for OneNAND
From: Tony Lindgren @ 2013-01-22 20:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CALF0-+XdsKvJJpmxZEYXyhTZksgKRoAJ4TcyPV+G9WUbb7Dt_g@mail.gmail.com>

* Ezequiel Garcia <elezegarcia@gmail.com> [130122 11:46]:
> On Tue, Jan 22, 2013 at 3:27 PM, Tony Lindgren <tony@atomide.com> wrote:
> > * Ezequiel Garcia <elezegarcia@gmail.com> [130122 10:17]:
> >> On Mon, Jan 21, 2013 at 10:32 PM, Daniel Mack <zonque@gmail.com> wrote:
> >> >
> >> > I'm currently far away from my computer and can't prepare a patch for this, sorry. But I think you are right, so please just submit a patch for that, anyone :-)
> >> >
> >>
> >> Ok, I'll try to submit a patch as soon as possible. If anyone wants to
> >> do it instead, fine by me.
> >
> > No please go ahead as it seems that you can easily test it too.
> >
> 
> No problem.
> 
> I now wonder if it's okey to exit upon probe failure.
> In particular, the for_each should be like this:
> 
>         for_each_node_by_name(child, "nand") {
>                 ret = gpmc_probe_nand_child(pdev, child);
>                 if (ret < 0) {
>                         of_node_put(child);
>                         return ret;
>                 }
>         }
> 
> or like this:
> 
>         for_each_node_by_name(child, "nand") {
>                 ret = gpmc_probe_nand_child(pdev, child);
>                 WARN_ON(ret < 0);
>         }
> 
> Ideas?

Well I would return and make sure the resources are freed.

However, if this relates to using bootloader configured values
for the few cases where we don't have the timing information
for calculations available, then just doing a warning is
the way to go.

Regards,

Tony

^ permalink raw reply

* [PATCH 3/6] arm: kconfig: don't select TWD with local timer for Armada 370/XP
From: Rob Herring @ 2013-01-22 20:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201301212044.41865.arnd@arndb.de>

On 01/21/2013 02:44 PM, Arnd Bergmann wrote:

>> On multiplatform kernels where at least one arch has TWD support, it
>> will be included, and where not, it will not.
>>
>> It doesn't seem logical for a feature descriptor (HAVE_ARM_TWD) to
>> rely on greater knowledge of what platforms may or may not support it.
>> If we had to include every platform in that list it would be unwieldy.
> 
> I would expect that all future platforms have ARM_TWD, so the list
> of the platforms that don't is not going to grow much, but the list
> of platforms that do will keep growing.

No, I expect all future platforms will have architected timers. TWD is
pretty much A9 and A5 only I believe. Same with SCU. I've probably
missed some in my list.

Rob

^ permalink raw reply

* [PATCH v5 01/45] percpu_rwlock: Introduce the global reader-writer lock backend
From: Steven Rostedt @ 2013-01-22 20:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <50FEEF5D.6080302@linux.vnet.ibm.com>

On Wed, 2013-01-23 at 01:28 +0530, Srivatsa S. Bhat wrote:

> > I thought global locks are now fair. That is, a reader will block if a
> > writer is waiting. Hence, the above should deadlock on the current
> > rwlock_t types.
> > 
> 
> Oh is it? Last I checked, lockdep didn't complain about this ABBA scenario!

It doesn't and Peter Zijlstra said we need to fix that ;-)  It only
recently became an issue with the new "fair" locking of rwlocks.

-- Steve

^ permalink raw reply

* [PATCH 13/15] USB: ehci: make orion and mxc bus glues coexist
From: Sascha Hauer @ 2013-01-22 21:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201301221538.55975.arnd@arndb.de>

On Tue, Jan 22, 2013 at 03:38:55PM +0000, Arnd Bergmann wrote:
> On Tuesday 22 January 2013, Alan Stern wrote:
> > In order to prevent this, you have to make sure that each glue driver
> > depends on USB_ARCH_HAS_EHCI.  A simple way to do this is to surround
> > the Kconfig entries for those drivers with "if USB && 
> > USB_ARCH_HAS_EHCI" ... "endif".
> 
> I was actually thinking we could remove the use of USB_ARCH_HAS_EHCI
> as well once we have inverted the logic for selecting USB_EHCI_HCD,
> but there is another problem with that, because then we still need
> something to select USB_ARCH_HAS_HCD, or kill that symbol as well.

+1 for killing it. Such symbols get more and more meaningless anyway
with multiarch kernels-

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

^ permalink raw reply

* [PATCH 15/15] staging/omapdrm: don't build on multiplatform
From: Arnd Bergmann @ 2013-01-22 21:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <50FED76B.10801@ti.com>

On Tuesday 22 January 2013, Rob Clark wrote:
> I think it should be safe.. or at least it built fine for multi-plat in 
> the recent past and shouldn't really do anything if there is no omapdss 
> platform device.
> 
> Do you want me to make a patch or are you already doing this?

Please make one. Feel free to reuse my changeset description if needed.

	Arnd

^ permalink raw reply

* [PATCH v3 0/3] Add support for gpio expander pca9505 used on Mirabox
From: Gregory CLEMENT @ 2013-01-22 21:10 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

This patch set adds the support for the i2c gpio expander pca9505 used
on the JTAG/GPIO box which can be connected to the Mirabox.

To be able to use the pca9505 I had to do several changes in the
driver. Indeed, until now the pca953x driver accessed all the bank of
a given register in a single command using only a 32 bits
variable. This expander comes with 40 GPIOs which no more fits in a 32
variable. This patch set makes the accesses to the registers more
generic by relying on an array of u8 variables. This fits exactly the
way the registers are represented in the hardware.

Once the per-bank representation was added, it was easier to introduce
helpers to access to a single register of a bank instead of reading or
writing all the banks for a given register. As the GPIO API allows
only the accesses to a single GPIO at a time there was no point to read
and write all the other banks. Hence it should help to decrease the
latency especially for the pca9505.

However as the block GPIO API from Roland Stigge is incoming I kept
the helpers used to access all the banks in the same time. I had to
make some modifications in the arguments that these functions
received, so it will have a conflict here. Currently my patch set is
based on v3.8-rc4, but I am willing to rebase onto gpio-for-next once
the GPIO block will be merged into it.

After the feedback from Maxime Ripard on the second version, I
continue to abuse of his good will as I didn't get any information on
the Mirabox about the interrupt pin. Thanks to him I managed to fix
the bug related to the interrupt part. Now the IRQ part have been also
validated! Thanks again to Maxime for his help.

I have also updated the branch gpio-pca9505 available at:
https://github.com/MISL-EBU-System-SW/mainline-public.git

Linus, now you can apply the first two patches on your git tree. I
kept your acked-by for the 3rd one, as I didn't change anything for
this one.

Thanks,

Changelog:
V1->V2:

- Fix the way to calculate the shift used to apply to register to
  access a given bank.
- Fix all the pending issue in the IRQ part which appeared once I have
  enable CONFIG_GPIO_PCA953X_IRQ!

V2->V3:

- Rebased on v3.8-rc4
- Fix the interrupt handler and not try to call an handler if there is
  no irq pending on a gpio bank


Gregory CLEMENT (3):
  gpio: pca953x: make the register access by GPIO bank
  gpio: pca953x: add support for pca9505
  arm: mvebu: enable gpio expander over i2c on Mirabox platform

 arch/arm/boot/dts/armada-370-mirabox.dts |   10 ++
 drivers/gpio/gpio-pca953x.c              |  283 +++++++++++++++++++-----------
 2 files changed, 187 insertions(+), 106 deletions(-)

-- 
1.7.9.5

^ permalink raw reply

* [PATCH v3 1/3] gpio: pca953x: make the register access by GPIO bank
From: Gregory CLEMENT @ 2013-01-22 21:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358889025-8530-1-git-send-email-gregory.clement@free-electrons.com>

Until now the pca953x driver accessed all the bank of a given register
in a single command using only a 32 bits variable. New expanders from
the pca53x family come with 40 GPIOs which no more fit in a 32
variable. This patch make access to the registers more generic by
relying on an array of u8 variables. This fits exactly the way the
registers are represented in the hardware.

It also adds helpers to access to a single register of a bank instead
of reading or writing all the banks for a given register.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Tested-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpio/gpio-pca953x.c |  281 +++++++++++++++++++++++++++----------------
 1 file changed, 175 insertions(+), 106 deletions(-)

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index cc102d2..b35ba06 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -71,18 +71,23 @@ static const struct i2c_device_id pca953x_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, pca953x_id);
 
+#define MAX_BANK 5
+#define BANK_SZ 8
+
+#define NBANK(chip) (chip->gpio_chip.ngpio / BANK_SZ)
+
 struct pca953x_chip {
 	unsigned gpio_start;
-	u32 reg_output;
-	u32 reg_direction;
+	u8 reg_output[MAX_BANK];
+	u8 reg_direction[MAX_BANK];
 	struct mutex i2c_lock;
 
 #ifdef CONFIG_GPIO_PCA953X_IRQ
 	struct mutex irq_lock;
-	u32 irq_mask;
-	u32 irq_stat;
-	u32 irq_trig_raise;
-	u32 irq_trig_fall;
+	u8 irq_mask[MAX_BANK];
+	u8 irq_stat[MAX_BANK];
+	u8 irq_trig_raise[MAX_BANK];
+	u8 irq_trig_fall[MAX_BANK];
 	int	 irq_base;
 	struct irq_domain *domain;
 #endif
@@ -93,33 +98,69 @@ struct pca953x_chip {
 	int	chip_type;
 };
 
-static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
+static int pca953x_read_single(struct pca953x_chip *chip, int reg, u32 *val,
+				int off)
+{
+	int ret;
+	int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+	int offset = off / BANK_SZ;
+
+	ret = i2c_smbus_read_byte_data(chip->client,
+				(reg << bank_shift) + offset);
+	*val = ret;
+
+	if (ret < 0) {
+		dev_err(&chip->client->dev, "failed reading register\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pca953x_write_single(struct pca953x_chip *chip, int reg, u32 val,
+				int off)
+{
+	int ret = 0;
+	int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+	int offset = off / BANK_SZ;
+
+	ret = i2c_smbus_write_byte_data(chip->client,
+					(reg << bank_shift) + offset, val);
+
+	if (ret < 0) {
+		dev_err(&chip->client->dev, "failed writing register\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pca953x_write_regs(struct pca953x_chip *chip, int reg, u8 *val)
 {
 	int ret = 0;
 
 	if (chip->gpio_chip.ngpio <= 8)
-		ret = i2c_smbus_write_byte_data(chip->client, reg, val);
-	else if (chip->gpio_chip.ngpio == 24) {
-		cpu_to_le32s(&val);
+		ret = i2c_smbus_write_byte_data(chip->client, reg, *val);
+	else if (chip->gpio_chip.ngpio >= 24) {
+		int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
 		ret = i2c_smbus_write_i2c_block_data(chip->client,
-						(reg << 2) | REG_ADDR_AI,
-						3,
-						(u8 *) &val);
+					(reg << bank_shift) | REG_ADDR_AI,
+					NBANK(chip), val);
 	}
 	else {
 		switch (chip->chip_type) {
 		case PCA953X_TYPE:
 			ret = i2c_smbus_write_word_data(chip->client,
-							reg << 1, val);
+							reg << 1, (u16) *val);
 			break;
 		case PCA957X_TYPE:
 			ret = i2c_smbus_write_byte_data(chip->client, reg << 1,
-							val & 0xff);
+							val[0]);
 			if (ret < 0)
 				break;
 			ret = i2c_smbus_write_byte_data(chip->client,
 							(reg << 1) + 1,
-							(val & 0xff00) >> 8);
+							val[1]);
 			break;
 		}
 	}
@@ -132,26 +173,24 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
 	return 0;
 }
 
-static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
+static int pca953x_read_regs(struct pca953x_chip *chip, int reg, u8 *val)
 {
 	int ret;
 
 	if (chip->gpio_chip.ngpio <= 8) {
 		ret = i2c_smbus_read_byte_data(chip->client, reg);
 		*val = ret;
-	}
-	else if (chip->gpio_chip.ngpio == 24) {
-		*val = 0;
+	} else if (chip->gpio_chip.ngpio >= 24) {
+		int bank_shift = fls((chip->gpio_chip.ngpio - 1) / BANK_SZ);
+
 		ret = i2c_smbus_read_i2c_block_data(chip->client,
-						(reg << 2) | REG_ADDR_AI,
-						3,
-						(u8 *) val);
-		le32_to_cpus(val);
+					(reg << bank_shift) | REG_ADDR_AI,
+					NBANK(chip), val);
 	} else {
 		ret = i2c_smbus_read_word_data(chip->client, reg << 1);
-		*val = ret;
+		val[0] = (u16)ret & 0xFF;
+		val[1] = (u16)ret >> 8;
 	}
-
 	if (ret < 0) {
 		dev_err(&chip->client->dev, "failed reading register\n");
 		return ret;
@@ -163,13 +202,13 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
 static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
 {
 	struct pca953x_chip *chip;
-	uint reg_val;
+	u8 reg_val;
 	int ret, offset = 0;
 
 	chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
 	mutex_lock(&chip->i2c_lock);
-	reg_val = chip->reg_direction | (1u << off);
+	reg_val = chip->reg_direction[off / BANK_SZ] | (1u << (off % BANK_SZ));
 
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
@@ -179,11 +218,11 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
 		offset = PCA957X_CFG;
 		break;
 	}
-	ret = pca953x_write_reg(chip, offset, reg_val);
+	ret = pca953x_write_single(chip, offset, reg_val, off);
 	if (ret)
 		goto exit;
 
-	chip->reg_direction = reg_val;
+	chip->reg_direction[off / BANK_SZ] = reg_val;
 	ret = 0;
 exit:
 	mutex_unlock(&chip->i2c_lock);
@@ -194,7 +233,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 		unsigned off, int val)
 {
 	struct pca953x_chip *chip;
-	uint reg_val;
+	u8 reg_val;
 	int ret, offset = 0;
 
 	chip = container_of(gc, struct pca953x_chip, gpio_chip);
@@ -202,9 +241,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 	mutex_lock(&chip->i2c_lock);
 	/* set output level */
 	if (val)
-		reg_val = chip->reg_output | (1u << off);
+		reg_val = chip->reg_output[off / BANK_SZ]
+			| (1u << (off % BANK_SZ));
 	else
-		reg_val = chip->reg_output & ~(1u << off);
+		reg_val = chip->reg_output[off / BANK_SZ]
+			& ~(1u << (off % BANK_SZ));
 
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
@@ -214,14 +255,14 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 		offset = PCA957X_OUT;
 		break;
 	}
-	ret = pca953x_write_reg(chip, offset, reg_val);
+	ret = pca953x_write_single(chip, offset, reg_val, off);
 	if (ret)
 		goto exit;
 
-	chip->reg_output = reg_val;
+	chip->reg_output[off / BANK_SZ] = reg_val;
 
 	/* then direction */
-	reg_val = chip->reg_direction & ~(1u << off);
+	reg_val = chip->reg_direction[off / BANK_SZ] & ~(1u << (off % BANK_SZ));
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
 		offset = PCA953X_DIRECTION;
@@ -230,11 +271,11 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
 		offset = PCA957X_CFG;
 		break;
 	}
-	ret = pca953x_write_reg(chip, offset, reg_val);
+	ret = pca953x_write_single(chip, offset, reg_val, off);
 	if (ret)
 		goto exit;
 
-	chip->reg_direction = reg_val;
+	chip->reg_direction[off / BANK_SZ] = reg_val;
 	ret = 0;
 exit:
 	mutex_unlock(&chip->i2c_lock);
@@ -258,7 +299,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 		offset = PCA957X_IN;
 		break;
 	}
-	ret = pca953x_read_reg(chip, offset, &reg_val);
+	ret = pca953x_read_single(chip, offset, &reg_val, off);
 	mutex_unlock(&chip->i2c_lock);
 	if (ret < 0) {
 		/* NOTE:  diagnostic already emitted; that's all we should
@@ -274,16 +315,18 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
 static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 {
 	struct pca953x_chip *chip;
-	u32 reg_val;
+	u8 reg_val;
 	int ret, offset = 0;
 
 	chip = container_of(gc, struct pca953x_chip, gpio_chip);
 
 	mutex_lock(&chip->i2c_lock);
 	if (val)
-		reg_val = chip->reg_output | (1u << off);
+		reg_val = chip->reg_output[off / BANK_SZ]
+			| (1u << (off % BANK_SZ));
 	else
-		reg_val = chip->reg_output & ~(1u << off);
+		reg_val = chip->reg_output[off / BANK_SZ]
+			& ~(1u << (off % BANK_SZ));
 
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
@@ -293,11 +336,11 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
 		offset = PCA957X_OUT;
 		break;
 	}
-	ret = pca953x_write_reg(chip, offset, reg_val);
+	ret = pca953x_write_single(chip, offset, reg_val, off);
 	if (ret)
 		goto exit;
 
-	chip->reg_output = reg_val;
+	chip->reg_output[off / BANK_SZ] = reg_val;
 exit:
 	mutex_unlock(&chip->i2c_lock);
 }
@@ -335,14 +378,14 @@ static void pca953x_irq_mask(struct irq_data *d)
 {
 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
 
-	chip->irq_mask &= ~(1 << d->hwirq);
+	chip->irq_mask[d->hwirq / BANK_SZ] &= ~(1 << (d->hwirq % BANK_SZ));
 }
 
 static void pca953x_irq_unmask(struct irq_data *d)
 {
 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
 
-	chip->irq_mask |= 1 << d->hwirq;
+	chip->irq_mask[d->hwirq / BANK_SZ] |= 1 << (d->hwirq % BANK_SZ);
 }
 
 static void pca953x_irq_bus_lock(struct irq_data *d)
@@ -355,17 +398,20 @@ static void pca953x_irq_bus_lock(struct irq_data *d)
 static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 {
 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
-	u32 new_irqs;
-	u32 level;
+	u8 new_irqs;
+	int level, i;
 
 	/* Look for any newly setup interrupt */
-	new_irqs = chip->irq_trig_fall | chip->irq_trig_raise;
-	new_irqs &= ~chip->reg_direction;
-
-	while (new_irqs) {
-		level = __ffs(new_irqs);
-		pca953x_gpio_direction_input(&chip->gpio_chip, level);
-		new_irqs &= ~(1 << level);
+	for (i = 0; i < NBANK(chip); i++) {
+		new_irqs = chip->irq_trig_fall[i] | chip->irq_trig_raise[i];
+		new_irqs &= ~chip->reg_direction[i];
+
+		while (new_irqs) {
+			level = __ffs(new_irqs);
+			pca953x_gpio_direction_input(&chip->gpio_chip,
+							level + (BANK_SZ * i));
+			new_irqs &= ~(1 << level);
+		}
 	}
 
 	mutex_unlock(&chip->irq_lock);
@@ -374,7 +420,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
 static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	struct pca953x_chip *chip = irq_data_get_irq_chip_data(d);
-	u32 mask = 1 << d->hwirq;
+	int bank_nb = d->hwirq / BANK_SZ;
+	u8 mask = 1 << (d->hwirq % BANK_SZ);
 
 	if (!(type & IRQ_TYPE_EDGE_BOTH)) {
 		dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
@@ -383,14 +430,14 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
 	}
 
 	if (type & IRQ_TYPE_EDGE_FALLING)
-		chip->irq_trig_fall |= mask;
+		chip->irq_trig_fall[bank_nb] |= mask;
 	else
-		chip->irq_trig_fall &= ~mask;
+		chip->irq_trig_fall[bank_nb] &= ~mask;
 
 	if (type & IRQ_TYPE_EDGE_RISING)
-		chip->irq_trig_raise |= mask;
+		chip->irq_trig_raise[bank_nb] |= mask;
 	else
-		chip->irq_trig_raise &= ~mask;
+		chip->irq_trig_raise[bank_nb] &= ~mask;
 
 	return 0;
 }
@@ -404,13 +451,13 @@ static struct irq_chip pca953x_irq_chip = {
 	.irq_set_type		= pca953x_irq_set_type,
 };
 
-static u32 pca953x_irq_pending(struct pca953x_chip *chip)
+static u8 pca953x_irq_pending(struct pca953x_chip *chip, u8 *pending)
 {
-	u32 cur_stat;
-	u32 old_stat;
-	u32 pending;
-	u32 trigger;
-	int ret, offset = 0;
+	u8 cur_stat[MAX_BANK];
+	u8 old_stat[MAX_BANK];
+	u8 pendings = 0;
+	u8 trigger[MAX_BANK], triggers = 0;
+	int ret, i, offset = 0;
 
 	switch (chip->chip_type) {
 	case PCA953X_TYPE:
@@ -420,45 +467,54 @@ static u32 pca953x_irq_pending(struct pca953x_chip *chip)
 		offset = PCA957X_IN;
 		break;
 	}
-	ret = pca953x_read_reg(chip, offset, &cur_stat);
+	ret = pca953x_read_regs(chip, offset, cur_stat);
 	if (ret)
 		return 0;
 
 	/* Remove output pins from the equation */
-	cur_stat &= chip->reg_direction;
+	for (i = 0; i < NBANK(chip); i++)
+		cur_stat[i] &= chip->reg_direction[i];
 
-	old_stat = chip->irq_stat;
-	trigger = (cur_stat ^ old_stat) & chip->irq_mask;
+	memcpy(old_stat, chip->irq_stat, NBANK(chip));
 
-	if (!trigger)
+	for (i = 0; i < NBANK(chip); i++) {
+		trigger[i] = (cur_stat[i] ^ old_stat[i]) & chip->irq_mask[i];
+		triggers += trigger[i];
+	}
+
+	if (!triggers)
 		return 0;
 
-	chip->irq_stat = cur_stat;
+	memcpy(chip->irq_stat, cur_stat, NBANK(chip));
 
-	pending = (old_stat & chip->irq_trig_fall) |
-		  (cur_stat & chip->irq_trig_raise);
-	pending &= trigger;
+	for (i = 0; i < NBANK(chip); i++) {
+		pending[i] = (old_stat[i] & chip->irq_trig_fall[i]) |
+			(cur_stat[i] & chip->irq_trig_raise[i]);
+		pending[i] &= trigger[i];
+		pendings += pending[i];
+	}
 
-	return pending;
+	return pendings;
 }
 
 static irqreturn_t pca953x_irq_handler(int irq, void *devid)
 {
 	struct pca953x_chip *chip = devid;
-	u32 pending;
-	u32 level;
-
-	pending = pca953x_irq_pending(chip);
+	u8 pending[MAX_BANK];
+	u8 level;
+	int i;
 
-	if (!pending)
+	if (!pca953x_irq_pending(chip, pending))
 		return IRQ_HANDLED;
 
-	do {
-		level = __ffs(pending);
-		handle_nested_irq(irq_find_mapping(chip->domain, level));
-
-		pending &= ~(1 << level);
-	} while (pending);
+	for (i = 0; i < NBANK(chip); i++) {
+		while (pending[i]) {
+			level = __ffs(pending[i]);
+			handle_nested_irq(irq_find_mapping(chip->domain,
+							level + (BANK_SZ * i)));
+			pending[i] &= ~(1 << level);
+		}
+	}
 
 	return IRQ_HANDLED;
 }
@@ -468,8 +524,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 			     int irq_base)
 {
 	struct i2c_client *client = chip->client;
-	int ret, offset = 0;
-	u32 temporary;
+	int ret, i, offset = 0;
 
 	if (irq_base != -1
 			&& (id->driver_data & PCA_INT)) {
@@ -483,8 +538,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 			offset = PCA957X_IN;
 			break;
 		}
-		ret = pca953x_read_reg(chip, offset, &temporary);
-		chip->irq_stat = temporary;
+		ret = pca953x_read_regs(chip, offset, chip->irq_stat);
 		if (ret)
 			goto out_failed;
 
@@ -493,7 +547,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
 		 * interrupt.  We have to rely on the previous read for
 		 * this purpose.
 		 */
-		chip->irq_stat &= chip->reg_direction;
+		for (i = 0; i < NBANK(chip); i++)
+			chip->irq_stat[i] &= chip->reg_direction[i];
 		mutex_init(&chip->irq_lock);
 
 		chip->irq_base = irq_alloc_descs(-1, irq_base, chip->gpio_chip.ngpio, -1);
@@ -619,18 +674,24 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert)
 static int device_pca953x_init(struct pca953x_chip *chip, u32 invert)
 {
 	int ret;
+	u8 val[MAX_BANK];
 
-	ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output);
+	ret = pca953x_read_regs(chip, PCA953X_OUTPUT, chip->reg_output);
 	if (ret)
 		goto out;
 
-	ret = pca953x_read_reg(chip, PCA953X_DIRECTION,
-			       &chip->reg_direction);
+	ret = pca953x_read_regs(chip, PCA953X_DIRECTION,
+			       chip->reg_direction);
 	if (ret)
 		goto out;
 
 	/* set platform specific polarity inversion */
-	ret = pca953x_write_reg(chip, PCA953X_INVERT, invert);
+	if (invert)
+		memset(val, 0xFF, NBANK(chip));
+	else
+		memset(val, 0, NBANK(chip));
+
+	ret = pca953x_write_regs(chip, PCA953X_INVERT, val);
 out:
 	return ret;
 }
@@ -638,28 +699,36 @@ out:
 static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
 {
 	int ret;
-	u32 val = 0;
+	u8 val[MAX_BANK];
 
 	/* Let every port in proper state, that could save power */
-	pca953x_write_reg(chip, PCA957X_PUPD, 0x0);
-	pca953x_write_reg(chip, PCA957X_CFG, 0xffff);
-	pca953x_write_reg(chip, PCA957X_OUT, 0x0);
-
-	ret = pca953x_read_reg(chip, PCA957X_IN, &val);
+	memset(val, 0, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_PUPD, val);
+	memset(val, 0xFF, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_CFG, val);
+	memset(val, 0, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_OUT, val);
+
+	ret = pca953x_read_regs(chip, PCA957X_IN, val);
 	if (ret)
 		goto out;
-	ret = pca953x_read_reg(chip, PCA957X_OUT, &chip->reg_output);
+	ret = pca953x_read_regs(chip, PCA957X_OUT, chip->reg_output);
 	if (ret)
 		goto out;
-	ret = pca953x_read_reg(chip, PCA957X_CFG, &chip->reg_direction);
+	ret = pca953x_read_regs(chip, PCA957X_CFG, chip->reg_direction);
 	if (ret)
 		goto out;
 
 	/* set platform specific polarity inversion */
-	pca953x_write_reg(chip, PCA957X_INVRT, invert);
+	if (invert)
+		memset(val, 0xFF, NBANK(chip));
+	else
+		memset(val, 0, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_INVRT, val);
 
 	/* To enable register 6, 7 to controll pull up and pull down */
-	pca953x_write_reg(chip, PCA957X_BKEN, 0x202);
+	memset(val, 0x02, NBANK(chip));
+	pca953x_write_regs(chip, PCA957X_BKEN, val);
 
 	return 0;
 out:
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v3 2/3] gpio: pca953x: add support for pca9505
From: Gregory CLEMENT @ 2013-01-22 21:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358889025-8530-1-git-send-email-gregory.clement@free-electrons.com>

Now that pca953x driver can handle GPIO expanders with more than 32
bits this patch adds the support for the pca9505 which cam with 40
GPIOs.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 drivers/gpio/gpio-pca953x.c |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index b35ba06..3a68aed 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -46,6 +46,7 @@
 #define PCA957X_TYPE		0x2000
 
 static const struct i2c_device_id pca953x_id[] = {
+	{ "pca9505", 40 | PCA953X_TYPE | PCA_INT, },
 	{ "pca9534", 8  | PCA953X_TYPE | PCA_INT, },
 	{ "pca9535", 16 | PCA953X_TYPE | PCA_INT, },
 	{ "pca9536", 4  | PCA953X_TYPE, },
@@ -835,6 +836,7 @@ static int pca953x_remove(struct i2c_client *client)
 }
 
 static const struct of_device_id pca953x_dt_ids[] = {
+	{ .compatible = "nxp,pca9505", },
 	{ .compatible = "nxp,pca9534", },
 	{ .compatible = "nxp,pca9535", },
 	{ .compatible = "nxp,pca9536", },
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH v3 3/3] arm: mvebu: enable gpio expander over i2c on Mirabox platform
From: Gregory CLEMENT @ 2013-01-22 21:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358889025-8530-1-git-send-email-gregory.clement@free-electrons.com>

The Globalscale Mirabox platform can be connected to the JTAG/GPIO box
through the Multi-IO port. The GPIO box use the NXP PCA9505 I/O port
expansion IC to provide 40-bit parallel input/output GPIOs. This patch
enable the use of this expander on the Mirabox.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
---
 arch/arm/boot/dts/armada-370-mirabox.dts |   10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/armada-370-mirabox.dts b/arch/arm/boot/dts/armada-370-mirabox.dts
index 3b40713..d9b32d3 100644
--- a/arch/arm/boot/dts/armada-370-mirabox.dts
+++ b/arch/arm/boot/dts/armada-370-mirabox.dts
@@ -52,5 +52,15 @@
 			phy = <&phy1>;
 			phy-mode = "rgmii-id";
 		};
+		i2c at d0011000 {
+			status = "okay";
+			clock-frequency = <100000>;
+			pca9505: pca9505 at 25 {
+				compatible = "nxp,pca9505";
+				gpio-controller;
+				#gpio-cells = <2>;
+				reg = <0x25>;
+			};
+		};
 	};
 };
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 3/6] arm: kconfig: don't select TWD with local timer for Armada 370/XP
From: Arnd Bergmann @ 2013-01-22 21:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <50FEFAB9.4030503@gmail.com>

On Tuesday 22 January 2013, Rob Herring wrote:
> No, I expect all future platforms will have architected timers. TWD is
> pretty much A9 and A5 only I believe. Same with SCU. I've probably
> missed some in my list.

Ah, I was incorrectly assuming that TWD was referring to the architected
timers, sorry about that.

Maybe we should do this differently then and do the more logical

config LOCAL_TIMERS
	bool

config ARM_TWD
	bool "ARM TWD local timer"
	depends on SMP && CPU_V7
	select LOCAL_TIMERS

config EXYNOS4_MCT
	bool "Samsung Exynos4 MCT Timer"
	depends on SMP && ARCH_EXYNOS
	select LOCAL_TIMERS

config MSM_LOCAL_TIMER
	bool "Qualcomm MSM Local Timer"
	depends on SMP && ARCH_MSM
	select LOCAL_TIMERS

That way we have no implicit assumptions. Everything will still work if you
disable local timers, but of course we will enable them in the defconfigs.

	Arnd

^ permalink raw reply

* [PATCH 14/15] samples/seccomp: be less stupid about cross compiling
From: Kees Cook @ 2013-01-22 21:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358788568-11137-15-git-send-email-arnd@arndb.de>

On Mon, Jan 21, 2013 at 9:16 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> The seccomp filters are currently built for the build
> host, not for the machine that they are going to run
> on, but they are also built for with the -m32 flag
> if the kernel is built for a 32 bit machine, both
> of which seems rather odd.
>
> It broke allyesconfig on my machine, which is x86-64, but
> building for 32 bit ARM, with this error message:
>
> In file included from /usr/include/stdio.h:28:0,
>                  from samples/seccomp/bpf-fancy.c:15:
> /usr/include/features.h:324:26: fatal error: bits/predefs.h: No such file or directory
>
> because there are no 32 bit libc headers installed on
> this machine. We should really be building all the
> samples for the target machine rather than the build
> host, but since the infrastructure for that appears
> to be missing right now, let's be a little bit smarter
> and not pass the '-m32' flag to the HOSTCC when cross-
> compiling.
>
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
> Cc: Kees Cook <keescook@chromium.org>
> Cc: James Morris <james.l.morris@oracle.com>

I'm fine with this. Thanks!

Acked-by: Kees Cook <keescook@chromium.org>

-Kees

> ---
>  samples/seccomp/Makefile |    2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/samples/seccomp/Makefile b/samples/seccomp/Makefile
> index bbbd276..7203e66 100644
> --- a/samples/seccomp/Makefile
> +++ b/samples/seccomp/Makefile
> @@ -19,6 +19,7 @@ bpf-direct-objs := bpf-direct.o
>
>  # Try to match the kernel target.
>  ifndef CONFIG_64BIT
> +ifndef CROSS_COMPILE
>
>  # s390 has -m31 flag to build 31 bit binaries
>  ifndef CONFIG_S390
> @@ -35,6 +36,7 @@ HOSTLOADLIBES_bpf-direct += $(MFLAG)
>  HOSTLOADLIBES_bpf-fancy += $(MFLAG)
>  HOSTLOADLIBES_dropper += $(MFLAG)
>  endif
> +endif
>
>  # Tell kbuild to always build the programs
>  always := $(hostprogs-y)
> --
> 1.7.10.4
>



--
Kees Cook
Chrome OS Security

^ permalink raw reply

* [PATCH V5 1/3] clk: tegra: add Tegra specific clocks
From: Mike Turquette @ 2013-01-22 21:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358369575-7325-1-git-send-email-swarren@wwwdotorg.org>

Quoting Stephen Warren (2013-01-16 12:52:53)
> From: Prashant Gaikwad <pgaikwad@nvidia.com>
> 
> Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
> 
> Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
> [swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
> storing pointers to stack variables, make a timeout loop more idiomatic,
> use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
> avoid redundant lock operations, unified tegra_clk_periph() and
> tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
> registration functions so they don't have the same name as the clock
> structs.]
> Signed-off-by: Stephen Warren <swarren@nvidia.com>
> ---
> V5: Implemented all changes marked [swarren] in the commit descriptions.
> 
> Mike, These patches depend on a couple patches in the Tegra tree, and
> various other Tegra patches depend on them. I'd like to take these through
> the Tegra tree. Can you please ack or otherwise OK this? Thanks.
> 

For the series, including the updated v6 patch 2/3:

Acked-by: Mike Turquette <mturquette@linaro.org>

>  drivers/clk/Makefile                |    1 +
>  drivers/clk/tegra/Makefile          |    8 +
>  drivers/clk/tegra/clk-audio-sync.c  |   87 +++++
>  drivers/clk/tegra/clk-divider.c     |  187 ++++++++++
>  drivers/clk/tegra/clk-periph-gate.c |  179 ++++++++++
>  drivers/clk/tegra/clk-periph.c      |  180 ++++++++++
>  drivers/clk/tegra/clk-pll-out.c     |  123 +++++++
>  drivers/clk/tegra/clk-pll.c         |  648 +++++++++++++++++++++++++++++++++++
>  drivers/clk/tegra/clk-super.c       |  154 +++++++++
>  drivers/clk/tegra/clk.c             |   69 ++++
>  drivers/clk/tegra/clk.h             |  490 ++++++++++++++++++++++++++
>  11 files changed, 2126 insertions(+)
>  create mode 100644 drivers/clk/tegra/Makefile
>  create mode 100644 drivers/clk/tegra/clk-audio-sync.c
>  create mode 100644 drivers/clk/tegra/clk-divider.c
>  create mode 100644 drivers/clk/tegra/clk-periph-gate.c
>  create mode 100644 drivers/clk/tegra/clk-periph.c
>  create mode 100644 drivers/clk/tegra/clk-pll-out.c
>  create mode 100644 drivers/clk/tegra/clk-pll.c
>  create mode 100644 drivers/clk/tegra/clk-super.c
>  create mode 100644 drivers/clk/tegra/clk.c
>  create mode 100644 drivers/clk/tegra/clk.h
> 
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index ee90e87..f0b269a 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -22,6 +22,7 @@ obj-$(CONFIG_ARCH_U8500)      += ux500/
>  obj-$(CONFIG_ARCH_VT8500)      += clk-vt8500.o
>  obj-$(CONFIG_ARCH_SUNXI)       += clk-sunxi.o
>  obj-$(CONFIG_ARCH_ZYNQ)                += clk-zynq.o
> +obj-$(CONFIG_ARCH_TEGRA)       += tegra/
>  
>  # Chip specific
>  obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
> diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
> new file mode 100644
> index 0000000..68bd353
> --- /dev/null
> +++ b/drivers/clk/tegra/Makefile
> @@ -0,0 +1,8 @@
> +obj-y                                  += clk.o
> +obj-y                                  += clk-audio-sync.o
> +obj-y                                  += clk-divider.o
> +obj-y                                  += clk-periph.o
> +obj-y                                  += clk-periph-gate.o
> +obj-y                                  += clk-pll.o
> +obj-y                                  += clk-pll-out.o
> +obj-y                                  += clk-super.o
> diff --git a/drivers/clk/tegra/clk-audio-sync.c b/drivers/clk/tegra/clk-audio-sync.c
> new file mode 100644
> index 0000000..c0f7843
> --- /dev/null
> +++ b/drivers/clk/tegra/clk-audio-sync.c
> @@ -0,0 +1,87 @@
> +/*
> + * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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/clk-provider.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +
> +#include "clk.h"
> +
> +static unsigned long clk_sync_source_recalc_rate(struct clk_hw *hw,
> +                                                unsigned long parent_rate)
> +{
> +       struct tegra_clk_sync_source *sync = to_clk_sync_source(hw);
> +
> +       return sync->rate;
> +}
> +
> +static long clk_sync_source_round_rate(struct clk_hw *hw, unsigned long rate,
> +                                      unsigned long *prate)
> +{
> +       struct tegra_clk_sync_source *sync = to_clk_sync_source(hw);
> +
> +       if (rate > sync->max_rate)
> +               return -EINVAL;
> +       else
> +               return rate;
> +}
> +
> +static int clk_sync_source_set_rate(struct clk_hw *hw, unsigned long rate,
> +                                   unsigned long parent_rate)
> +{
> +       struct tegra_clk_sync_source *sync = to_clk_sync_source(hw);
> +
> +       sync->rate = rate;
> +       return 0;
> +}
> +
> +const struct clk_ops tegra_clk_sync_source_ops = {
> +       .round_rate = clk_sync_source_round_rate,
> +       .set_rate = clk_sync_source_set_rate,
> +       .recalc_rate = clk_sync_source_recalc_rate,
> +};
> +
> +struct clk *tegra_clk_register_sync_source(const char *name,
> +               unsigned long rate, unsigned long max_rate)
> +{
> +       struct tegra_clk_sync_source *sync;
> +       struct clk_init_data init;
> +       struct clk *clk;
> +
> +       sync = kzalloc(sizeof(*sync), GFP_KERNEL);
> +       if (!sync) {
> +               pr_err("%s: could not allocate sync source clk\n", __func__);
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       sync->rate = rate;
> +       sync->max_rate = max_rate;
> +
> +       init.ops = &tegra_clk_sync_source_ops;
> +       init.name = name;
> +       init.flags = CLK_IS_ROOT;
> +       init.parent_names = NULL;
> +       init.num_parents = 0;
> +
> +       /* Data in .init is copied by clk_register(), so stack variable OK */
> +       sync->hw.init = &init;
> +
> +       clk = clk_register(NULL, &sync->hw);
> +       if (IS_ERR(clk))
> +               kfree(sync);
> +
> +       return clk;
> +}
> diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
> new file mode 100644
> index 0000000..4d75b1f
> --- /dev/null
> +++ b/drivers/clk/tegra/clk-divider.c
> @@ -0,0 +1,187 @@
> +/*
> + * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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/kernel.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include <linux/slab.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clk.h>
> +
> +#include "clk.h"
> +
> +#define pll_out_override(p) (BIT((p->shift - 6)))
> +#define div_mask(d) ((1 << (d->width)) - 1)
> +#define get_mul(d) (1 << d->frac_width)
> +#define get_max_div(d) div_mask(d)
> +
> +#define PERIPH_CLK_UART_DIV_ENB BIT(24)
> +
> +static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate,
> +                  unsigned long parent_rate)
> +{
> +       s64 divider_ux1 = parent_rate;
> +       u8 flags = divider->flags;
> +       int mul;
> +
> +       if (!rate)
> +               return 0;
> +
> +       mul = get_mul(divider);
> +
> +       if (!(flags & TEGRA_DIVIDER_INT))
> +               divider_ux1 *= mul;
> +
> +       if (flags & TEGRA_DIVIDER_ROUND_UP)
> +               divider_ux1 += rate - 1;
> +
> +       do_div(divider_ux1, rate);
> +
> +       if (flags & TEGRA_DIVIDER_INT)
> +               divider_ux1 *= mul;
> +
> +       divider_ux1 -= mul;
> +
> +       if (divider_ux1 < 0)
> +               return 0;
> +
> +       if (divider_ux1 > get_max_div(divider))
> +               return -EINVAL;
> +
> +       return divider_ux1;
> +}
> +
> +static unsigned long clk_frac_div_recalc_rate(struct clk_hw *hw,
> +                                            unsigned long parent_rate)
> +{
> +       struct tegra_clk_frac_div *divider = to_clk_frac_div(hw);
> +       u32 reg;
> +       int div, mul;
> +       u64 rate = parent_rate;
> +
> +       reg = readl_relaxed(divider->reg) >> divider->shift;
> +       div = reg & div_mask(divider);
> +
> +       mul = get_mul(divider);
> +       div += mul;
> +
> +       rate *= mul;
> +       rate += div - 1;
> +       do_div(rate, div);
> +
> +       return rate;
> +}
> +
> +static long clk_frac_div_round_rate(struct clk_hw *hw, unsigned long rate,
> +                                  unsigned long *prate)
> +{
> +       struct tegra_clk_frac_div *divider = to_clk_frac_div(hw);
> +       int div, mul;
> +       unsigned long output_rate = *prate;
> +
> +       if (!rate)
> +               return output_rate;
> +
> +       div = get_div(divider, rate, output_rate);
> +       if (div < 0)
> +               return *prate;
> +
> +       mul = get_mul(divider);
> +
> +       return DIV_ROUND_UP(output_rate * mul, div + mul);
> +}
> +
> +static int clk_frac_div_set_rate(struct clk_hw *hw, unsigned long rate,
> +                               unsigned long parent_rate)
> +{
> +       struct tegra_clk_frac_div *divider = to_clk_frac_div(hw);
> +       int div;
> +       unsigned long flags = 0;
> +       u32 val;
> +
> +       div = get_div(divider, rate, parent_rate);
> +       if (div < 0)
> +               return div;
> +
> +       if (divider->lock)
> +               spin_lock_irqsave(divider->lock, flags);
> +
> +       val = readl_relaxed(divider->reg);
> +       val &= ~(div_mask(divider) << divider->shift);
> +       val |= div << divider->shift;
> +
> +       if (divider->flags & TEGRA_DIVIDER_UART) {
> +               if (div)
> +                       val |= PERIPH_CLK_UART_DIV_ENB;
> +               else
> +                       val &= ~PERIPH_CLK_UART_DIV_ENB;
> +       }
> +
> +       if (divider->flags & TEGRA_DIVIDER_FIXED)
> +               val |= pll_out_override(divider);
> +
> +       writel_relaxed(val, divider->reg);
> +
> +       if (divider->lock)
> +               spin_unlock_irqrestore(divider->lock, flags);
> +
> +       return 0;
> +}
> +
> +const struct clk_ops tegra_clk_frac_div_ops = {
> +       .recalc_rate = clk_frac_div_recalc_rate,
> +       .set_rate = clk_frac_div_set_rate,
> +       .round_rate = clk_frac_div_round_rate,
> +};
> +
> +struct clk *tegra_clk_register_divider(const char *name,
> +               const char *parent_name, void __iomem *reg,
> +               unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width,
> +               u8 frac_width, spinlock_t *lock)
> +{
> +       struct tegra_clk_frac_div *divider;
> +       struct clk *clk;
> +       struct clk_init_data init;
> +
> +       divider = kzalloc(sizeof(*divider), GFP_KERNEL);
> +       if (!divider) {
> +               pr_err("%s: could not allocate fractional divider clk\n",
> +                      __func__);
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       init.name = name;
> +       init.ops = &tegra_clk_frac_div_ops;
> +       init.flags = flags;
> +       init.parent_names = parent_name ? &parent_name : NULL;
> +       init.num_parents = parent_name ? 1 : 0;
> +
> +       divider->reg = reg;
> +       divider->shift = shift;
> +       divider->width = width;
> +       divider->frac_width = frac_width;
> +       divider->lock = lock;
> +       divider->flags = clk_divider_flags;
> +
> +       /* Data in .init is copied by clk_register(), so stack variable OK */
> +       divider->hw.init = &init;
> +
> +       clk = clk_register(NULL, &divider->hw);
> +       if (IS_ERR(clk))
> +               kfree(divider);
> +
> +       return clk;
> +}
> diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c
> new file mode 100644
> index 0000000..6dd5332
> --- /dev/null
> +++ b/drivers/clk/tegra/clk-periph-gate.c
> @@ -0,0 +1,179 @@
> +/*
> + * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/slab.h>
> +#include <linux/io.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/tegra-soc.h>
> +
> +#include "clk.h"
> +
> +static DEFINE_SPINLOCK(periph_ref_lock);
> +
> +/* Macros to assist peripheral gate clock */
> +#define read_enb(gate) \
> +       readl_relaxed(gate->clk_base + (gate->regs->enb_reg))
> +#define write_enb_set(val, gate) \
> +       writel_relaxed(val, gate->clk_base + (gate->regs->enb_set_reg))
> +#define write_enb_clr(val, gate) \
> +       writel_relaxed(val, gate->clk_base + (gate->regs->enb_clr_reg))
> +
> +#define read_rst(gate) \
> +       readl_relaxed(gate->clk_base + (gate->regs->rst_reg))
> +#define write_rst_set(val, gate) \
> +       writel_relaxed(val, gate->clk_base + (gate->regs->rst_set_reg))
> +#define write_rst_clr(val, gate) \
> +       writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg))
> +
> +#define periph_clk_to_bit(periph) (1 << (gate->clk_num % 32))
> +
> +/* Peripheral gate clock ops */
> +static int clk_periph_is_enabled(struct clk_hw *hw)
> +{
> +       struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
> +       int state = 1;
> +
> +       if (!(read_enb(gate) & periph_clk_to_bit(gate)))
> +               state = 0;
> +
> +       if (!(gate->flags & TEGRA_PERIPH_NO_RESET))
> +               if (read_rst(gate) & periph_clk_to_bit(gate))
> +                       state = 0;
> +
> +       return state;
> +}
> +
> +static int clk_periph_enable(struct clk_hw *hw)
> +{
> +       struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
> +       unsigned long flags = 0;
> +
> +       spin_lock_irqsave(&periph_ref_lock, flags);
> +
> +       gate->enable_refcnt[gate->clk_num]++;
> +       if (gate->enable_refcnt[gate->clk_num] > 1) {
> +               spin_unlock_irqrestore(&periph_ref_lock, flags);
> +               return 0;
> +       }
> +
> +       write_enb_set(periph_clk_to_bit(gate), gate);
> +       udelay(2);
> +
> +       if (!(gate->flags & TEGRA_PERIPH_NO_RESET) &&
> +           !(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) {
> +               if (read_rst(gate) & periph_clk_to_bit(gate)) {
> +                       udelay(5); /* reset propogation delay */
> +                       write_rst_clr(periph_clk_to_bit(gate), gate);
> +               }
> +       }
> +
> +       spin_unlock_irqrestore(&periph_ref_lock, flags);
> +
> +       return 0;
> +}
> +
> +static void clk_periph_disable(struct clk_hw *hw)
> +{
> +       struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
> +       unsigned long flags = 0;
> +
> +       spin_lock_irqsave(&periph_ref_lock, flags);
> +
> +       gate->enable_refcnt[gate->clk_num]--;
> +       if (gate->enable_refcnt[gate->clk_num] > 0) {
> +               spin_unlock_irqrestore(&periph_ref_lock, flags);
> +               return;
> +       }
> +
> +       /*
> +        * If peripheral is in the APB bus then read the APB bus to
> +        * flush the write operation in apb bus. This will avoid the
> +        * peripheral access after disabling clock
> +        */
> +       if (gate->flags & TEGRA_PERIPH_ON_APB)
> +               tegra_read_chipid();
> +
> +       write_enb_clr(periph_clk_to_bit(gate), gate);
> +
> +       spin_unlock_irqrestore(&periph_ref_lock, flags);
> +}
> +
> +void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert)
> +{
> +       if (gate->flags & TEGRA_PERIPH_NO_RESET)
> +               return;
> +
> +       if (assert) {
> +               /*
> +                * If peripheral is in the APB bus then read the APB bus to
> +                * flush the write operation in apb bus. This will avoid the
> +                * peripheral access after disabling clock
> +                */
> +               if (gate->flags & TEGRA_PERIPH_ON_APB)
> +                       tegra_read_chipid();
> +
> +               write_rst_set(periph_clk_to_bit(gate), gate);
> +       } else {
> +               write_rst_clr(periph_clk_to_bit(gate), gate);
> +       }
> +}
> +
> +const struct clk_ops tegra_clk_periph_gate_ops = {
> +       .is_enabled = clk_periph_is_enabled,
> +       .enable = clk_periph_enable,
> +       .disable = clk_periph_disable,
> +};
> +
> +struct clk *tegra_clk_register_periph_gate(const char *name,
> +               const char *parent_name, u8 gate_flags, void __iomem *clk_base,
> +               unsigned long flags, int clk_num,
> +               struct tegra_clk_periph_regs *pregs, int *enable_refcnt)
> +{
> +       struct tegra_clk_periph_gate *gate;
> +       struct clk *clk;
> +       struct clk_init_data init;
> +
> +       gate = kzalloc(sizeof(*gate), GFP_KERNEL);
> +       if (!gate) {
> +               pr_err("%s: could not allocate periph gate clk\n", __func__);
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       init.name = name;
> +       init.flags = flags;
> +       init.parent_names = parent_name ? &parent_name : NULL;
> +       init.num_parents = parent_name ? 1 : 0;
> +       init.ops = &tegra_clk_periph_gate_ops;
> +
> +       gate->magic = TEGRA_CLK_PERIPH_GATE_MAGIC;
> +       gate->clk_base = clk_base;
> +       gate->clk_num = clk_num;
> +       gate->flags = gate_flags;
> +       gate->enable_refcnt = enable_refcnt;
> +       gate->regs = pregs;
> +
> +       /* Data in .init is copied by clk_register(), so stack variable OK */
> +       gate->hw.init = &init;
> +
> +       clk = clk_register(NULL, &gate->hw);
> +       if (IS_ERR(clk))
> +               kfree(gate);
> +
> +       return clk;
> +}
> diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
> new file mode 100644
> index 0000000..5978e81
> --- /dev/null
> +++ b/drivers/clk/tegra/clk-periph.c
> @@ -0,0 +1,180 @@
> +/*
> + * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +
> +#include "clk.h"
> +
> +static u8 clk_periph_get_parent(struct clk_hw *hw)
> +{
> +       struct tegra_clk_periph *periph = to_clk_periph(hw);
> +       const struct clk_ops *mux_ops = periph->mux_ops;
> +       struct clk_hw *mux_hw = &periph->mux.hw;
> +
> +       mux_hw->clk = hw->clk;
> +
> +       return mux_ops->get_parent(mux_hw);
> +}
> +
> +static int clk_periph_set_parent(struct clk_hw *hw, u8 index)
> +{
> +       struct tegra_clk_periph *periph = to_clk_periph(hw);
> +       const struct clk_ops *mux_ops = periph->mux_ops;
> +       struct clk_hw *mux_hw = &periph->mux.hw;
> +
> +       mux_hw->clk = hw->clk;
> +
> +       return mux_ops->set_parent(mux_hw, index);
> +}
> +
> +static unsigned long clk_periph_recalc_rate(struct clk_hw *hw,
> +                                           unsigned long parent_rate)
> +{
> +       struct tegra_clk_periph *periph = to_clk_periph(hw);
> +       const struct clk_ops *div_ops = periph->div_ops;
> +       struct clk_hw *div_hw = &periph->divider.hw;
> +
> +       div_hw->clk = hw->clk;
> +
> +       return div_ops->recalc_rate(div_hw, parent_rate);
> +}
> +
> +static long clk_periph_round_rate(struct clk_hw *hw, unsigned long rate,
> +                                 unsigned long *prate)
> +{
> +       struct tegra_clk_periph *periph = to_clk_periph(hw);
> +       const struct clk_ops *div_ops = periph->div_ops;
> +       struct clk_hw *div_hw = &periph->divider.hw;
> +
> +       div_hw->clk = hw->clk;
> +
> +       return div_ops->round_rate(div_hw, rate, prate);
> +}
> +
> +static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate,
> +                              unsigned long parent_rate)
> +{
> +       struct tegra_clk_periph *periph = to_clk_periph(hw);
> +       const struct clk_ops *div_ops = periph->div_ops;
> +       struct clk_hw *div_hw = &periph->divider.hw;
> +
> +       div_hw->clk = hw->clk;
> +
> +       return div_ops->set_rate(div_hw, rate, parent_rate);
> +}
> +
> +static int clk_periph_is_enabled(struct clk_hw *hw)
> +{
> +       struct tegra_clk_periph *periph = to_clk_periph(hw);
> +       const struct clk_ops *gate_ops = periph->gate_ops;
> +       struct clk_hw *gate_hw = &periph->gate.hw;
> +
> +       gate_hw->clk = hw->clk;
> +
> +       return gate_ops->is_enabled(gate_hw);
> +}
> +
> +static int clk_periph_enable(struct clk_hw *hw)
> +{
> +       struct tegra_clk_periph *periph = to_clk_periph(hw);
> +       const struct clk_ops *gate_ops = periph->gate_ops;
> +       struct clk_hw *gate_hw = &periph->gate.hw;
> +
> +       gate_hw->clk = hw->clk;
> +
> +       return gate_ops->enable(gate_hw);
> +}
> +
> +static void clk_periph_disable(struct clk_hw *hw)
> +{
> +       struct tegra_clk_periph *periph = to_clk_periph(hw);
> +       const struct clk_ops *gate_ops = periph->gate_ops;
> +       struct clk_hw *gate_hw = &periph->gate.hw;
> +
> +       gate_ops->disable(gate_hw);
> +}
> +
> +const struct clk_ops tegra_clk_periph_ops = {
> +       .get_parent = clk_periph_get_parent,
> +       .set_parent = clk_periph_set_parent,
> +       .recalc_rate = clk_periph_recalc_rate,
> +       .round_rate = clk_periph_round_rate,
> +       .set_rate = clk_periph_set_rate,
> +       .is_enabled = clk_periph_is_enabled,
> +       .enable = clk_periph_enable,
> +       .disable = clk_periph_disable,
> +};
> +
> +const struct clk_ops tegra_clk_periph_nodiv_ops = {
> +       .get_parent = clk_periph_get_parent,
> +       .set_parent = clk_periph_set_parent,
> +       .is_enabled = clk_periph_is_enabled,
> +       .enable = clk_periph_enable,
> +       .disable = clk_periph_disable,
> +};
> +
> +static struct clk *_tegra_clk_register_periph(const char *name,
> +                       const char **parent_names, int num_parents,
> +                       struct tegra_clk_periph *periph,
> +                       void __iomem *clk_base, u32 offset, bool div)
> +{
> +       struct clk *clk;
> +       struct clk_init_data init;
> +
> +       init.name = name;
> +       init.ops = div ? &tegra_clk_periph_ops : &tegra_clk_periph_nodiv_ops;
> +       init.flags = div ? 0 : CLK_SET_RATE_PARENT;
> +       init.parent_names = parent_names;
> +       init.num_parents = num_parents;
> +
> +       /* Data in .init is copied by clk_register(), so stack variable OK */
> +       periph->hw.init = &init;
> +       periph->magic = TEGRA_CLK_PERIPH_MAGIC;
> +       periph->mux.reg = clk_base + offset;
> +       periph->divider.reg = div ? (clk_base + offset) : NULL;
> +       periph->gate.clk_base = clk_base;
> +
> +       clk = clk_register(NULL, &periph->hw);
> +       if (IS_ERR(clk))
> +               return clk;
> +
> +       periph->mux.hw.clk = clk;
> +       periph->divider.hw.clk = div ? clk : NULL;
> +       periph->gate.hw.clk = clk;
> +
> +       return clk;
> +}
> +
> +struct clk *tegra_clk_register_periph(const char *name,
> +               const char **parent_names, int num_parents,
> +               struct tegra_clk_periph *periph, void __iomem *clk_base,
> +               u32 offset)
> +{
> +       return _tegra_clk_register_periph(name, parent_names, num_parents,
> +                       periph, clk_base, offset, true);
> +}
> +
> +struct clk *tegra_clk_register_periph_nodiv(const char *name,
> +               const char **parent_names, int num_parents,
> +               struct tegra_clk_periph *periph, void __iomem *clk_base,
> +               u32 offset)
> +{
> +       return _tegra_clk_register_periph(name, parent_names, num_parents,
> +                       periph, clk_base, offset, false);
> +}
> diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c
> new file mode 100644
> index 0000000..3598987
> --- /dev/null
> +++ b/drivers/clk/tegra/clk-pll-out.c
> @@ -0,0 +1,123 @@
> +/*
> + * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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/kernel.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include <linux/delay.h>
> +#include <linux/slab.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clk.h>
> +
> +#include "clk.h"
> +
> +#define pll_out_enb(p) (BIT(p->enb_bit_idx))
> +#define pll_out_rst(p) (BIT(p->rst_bit_idx))
> +
> +static int clk_pll_out_is_enabled(struct clk_hw *hw)
> +{
> +       struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
> +       u32 val = readl_relaxed(pll_out->reg);
> +       int state;
> +
> +       state = (val & pll_out_enb(pll_out)) ? 1 : 0;
> +       if (!(val & (pll_out_rst(pll_out))))
> +               state = 0;
> +       return state;
> +}
> +
> +static int clk_pll_out_enable(struct clk_hw *hw)
> +{
> +       struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
> +       unsigned long flags = 0;
> +       u32 val;
> +
> +       if (pll_out->lock)
> +               spin_lock_irqsave(pll_out->lock, flags);
> +
> +       val = readl_relaxed(pll_out->reg);
> +
> +       val |= (pll_out_enb(pll_out) | pll_out_rst(pll_out));
> +
> +       writel_relaxed(val, pll_out->reg);
> +       udelay(2);
> +
> +       if (pll_out->lock)
> +               spin_unlock_irqrestore(pll_out->lock, flags);
> +
> +       return 0;
> +}
> +
> +static void clk_pll_out_disable(struct clk_hw *hw)
> +{
> +       struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
> +       unsigned long flags = 0;
> +       u32 val;
> +
> +       if (pll_out->lock)
> +               spin_lock_irqsave(pll_out->lock, flags);
> +
> +       val = readl_relaxed(pll_out->reg);
> +
> +       val &= ~(pll_out_enb(pll_out) | pll_out_rst(pll_out));
> +
> +       writel_relaxed(val, pll_out->reg);
> +       udelay(2);
> +
> +       if (pll_out->lock)
> +               spin_unlock_irqrestore(pll_out->lock, flags);
> +}
> +
> +const struct clk_ops tegra_clk_pll_out_ops = {
> +       .is_enabled = clk_pll_out_is_enabled,
> +       .enable = clk_pll_out_enable,
> +       .disable = clk_pll_out_disable,
> +};
> +
> +struct clk *tegra_clk_register_pll_out(const char *name,
> +               const char *parent_name, void __iomem *reg, u8 enb_bit_idx,
> +               u8 rst_bit_idx, unsigned long flags, u8 pll_out_flags,
> +               spinlock_t *lock)
> +{
> +       struct tegra_clk_pll_out *pll_out;
> +       struct clk *clk;
> +       struct clk_init_data init;
> +
> +       pll_out = kzalloc(sizeof(*pll_out), GFP_KERNEL);
> +       if (!pll_out)
> +               return ERR_PTR(-ENOMEM);
> +
> +       init.name = name;
> +       init.ops = &tegra_clk_pll_out_ops;
> +       init.parent_names = (parent_name ? &parent_name : NULL);
> +       init.num_parents = (parent_name ? 1 : 0);
> +       init.flags = flags;
> +
> +       pll_out->reg = reg;
> +       pll_out->enb_bit_idx = enb_bit_idx;
> +       pll_out->rst_bit_idx = rst_bit_idx;
> +       pll_out->flags = pll_out_flags;
> +       pll_out->lock = lock;
> +
> +       /* Data in .init is copied by clk_register(), so stack variable OK */
> +       pll_out->hw.init = &init;
> +
> +       clk = clk_register(NULL, &pll_out->hw);
> +       if (IS_ERR(clk))
> +               kfree(pll_out);
> +
> +       return clk;
> +}
> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
> new file mode 100644
> index 0000000..8dff93f
> --- /dev/null
> +++ b/drivers/clk/tegra/clk-pll.c
> @@ -0,0 +1,648 @@
> +/*
> + * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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/slab.h>
> +#include <linux/io.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clk.h>
> +
> +#include "clk.h"
> +
> +#define PLL_BASE_BYPASS BIT(31)
> +#define PLL_BASE_ENABLE BIT(30)
> +#define PLL_BASE_REF_ENABLE BIT(29)
> +#define PLL_BASE_OVERRIDE BIT(28)
> +
> +#define PLL_BASE_DIVP_SHIFT 20
> +#define PLL_BASE_DIVP_WIDTH 3
> +#define PLL_BASE_DIVN_SHIFT 8
> +#define PLL_BASE_DIVN_WIDTH 10
> +#define PLL_BASE_DIVM_SHIFT 0
> +#define PLL_BASE_DIVM_WIDTH 5
> +#define PLLU_POST_DIVP_MASK 0x1
> +
> +#define PLL_MISC_DCCON_SHIFT 20
> +#define PLL_MISC_CPCON_SHIFT 8
> +#define PLL_MISC_CPCON_WIDTH 4
> +#define PLL_MISC_CPCON_MASK ((1 << PLL_MISC_CPCON_WIDTH) - 1)
> +#define PLL_MISC_LFCON_SHIFT 4
> +#define PLL_MISC_LFCON_WIDTH 4
> +#define PLL_MISC_LFCON_MASK ((1 << PLL_MISC_LFCON_WIDTH) - 1)
> +#define PLL_MISC_VCOCON_SHIFT 0
> +#define PLL_MISC_VCOCON_WIDTH 4
> +#define PLL_MISC_VCOCON_MASK ((1 << PLL_MISC_VCOCON_WIDTH) - 1)
> +
> +#define OUT_OF_TABLE_CPCON 8
> +
> +#define PMC_PLLP_WB0_OVERRIDE 0xf8
> +#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE BIT(12)
> +#define PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE BIT(11)
> +
> +#define PLL_POST_LOCK_DELAY 50
> +
> +#define PLLDU_LFCON_SET_DIVN 600
> +
> +#define PLLE_BASE_DIVCML_SHIFT 24
> +#define PLLE_BASE_DIVCML_WIDTH 4
> +#define PLLE_BASE_DIVP_SHIFT 16
> +#define PLLE_BASE_DIVP_WIDTH 7
> +#define PLLE_BASE_DIVN_SHIFT 8
> +#define PLLE_BASE_DIVN_WIDTH 8
> +#define PLLE_BASE_DIVM_SHIFT 0
> +#define PLLE_BASE_DIVM_WIDTH 8
> +
> +#define PLLE_MISC_SETUP_BASE_SHIFT 16
> +#define PLLE_MISC_SETUP_BASE_MASK (0xffff << PLLE_MISC_SETUP_BASE_SHIFT)
> +#define PLLE_MISC_LOCK_ENABLE BIT(9)
> +#define PLLE_MISC_READY BIT(15)
> +#define PLLE_MISC_SETUP_EX_SHIFT 2
> +#define PLLE_MISC_SETUP_EX_MASK (3 << PLLE_MISC_SETUP_EX_SHIFT)
> +#define PLLE_MISC_SETUP_MASK (PLLE_MISC_SETUP_BASE_MASK |      \
> +                             PLLE_MISC_SETUP_EX_MASK)
> +#define PLLE_MISC_SETUP_VALUE (7 << PLLE_MISC_SETUP_BASE_SHIFT)
> +
> +#define PLLE_SS_CTRL 0x68
> +#define PLLE_SS_DISABLE (7 << 10)
> +
> +#define PMC_SATA_PWRGT 0x1ac
> +#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5)
> +#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4)
> +
> +#define pll_readl(offset, p) readl_relaxed(p->clk_base + offset)
> +#define pll_readl_base(p) pll_readl(p->params->base_reg, p)
> +#define pll_readl_misc(p) pll_readl(p->params->misc_reg, p)
> +
> +#define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset)
> +#define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p)
> +#define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p)
> +
> +#define mask(w) ((1 << (w)) - 1)
> +#define divm_mask(p) mask(p->divm_width)
> +#define divn_mask(p) mask(p->divn_width)
> +#define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK :    \
> +                     mask(p->divp_width))
> +
> +#define divm_max(p) (divm_mask(p))
> +#define divn_max(p) (divn_mask(p))
> +#define divp_max(p) (1 << (divp_mask(p)))
> +
> +static void clk_pll_enable_lock(struct tegra_clk_pll *pll)
> +{
> +       u32 val;
> +
> +       if (!(pll->flags & TEGRA_PLL_USE_LOCK))
> +               return;
> +
> +       val = pll_readl_misc(pll);
> +       val |= BIT(pll->params->lock_enable_bit_idx);
> +       pll_writel_misc(val, pll);
> +}
> +
> +static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll,
> +                                void __iomem *lock_addr, u32 lock_bit_idx)
> +{
> +       int i;
> +       u32 val;
> +
> +       if (!(pll->flags & TEGRA_PLL_USE_LOCK)) {
> +               udelay(pll->params->lock_delay);
> +               return 0;
> +       }
> +
> +       for (i = 0; i < pll->params->lock_delay; i++) {
> +               val = readl_relaxed(lock_addr);
> +               if (val & BIT(lock_bit_idx)) {
> +                       udelay(PLL_POST_LOCK_DELAY);
> +                       return 0;
> +               }
> +               udelay(2); /* timeout = 2 * lock time */
> +       }
> +
> +       pr_err("%s: Timed out waiting for pll %s lock\n", __func__,
> +              __clk_get_name(pll->hw.clk));
> +
> +       return -1;
> +}
> +
> +static int clk_pll_is_enabled(struct clk_hw *hw)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +       u32 val;
> +
> +       if (pll->flags & TEGRA_PLLM) {
> +               val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE);
> +               if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)
> +                       return val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE ? 1 : 0;
> +       }
> +
> +       val = pll_readl_base(pll);
> +
> +       return val & PLL_BASE_ENABLE ? 1 : 0;
> +}
> +
> +static int _clk_pll_enable(struct clk_hw *hw)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +       u32 val;
> +
> +       clk_pll_enable_lock(pll);
> +
> +       val = pll_readl_base(pll);
> +       val &= ~PLL_BASE_BYPASS;
> +       val |= PLL_BASE_ENABLE;
> +       pll_writel_base(val, pll);
> +
> +       if (pll->flags & TEGRA_PLLM) {
> +               val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE);
> +               val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
> +               writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE);
> +       }
> +
> +       clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->base_reg,
> +                             pll->params->lock_bit_idx);
> +
> +       return 0;
> +}
> +
> +static void _clk_pll_disable(struct clk_hw *hw)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +       u32 val;
> +
> +       val = pll_readl_base(pll);
> +       val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
> +       pll_writel_base(val, pll);
> +
> +       if (pll->flags & TEGRA_PLLM) {
> +               val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE);
> +               val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE;
> +               writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE);
> +       }
> +}
> +
> +static int clk_pll_enable(struct clk_hw *hw)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +       unsigned long flags = 0;
> +       int ret;
> +
> +       if (pll->lock)
> +               spin_lock_irqsave(pll->lock, flags);
> +
> +       ret = _clk_pll_enable(hw);
> +
> +       if (pll->lock)
> +               spin_unlock_irqrestore(pll->lock, flags);
> +
> +       return ret;
> +}
> +
> +static void clk_pll_disable(struct clk_hw *hw)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +       unsigned long flags = 0;
> +
> +       if (pll->lock)
> +               spin_lock_irqsave(pll->lock, flags);
> +
> +       _clk_pll_disable(hw);
> +
> +       if (pll->lock)
> +               spin_unlock_irqrestore(pll->lock, flags);
> +}
> +
> +static int _get_table_rate(struct clk_hw *hw,
> +                          struct tegra_clk_pll_freq_table *cfg,
> +                          unsigned long rate, unsigned long parent_rate)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +       struct tegra_clk_pll_freq_table *sel;
> +
> +       for (sel = pll->freq_table; sel->input_rate != 0; sel++)
> +               if (sel->input_rate == parent_rate &&
> +                   sel->output_rate == rate)
> +                       break;
> +
> +       if (sel->input_rate == 0)
> +               return -EINVAL;
> +
> +       BUG_ON(sel->p < 1);
> +
> +       cfg->input_rate = sel->input_rate;
> +       cfg->output_rate = sel->output_rate;
> +       cfg->m = sel->m;
> +       cfg->n = sel->n;
> +       cfg->p = sel->p;
> +       cfg->cpcon = sel->cpcon;
> +
> +       return 0;
> +}
> +
> +static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
> +                     unsigned long rate, unsigned long parent_rate)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +       unsigned long cfreq;
> +       u32 p_div = 0;
> +
> +       switch (parent_rate) {
> +       case 12000000:
> +       case 26000000:
> +               cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2000000;
> +               break;
> +       case 13000000:
> +               cfreq = (rate <= 1000000 * 1000) ? 1000000 : 2600000;
> +               break;
> +       case 16800000:
> +       case 19200000:
> +               cfreq = (rate <= 1200000 * 1000) ? 1200000 : 2400000;
> +               break;
> +       case 9600000:
> +       case 28800000:
> +               /*
> +                * PLL_P_OUT1 rate is not listed in PLLA table
> +                */
> +               cfreq = parent_rate/(parent_rate/1000000);
> +               break;
> +       default:
> +               pr_err("%s Unexpected reference rate %lu\n",
> +                      __func__, parent_rate);
> +               BUG();
> +       }
> +
> +       /* Raise VCO to guarantee 0.5% accuracy */
> +       for (cfg->output_rate = rate; cfg->output_rate < 200 * cfreq;
> +            cfg->output_rate <<= 1)
> +               p_div++;
> +
> +       cfg->p = 1 << p_div;
> +       cfg->m = parent_rate / cfreq;
> +       cfg->n = cfg->output_rate / cfreq;
> +       cfg->cpcon = OUT_OF_TABLE_CPCON;
> +
> +       if (cfg->m > divm_max(pll) || cfg->n > divn_max(pll) ||
> +           cfg->p > divp_max(pll) || cfg->output_rate > pll->params->vco_max) {
> +               pr_err("%s: Failed to set %s rate %lu\n",
> +                      __func__, __clk_get_name(hw->clk), rate);
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
> +                       unsigned long rate)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +       unsigned long flags = 0;
> +       u32 divp, val, old_base;
> +       int state;
> +
> +       divp = __ffs(cfg->p);
> +
> +       if (pll->flags & TEGRA_PLLU)
> +               divp ^= 1;
> +
> +       if (pll->lock)
> +               spin_lock_irqsave(pll->lock, flags);
> +
> +       old_base = val = pll_readl_base(pll);
> +       val &= ~((divm_mask(pll) << pll->divm_shift) |
> +                (divn_mask(pll) << pll->divn_shift) |
> +                (divp_mask(pll) << pll->divp_shift));
> +       val |= ((cfg->m << pll->divm_shift) |
> +               (cfg->n << pll->divn_shift) |
> +               (divp << pll->divp_shift));
> +       if (val == old_base) {
> +               if (pll->lock)
> +                       spin_unlock_irqrestore(pll->lock, flags);
> +               return 0;
> +       }
> +
> +       state = clk_pll_is_enabled(hw);
> +
> +       if (state) {
> +               _clk_pll_disable(hw);
> +               val &= ~(PLL_BASE_BYPASS | PLL_BASE_ENABLE);
> +       }
> +       pll_writel_base(val, pll);
> +
> +       if (pll->flags & TEGRA_PLL_HAS_CPCON) {
> +               val = pll_readl_misc(pll);
> +               val &= ~(PLL_MISC_CPCON_MASK << PLL_MISC_CPCON_SHIFT);
> +               val |= cfg->cpcon << PLL_MISC_CPCON_SHIFT;
> +               if (pll->flags & TEGRA_PLL_SET_LFCON) {
> +                       val &= ~(PLL_MISC_LFCON_MASK << PLL_MISC_LFCON_SHIFT);
> +                       if (cfg->n >= PLLDU_LFCON_SET_DIVN)
> +                               val |= 0x1 << PLL_MISC_LFCON_SHIFT;
> +               } else if (pll->flags & TEGRA_PLL_SET_DCCON) {
> +                       val &= ~(0x1 << PLL_MISC_DCCON_SHIFT);
> +                       if (rate >= (pll->params->vco_max >> 1))
> +                               val |= 0x1 << PLL_MISC_DCCON_SHIFT;
> +               }
> +               pll_writel_misc(val, pll);
> +       }
> +
> +       if (pll->lock)
> +               spin_unlock_irqrestore(pll->lock, flags);
> +
> +       if (state)
> +               clk_pll_enable(hw);
> +
> +       return 0;
> +}
> +
> +static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> +                       unsigned long parent_rate)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +       struct tegra_clk_pll_freq_table cfg;
> +
> +       if (pll->flags & TEGRA_PLL_FIXED) {
> +               if (rate != pll->fixed_rate) {
> +                       pr_err("%s: Can not change %s fixed rate %lu to %lu\n",
> +                               __func__, __clk_get_name(hw->clk),
> +                               pll->fixed_rate, rate);
> +                       return -EINVAL;
> +               }
> +               return 0;
> +       }
> +
> +       if (_get_table_rate(hw, &cfg, rate, parent_rate) &&
> +           _calc_rate(hw, &cfg, rate, parent_rate))
> +               return -EINVAL;
> +
> +       return _program_pll(hw, &cfg, rate);
> +}
> +
> +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
> +                       unsigned long *prate)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +       struct tegra_clk_pll_freq_table cfg;
> +       u64 output_rate = *prate;
> +
> +       if (pll->flags & TEGRA_PLL_FIXED)
> +               return pll->fixed_rate;
> +
> +       /* PLLM is used for memory; we do not change rate */
> +       if (pll->flags & TEGRA_PLLM)
> +               return __clk_get_rate(hw->clk);
> +
> +       if (_get_table_rate(hw, &cfg, rate, *prate) &&
> +           _calc_rate(hw, &cfg, rate, *prate))
> +               return -EINVAL;
> +
> +       output_rate *= cfg.n;
> +       do_div(output_rate, cfg.m * cfg.p);
> +
> +       return output_rate;
> +}
> +
> +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
> +                                        unsigned long parent_rate)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +       u32 val = pll_readl_base(pll);
> +       u32 divn = 0, divm = 0, divp = 0;
> +       u64 rate = parent_rate;
> +
> +       if (val & PLL_BASE_BYPASS)
> +               return parent_rate;
> +
> +       if ((pll->flags & TEGRA_PLL_FIXED) && !(val & PLL_BASE_OVERRIDE)) {
> +               struct tegra_clk_pll_freq_table sel;
> +               if (_get_table_rate(hw, &sel, pll->fixed_rate, parent_rate)) {
> +                       pr_err("Clock %s has unknown fixed frequency\n",
> +                              __clk_get_name(hw->clk));
> +                       BUG();
> +               }
> +               return pll->fixed_rate;
> +       }
> +
> +       divp = (val >> pll->divp_shift) & (divp_mask(pll));
> +       if (pll->flags & TEGRA_PLLU)
> +               divp ^= 1;
> +
> +       divn = (val >> pll->divn_shift) & (divn_mask(pll));
> +       divm = (val >> pll->divm_shift) & (divm_mask(pll));
> +       divm *= (1 << divp);
> +
> +       rate *= divn;
> +       do_div(rate, divm);
> +       return rate;
> +}
> +
> +static int clk_plle_training(struct tegra_clk_pll *pll)
> +{
> +       u32 val;
> +       unsigned long timeout;
> +
> +       if (!pll->pmc)
> +               return -ENOSYS;
> +
> +       /*
> +        * PLLE is already disabled, and setup cleared;
> +        * create falling edge on PLLE IDDQ input.
> +        */
> +       val = readl(pll->pmc + PMC_SATA_PWRGT);
> +       val |= PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
> +       writel(val, pll->pmc + PMC_SATA_PWRGT);
> +
> +       val = readl(pll->pmc + PMC_SATA_PWRGT);
> +       val |= PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL;
> +       writel(val, pll->pmc + PMC_SATA_PWRGT);
> +
> +       val = readl(pll->pmc + PMC_SATA_PWRGT);
> +       val &= ~PMC_SATA_PWRGT_PLLE_IDDQ_VALUE;
> +       writel(val, pll->pmc + PMC_SATA_PWRGT);
> +
> +       val = pll_readl_misc(pll);
> +
> +       timeout = jiffies + msecs_to_jiffies(100);
> +       while (1) {
> +               val = pll_readl_misc(pll);
> +               if (val & PLLE_MISC_READY)
> +                       break;
> +               if (time_after(jiffies, timeout)) {
> +                       pr_err("%s: timeout waiting for PLLE\n", __func__);
> +                       return -EBUSY;
> +               }
> +               udelay(300);
> +       }
> +
> +       return 0;
> +}
> +
> +static int clk_plle_enable(struct clk_hw *hw)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +       unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk));
> +       struct tegra_clk_pll_freq_table sel;
> +       u32 val;
> +       int err;
> +
> +       if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate))
> +               return -EBUSY;
> +
> +       clk_pll_disable(hw);
> +
> +       val = pll_readl_misc(pll);
> +       val &= ~(PLLE_MISC_LOCK_ENABLE | PLLE_MISC_SETUP_MASK);
> +       pll_writel_misc(val, pll);
> +
> +       val = pll_readl_misc(pll);
> +       if (!(val & PLLE_MISC_READY)) {
> +               err = clk_plle_training(pll);
> +               if (err)
> +                       return err;
> +       }
> +
> +       if (pll->flags & TEGRA_PLLE_CONFIGURE) {
> +               /* configure dividers */
> +               val = pll_readl_base(pll);
> +               val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll));
> +               val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT);
> +               val |= sel.m << pll->divm_shift;
> +               val |= sel.n << pll->divn_shift;
> +               val |= sel.p << pll->divp_shift;
> +               val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
> +               pll_writel_base(val, pll);
> +       }
> +
> +       val = pll_readl_misc(pll);
> +       val |= PLLE_MISC_SETUP_VALUE;
> +       val |= PLLE_MISC_LOCK_ENABLE;
> +       pll_writel_misc(val, pll);
> +
> +       val = readl(pll->clk_base + PLLE_SS_CTRL);
> +       val |= PLLE_SS_DISABLE;
> +       writel(val, pll->clk_base + PLLE_SS_CTRL);
> +
> +       val |= pll_readl_base(pll);
> +       val |= (PLL_BASE_BYPASS | PLL_BASE_ENABLE);
> +       pll_writel_base(val, pll);
> +
> +       clk_pll_wait_for_lock(pll, pll->clk_base + pll->params->misc_reg,
> +                             pll->params->lock_bit_idx);
> +       return 0;
> +}
> +
> +static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
> +                                        unsigned long parent_rate)
> +{
> +       struct tegra_clk_pll *pll = to_clk_pll(hw);
> +       u32 val = pll_readl_base(pll);
> +       u32 divn = 0, divm = 0, divp = 0;
> +       u64 rate = parent_rate;
> +
> +       divp = (val >> pll->divp_shift) & (divp_mask(pll));
> +       divn = (val >> pll->divn_shift) & (divn_mask(pll));
> +       divm = (val >> pll->divm_shift) & (divm_mask(pll));
> +       divm *= divp;
> +
> +       rate *= divn;
> +       do_div(rate, divm);
> +       return rate;
> +}
> +
> +const struct clk_ops tegra_clk_pll_ops = {
> +       .is_enabled = clk_pll_is_enabled,
> +       .enable = clk_pll_enable,
> +       .disable = clk_pll_disable,
> +       .recalc_rate = clk_pll_recalc_rate,
> +       .round_rate = clk_pll_round_rate,
> +       .set_rate = clk_pll_set_rate,
> +};
> +
> +const struct clk_ops tegra_clk_plle_ops = {
> +       .recalc_rate = clk_plle_recalc_rate,
> +       .is_enabled = clk_pll_is_enabled,
> +       .disable = clk_pll_disable,
> +       .enable = clk_plle_enable,
> +};
> +
> +static struct clk *_tegra_clk_register_pll(const char *name,
> +               const char *parent_name, void __iomem *clk_base,
> +               void __iomem *pmc, unsigned long flags,
> +               unsigned long fixed_rate,
> +               struct tegra_clk_pll_params *pll_params, u8 pll_flags,
> +               struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock,
> +               bool plle)
> +{
> +       struct tegra_clk_pll *pll;
> +       struct clk *clk;
> +       struct clk_init_data init;
> +
> +       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
> +       if (!pll)
> +               return ERR_PTR(-ENOMEM);
> +
> +       init.name = name;
> +       init.ops = plle ? &tegra_clk_plle_ops : &tegra_clk_pll_ops;
> +       init.flags = flags;
> +       init.parent_names = (parent_name ? &parent_name : NULL);
> +       init.num_parents = (parent_name ? 1 : 0);
> +
> +       pll->clk_base = clk_base;
> +       pll->pmc = pmc;
> +
> +       pll->freq_table = freq_table;
> +       pll->params = pll_params;
> +       pll->fixed_rate = fixed_rate;
> +       pll->flags = pll_flags;
> +       pll->lock = lock;
> +
> +       pll->divp_shift = PLL_BASE_DIVP_SHIFT;
> +       pll->divp_width = PLL_BASE_DIVP_WIDTH;
> +       pll->divn_shift = PLL_BASE_DIVN_SHIFT;
> +       pll->divn_width = PLL_BASE_DIVN_WIDTH;
> +       pll->divm_shift = PLL_BASE_DIVM_SHIFT;
> +       pll->divm_width = PLL_BASE_DIVM_WIDTH;
> +
> +       /* Data in .init is copied by clk_register(), so stack variable OK */
> +       pll->hw.init = &init;
> +
> +       clk = clk_register(NULL, &pll->hw);
> +       if (IS_ERR(clk))
> +               kfree(pll);
> +
> +       return clk;
> +}
> +
> +struct clk *tegra_clk_register_pll(const char *name, const char *parent_name,
> +               void __iomem *clk_base, void __iomem *pmc,
> +               unsigned long flags, unsigned long fixed_rate,
> +               struct tegra_clk_pll_params *pll_params, u8 pll_flags,
> +               struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock)
> +{
> +       return _tegra_clk_register_pll(name, parent_name, clk_base, pmc,
> +                       flags, fixed_rate, pll_params, pll_flags, freq_table,
> +                       lock, false);
> +}
> +
> +struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
> +               void __iomem *clk_base, void __iomem *pmc,
> +               unsigned long flags, unsigned long fixed_rate,
> +               struct tegra_clk_pll_params *pll_params, u8 pll_flags,
> +               struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock)
> +{
> +       return _tegra_clk_register_pll(name, parent_name, clk_base, pmc,
> +                       flags, fixed_rate, pll_params, pll_flags, freq_table,
> +                       lock, true);
> +}
> diff --git a/drivers/clk/tegra/clk-super.c b/drivers/clk/tegra/clk-super.c
> new file mode 100644
> index 0000000..7ad48a8
> --- /dev/null
> +++ b/drivers/clk/tegra/clk-super.c
> @@ -0,0 +1,154 @@
> +/*
> + * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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/kernel.h>
> +#include <linux/io.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/slab.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clk.h>
> +
> +#include "clk.h"
> +
> +#define SUPER_STATE_IDLE 0
> +#define SUPER_STATE_RUN 1
> +#define SUPER_STATE_IRQ 2
> +#define SUPER_STATE_FIQ 3
> +
> +#define SUPER_STATE_SHIFT 28
> +#define SUPER_STATE_MASK ((BIT(SUPER_STATE_IDLE) | BIT(SUPER_STATE_RUN) | \
> +                          BIT(SUPER_STATE_IRQ) | BIT(SUPER_STATE_FIQ)) \
> +                         << SUPER_STATE_SHIFT)
> +
> +#define SUPER_LP_DIV2_BYPASS (1 << 16)
> +
> +#define super_state(s) (BIT(s) << SUPER_STATE_SHIFT)
> +#define super_state_to_src_shift(m, s) ((m->width * s))
> +#define super_state_to_src_mask(m) (((1 << m->width) - 1))
> +
> +static u8 clk_super_get_parent(struct clk_hw *hw)
> +{
> +       struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
> +       u32 val, state;
> +       u8 source, shift;
> +
> +       val = readl_relaxed(mux->reg);
> +
> +       state = val & SUPER_STATE_MASK;
> +
> +       BUG_ON((state != super_state(SUPER_STATE_RUN)) &&
> +              (state != super_state(SUPER_STATE_IDLE)));
> +       shift = (state == super_state(SUPER_STATE_IDLE)) ?
> +               super_state_to_src_shift(mux, SUPER_STATE_IDLE) :
> +               super_state_to_src_shift(mux, SUPER_STATE_RUN);
> +
> +       source = (val >> shift) & super_state_to_src_mask(mux);
> +
> +       /*
> +        * If LP_DIV2_BYPASS is not set and PLLX is current parent then
> +        * PLLX/2 is the input source to CCLKLP.
> +        */
> +       if ((mux->flags & TEGRA_DIVIDER_2) && !(val & SUPER_LP_DIV2_BYPASS) &&
> +           (source == mux->pllx_index))
> +               source = mux->div2_index;
> +
> +       return source;
> +}
> +
> +static int clk_super_set_parent(struct clk_hw *hw, u8 index)
> +{
> +       struct tegra_clk_super_mux *mux = to_clk_super_mux(hw);
> +       u32 val, state;
> +       u8 parent_index, shift;
> +
> +       val = readl_relaxed(mux->reg);
> +       state = val & SUPER_STATE_MASK;
> +       BUG_ON((state != super_state(SUPER_STATE_RUN)) &&
> +              (state != super_state(SUPER_STATE_IDLE)));
> +       shift = (state == super_state(SUPER_STATE_IDLE)) ?
> +               super_state_to_src_shift(mux, SUPER_STATE_IDLE) :
> +               super_state_to_src_shift(mux, SUPER_STATE_RUN);
> +
> +       /*
> +        * For LP mode super-clock switch between PLLX direct
> +        * and divided-by-2 outputs is allowed only when other
> +        * than PLLX clock source is current parent.
> +        */
> +       if ((mux->flags & TEGRA_DIVIDER_2) && ((index == mux->div2_index) ||
> +                                              (index == mux->pllx_index))) {
> +               parent_index = clk_super_get_parent(hw);
> +               if ((parent_index == mux->div2_index) ||
> +                   (parent_index == mux->pllx_index))
> +                       return -EINVAL;
> +
> +               val ^= SUPER_LP_DIV2_BYPASS;
> +               writel_relaxed(val, mux->reg);
> +               udelay(2);
> +
> +               if (index == mux->div2_index)
> +                       index = mux->pllx_index;
> +       }
> +       val &= ~((super_state_to_src_mask(mux)) << shift);
> +       val |= (index & (super_state_to_src_mask(mux))) << shift;
> +
> +       writel_relaxed(val, mux->reg);
> +       udelay(2);
> +       return 0;
> +}
> +
> +const struct clk_ops tegra_clk_super_ops = {
> +       .get_parent = clk_super_get_parent,
> +       .set_parent = clk_super_set_parent,
> +};
> +
> +struct clk *tegra_clk_register_super_mux(const char *name,
> +               const char **parent_names, u8 num_parents,
> +               unsigned long flags, void __iomem *reg, u8 clk_super_flags,
> +               u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock)
> +{
> +       struct tegra_clk_super_mux *super;
> +       struct clk *clk;
> +       struct clk_init_data init;
> +
> +       super = kzalloc(sizeof(*super), GFP_KERNEL);
> +       if (!super) {
> +               pr_err("%s: could not allocate super clk\n", __func__);
> +               return ERR_PTR(-ENOMEM);
> +       }
> +
> +       init.name = name;
> +       init.ops = &tegra_clk_super_ops;
> +       init.flags = flags;
> +       init.parent_names = parent_names;
> +       init.num_parents = num_parents;
> +
> +       super->reg = reg;
> +       super->pllx_index = pllx_index;
> +       super->div2_index = div2_index;
> +       super->lock = lock;
> +       super->width = width;
> +       super->flags = clk_super_flags;
> +
> +       /* Data in .init is copied by clk_register(), so stack variable OK */
> +       super->hw.init = &init;
> +
> +       clk = clk_register(NULL, &super->hw);
> +       if (IS_ERR(clk))
> +               kfree(super);
> +
> +       return clk;
> +}
> diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
> new file mode 100644
> index 0000000..cf023a9
> --- /dev/null
> +++ b/drivers/clk/tegra/clk.c
> @@ -0,0 +1,69 @@
> +/*
> + * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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/clk.h>
> +#include <linux/clk-provider.h>
> +
> +#include "clk.h"
> +
> +void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,
> +                               struct clk *clks[], int clk_max)
> +{
> +       struct clk *clk;
> +
> +       for (; dup_list->clk_id < clk_max; dup_list++) {
> +               clk = clks[dup_list->clk_id];
> +               dup_list->lookup.clk = clk;
> +               clkdev_add(&dup_list->lookup);
> +       }
> +}
> +
> +void __init tegra_init_from_table(struct tegra_clk_init_table *tbl,
> +                                 struct clk *clks[], int clk_max)
> +{
> +       struct clk *clk;
> +
> +       for (; tbl->clk_id < clk_max; tbl++) {
> +               clk = clks[tbl->clk_id];
> +               if (IS_ERR_OR_NULL(clk))
> +                       return;
> +
> +               if (tbl->parent_id < clk_max) {
> +                       struct clk *parent = clks[tbl->parent_id];
> +                       if (clk_set_parent(clk, parent)) {
> +                               pr_err("%s: Failed to set parent %s of %s\n",
> +                                      __func__, __clk_get_name(parent),
> +                                      __clk_get_name(clk));
> +                               WARN_ON(1);
> +                       }
> +               }
> +
> +               if (tbl->rate)
> +                       if (clk_set_rate(clk, tbl->rate)) {
> +                               pr_err("%s: Failed to set rate %lu of %s\n",
> +                                      __func__, tbl->rate,
> +                                      __clk_get_name(clk));
> +                               WARN_ON(1);
> +                       }
> +
> +               if (tbl->state)
> +                       if (clk_prepare_enable(clk)) {
> +                               pr_err("%s: Failed to enable %s\n", __func__,
> +                                      __clk_get_name(clk));
> +                               WARN_ON(1);
> +                       }
> +       }
> +}
> diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
> new file mode 100644
> index 0000000..5fcfa51
> --- /dev/null
> +++ b/drivers/clk/tegra/clk.h
> @@ -0,0 +1,490 @@
> +/*
> + * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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 __TEGRA_CLK_H
> +#define __TEGRA_CLK_H
> +
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +
> +/**
> + * struct tegra_clk_sync_source - external clock source from codec
> + *
> + * @hw: handle between common and hardware-specific interfaces
> + * @rate: input frequency from source
> + * @max_rate: max rate allowed
> + */
> +struct tegra_clk_sync_source {
> +       struct          clk_hw hw;
> +       unsigned long   rate;
> +       unsigned long   max_rate;
> +};
> +
> +#define to_clk_sync_source(_hw)                                        \
> +       container_of(_hw, struct tegra_clk_sync_source, hw)
> +
> +extern const struct clk_ops tegra_clk_sync_source_ops;
> +struct clk *tegra_clk_register_sync_source(const char *name,
> +               unsigned long fixed_rate, unsigned long max_rate);
> +
> +/**
> + * struct tegra_clk_frac_div - fractional divider clock
> + *
> + * @hw:                handle between common and hardware-specific interfaces
> + * @reg:       register containing divider
> + * @flags:     hardware-specific flags
> + * @shift:     shift to the divider bit field
> + * @width:     width of the divider bit field
> + * @frac_width:        width of the fractional bit field
> + * @lock:      register lock
> + *
> + * Flags:
> + * TEGRA_DIVIDER_ROUND_UP - This flags indicates to round up the divider value.
> + * TEGRA_DIVIDER_FIXED - Fixed rate PLL dividers has addition override bit, this
> + *      flag indicates that this divider is for fixed rate PLL.
> + * TEGRA_DIVIDER_INT - Some modules can not cope with the duty cycle when
> + *      fraction bit is set. This flags indicates to calculate divider for which
> + *      fracton bit will be zero.
> + * TEGRA_DIVIDER_UART - UART module divider has additional enable bit which is
> + *      set when divider value is not 0. This flags indicates that the divider
> + *      is for UART module.
> + */
> +struct tegra_clk_frac_div {
> +       struct clk_hw   hw;
> +       void __iomem    *reg;
> +       u8              flags;
> +       u8              shift;
> +       u8              width;
> +       u8              frac_width;
> +       spinlock_t      *lock;
> +};
> +
> +#define to_clk_frac_div(_hw) container_of(_hw, struct tegra_clk_frac_div, hw)
> +
> +#define TEGRA_DIVIDER_ROUND_UP BIT(0)
> +#define TEGRA_DIVIDER_FIXED BIT(1)
> +#define TEGRA_DIVIDER_INT BIT(2)
> +#define TEGRA_DIVIDER_UART BIT(3)
> +
> +extern const struct clk_ops tegra_clk_frac_div_ops;
> +struct clk *tegra_clk_register_divider(const char *name,
> +               const char *parent_name, void __iomem *reg,
> +               unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width,
> +               u8 frac_width, spinlock_t *lock);
> +
> +/*
> + * Tegra PLL:
> + *
> + * In general, there are 3 requirements for each PLL
> + * that SW needs to be comply with.
> + * (1) Input frequency range (REF).
> + * (2) Comparison frequency range (CF). CF = REF/DIVM.
> + * (3) VCO frequency range (VCO).  VCO = CF * DIVN.
> + *
> + * The final PLL output frequency (FO) = VCO >> DIVP.
> + */
> +
> +/**
> + * struct tegra_clk_pll_freq_table - PLL frequecy table
> + *
> + * @input_rate:                input rate from source
> + * @output_rate:       output rate from PLL for the input rate
> + * @n:                 feedback divider
> + * @m:                 input divider
> + * @p:                 post divider
> + * @cpcon:             charge pump current
> + */
> +struct tegra_clk_pll_freq_table {
> +       unsigned long   input_rate;
> +       unsigned long   output_rate;
> +       u16             n;
> +       u16             m;
> +       u8              p;
> +       u8              cpcon;
> +};
> +
> +/**
> + * struct clk_pll_params - PLL parameters
> + *
> + * @input_min:                 Minimum input frequency
> + * @input_max:                 Maximum input frequency
> + * @cf_min:                    Minimum comparison frequency
> + * @cf_max:                    Maximum comparison frequency
> + * @vco_min:                   Minimum VCO frequency
> + * @vco_max:                   Maximum VCO frequency
> + * @base_reg:                  PLL base reg offset
> + * @misc_reg:                  PLL misc reg offset
> + * @lock_reg:                  PLL lock reg offset
> + * @lock_bit_idx:              Bit index for PLL lock status
> + * @lock_enable_bit_idx:       Bit index to enable PLL lock
> + * @lock_delay:                        Delay in us if PLL lock is not used
> + */
> +struct tegra_clk_pll_params {
> +       unsigned long   input_min;
> +       unsigned long   input_max;
> +       unsigned long   cf_min;
> +       unsigned long   cf_max;
> +       unsigned long   vco_min;
> +       unsigned long   vco_max;
> +
> +       u32             base_reg;
> +       u32             misc_reg;
> +       u32             lock_reg;
> +       u32             lock_bit_idx;
> +       u32             lock_enable_bit_idx;
> +       int             lock_delay;
> +};
> +
> +/**
> + * struct tegra_clk_pll - Tegra PLL clock
> + *
> + * @hw:                handle between common and hardware-specifix interfaces
> + * @clk_base:  address of CAR controller
> + * @pmc:       address of PMC, required to read override bits
> + * @freq_table:        array of frequencies supported by PLL
> + * @params:    PLL parameters
> + * @flags:     PLL flags
> + * @fixed_rate:        PLL rate if it is fixed
> + * @lock:      register lock
> + * @divn_shift:        shift to the feedback divider bit field
> + * @divn_width:        width of the feedback divider bit field
> + * @divm_shift:        shift to the input divider bit field
> + * @divm_width:        width of the input divider bit field
> + * @divp_shift:        shift to the post divider bit field
> + * @divp_width:        width of the post divider bit field
> + *
> + * Flags:
> + * TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
> + *     PLL locking. If not set it will use lock_delay value to wait.
> + * TEGRA_PLL_HAS_CPCON - This flag indicates that CPCON value needs
> + *     to be programmed to change output frequency of the PLL.
> + * TEGRA_PLL_SET_LFCON - This flag indicates that LFCON value needs
> + *     to be programmed to change output frequency of the PLL.
> + * TEGRA_PLL_SET_DCCON - This flag indicates that DCCON value needs
> + *     to be programmed to change output frequency of the PLL.
> + * TEGRA_PLLU - PLLU has inverted post divider. This flags indicated
> + *     that it is PLLU and invert post divider value.
> + * TEGRA_PLLM - PLLM has additional override settings in PMC. This
> + *     flag indicates that it is PLLM and use override settings.
> + * TEGRA_PLL_FIXED - We are not supposed to change output frequency
> + *     of some plls.
> + * TEGRA_PLLE_CONFIGURE - Configure PLLE when enabling.
> + */
> +struct tegra_clk_pll {
> +       struct clk_hw   hw;
> +       void __iomem    *clk_base;
> +       void __iomem    *pmc;
> +       u8              flags;
> +       unsigned long   fixed_rate;
> +       spinlock_t      *lock;
> +       u8              divn_shift;
> +       u8              divn_width;
> +       u8              divm_shift;
> +       u8              divm_width;
> +       u8              divp_shift;
> +       u8              divp_width;
> +       struct tegra_clk_pll_freq_table *freq_table;
> +       struct tegra_clk_pll_params     *params;
> +};
> +
> +#define to_clk_pll(_hw) container_of(_hw, struct tegra_clk_pll, hw)
> +
> +#define TEGRA_PLL_USE_LOCK BIT(0)
> +#define TEGRA_PLL_HAS_CPCON BIT(1)
> +#define TEGRA_PLL_SET_LFCON BIT(2)
> +#define TEGRA_PLL_SET_DCCON BIT(3)
> +#define TEGRA_PLLU BIT(4)
> +#define TEGRA_PLLM BIT(5)
> +#define TEGRA_PLL_FIXED BIT(6)
> +#define TEGRA_PLLE_CONFIGURE BIT(7)
> +
> +extern const struct clk_ops tegra_clk_pll_ops;
> +extern const struct clk_ops tegra_clk_plle_ops;
> +struct clk *tegra_clk_register_pll(const char *name, const char *parent_name,
> +               void __iomem *clk_base, void __iomem *pmc,
> +               unsigned long flags, unsigned long fixed_rate,
> +               struct tegra_clk_pll_params *pll_params, u8 pll_flags,
> +               struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock);
> +struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
> +               void __iomem *clk_base, void __iomem *pmc,
> +               unsigned long flags, unsigned long fixed_rate,
> +               struct tegra_clk_pll_params *pll_params, u8 pll_flags,
> +               struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock);
> +
> +/**
> + * struct tegra_clk_pll_out - PLL divider down clock
> + *
> + * @hw:                        handle between common and hardware-specific interfaces
> + * @reg:               register containing the PLL divider
> + * @enb_bit_idx:       bit to enable/disable PLL divider
> + * @rst_bit_idx:       bit to reset PLL divider
> + * @lock:              register lock
> + * @flags:             hardware-specific flags
> + */
> +struct tegra_clk_pll_out {
> +       struct clk_hw   hw;
> +       void __iomem    *reg;
> +       u8              enb_bit_idx;
> +       u8              rst_bit_idx;
> +       spinlock_t      *lock;
> +       u8              flags;
> +};
> +
> +#define to_clk_pll_out(_hw) container_of(_hw, struct tegra_clk_pll_out, hw)
> +
> +extern const struct clk_ops tegra_clk_pll_out_ops;
> +struct clk *tegra_clk_register_pll_out(const char *name,
> +               const char *parent_name, void __iomem *reg, u8 enb_bit_idx,
> +               u8 rst_bit_idx, unsigned long flags, u8 pll_div_flags,
> +               spinlock_t *lock);
> +
> +/**
> + * struct tegra_clk_periph_regs -  Registers controlling peripheral clock
> + *
> + * @enb_reg:           read the enable status
> + * @enb_set_reg:       write 1 to enable clock
> + * @enb_clr_reg:       write 1 to disable clock
> + * @rst_reg:           read the reset status
> + * @rst_set_reg:       write 1 to assert the reset of peripheral
> + * @rst_clr_reg:       write 1 to deassert the reset of peripheral
> + */
> +struct tegra_clk_periph_regs {
> +       u32 enb_reg;
> +       u32 enb_set_reg;
> +       u32 enb_clr_reg;
> +       u32 rst_reg;
> +       u32 rst_set_reg;
> +       u32 rst_clr_reg;
> +};
> +
> +/**
> + * struct tegra_clk_periph_gate - peripheral gate clock
> + *
> + * @magic:             magic number to validate type
> + * @hw:                        handle between common and hardware-specific interfaces
> + * @clk_base:          address of CAR controller
> + * @regs:              Registers to control the peripheral
> + * @flags:             hardware-specific flags
> + * @clk_num:           Clock number
> + * @enable_refcnt:     array to maintain reference count of the clock
> + *
> + * Flags:
> + * TEGRA_PERIPH_NO_RESET - This flag indicates that reset is not allowed
> + *     for this module.
> + * TEGRA_PERIPH_MANUAL_RESET - This flag indicates not to reset module
> + *     after clock enable and driver for the module is responsible for
> + *     doing reset.
> + * TEGRA_PERIPH_ON_APB - If peripheral is in the APB bus then read the
> + *     bus to flush the write operation in apb bus. This flag indicates
> + *     that this peripheral is in apb bus.
> + */
> +struct tegra_clk_periph_gate {
> +       u32                     magic;
> +       struct clk_hw           hw;
> +       void __iomem            *clk_base;
> +       u8                      flags;
> +       int                     clk_num;
> +       int                     *enable_refcnt;
> +       struct tegra_clk_periph_regs    *regs;
> +};
> +
> +#define to_clk_periph_gate(_hw)                                        \
> +       container_of(_hw, struct tegra_clk_periph_gate, hw)
> +
> +#define TEGRA_CLK_PERIPH_GATE_MAGIC 0x17760309
> +
> +#define TEGRA_PERIPH_NO_RESET BIT(0)
> +#define TEGRA_PERIPH_MANUAL_RESET BIT(1)
> +#define TEGRA_PERIPH_ON_APB BIT(2)
> +
> +void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert);
> +extern const struct clk_ops tegra_clk_periph_gate_ops;
> +struct clk *tegra_clk_register_periph_gate(const char *name,
> +               const char *parent_name, u8 gate_flags, void __iomem *clk_base,
> +               unsigned long flags, int clk_num,
> +               struct tegra_clk_periph_regs *pregs, int *enable_refcnt);
> +
> +/**
> + * struct clk-periph - peripheral clock
> + *
> + * @magic:     magic number to validate type
> + * @hw:                handle between common and hardware-specific interfaces
> + * @mux:       mux clock
> + * @divider:   divider clock
> + * @gate:      gate clock
> + * @mux_ops:   mux clock ops
> + * @div_ops:   divider clock ops
> + * @gate_ops:  gate clock ops
> + */
> +struct tegra_clk_periph {
> +       u32                     magic;
> +       struct clk_hw           hw;
> +       struct clk_mux          mux;
> +       struct tegra_clk_frac_div       divider;
> +       struct tegra_clk_periph_gate    gate;
> +
> +       const struct clk_ops    *mux_ops;
> +       const struct clk_ops    *div_ops;
> +       const struct clk_ops    *gate_ops;
> +};
> +
> +#define to_clk_periph(_hw) container_of(_hw, struct tegra_clk_periph, hw)
> +
> +#define TEGRA_CLK_PERIPH_MAGIC 0x18221223
> +
> +extern const struct clk_ops tegra_clk_periph_ops;
> +struct clk *tegra_clk_register_periph(const char *name,
> +               const char **parent_names, int num_parents,
> +               struct tegra_clk_periph *periph, void __iomem *clk_base,
> +               u32 offset);
> +struct clk *tegra_clk_register_periph_nodiv(const char *name,
> +               const char **parent_names, int num_parents,
> +               struct tegra_clk_periph *periph, void __iomem *clk_base,
> +               u32 offset);
> +
> +#define TEGRA_CLK_PERIPH(_mux_shift, _mux_width, _mux_flags,           \
> +                        _div_shift, _div_width, _div_frac_width,       \
> +                        _div_flags, _clk_num, _enb_refcnt, _regs,      \
> +                        _gate_flags)                                   \
> +       {                                                               \
> +               .mux = {                                                \
> +                       .flags = _mux_flags,                            \
> +                       .shift = _mux_shift,                            \
> +                       .width = _mux_width,                            \
> +               },                                                      \
> +               .divider = {                                            \
> +                       .flags = _div_flags,                            \
> +                       .shift = _div_shift,                            \
> +                       .width = _div_width,                            \
> +                       .frac_width = _div_frac_width,                  \
> +               },                                                      \
> +               .gate = {                                               \
> +                       .flags = _gate_flags,                           \
> +                       .clk_num = _clk_num,                            \
> +                       .enable_refcnt = _enb_refcnt,                   \
> +                       .regs = _regs,                                  \
> +               },                                                      \
> +               .mux_ops = &clk_mux_ops,                                \
> +               .div_ops = &tegra_clk_frac_div_ops,                     \
> +               .gate_ops = &tegra_clk_periph_gate_ops,                 \
> +       }
> +
> +struct tegra_periph_init_data {
> +       const char *name;
> +       int clk_id;
> +       const char **parent_names;
> +       int num_parents;
> +       struct tegra_clk_periph periph;
> +       u32 offset;
> +       const char *con_id;
> +       const char *dev_id;
> +};
> +
> +#define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset, \
> +                       _mux_shift, _mux_width, _mux_flags, _div_shift, \
> +                       _div_width, _div_frac_width, _div_flags, _regs, \
> +                       _clk_num, _enb_refcnt, _gate_flags, _clk_id)    \
> +       {                                                               \
> +               .name = _name,                                          \
> +               .clk_id = _clk_id,                                      \
> +               .parent_names = _parent_names,                          \
> +               .num_parents = ARRAY_SIZE(_parent_names),               \
> +               .periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_width,      \
> +                                          _mux_flags, _div_shift,      \
> +                                          _div_width, _div_frac_width, \
> +                                          _div_flags, _clk_num,        \
> +                                          _enb_refcnt, _regs,          \
> +                                          _gate_flags),                \
> +               .offset = _offset,                                      \
> +               .con_id = _con_id,                                      \
> +               .dev_id = _dev_id,                                      \
> +       }
> +
> +/**
> + * struct clk_super_mux - super clock
> + *
> + * @hw:                handle between common and hardware-specific interfaces
> + * @reg:       register controlling multiplexer
> + * @width:     width of the multiplexer bit field
> + * @flags:     hardware-specific flags
> + * @div2_index:        bit controlling divide-by-2
> + * @pllx_index:        PLLX index in the parent list
> + * @lock:      register lock
> + *
> + * Flags:
> + * TEGRA_DIVIDER_2 - LP cluster has additional divider. This flag indicates
> + *     that this is LP cluster clock.
> + */
> +struct tegra_clk_super_mux {
> +       struct clk_hw   hw;
> +       void __iomem    *reg;
> +       u8              width;
> +       u8              flags;
> +       u8              div2_index;
> +       u8              pllx_index;
> +       spinlock_t      *lock;
> +};
> +
> +#define to_clk_super_mux(_hw) container_of(_hw, struct tegra_clk_super_mux, hw)
> +
> +#define TEGRA_DIVIDER_2 BIT(0)
> +
> +extern const struct clk_ops tegra_clk_super_ops;
> +struct clk *tegra_clk_register_super_mux(const char *name,
> +               const char **parent_names, u8 num_parents,
> +               unsigned long flags, void __iomem *reg, u8 clk_super_flags,
> +               u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock);
> +
> +/**
> + * struct clk_init_tabel - clock initialization table
> + * @clk_id:    clock id as mentioned in device tree bindings
> + * @parent_id: parent clock id as mentioned in device tree bindings
> + * @rate:      rate to set
> + * @state:     enable/disable
> + */
> +struct tegra_clk_init_table {
> +       unsigned int    clk_id;
> +       unsigned int    parent_id;
> +       unsigned long   rate;
> +       int             state;
> +};
> +
> +/**
> + * struct clk_duplicate - duplicate clocks
> + * @clk_id:    clock id as mentioned in device tree bindings
> + * @lookup:    duplicate lookup entry for the clock
> + */
> +struct tegra_clk_duplicate {
> +       int                     clk_id;
> +       struct clk_lookup       lookup;
> +};
> +
> +#define TEGRA_CLK_DUPLICATE(_clk_id, _dev, _con) \
> +       {                                       \
> +               .clk_id = _clk_id,              \
> +               .lookup = {                     \
> +                       .dev_id = _dev,         \
> +                       .con_id = _con,         \
> +               },                              \
> +       }
> +
> +void tegra_init_from_table(struct tegra_clk_init_table *tbl,
> +               struct clk *clks[], int clk_max);
> +
> +void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,
> +               struct clk *clks[], int clk_max);
> +
> +#endif /* TEGRA_CLK_H */
> -- 
> 1.7.10.4

^ permalink raw reply

* [PATCH] ARM: dts: remove generated .dtb files on clean
From: Nishanth Menon @ 2013-01-22 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

commit 5f300acd8ae9f3d4585154370012ffc5c665330f
(ARM: 7152/1: distclean: Remove generated .dtb files)
ensured that dtbs were cleaned up when they were in
arch/arm/boot.
However, with the following commit:
commit 499cd8298628eeabf0eb5eb6525d4faa0eec80d8
(ARM: dt: change .dtb build rules to build in dts directory)

make clean now leaves dtbs in arch/arm/boot/dts/
untouched. Include dts directory so that clean-files rule
from arch/arm/boot/dts/Makefile is invoked when make
clean is done.

Cc: Dirk Behme <dirk.behme@de.bosch.com>
CC: Grant Likely <grant.likely@secretlab.ca>

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 arch/arm/boot/Makefile |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index abfce28..3837f97 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -115,4 +115,4 @@ i:
 	$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
 	$(obj)/Image System.map "$(INSTALL_PATH)"
 
-subdir-	    := bootp compressed
+subdir-	    := bootp compressed dts
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH] OMAPDSS: enable omapdss for ARCH_MULTIPLATFORM
From: Rob Clark @ 2013-01-22 21:46 UTC (permalink / raw)
  To: linux-arm-kernel

At least core omapdss does not have any build dependencies on
ARCH_OMAP2PLUS, and adding this dependency in the Kconfig breaks omapdrm
for ARCH_MULTIPLATFORM builds.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 drivers/video/omap2/Kconfig | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig
index b07b2b0..011e549 100644
--- a/drivers/video/omap2/Kconfig
+++ b/drivers/video/omap2/Kconfig
@@ -1,9 +1,14 @@
 config OMAP2_VRFB
 	bool
 
-if ARCH_OMAP2PLUS
+if ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM
 
 source "drivers/video/omap2/dss/Kconfig"
+
+endif
+
+if ARCH_OMAP2PLUS
+
 source "drivers/video/omap2/omapfb/Kconfig"
 source "drivers/video/omap2/displays/Kconfig"
 
-- 
1.8.1

^ permalink raw reply related

* [PATCH v2 1/3] ARM: DT: tegra: move serial clock-frequency attr into the SoC dtsi
From: Lucas Stach @ 2013-01-22 21:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358423961-24318-1-git-send-email-dev@lynxeye.de>

No Tegra Platform is running PLL_P at another rate than 216MHz, nor is
any using an other PLL as UART source clock. Move attribute into SoC
level dtsi file to slim down board DT files.

Signed-off-by: Lucas Stach <dev@lynxeye.de>
---
v2:
- initial revision
---
 arch/arm/boot/dts/tegra20-harmony.dts   | 1 -
 arch/arm/boot/dts/tegra20-paz00.dts     | 2 --
 arch/arm/boot/dts/tegra20-seaboard.dts  | 1 -
 arch/arm/boot/dts/tegra20-tamonten.dtsi | 1 -
 arch/arm/boot/dts/tegra20-trimslice.dts | 1 -
 arch/arm/boot/dts/tegra20-ventana.dts   | 1 -
 arch/arm/boot/dts/tegra20-whistler.dts  | 1 -
 arch/arm/boot/dts/tegra20.dtsi          | 5 +++++
 8 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/arch/arm/boot/dts/tegra20-harmony.dts b/arch/arm/boot/dts/tegra20-harmony.dts
index 54295e3..96f4ccd 100644
--- a/arch/arm/boot/dts/tegra20-harmony.dts
+++ b/arch/arm/boot/dts/tegra20-harmony.dts
@@ -252,7 +252,6 @@
 
 	serial at 70006300 {
 		status = "okay";
-		clock-frequency = <216000000>;
 	};
 
 	i2c at 7000c000 {
diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts
index 80d9635..7744c8b 100644
--- a/arch/arm/boot/dts/tegra20-paz00.dts
+++ b/arch/arm/boot/dts/tegra20-paz00.dts
@@ -244,12 +244,10 @@
 
 	serial at 70006000 {
 		status = "okay";
-		clock-frequency = <216000000>;
 	};
 
 	serial at 70006200 {
 		status = "okay";
-		clock-frequency = <216000000>;
 	};
 
 	i2c at 7000c000 {
diff --git a/arch/arm/boot/dts/tegra20-seaboard.dts b/arch/arm/boot/dts/tegra20-seaboard.dts
index d4e4ff2..0b48359 100644
--- a/arch/arm/boot/dts/tegra20-seaboard.dts
+++ b/arch/arm/boot/dts/tegra20-seaboard.dts
@@ -303,7 +303,6 @@
 
 	serial at 70006300 {
 		status = "okay";
-		clock-frequency = <216000000>;
 	};
 
 	i2c at 7000c000 {
diff --git a/arch/arm/boot/dts/tegra20-tamonten.dtsi b/arch/arm/boot/dts/tegra20-tamonten.dtsi
index a239ccd..4766aba 100644
--- a/arch/arm/boot/dts/tegra20-tamonten.dtsi
+++ b/arch/arm/boot/dts/tegra20-tamonten.dtsi
@@ -276,7 +276,6 @@
 	};
 
 	serial at 70006300 {
-		clock-frequency = <216000000>;
 		status = "okay";
 	};
 
diff --git a/arch/arm/boot/dts/tegra20-trimslice.dts b/arch/arm/boot/dts/tegra20-trimslice.dts
index 4b6c486..adf6024 100644
--- a/arch/arm/boot/dts/tegra20-trimslice.dts
+++ b/arch/arm/boot/dts/tegra20-trimslice.dts
@@ -263,7 +263,6 @@
 
 	serial at 70006000 {
 		status = "okay";
-		clock-frequency = <216000000>;
 	};
 
 	dvi_ddc: i2c at 7000c000 {
diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts
index e3d3b29..5b15c30 100644
--- a/arch/arm/boot/dts/tegra20-ventana.dts
+++ b/arch/arm/boot/dts/tegra20-ventana.dts
@@ -300,7 +300,6 @@
 
 	serial at 70006300 {
 		status = "okay";
-		clock-frequency = <216000000>;
 	};
 
 	i2c at 7000c000 {
diff --git a/arch/arm/boot/dts/tegra20-whistler.dts b/arch/arm/boot/dts/tegra20-whistler.dts
index b8e0ee1..ea57c0f 100644
--- a/arch/arm/boot/dts/tegra20-whistler.dts
+++ b/arch/arm/boot/dts/tegra20-whistler.dts
@@ -255,7 +255,6 @@
 
 	serial at 70006000 {
 		status = "okay";
-		clock-frequency = <216000000>;
 	};
 
 	hdmi_ddc: i2c at 7000c400 {
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 9c4870f..8324ef4 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -223,6 +223,7 @@
 		reg = <0x70006000 0x40>;
 		reg-shift = <2>;
 		interrupts = <0 36 0x04>;
+		clock-frequency = <216000000>;
 		nvidia,dma-request-selector = <&apbdma 8>;
 		status = "disabled";
 	};
@@ -232,6 +233,7 @@
 		reg = <0x70006040 0x40>;
 		reg-shift = <2>;
 		interrupts = <0 37 0x04>;
+		clock-frequency = <216000000>;
 		nvidia,dma-request-selector = <&apbdma 9>;
 		status = "disabled";
 	};
@@ -241,6 +243,7 @@
 		reg = <0x70006200 0x100>;
 		reg-shift = <2>;
 		interrupts = <0 46 0x04>;
+		clock-frequency = <216000000>;
 		nvidia,dma-request-selector = <&apbdma 10>;
 		status = "disabled";
 	};
@@ -250,6 +253,7 @@
 		reg = <0x70006300 0x100>;
 		reg-shift = <2>;
 		interrupts = <0 90 0x04>;
+		clock-frequency = <216000000>;
 		nvidia,dma-request-selector = <&apbdma 19>;
 		status = "disabled";
 	};
@@ -259,6 +263,7 @@
 		reg = <0x70006400 0x100>;
 		reg-shift = <2>;
 		interrupts = <0 91 0x04>;
+		clock-frequency = <216000000>;
 		nvidia,dma-request-selector = <&apbdma 20>;
 		status = "disabled";
 	};
-- 
1.8.0.2

^ permalink raw reply related

* [PATCH v2 2/3] ARM: DT: tegra: Add Colibri T20 512MB COM
From: Lucas Stach @ 2013-01-22 21:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358891169-5939-1-git-send-email-dev@lynxeye.de>

This adds the device tree include file for the Toradex Colibri T20
Computer on Module (COM). It's only valid for the 512MB RAM version of
the module, as the 256MB version needs different EMC tables and flash
configuration. To make this clear the suffix -512 was added to the board
compatible string.

The Colibri T20 uses a Tegra2 SoC and has onboard USB Ethernet and AC97
sound.

Still some things like onboard NAND support missing, but should be a
good base for further development.

Signed-off-by: Lucas Stach <dev@lynxeye.de>
---
v2:
- remove some whitespace
- remove nodes that don't carry any additional info
- unify regulator node between module and carrier board
---
 Documentation/devicetree/bindings/arm/tegra.txt |   1 +
 arch/arm/boot/dts/tegra20-colibri-512.dtsi      | 491 ++++++++++++++++++++++++
 2 files changed, 492 insertions(+)
 create mode 100644 arch/arm/boot/dts/tegra20-colibri-512.dtsi

diff --git a/Documentation/devicetree/bindings/arm/tegra.txt b/Documentation/devicetree/bindings/arm/tegra.txt
index a5d3353..ccd4ef4 100644
--- a/Documentation/devicetree/bindings/arm/tegra.txt
+++ b/Documentation/devicetree/bindings/arm/tegra.txt
@@ -30,3 +30,4 @@ board-specific compatible values:
   nvidia,seaboard
   nvidia,ventana
   nvidia,whistler
+  toradex,colibri_t20-512
diff --git a/arch/arm/boot/dts/tegra20-colibri-512.dtsi b/arch/arm/boot/dts/tegra20-colibri-512.dtsi
new file mode 100644
index 0000000..4441620
--- /dev/null
+++ b/arch/arm/boot/dts/tegra20-colibri-512.dtsi
@@ -0,0 +1,491 @@
+/include/ "tegra20.dtsi"
+
+/ {
+	model = "Toradex Colibri T20 512MB";
+	compatible = "toradex,colibri_t20-512", "nvidia,tegra20";
+
+	memory {
+		reg = <0x00000000 0x20000000>;
+	};
+
+	host1x {
+		hdmi {
+			vdd-supply = <&hdmi_vdd_reg>;
+			pll-supply = <&hdmi_pll_reg>;
+
+			nvidia,ddc-i2c-bus = <&i2c_ddc>;
+			nvidia,hpd-gpio = <&gpio 111 0>; /* PN7 */
+		};
+	};
+
+	pinmux {
+		pinctrl-names = "default";
+		pinctrl-0 = <&state_default>;
+
+		state_default: pinmux {
+			audio_refclk {
+				nvidia,pins = "cdev1";
+				nvidia,function = "plla_out";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			crt {
+				nvidia,pins = "crtp";
+				nvidia,function = "crt";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			dap3 {
+				nvidia,pins = "dap3";
+				nvidia,function = "dap3";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			displaya {
+				nvidia,pins = "ld0", "ld1", "ld2", "ld3",
+					"ld4", "ld5", "ld6", "ld7", "ld8",
+					"ld9", "ld10", "ld11", "ld12", "ld13",
+					"ld14", "ld15", "ld16", "ld17",
+					"lhs", "lpw0", "lpw2", "lsc0",
+					"lsc1", "lsck", "lsda", "lspi", "lvs";
+				nvidia,function = "displaya";
+				nvidia,tristate = <1>;
+			};
+			gpio_dte {
+				nvidia,pins = "dte";
+				nvidia,function = "rsvd1";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			gpio_gmi {
+				nvidia,pins = "ata", "atc", "atd", "ate",
+					"dap1", "dap2", "dap4", "gpu", "irrx",
+					"irtx", "spia", "spib", "spic";
+				nvidia,function = "gmi";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			gpio_pta {
+				nvidia,pins = "pta";
+				nvidia,function = "rsvd4";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			gpio_uac {
+				nvidia,pins = "uac";
+				nvidia,function = "rsvd2";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			hdint {
+				nvidia,pins = "hdint";
+				nvidia,function = "hdmi";
+				nvidia,tristate = <1>;
+			};
+			i2c1 {
+				nvidia,pins = "rm";
+				nvidia,function = "i2c1";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			i2c3 {
+				nvidia,pins = "dtf";
+				nvidia,function = "i2c3";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			i2cddc {
+				nvidia,pins = "ddc";
+				nvidia,function = "i2c2";
+				nvidia,pull = <2>;
+				nvidia,tristate = <1>;
+			};
+			i2cp {
+				nvidia,pins = "i2cp";
+				nvidia,function = "i2cp";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			irda {
+				nvidia,pins = "uad";
+				nvidia,function = "irda";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			nand {
+				nvidia,pins = "kbca", "kbcc", "kbcd",
+					"kbce", "kbcf";
+				nvidia,function = "nand";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			owc {
+				nvidia,pins = "owc";
+				nvidia,function = "owr";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			pmc {
+				nvidia,pins = "pmc";
+				nvidia,function = "pwr_on";
+				nvidia,tristate = <0>;
+			};
+			pwm {
+				nvidia,pins = "sdb", "sdc", "sdd";
+				nvidia,function = "pwm";
+				nvidia,tristate = <1>;
+			};
+			sdio4 {
+				nvidia,pins = "atb", "gma", "gme";
+				nvidia,function = "sdio4";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			spi1 {
+				nvidia,pins = "spid", "spie", "spif";
+				nvidia,function = "spi1";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			spi4 {
+				nvidia,pins = "slxa", "slxc", "slxd", "slxk";
+				nvidia,function = "spi4";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			uarta {
+				nvidia,pins = "sdio1";
+				nvidia,function = "uarta";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			uartd {
+				nvidia,pins = "gmc";
+				nvidia,function = "uartd";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			ulpi {
+				nvidia,pins = "uaa", "uab", "uda";
+				nvidia,function = "ulpi";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			ulpi_refclk {
+				nvidia,pins = "cdev2";
+				nvidia,function = "pllp_out4";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			usb_gpio {
+				nvidia,pins = "spig", "spih";
+				nvidia,function = "spi2_alt";
+				nvidia,pull = <0>;
+				nvidia,tristate = <0>;
+			};
+			vi {
+				nvidia,pins = "dta", "dtb", "dtc", "dtd";
+				nvidia,function = "vi";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+			vi_sc {
+				nvidia,pins = "csus";
+				nvidia,function = "vi_sensor_clk";
+				nvidia,pull = <0>;
+				nvidia,tristate = <1>;
+			};
+		};
+	};
+
+	i2c at 7000c000 {
+		clock-frequency = <400000>;
+	};
+
+	i2c_ddc: i2c at 7000c400 {
+		clock-frequency = <100000>;
+	};
+
+	i2c at 7000c500 {
+		clock-frequency = <400000>;
+	};
+
+	i2c at 7000d000 {
+		status = "okay";
+		clock-frequency = <400000>;
+
+		pmic: tps6586x at 34 {
+			compatible = "ti,tps6586x";
+			reg = <0x34>;
+			interrupts = <0 86 0x4>;
+
+			ti,system-power-controller;
+
+			#gpio-cells = <2>;
+			gpio-controller;
+
+			sys-supply = <&vdd_5v0_reg>;
+			vin-sm0-supply = <&sys_reg>;
+			vin-sm1-supply = <&sys_reg>;
+			vin-sm2-supply = <&sys_reg>;
+			vinldo01-supply = <&sm2_reg>;
+			vinldo23-supply = <&sm2_reg>;
+			vinldo4-supply = <&sm2_reg>;
+			vinldo678-supply = <&sm2_reg>;
+			vinldo9-supply = <&sm2_reg>;
+
+			regulators {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				sys_reg: regulator at 0 {
+					reg = <0>;
+					regulator-compatible = "sys";
+					regulator-name = "vdd_sys";
+					regulator-always-on;
+				};
+
+				regulator at 1 {
+					reg = <1>;
+					regulator-compatible = "sm0";
+					regulator-name = "vdd_sm0,vdd_core";
+					regulator-min-microvolt = <1275000>;
+					regulator-max-microvolt = <1275000>;
+					regulator-always-on;
+				};
+
+				regulator at 2 {
+					reg = <2>;
+					regulator-compatible = "sm1";
+					regulator-name = "vdd_sm1,vdd_cpu";
+					regulator-min-microvolt = <1100000>;
+					regulator-max-microvolt = <1100000>;
+					regulator-always-on;
+				};
+
+				sm2_reg: regulator at 3 {
+					reg = <3>;
+					regulator-compatible = "sm2";
+					regulator-name = "vdd_sm2,vin_ldo*";
+					regulator-min-microvolt = <3700000>;
+					regulator-max-microvolt = <3700000>;
+					regulator-always-on;
+				};
+
+				/* LDO0 is not connected to anything */
+
+				regulator at 5 {
+					reg = <5>;
+					regulator-compatible = "ldo1";
+					regulator-name = "vdd_ldo1,avdd_pll*";
+					regulator-min-microvolt = <1100000>;
+					regulator-max-microvolt = <1100000>;
+					regulator-always-on;
+				};
+
+				regulator at 6 {
+					reg = <6>;
+					regulator-compatible = "ldo2";
+					regulator-name = "vdd_ldo2,vdd_rtc";
+					regulator-min-microvolt = <1200000>;
+					regulator-max-microvolt = <1200000>;
+				};
+
+				/* LDO3 is not connected to anything */
+
+				regulator at 8 {
+					reg = <8>;
+					regulator-compatible = "ldo4";
+					regulator-name = "vdd_ldo4,avdd_osc,vddio_sys";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+					regulator-always-on;
+				};
+
+				ldo5_reg: regulator at 9 {
+					reg = <9>;
+					regulator-compatible = "ldo5";
+					regulator-name = "vdd_ldo5,vdd_fuse";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-always-on;
+				};
+
+				regulator at 10 {
+					reg = <10>;
+					regulator-compatible = "ldo6";
+					regulator-name = "vdd_ldo6,avdd_vdac,vddio_vi,vddio_cam";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				hdmi_vdd_reg: regulator at 11 {
+					reg = <11>;
+					regulator-compatible = "ldo7";
+					regulator-name = "vdd_ldo7,avdd_hdmi";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+				};
+
+				hdmi_pll_reg: regulator at 12 {
+					reg = <12>;
+					regulator-compatible = "ldo8";
+					regulator-name = "vdd_ldo8,avdd_hdmi_pll";
+					regulator-min-microvolt = <1800000>;
+					regulator-max-microvolt = <1800000>;
+				};
+
+				regulator at 13 {
+					reg = <13>;
+					regulator-compatible = "ldo9";
+					regulator-name = "vdd_ldo9,avdd_2v85,vdd_ddr_rx";
+					regulator-min-microvolt = <2850000>;
+					regulator-max-microvolt = <2850000>;
+					regulator-always-on;
+				};
+
+				regulator at 14 {
+					reg = <14>;
+					regulator-compatible = "ldo_rtc";
+					regulator-name = "vdd_rtc_out,vdd_cell";
+					regulator-min-microvolt = <3300000>;
+					regulator-max-microvolt = <3300000>;
+					regulator-always-on;
+				};
+			};
+		};
+
+		temperature-sensor at 4c {
+			compatible = "national,lm95245";
+			reg = <0x4c>;
+		};
+	};
+
+	memory-controller at 7000f400 {
+		emc-table at 83250 {
+			reg = <83250>;
+			compatible = "nvidia,tegra20-emc-table";
+			clock-frequency = <83250>;
+			nvidia,emc-registers =   <0x00000005 0x00000011
+				0x00000004 0x00000002 0x00000004 0x00000004
+				0x00000001 0x0000000a 0x00000002 0x00000002
+				0x00000001 0x00000001 0x00000003 0x00000004
+				0x00000003 0x00000009 0x0000000c 0x0000025f
+				0x00000000 0x00000003 0x00000003 0x00000002
+				0x00000002 0x00000001 0x00000008 0x000000c8
+				0x00000003 0x00000005 0x00000003 0x0000000c
+				0x00000002 0x00000000 0x00000000 0x00000002
+				0x00000000 0x00000000 0x00000083 0x00520006
+				0x00000010 0x00000008 0x00000000 0x00000000
+				0x00000000 0x00000000 0x00000000 0x00000000>;
+		};
+		emc-table at 133200 {
+			reg = <133200>;
+			compatible = "nvidia,tegra20-emc-table";
+			clock-frequency = <133200>;
+			nvidia,emc-registers =   <0x00000008 0x00000019
+				0x00000006 0x00000002 0x00000004 0x00000004
+				0x00000001 0x0000000a 0x00000002 0x00000002
+				0x00000002 0x00000001 0x00000003 0x00000004
+				0x00000003 0x00000009 0x0000000c 0x0000039f
+				0x00000000 0x00000003 0x00000003 0x00000002
+				0x00000002 0x00000001 0x00000008 0x000000c8
+				0x00000003 0x00000007 0x00000003 0x0000000c
+				0x00000002 0x00000000 0x00000000 0x00000002
+				0x00000000 0x00000000 0x00000083 0x00510006
+				0x00000010 0x00000008 0x00000000 0x00000000
+				0x00000000 0x00000000 0x00000000 0x00000000>;
+		};
+		emc-table at 166500 {
+			reg = <166500>;
+			compatible = "nvidia,tegra20-emc-table";
+			clock-frequency = <166500>;
+			nvidia,emc-registers =   <0x0000000a 0x00000021
+				0x00000008 0x00000003 0x00000004 0x00000004
+				0x00000002 0x0000000a 0x00000003 0x00000003
+				0x00000002 0x00000001 0x00000003 0x00000004
+				0x00000003 0x00000009 0x0000000c 0x000004df
+				0x00000000 0x00000003 0x00000003 0x00000003
+				0x00000003 0x00000001 0x00000009 0x000000c8
+				0x00000003 0x00000009 0x00000004 0x0000000c
+				0x00000002 0x00000000 0x00000000 0x00000002
+				0x00000000 0x00000000 0x00000083 0x004f0006
+				0x00000010 0x00000008 0x00000000 0x00000000
+				0x00000000 0x00000000 0x00000000 0x00000000>;
+		};
+		emc-table at 333000 {
+			reg = <333000>;
+			compatible = "nvidia,tegra20-emc-table";
+			clock-frequency = <333000>;
+			nvidia,emc-registers =   <0x00000014 0x00000041
+				0x0000000f 0x00000005 0x00000004 0x00000005
+				0x00000003 0x0000000a 0x00000005 0x00000005
+				0x00000004 0x00000001 0x00000003 0x00000004
+				0x00000003 0x00000009 0x0000000c 0x000009ff
+				0x00000000 0x00000003 0x00000003 0x00000005
+				0x00000005 0x00000001 0x0000000e 0x000000c8
+				0x00000003 0x00000011 0x00000006 0x0000000c
+				0x00000002 0x00000000 0x00000000 0x00000002
+				0x00000000 0x00000000 0x00000083 0x00380006
+				0x00000010 0x00000008 0x00000000 0x00000000
+				0x00000000 0x00000000 0x00000000 0x00000000>;
+		};
+	};
+
+	ac97: ac97 {
+		status = "okay";
+		nvidia,codec-reset-gpio = <&gpio 168 0>; /* gpio PV0 */
+		nvidia,codec-sync-gpio = <&gpio 120 0>; /* gpio PP0 */
+	};
+
+	usb at c5004000 {
+		status = "okay";
+		nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+	};
+
+	sdhci at c8000600 {
+		cd-gpios = <&gpio 23 0>; /* gpio PC7 */
+	};
+
+	sound {
+		compatible = "nvidia,tegra-audio-wm9712-colibri_t20",
+			         "nvidia,tegra-audio-wm9712";
+		nvidia,model = "Colibri T20 AC97 Audio";
+
+		nvidia,audio-routing =
+			"Headphone", "HPOUTL",
+			"Headphone", "HPOUTR",
+			"LineIn", "LINEINL",
+			"LineIn", "LINEINR",
+			"Mic", "MIC1";
+
+		nvidia,ac97-controller = <&ac97>;
+	};
+
+	regulators {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		vdd_5v0_reg: regulator at 100 {
+			compatible = "regulator-fixed";
+			reg = <100>;
+			regulator-name = "vdd_5v0";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			regulator-always-on;
+		};
+
+		regulator at 101 {
+			compatible = "regulator-fixed";
+			reg = <101>;
+			regulator-name = "internal_usb";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			enable-active-high;
+			regulator-boot-on;
+			regulator-always-on;
+			gpio = <&gpio 217 0>;
+		};
+	};
+};
-- 
1.8.0.2

^ permalink raw reply related

* [PATCH v2 3/3] ARM: DT: tegra: Add Toradex Iris carrier board with T20 512MB COM
From: Lucas Stach @ 2013-01-22 21:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358891169-5939-1-git-send-email-dev@lynxeye.de>

This adds the device tree for the Toradex Iris carrier board used
together with a Colibri T20 512MB COM.

The Iris has the following features, in brackets the current status:
- DVI and VGA output through DVI-I connector (DVI-D enabled and tested)
- LVDS output
- 1 USB host port (enabled and tested)
- 1 USB OTG port (enabled)
- 100 MBit Ethernet (enabled and tested)
- 5 UART ports  (2 on 10way headers enabled and tested)
- 1 MicroSD Slot (enabled and tested)
- Audio connectors (enabled, only HP out and Line-in tested)
- i2c RTC
- GPIO connector (enabled, only sparsely tested)
- external i2c bus
- 4 PWM out
- analog in

Signed-off-by: Lucas Stach <dev@lynxeye.de>
---
v2:
- unify regulator node between module and carrier
- use correct regulator for sdhci
---
 Documentation/devicetree/bindings/arm/tegra.txt |  1 +
 arch/arm/boot/dts/Makefile                      |  1 +
 arch/arm/boot/dts/tegra20-iris-512.dts          | 89 +++++++++++++++++++++++++
 3 files changed, 91 insertions(+)
 create mode 100644 arch/arm/boot/dts/tegra20-iris-512.dts

diff --git a/Documentation/devicetree/bindings/arm/tegra.txt b/Documentation/devicetree/bindings/arm/tegra.txt
index ccd4ef4..ed9c853 100644
--- a/Documentation/devicetree/bindings/arm/tegra.txt
+++ b/Documentation/devicetree/bindings/arm/tegra.txt
@@ -31,3 +31,4 @@ board-specific compatible values:
   nvidia,ventana
   nvidia,whistler
   toradex,colibri_t20-512
+  toradex,iris
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 5c13de2..b756c51 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -134,6 +134,7 @@ dtb-$(CONFIG_ARCH_SPEAR6XX)+= spear600-evb.dtb
 dtb-$(CONFIG_ARCH_SUNXI) += sun4i-a10-cubieboard.dtb \
 	sun5i-a13-olinuxino.dtb
 dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
+	tegra20-iris-512.dtb \
 	tegra20-medcom-wide.dtb \
 	tegra20-paz00.dtb \
 	tegra20-plutux.dtb \
diff --git a/arch/arm/boot/dts/tegra20-iris-512.dts b/arch/arm/boot/dts/tegra20-iris-512.dts
new file mode 100644
index 0000000..52f1103
--- /dev/null
+++ b/arch/arm/boot/dts/tegra20-iris-512.dts
@@ -0,0 +1,89 @@
+/dts-v1/;
+
+/include/ "tegra20-colibri-512.dtsi"
+
+/ {
+	model = "Toradex Colibri T20 512MB on Iris";
+	compatible = "toradex,iris", "toradex,colibri_t20-512", "nvidia,tegra20";
+
+	host1x {
+		hdmi {
+			status = "okay";
+		};
+	};
+
+	pinmux {
+		state_default: pinmux {
+			hdint {
+				nvidia,tristate = <0>;
+			};
+
+			i2cddc {
+				nvidia,tristate = <0>;
+			};
+
+			sdio4 {
+				nvidia,tristate = <0>;
+			};
+
+			uarta {
+				nvidia,tristate = <0>;
+			};
+
+			uartd {
+				nvidia,tristate = <0>;
+			};
+		};
+	};
+
+	usb at c5000000 {
+		status = "okay";
+		dr_mode = "otg";
+	};
+
+	usb at c5008000 {
+		status = "okay";
+	};
+
+	serial at 70006000 {
+		status = "okay";
+	};
+
+	serial at 70006300 {
+		status = "okay";
+	};
+
+	i2c_ddc: i2c at 7000c400 {
+		status = "okay";
+	};
+
+	sdhci at c8000600 {
+		status = "okay";
+		bus-width = <4>;
+		vmmc-supply = <&vcc_sd_reg>;
+		vqmmc-supply = <&vcc_sd_reg>;
+	};
+
+	regulators {
+		regulator at 0 {
+			compatible = "regulator-fixed";
+			reg = <0>;
+			regulator-name = "usb_host_vbus";
+			regulator-min-microvolt = <5000000>;
+			regulator-max-microvolt = <5000000>;
+			regulator-boot-on;
+			regulator-always-on;
+			gpio = <&gpio 178 0>;
+		};
+
+		vcc_sd_reg: regulator at 1 {
+			compatible = "regulator-fixed";
+			reg = <1>;
+			regulator-name = "vcc_sd";
+			regulator-min-microvolt = <3300000>;
+			regulator-max-microvolt = <3300000>;
+			regulator-boot-on;
+			regulator-always-on;
+		};
+	};
+};
-- 
1.8.0.2

^ permalink raw reply related

* One of these things (CONFIG_HZ) is not like the others..
From: Tony Lindgren @ 2013-01-22 21:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <50FEE175.90504@linaro.org>

* John Stultz <john.stultz@linaro.org> [130122 11:02]:
> 
> Correct, with HRT, we actually trigger the HZ-frequency timer tick
> from an hrtimer (which expires based on the system time driven by
> the clocksource). Thus even if there is a theoretical error between
> the ideal HZ and what the hardware can do, that error will not
> propagate forward.

If there's no cumulative error, sounds like the way to go is to select
HRT for ARM multiplatform builds and set the HZ to 100 then.

Regards,

Tony

^ permalink raw reply

* [PATCH] OMAPDSS: enable omapdss for ARCH_MULTIPLATFORM
From: Arnd Bergmann @ 2013-01-22 21:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358891160-9534-1-git-send-email-robdclark@gmail.com>

On Tuesday 22 January 2013, Rob Clark wrote:
> At least core omapdss does not have any build dependencies on
> ARCH_OMAP2PLUS, and adding this dependency in the Kconfig breaks omapdrm
> for ARCH_MULTIPLATFORM builds.
> 
> Signed-off-by: Rob Clark <robdclark@gmail.com>

Acked-by: Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply

* [PATCH] ARM: dts: specify all the per-cpu interrupts of arch timer for exynos5440
From: Kukjin Kim @ 2013-01-22 22:05 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130122101554.GA18876@e106331-lin.cambridge.arm.com>

Mark Rutland wrote:
>
+ devicetree-discuss, Grant Likely, Rob Herring and Tony Lindgren
 
> On Tue, Jan 22, 2013 at 01:41:27AM +0000, Kukjin Kim wrote:
> > From: Thomas Abraham <thomas.ab@samsung.com>
> >
> > Need to be changed requirements in the 'cpus' node for exynos5440
> > to specify all the per-cpu interrupts of arch timer.
> 
> The node(s) for the arch timer should not be in the cpus/cpu at N nodes.
> Instead, there should be one node (in the root of the tree).
> 
Well, I don't think so. As per my understanding, the local timers are
attached to every ARM cores (cpus) and it generates certain interrupt to the
GIC. So the correct representation for this in device tree is to include the
interrupts in the cpu nodes in dts file. Your comments  refer to a
limitation in the Linux kernel implementation of the arch_timer and it
should not result in representing the hardware details incorrectly in the
dts file.

> If this works currently it's only because the driver picks up one of the
nodes,
> and luckily it's the same as the others. This is not guaranteed to work in
> future, and will likely break.
> 
It is up to the Linux kernel implementation of arch_timer to handle the
hardware details in dts file accordingly.

> >
> > Signed-off-by: Thomas Abraham <thomas.ab@samsung.com>
> > Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
> > ---
> >  arch/arm/boot/dts/exynos5440.dtsi |   20 ++++++++++++++++----
> >  1 file changed, 16 insertions(+), 4 deletions(-)
> >
> > diff --git a/arch/arm/boot/dts/exynos5440.dtsi
> b/arch/arm/boot/dts/exynos5440.dtsi
> > index 5406689..c5bd8ed 100644
> > --- a/arch/arm/boot/dts/exynos5440.dtsi
> > +++ b/arch/arm/boot/dts/exynos5440.dtsi
> > @@ -28,7 +28,10 @@
> >  			compatible = "arm,cortex-a15";
> >  			timer {
> >  				compatible = "arm,armv7-timer";
> > -				interrupts = <1 13 0xf08>;
> > +				interrupts = <1 13 0xf08>,
> > +					     <1 14 0xf08>,
> > +					     <1 11 0xf08>,
> > +					     <1 10 0xf08>;
> 
> Also, this interrupts list is updated differently to all the other nodes.
Typo?
> 
Hmm, I think this should be fine. If any concerns, please let me know in
detail.

[...]

Thanks.

- Kukjin

^ permalink raw reply

* [PATCH V5 1/3] clk: tegra: add Tegra specific clocks
From: Stephen Warren @ 2013-01-22 22:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130122212448.24671.89455@quantum>

On 01/22/2013 02:24 PM, Mike Turquette wrote:
> Quoting Stephen Warren (2013-01-16 12:52:53)
>> From: Prashant Gaikwad <pgaikwad@nvidia.com>
>>
>> Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
>>
>> Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
>> [swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
>> storing pointers to stack variables, make a timeout loop more idiomatic,
>> use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
>> avoid redundant lock operations, unified tegra_clk_periph() and
>> tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
>> registration functions so they don't have the same name as the clock
>> structs.]
>> Signed-off-by: Stephen Warren <swarren@nvidia.com>
>> ---
>> V5: Implemented all changes marked [swarren] in the commit descriptions.
>>
>> Mike, These patches depend on a couple patches in the Tegra tree, and
>> various other Tegra patches depend on them. I'd like to take these through
>> the Tegra tree. Can you please ack or otherwise OK this? Thanks.
>>
> 
> For the series, including the updated v6 patch 2/3:
> 
> Acked-by: Mike Turquette <mturquette@linaro.org>

Thanks very much for the review.

I'm working on applying these patches and the other related ARM-side
patches to the Tegra for-3.9/soc branch as we speak.

^ 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