Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 5/5] ARM: gic: add OF based initialization
From: Cousson, Benoit @ 2011-09-15 13:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4E71F978.6020402@gmail.com>

On 9/15/2011 3:11 PM, Rob Herring wrote:
> Benoit,
>
> On 09/15/2011 05:07 AM, Cousson, Benoit wrote:
>> Hi Rob,
>>
>> On 9/15/2011 9:55 AM, Thomas Abraham wrote:
>>> Hi Rob,
>>>
>>> On 14 September 2011 22:01, Rob Herring<robherring2@gmail.com>   wrote:
>>>> From: Rob Herring<rob.herring@calxeda.com>
>>>>
>>>> This adds gic initialization using device tree data. The initialization
>>>> functions are intended to be called by a generic OF interrupt
>>>> controller parsing function once the right pieces are in place.
>>>>
>>>> PPIs are handled using 3rd cell of interrupts properties to specify
>>>> the cpu
>>>> mask the PPI is assigned to.
>>>>
>>>> Signed-off-by: Rob Herring<rob.herring@calxeda.com>
>>>> ---
>>>>    Documentation/devicetree/bindings/arm/gic.txt |   53
>>>> ++++++++++++++++++++++++
>>>>    arch/arm/common/gic.c                         |   55
>>>> +++++++++++++++++++++++--
>>>>    arch/arm/include/asm/hardware/gic.h           |   10 +++++
>>>>    3 files changed, 114 insertions(+), 4 deletions(-)
>>>>    create mode 100644 Documentation/devicetree/bindings/arm/gic.txt
>>>
>>> [...]
>>>
>>>
>>>> diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
>>>> index d1ccc72..14de380 100644
>>>> --- a/arch/arm/common/gic.c
>>>> +++ b/arch/arm/common/gic.c
>>>
>>> [...]
>>>
>>>> +void __init gic_of_init(struct device_node *node, struct device_node
>>>> *parent)
>>>> +{
>>>> +       void __iomem *cpu_base;
>>>> +       void __iomem *dist_base;
>>>> +       int irq;
>>>> +       struct irq_domain *domain =&gic_data[gic_cnt].domain;
>>>> +
>>>> +       if (WARN_ON(!node))
>>>> +               return;
>>>> +
>>>> +       dist_base = of_iomap(node, 0);
>>>> +       WARN(!dist_base, "unable to map gic dist registers\n");
>>>> +
>>>> +       cpu_base = of_iomap(node, 1);
>>>> +       WARN(!cpu_base, "unable to map gic cpu registers\n");
>>>> +
>>>> +       domain->nr_irq = gic_irq_count(dist_base);
>>>> +       domain->irq_base = irq_alloc_descs(-1, 0, domain->nr_irq,
>>>> numa_node_id());
>>>
>>> For exynos4, all the interrupts originating from GIC are statically
>>> mapped to start from 32 in the linux virq space (GIC SPI interrupts
>>> start from 64). In the above code, since irq_base would be 0 for
>>> exynos4, the interrupt mapping is not working correctly. In your
>>> previous version of the patch, you have given a option to the platform
>>> code to choose the offset. Could that option be added to this series
>>> also. Or a provision to use platform specific translate function
>>> instead of the irq_domain_simple translator.
>>
>> I have another concern on a similar topic.
>>
>> On OMAP4 the SoC interrupts external to the MPU (SPI) have an offset of
>> 32. Only the internal PPI are between 0 and 31.
>>
>> For the moment we add 32 to every SoC interrupts in the irq.h define,
>
> Those defines will not be used in the DT case. So the question is
> whether to add 32 or not in the DT. Since we have just a single node and
> a linear mapping of PPIs and SPIs, the only choice is to have SPIs start
> at 32. And from the h/w definition, SPIs always start at 32, so it's in
> agreement.

This is a agreement inside the MPUSS, but not outside.
Both Tegra and OMAP4 must add an offset to the HW irq number to deal 
with that today.

>> but I'm assuming that this offset calculation should be done thanks to a
>> dedicated irq domain for the SPI.
>> The real HW physical number start at 0, and thus this is that value that
>> should be in the irq binding of the device.
>>
>> So ideally we should have a irq domain for the PPI starting at 0 and
>> another one for the SPI starting at 32. Or 32 and 64 for the exynos4
>> case, but it looks like the PPI/SPI offset is always 32.
>>
>
> That offset of SPIs is always there. If you have a GIC as a secondary
> controller, It will have 32 reserved interrupts and the register layout
> is exactly the same as a cpu's GIC.

Yep, but that's the GIC view and not the SoC one. My concern is to have 
to tweak the HW number provided by the HW spec in order to add that offset.
If you look at SoC level, the MPUSS is just an IP that can be 
potentially replaced by other one that will not have a GIC. In that case 
you will not change the IRQ mapping at SoC level.
For example if you replace the Dual-cortexA9 by a single CortexA8, then 
all the interrupts will have to be shifted by 32 just because the MPU 
subsystem is different.

Since that offset is dependent of the GIC internals and is not exposed 
outside the MPUSS, it should not be visible by the SoC IPs. And the HW 
spec is exposing exactly that.

> Since the idea of splitting PPIs for each core out to a flattened linux
> irq map has been abandoned, I see no reason to have more than 1 domain
> with a simple linear translation. Ultimately, domains will do dynamic
> irqdesc allocation and the translation within the gic will be completely
> dynamic.

I think the only reason to do that is to separate internal MPU 
interrupts with the external ones that should not have a clue about the GIC.

Regards,
Benoit

^ permalink raw reply

* [PATCH 0/5] GIC OF bindings
From: Shawn Guo @ 2011-09-15 13:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316017900-19918-1-git-send-email-robherring2@gmail.com>

On Wed, Sep 14, 2011 at 11:31:35AM -0500, Rob Herring wrote:
> From: Rob Herring <rob.herring@calxeda.com>
> 
> This series introduces of_irq_init to scan the device tree for interrupt
> controller nodes and call their init functions in proper order. The GIC
> init function is then called from this function. The platform code then
> looks something like this:
> 
> const static struct of_device_id irq_match[] = {
> 	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
> 	{}
> };
> 
> static void __init highbank_init_irq(void)
> {
> 	of_irq_init(irq_match);
> }
> 
> The binding for GIC PPIs is now done with a 3rd interrupt cell to specify
> a cpu mask for which cpu the PPI is connected to. This was discussed at LPC
> and suggested by Grant.
> 
> I dropped the public intc_desc struct. The the interrupt controller's node
> and the interrupt parent's node are passed in directly to the controller's
> init function. The linux irq assignment is now done dynamically using
> irq_alloc_descs.
> 
> The first 2 patches are minor fixes to irqdomains.
> 
> Rob
> 
> Rob Herring (5):
>   irq: add declaration of irq_domain_simple_ops to irqdomain.h
>   irq: fix existing domain check in irq_domain_add
>   of/irq: introduce of_irq_init
>   ARM: gic: allow irq_start to be 0
>   ARM: gic: add OF based initialization
> 
>  Documentation/devicetree/bindings/arm/gic.txt |   53 ++++++++++++++
>  arch/arm/common/gic.c                         |   57 +++++++++++++--
>  arch/arm/include/asm/hardware/gic.h           |   10 +++
>  drivers/of/irq.c                              |   96 +++++++++++++++++++++++++
>  include/linux/irqdomain.h                     |    1 +
>  include/linux/of_irq.h                        |    1 +
>  kernel/irq/irqdomain.c                        |    2 +-
>  7 files changed, 214 insertions(+), 6 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/gic.txt

On imx6q:

Tested-by: Shawn Guo <shawn.guo@linaro.org>

-- 
Regards,
Shawn

^ permalink raw reply

* [PATCH v3 1/1] ASoC: mxs-saif: add record function
From: Wolfram Sang @ 2011-09-15 13:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <65EE16ACC360FA4D99C96DC085B3F77225DB00@039-SN1MPN1-003.039d.mgd.msft.net>


> > I think we should use usleep_range for both udelays here? Having a rate
> > of 8000, we'd burn 250us here.
> >
> Yes, I agree that it's a bit long for 8000.
> I tried sleep way but I found the trigger function is called with
> spin_lock held, so it seems we may not be able to sleep here.
> 
> I think the way of dynamically calculate delay suggested by Liam has
> Already minimize the affection, especially for high sample rate, it
> may work more efficiency than sleep (context switch cost).
> 
> Do you think if it's reasonable to accept it?

Yes, it can be fixed when it becomes necessary

Reviewed-by: Wolfram Sang <w.sang@pengutronix.de>

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110915/f6022c16/attachment.sig>

^ permalink raw reply

* [RFC PATCH 09/11] DT: regulator: Helper to extract regulator node based on supply name
From: Mark Brown @ 2011-09-15 13:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316085727-15023-10-git-send-email-rnayak@ti.com>

On Thu, Sep 15, 2011 at 04:52:05PM +0530, Rajendra Nayak wrote:

> 		regulator = <&regulator1>,<&regulator2>;
> 		regulator-names = "supply1","supply2";
> 	};

This syntax is really painful - we're relying on keeping two arrays in
sync which isn't good for legibility or robustness.  I'd expect
something like having a property with the supply name referencing the
regulator node concerned like:

	dbvdd = <&regulator1>;
	dcvdd = <&regulator2>;

or something.  Keeping the two arrays separate doesn't seem great.

^ permalink raw reply

* [RFC PATCH 10/11] regulator: Implement consumer regulator mapping from device tree
From: Mark Brown @ 2011-09-15 13:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316085727-15023-11-git-send-email-rnayak@ti.com>

On Thu, Sep 15, 2011 at 04:52:06PM +0530, Rajendra Nayak wrote:

> +#ifdef CONFIG_OF
> +	struct device_node *node;
> +	node = of_get_regulator(dev, id);
> +	if (!node)
> +		goto out;
> +	list_for_each_entry(rdev, &regulator_list, list)
> +		if (node == rdev->node)
> +			goto found;
> +#else
>  	list_for_each_entry(map, &regulator_map_list, list) {
>  		/* If the mapping has a device set up it must match */
>  		if (map->dev_name &&
> @@ -1178,6 +1189,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
>  			goto found;
>  		}
>  	}
> +#endif

This forces all machines to use device tree when CONFIG_OF is enabled.
I'd expect to see both mechanisms supported simultaneously, for example
by falling back to the current code if the device tree lookup fails.

> @@ -1216,6 +1228,15 @@ found:
>  	if (!try_module_get(rdev->owner))
>  		goto out;
>  
> +#ifdef CONFIG_OF
> +	ret = set_consumer_device_supply(rdev, dev, devname, id);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to set supply %d\n", ret);
> +		unset_regulator_supplies(rdev);
> +		goto out;
> +	}
> +#endif
> +

This seems wrong, why are we adding things to the regulator_map which is
really only there for lookups when we already did the lookup using the
device tree?

> @@ -2619,6 +2640,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
>  	rdev->reg_data = driver_data;
>  	rdev->owner = regulator_desc->owner;
>  	rdev->desc = regulator_desc;
> +	if (dev && dev->of_node)
> +		rdev->node = dev->of_node;

dev is mandatory.

^ permalink raw reply

* [PATCH v4] DRM: add DRM Driver for Samsung SoC EXYNOS4210.
From: Konrad Rzeszutek Wilk @ 2011-09-15 14:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <002c01cc738b$1c717df0$555479d0$%dae@samsung.com>

On Thu, Sep 15, 2011 at 06:37:39PM +0900, Inki Dae wrote:
> Hello, Konrad Rzeszutek Wilk.
> 
> Your review and comments are so very detail. it was very helpful. thank you
> again.

.. snip ..
> > > +		/* FIXME: error check */
> > 
> > You might as well do it now - before you do the next posting.
> > 
> 
> Ok, get it. you mean, send this patch modified now, not next posting.?

When you are ready to send V5 (hopefully the last version) of these patches.

.. snip..
> > > + * @ops: pointer to samsung_drm_overlay_ops.
> > > + *
> > > + * this structure is common to Samsung SoC and would be copied
> > > + * to hardware specific overlay info.
> > 
> > Uh?
> 
> This means that contents of samsung_drm_overlay object will copied to fimd's
> one, struct fimd_win_data.

Ok, lets use that comment instead then.
> 
> > > + */
> > > +struct samsung_drm_overlay {
> > > +	unsigned int offset_x;
> > > +	unsigned int offset_y;
> > > +	unsigned int width;
> > > +	unsigned int height;
> > > +	unsigned int paddr;
> > 
> > You don't want to use 'dma_addr_t' ?
> > 
> 
> You are right. I will correct it. thank you.
> 
> > > +	void __iomem *vaddr;
> > > +	unsigned int buf_off;
> > > +	unsigned int end_buf_off;
> > > +	unsigned int buf_offsize;
> > > +	unsigned int line_size;
> > > +
> > > +	bool default_win;
> > > +	bool color_key;
> > > +	unsigned int index_color;
> > > +	bool local_path;
> > > +	bool transparency;
> > > +	bool activated;
> > > +};
> > > +
> > > +/**
> > > + * Samsung DRM Display Structure.
> > > + *	- this structure is common to analog tv, digital tv and lcd panel.
> > > + *
> > > + * @dev: pointer to specific device object.
> > 
> > ??
> 
> Ah, this should be removed. Thank you.
> 
> > > + * @is_connected: check for that display is connected or not.
> > > + * @get_edid: get edid modes from display driver.
> > > + * @get_timing: get timing object from display driver.
> > > + * @check_timing: check if timing is valid or not.
> > > + * @power_on: display device on or off.
> > > + */
> > > +struct samsung_drm_display {
> > > +	unsigned int type;
> > > +	bool (*is_connected)(struct device *dev);
> > > +	int (*get_edid)(struct device *dev, struct drm_connector *connector,
> > > +				u8 *edid, int len);
> > > +	void *(*get_timing)(struct device *dev);
> > > +	int (*check_timing)(struct device *dev, void *timing);
> > > +	int (*power_on)(struct device *dev, int mode);
> > > +};
> > > +
> > > +/**
> > > + * Samsung drm manager ops
> > > + *
> > > + * @mode_set: convert drm_display_mode to hw specific display mode and
> > > + *	      would be called by encoder->mode_set().
> > > + * @commit: set current hw specific display mode to hw.
> > > + * @enable_vblank: specific driver callback for enabling vblank
> > interrupt.
> > > + * @disable_vblank: specific driver callback for disabling vblank
> > interrupt.
> > > + */
> > > +struct samsung_drm_manager_ops {
> > > +	void (*mode_set)(struct device *subdrv_dev, void *mode);
> > > +	void (*commit)(struct device *subdrv_dev);
> > > +	int (*enable_vblank)(struct device *subdrv_dev);
> > > +	void (*disable_vblank)(struct device *subdrv_dev);
> > > +};
> > > +
> > > +/**
> > > + * Samsung drm common manager structure.
> > > + *
> > > + * @dev: pointer to device object for subdrv device driver.
> > > + * @ops: ops pointer to samsung drm common framebuffer.
> > > + *	 ops of fimd or hdmi driver should be set to this ones.
> > > + */
> > > +struct samsung_drm_manager {
> > > +	struct device *dev;
> > > +	int pipe;
> > 
> > No comment for that?
> 
> Ok, get it. I will add some comment for that. thank you.
> 
> > > +	struct samsung_drm_manager_ops *ops;
> > > +	struct samsung_drm_overlay_ops *overlay_ops;
> > > +	struct samsung_drm_display *display;
> > 
> > And you are missing the comments for these two.
> 
> Also.
> 
> > > +};
> > > +
> > > +/**
> > 
> > I just noticed it, but the '**' is not the kerneldoc
> > style comment. You might want to remove them from all the files.
> > 
> 
> Ok, get it. thank you.
> 
> > > + * Samsung drm private structure.
> > 
> > Ok, you are defining it in a public header so you should at
> > least document what the fields mean.
> > 
> 
> Ok, get it. I will add comments to all fields and thank you for your
> pointing.
> 
> > If you don't want the public to use it - make another header
> > file, helpfully called 'xxx_private.h'
> > 
> > 
> > > + */
> > > +struct samsung_drm_private {
> > > +	struct drm_fb_helper *fb_helper;
> > > +
> > > +	/* for pageflip */
> > > +	struct list_head pageflip_event_list;
> > > +	bool pageflip_event;
> > > +
> > > +	struct drm_crtc *crtc[MAX_CRTC];
> > > +
> > > +	/* add some structures. */
> > 
> > Umm, which ones?
> > 
> 
> This comment will be removed. Thank you.
> 
> > > +};
> > > +
> > > +struct samsung_drm_subdrv {
> > > +	struct list_head list;
> > > +	struct drm_device *drm_dev;
> > > +
> > > +	/* driver ops */
> > > +	int (*probe)(struct drm_device *dev);
> > > +	void (*remove)(struct drm_device *dev);
> > > +
> > > +	struct samsung_drm_manager manager;
> > > +	struct drm_encoder *encoder;
> > > +	struct drm_connector *connector;
> > > +};
> > > +
> > > +int samsung_drm_device_register(struct drm_device *dev);
> > > +void samsung_drm_device_unregister(struct drm_device *dev);
> > > +int samsung_drm_subdrv_register(struct samsung_drm_subdrv *drm_subdrv);
> > > +void samsung_drm_subdrv_unregister(struct samsung_drm_subdrv
> > *drm_subdrv);
> > > +
> > > +#endif
> > > diff --git a/drivers/gpu/drm/samsung/samsung_drm_encoder.c
> > b/drivers/gpu/drm/samsung/samsung_drm_encoder.c
> > > new file mode 100644
> > > index 0000000..c875968
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/samsung/samsung_drm_encoder.c
> > > @@ -0,0 +1,261 @@
> > > +/*
> > > + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> > > + * Authors:
> > > + *	Inki Dae <inki.dae@samsung.com>
> > > + *	Joonyoung Shim <jy0922.shim@samsung.com>
> > > + *	SeungWoo Kim <sw0312.kim@samsung.com>
> > > + *
> > > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > > + * copy of this software and associated documentation files (the
> > "Software"),
> > > + * to deal in the Software without restriction, including without
> > limitation
> > > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > > + * and/or sell copies of the Software, and to permit persons to whom
> > the
> > > + * Software is furnished to do so, subject to the following conditions:
> > > + *
> > > + * The above copyright notice and this permission notice (including the
> > next
> > > + * paragraph) shall be included in all copies or substantial portions
> > of the
> > > + * Software.
> > > + *
> > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
> > SHALL
> > > + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES OR
> > > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> OTHERWISE,
> > > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
> > OR
> > > + * OTHER DEALINGS IN THE SOFTWARE.
> > > + */
> > > +
> > > +#include "drmP.h"
> > > +#include "drm_crtc_helper.h"
> > > +
> > > +#include "samsung_drm_drv.h"
> > > +#include "samsung_drm_crtc.h"
> > > +#include "samsung_drm_encoder.h"
> > > +
> > > +#define to_samsung_encoder(x)	container_of(x, struct
> > samsung_drm_encoder,\
> > > +				drm_encoder)
> > > +
> > > +struct samsung_drm_encoder {
> > > +	struct drm_encoder		drm_encoder;
> > > +	struct samsung_drm_manager	*manager;
> > > +};
> > > +
> > > +static void samsung_drm_encoder_dpms(struct drm_encoder *encoder, int
> > mode)
> > > +{
> > > +	struct drm_device *dev = encoder->dev;
> > > +	struct drm_connector *connector;
> > > +	struct samsung_drm_manager *manager =
> > samsung_drm_get_manager(encoder);
> > > +
> > > +	DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);
> > > +
> > > +	list_for_each_entry(connector, &dev->mode_config.connector_list,
> > head) {
> > > +		if (connector->encoder == encoder) {
> > > +			struct samsung_drm_display *display =
> manager->display;
> > > +
> > > +			if (display && display->power_on)
> > > +				display->power_on(manager->dev, mode);
> > > +		}
> > > +	}
> > > +}
> > > +
> > > +static bool
> > > +samsung_drm_encoder_mode_fixup(struct drm_encoder *encoder,
> > > +			       struct drm_display_mode *mode,
> > > +			       struct drm_display_mode *adjusted_mode)
> > > +{
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	return true;
> > > +}
> > > +
> > > +static void samsung_drm_encoder_mode_set(struct drm_encoder *encoder,
> > > +					 struct drm_display_mode *mode,
> > > +					 struct drm_display_mode
> *adjusted_mode)
> > > +{
> > > +	struct drm_device *dev = encoder->dev;
> > > +	struct drm_connector *connector;
> > > +	struct samsung_drm_manager *manager =
> > samsung_drm_get_manager(encoder);
> > > +	struct samsung_drm_manager_ops *manager_ops = manager->ops;
> > > +	struct samsung_drm_overlay_ops *overlay_ops = manager->overlay_ops;
> > > +	struct samsung_drm_overlay *overlay = get_samsung_drm_overlay(dev,
> > > +						encoder->crtc);
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	mode = adjusted_mode;
> > > +
> > > +	list_for_each_entry(connector, &dev->mode_config.connector_list,
> > head) {
> > > +		if (connector->encoder == encoder) {
> > > +			if (manager_ops && manager_ops->mode_set)
> > > +				manager_ops->mode_set(manager->dev, mode);
> > > +
> > > +			if (overlay_ops && overlay_ops->mode_set)
> > > +				overlay_ops->mode_set(manager->dev,
> overlay);
> > > +		}
> > > +	}
> > > +}
> > > +
> > > +static void samsung_drm_encoder_prepare(struct drm_encoder *encoder)
> > > +{
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +}
> > > +
> > > +static void samsung_drm_encoder_commit(struct drm_encoder *encoder)
> > > +{
> > > +	struct samsung_drm_manager *manager =
> > samsung_drm_get_manager(encoder);
> > > +	struct samsung_drm_manager_ops *manager_ops = manager->ops;
> > > +	struct samsung_drm_overlay_ops *overlay_ops = manager->overlay_ops;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	if (manager_ops && manager_ops->commit)
> > > +		manager_ops->commit(manager->dev);
> > > +
> > > +	if (overlay_ops && overlay_ops->commit)
> > > +		overlay_ops->commit(manager->dev);
> > > +}
> > > +
> > > +static struct drm_crtc *
> > > +samsung_drm_encoder_get_crtc(struct drm_encoder *encoder)
> > > +{
> > > +	return encoder->crtc;
> > > +}
> > > +
> > > +static struct drm_encoder_helper_funcs samsung_encoder_helper_funcs = {
> > > +	.dpms		= samsung_drm_encoder_dpms,
> > > +	.mode_fixup	= samsung_drm_encoder_mode_fixup,
> > > +	.mode_set	= samsung_drm_encoder_mode_set,
> > > +	.prepare	= samsung_drm_encoder_prepare,
> > > +	.commit		= samsung_drm_encoder_commit,
> > > +	.get_crtc	= samsung_drm_encoder_get_crtc,
> > > +};
> > > +
> > > +static void samsung_drm_encoder_destroy(struct drm_encoder *encoder)
> > > +{
> > > +	struct samsung_drm_encoder *samsung_encoder =
> > > +		to_samsung_encoder(encoder);
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	samsung_encoder->manager->pipe = -1;
> > > +
> > > +	drm_encoder_cleanup(encoder);
> > > +	encoder->dev->mode_config.num_encoder--;
> > > +	kfree(samsung_encoder);
> > > +}
> > > +
> > > +static struct drm_encoder_funcs samsung_encoder_funcs = {
> > > +	.destroy = samsung_drm_encoder_destroy,
> > > +};
> > > +
> > > +struct drm_encoder *
> > > +samsung_drm_encoder_create(struct drm_device *dev,
> > > +			   struct samsung_drm_manager *manager,
> > > +			   unsigned int possible_crtcs)
> > > +{
> > > +	struct drm_encoder *encoder;
> > > +	struct samsung_drm_encoder *samsung_encoder;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	if (!manager || !possible_crtcs)
> > > +		return NULL;
> > > +
> > > +	if (!manager->dev)
> > > +		return NULL;
> > > +
> > > +	samsung_encoder = kzalloc(sizeof(*samsung_encoder), GFP_KERNEL);
> > > +	if (!samsung_encoder) {
> > > +		DRM_ERROR("failed to allocate encoder\n");
> > > +		return NULL;
> > > +	}
> > > +
> > > +	samsung_encoder->manager = manager;
> > > +	encoder = &samsung_encoder->drm_encoder;
> > > +	encoder->possible_crtcs = possible_crtcs;
> > > +
> > > +	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
> > > +
> > > +	drm_encoder_init(dev, encoder, &samsung_encoder_funcs,
> > > +			DRM_MODE_ENCODER_TMDS);
> > > +
> > > +	drm_encoder_helper_add(encoder, &samsung_encoder_helper_funcs);
> > > +
> > > +	DRM_DEBUG_KMS("encoder has been created\n");
> > > +
> > > +	return encoder;
> > > +}
> > > +
> > > +struct samsung_drm_manager *samsung_drm_get_manager(struct drm_encoder
> > *encoder)
> > > +{
> > > +	return to_samsung_encoder(encoder)->manager;
> > > +}
> > > +
> > > +void samsung_drm_fn_encoder(struct drm_crtc *crtc, void *data,
> > > +			    void (*fn)(struct drm_encoder *, void *))
> > > +{
> > > +	struct drm_device *dev = crtc->dev;
> > > +	struct drm_encoder *encoder;
> > > +
> > > +	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
> > {
> > > +		if (encoder->crtc != crtc)
> > > +			continue;
> > > +
> > > +		fn(encoder, data);
> > > +	}
> > > +}
> > > +
> > > +void samsung_drm_enable_vblank(struct drm_encoder *encoder, void *data)
> > > +{
> > > +	struct samsung_drm_manager *manager =
> > > +		to_samsung_encoder(encoder)->manager;
> > > +	struct samsung_drm_manager_ops *manager_ops = manager->ops;
> > > +	int crtc = *(int *)data;
> > > +
> > > +	if (manager->pipe == -1)
> > > +		manager->pipe = crtc;
> > > +
> > > +	/* old_crtc checking needs? FIXME!!! */
> > 
> > Is this still pertient?
> > 
> 
> I will remove this comment after looking over more. Thank you.
> 
> > > +
> > > +	if (manager_ops->enable_vblank)
> > > +		manager_ops->enable_vblank(manager->dev);
> > > +}
> > > +
> > > +void samsung_drm_disable_vblank(struct drm_encoder *encoder, void
> *data)
> > > +{
> > > +	struct samsung_drm_manager *manager =
> > > +		to_samsung_encoder(encoder)->manager;
> > > +	struct samsung_drm_manager_ops *manager_ops = manager->ops;
> > > +	int crtc = *(int *)data;
> > 
> > You don't want to check whether data is NULL before you
> > derefernce it?
> > 
> 
> Ok, get it. thank you.
> 
> > > +
> > > +	if (manager->pipe == -1)
> > > +		manager->pipe = crtc;
> > > +
> > > +	/* old_crtc checking needs? FIXME!!! */
> > 
> > I am not really sure what it means.. It probably means something to you -
> > but
> > perhaps it might make sense to expand it in case somebody else wants to
> > implement this?
> > 
> 
> As I mentioned above, I will remove this comment after looking over more.
> Thank you.
> 
> > > +
> > > +	if (manager_ops->disable_vblank)
> > > +		manager_ops->disable_vblank(manager->dev);
> > > +}
> > > +
> > > +void samsung_drm_encoder_crtc_commit(struct drm_encoder *encoder, void
> > *data)
> > > +{
> > > +	struct samsung_drm_manager *manager =
> > > +		to_samsung_encoder(encoder)->manager;
> > > +	struct samsung_drm_overlay_ops *overlay_ops = manager->overlay_ops;
> > > +
> > > +	overlay_ops->commit(manager->dev);
> > > +}
> > > +
> > > +void samsung_drm_encoder_crtc_mode_set(struct drm_encoder *encoder,
> > void *data)
> > > +{
> > > +	struct samsung_drm_manager *manager =
> > > +		to_samsung_encoder(encoder)->manager;
> > > +	struct samsung_drm_overlay_ops *overlay_ops = manager->overlay_ops;
> > > +	struct samsung_drm_overlay *overlay = data;
> > > +
> > > +	overlay_ops->mode_set(manager->dev, overlay);
> > > +}
> > > +
> > > +MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
> > 
> > You don't want to include the rest of the authors?
> 
> Definitely no. I will add other authors. Thank you.
> 
> > > +MODULE_DESCRIPTION("Samsung SoC DRM Encoder Driver");
> > > +MODULE_LICENSE("GPL");
> > > diff --git a/drivers/gpu/drm/samsung/samsung_drm_encoder.h
> > b/drivers/gpu/drm/samsung/samsung_drm_encoder.h
> > > new file mode 100644
> > > index 0000000..99040b2
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/samsung/samsung_drm_encoder.h
> > > @@ -0,0 +1,45 @@
> > > +/*
> > > + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> > > + * Authors:
> > > + *	Inki Dae <inki.dae@samsung.com>
> > > + *	Joonyoung Shim <jy0922.shim@samsung.com>
> > > + *	SeungWoo Kim <sw0312.kim@samsung.com>
> > > + *
> > > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > > + * copy of this software and associated documentation files (the
> > "Software"),
> > > + * to deal in the Software without restriction, including without
> > limitation
> > > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > > + * and/or sell copies of the Software, and to permit persons to whom
> > the
> > > + * Software is furnished to do so, subject to the following conditions:
> > > + *
> > > + * The above copyright notice and this permission notice (including the
> > next
> > > + * paragraph) shall be included in all copies or substantial portions
> > of the
> > > + * Software.
> > > + *
> > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
> > SHALL
> > > + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES OR
> > > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> OTHERWISE,
> > > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
> > OR
> > > + * OTHER DEALINGS IN THE SOFTWARE.
> > > + */
> > > +
> > > +#ifndef _SAMSUNG_DRM_ENCODER_H_
> > > +#define _SAMSUNG_DRM_ENCODER_H_
> > > +
> > > +struct samsung_drm_manager;
> > > +
> > > +struct drm_encoder *samsung_drm_encoder_create(struct drm_device *dev,
> > > +					       struct samsung_drm_manager
> *mgr,
> > > +					       unsigned int possible_crtcs);
> > > +struct samsung_drm_manager *
> > > +samsung_drm_get_manager(struct drm_encoder *encoder);
> > > +void samsung_drm_fn_encoder(struct drm_crtc *crtc, void *data,
> > > +			    void (*fn)(struct drm_encoder *, void *));
> > > +void samsung_drm_enable_vblank(struct drm_encoder *encoder, void
> *data);
> > > +void samsung_drm_disable_vblank(struct drm_encoder *encoder, void
> > *data);
> > > +void samsung_drm_encoder_crtc_commit(struct drm_encoder *encoder, void
> > *data);
> > > +void samsung_drm_encoder_crtc_mode_set(struct drm_encoder *encoder,
> > void *data);
> > > +
> > > +#endif
> > > diff --git a/drivers/gpu/drm/samsung/samsung_drm_fb.c
> > b/drivers/gpu/drm/samsung/samsung_drm_fb.c
> > > new file mode 100644
> > > index 0000000..f087ecf
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/samsung/samsung_drm_fb.c
> > > @@ -0,0 +1,262 @@
> > > +/*
> > > + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> > > + * Authors:
> > > + *	Inki Dae <inki.dae@samsung.com>
> > > + *	Joonyoung Shim <jy0922.shim@samsung.com>
> > > + *	SeungWoo Kim <sw0312.kim@samsung.com>
> > > + *
> > > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > > + * copy of this software and associated documentation files (the
> > "Software"),
> > > + * to deal in the Software without restriction, including without
> > limitation
> > > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > > + * and/or sell copies of the Software, and to permit persons to whom
> > the
> > > + * Software is furnished to do so, subject to the following conditions:
> > > + *
> > > + * The above copyright notice and this permission notice (including the
> > next
> > > + * paragraph) shall be included in all copies or substantial portions
> > of the
> > > + * Software.
> > > + *
> > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
> > SHALL
> > > + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES OR
> > > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> OTHERWISE,
> > > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
> > OR
> > > + * OTHER DEALINGS IN THE SOFTWARE.
> > > + */
> > > +
> > > +#include "drmP.h"
> > > +#include "drm_crtc.h"
> > > +#include "drm_crtc_helper.h"
> > > +
> > > +#include "samsung_drm_fb.h"
> > > +#include "samsung_drm_buf.h"
> > > +#include "samsung_drm_gem.h"
> > > +
> > > +#define to_samsung_fb(x)	container_of(x, struct samsung_drm_fb,
> > fb)
> > > +
> > > +struct samsung_drm_fb {
> > > +	struct drm_framebuffer		fb;
> > > +	struct samsung_drm_gem_obj	*samsung_gem_obj;
> > > +
> > > +	unsigned int			fb_size;
> > > +	dma_addr_t			paddr;
> > > +	void __iomem			*vaddr;
> > > +};
> > > +
> > > +static void samsung_drm_fb_destroy(struct drm_framebuffer *fb)
> > > +{
> > > +	struct samsung_drm_fb *samsung_fb = to_samsung_fb(fb);
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	drm_framebuffer_cleanup(fb);
> > > +
> > > +	/* default framebuffer has no gem object so it releases buffer. */
> > 
> > What is 'it' ?
> > 
> 
> Please, ignore 'it'. and  I will correct this comment. Thank you.
> 
> > > +	if (!samsung_fb->samsung_gem_obj)
> > > +		samsung_drm_buf_destroy(fb->dev,
> > > +				samsung_fb->samsung_gem_obj->entry);
> > > +
> > > +	kfree(samsung_fb);
> > 
> > samsung_fb = NULL;
> > 
> 
> Thank you.
> 
> > > +}
> > > +
> > > +static int samsung_drm_fb_create_handle(struct drm_framebuffer *fb,
> > > +					struct drm_file *file_priv,
> > > +					unsigned int *handle)
> > > +{
> > > +	struct samsung_drm_fb *samsung_fb = to_samsung_fb(fb);
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	return drm_gem_handle_create(file_priv,
> > > +					&samsung_fb->samsung_gem_obj->base,
> > > +					handle);
> > > +}
> > > +
> > > +static int samsung_drm_fb_dirty(struct drm_framebuffer *fb,
> > > +				struct drm_file *file_priv, unsigned flags,
> > > +				unsigned color, struct drm_clip_rect *clips,
> > > +				unsigned num_clips)
> > > +{
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	/*
> > > +	 * update framebuffer and its hardware.
> > > +	 * - this callback would be called by user application
> > > +	 *	with DRM_IOCTL_MODE_DIRTYFB command.
> > > +	 *
> > > +	 * ps. Userspace can notify the driver via this callback
> > > +	 * that an area of the framebuffer has been changed then should
> > > +	 * be flushed to the display hardware.
> > > +	 */
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static struct drm_framebuffer_funcs samsung_drm_fb_funcs = {
> > > +	.destroy	= samsung_drm_fb_destroy,
> > > +	.create_handle	= samsung_drm_fb_create_handle,
> > > +	.dirty		= samsung_drm_fb_dirty,
> > > +};
> > > +
> > > +static struct drm_framebuffer *
> > > +samsung_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev,
> > > +		    struct drm_mode_fb_cmd *mode_cmd)
> > > +{
> > > +	struct samsung_drm_fb *samsung_fb;
> > > +	struct drm_framebuffer *fb;
> > > +	struct samsung_drm_gem_obj *samsung_gem_obj = NULL;
> > > +	struct drm_gem_object *obj;
> > > +	unsigned int size;
> > > +	int ret;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	mode_cmd->pitch = max(mode_cmd->pitch,
> > > +			mode_cmd->width * (mode_cmd->bpp >> 3));
> > > +
> > > +	DRM_LOG_KMS("drm fb create(%dx%d)\n",
> > > +			mode_cmd->width, mode_cmd->height);
> > > +
> > > +	samsung_fb = kzalloc(sizeof(*samsung_fb), GFP_KERNEL);
> > > +	if (!samsung_fb) {
> > > +		DRM_ERROR("failed to allocate samsung drm framebuffer.\n");
> > > +		return ERR_PTR(-ENOMEM);
> > > +	}
> > > +
> > > +	fb = &samsung_fb->fb;
> > > +	ret = drm_framebuffer_init(dev, fb, &samsung_drm_fb_funcs);
> > > +	if (ret) {
> > > +		DRM_ERROR("failed to initialize framebuffer.\n");
> > > +		goto err_init;
> > > +	}
> > > +
> > > +	DRM_LOG_KMS("create: fb id: %d\n", fb->base.id);
> > > +
> > > +	size = mode_cmd->pitch * mode_cmd->height;
> > > +
> > > +	/*
> > > +	 * mode_cmd->handle could be pointer to a buffer allocated by user
> > > +	 * application using KMS library.
> > > +	 */
> > > +	if (!mode_cmd->handle) {
> > > +		/*
> > > +		 * in case that file_priv is NULL, it allocates only buffer
> > and
> > > +		 * this buffer would be used for default framebuffer.
> > > +		 */
> > > +		if (!file_priv) {
> > > +			struct samsung_drm_buf_entry *entry;
> > > +
> > > +			entry = samsung_drm_buf_create(dev, size);
> > > +			if (IS_ERR(entry)) {
> > > +				ret = PTR_ERR(entry);
> > > +				goto err_buf_create;
> > > +			}
> > > +
> > > +			samsung_fb->vaddr = entry->vaddr;
> > > +			samsung_fb->paddr = entry->paddr;
> > > +
> > > +			DRM_LOG_KMS("default fb: paddr = 0x%x, size =
> 0x%x\n",
> > > +					entry->paddr, size);
> > > +
> > > +			goto out;
> > > +		} else {
> > > +			samsung_gem_obj = samsung_drm_gem_create(file_priv,
> > dev,
> > > +							size,
> > > +							&mode_cmd->handle);
> > > +			if (IS_ERR(samsung_gem_obj)) {
> > > +				ret = PTR_ERR(samsung_gem_obj);
> > > +				goto err_gem_create;
> > > +			}
> > > +		}
> > > +	} else {
> > > +		obj = drm_gem_object_lookup(dev, file_priv, mode_cmd-
> > >handle);
> > > +		if (!obj) {
> > > +			DRM_ERROR("failed to lookup gem object.\n");
> > > +			goto err_lookup;
> > > +		}
> > > +
> > > +		samsung_gem_obj = to_samsung_gem_obj(obj);
> > > +
> > > +		drm_gem_object_unreference_unlocked(obj);
> > > +	}
> > > +
> > > +	/*
> > > +	 * in case of getting samsung_gem_obj from either handle or
> > > +	 * new creation.
> > > +	 */
> > > +	samsung_fb->vaddr = samsung_gem_obj->entry->vaddr;
> > > +	samsung_fb->paddr = samsung_gem_obj->entry->paddr;
> > > +
> > > +	DRM_LOG_KMS("paddr = 0x%x, size = 0x%x, gem object = 0x%x\n",
> > > +			samsung_fb->paddr, size,
> (u32)&samsung_gem_obj->base);
> > 
> > Why truncating it to be 4GB? Is it potentially possible that this
> > could run a machine with 5GB?
> > 
> 
> You are right. I will correct it. thank you.
> 
> > > +
> > > +out:
> > > +	samsung_fb->samsung_gem_obj = samsung_gem_obj;
> > > +	samsung_fb->fb_size = size;
> > > +
> > > +	drm_helper_mode_fill_fb_struct(fb, mode_cmd);
> > > +
> > > +	return fb;
> > > +
> > > +err_lookup:
> > > +err_gem_create:
> > > +err_buf_create:
> > 
> > Why don't you just coalesce them all together and call it:
> > err:
> > 
> 
> Ok, get it. your saying is more clean. Thank you.
> 
> 
> > > +	drm_framebuffer_cleanup(fb);
> > > +
> > > +err_init:
> > > +	kfree(samsung_fb);
> > > +
> > > +	return ERR_PTR(ret);
> > > +}
> > > +
> > > +struct drm_framebuffer *samsung_drm_fb_create(struct drm_device *dev,
> > > +					      struct drm_file *file_priv,
> > > +					      struct drm_mode_fb_cmd
> *mode_cmd)
> > > +{
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	return samsung_drm_fb_init(file_priv, dev, mode_cmd);
> > > +}
> > > +
> > > +void samsung_drm_fb_update_buf_off(struct drm_framebuffer *fb,
> > > +				   unsigned int x, unsigned int y,
> > > +				   struct samsung_drm_buffer_info *info)
> > > +{
> > > +	struct samsung_drm_fb *samsung_fb = to_samsung_fb(fb);
> > > +	unsigned long offset;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	offset = x * (fb->bits_per_pixel >> 3);
> > > +	offset += y * fb->pitch;
> > > +
> > > +	info->base_addr = samsung_fb->paddr;
> > > +	info->vaddr = samsung_fb->vaddr + offset;
> > > +	info->paddr = samsung_fb->paddr + offset;
> > > +
> > > +	DRM_DEBUG_KMS("updated vaddr = 0x%x, paddr = 0x%x, offset = 0x%x\n",
> > > +			(unsigned int)info->vaddr,
> > > +			(unsigned int)info->paddr,
> > > +			(unsigned int)offset);
> > > +}
> > > +
> > > +static struct drm_mode_config_funcs samsung_drm_mode_config_funcs = {
> > > +	.fb_create = samsung_drm_fb_create,
> > > +};
> > > +
> > > +void samsung_drm_mode_config_init(struct drm_device *dev)
> > > +{
> > > +	dev->mode_config.min_width = 0;
> > > +	dev->mode_config.min_height = 0;
> > > +
> > > +	/*
> > > +	 * It sets max width and height as default value(4096x4096).
> > > +	 * this value would be used to check for framebuffer size
> > limitation
> > > +	 * at drm_mode_addfb().
> > > +	 */
> > > +	dev->mode_config.max_width = 4096;
> > > +	dev->mode_config.max_height = 4096;
> > > +
> > > +	dev->mode_config.funcs = &samsung_drm_mode_config_funcs;
> > > +}
> > > diff --git a/drivers/gpu/drm/samsung/samsung_drm_fb.h
> > b/drivers/gpu/drm/samsung/samsung_drm_fb.h
> > > new file mode 100644
> > > index 0000000..6256089
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/samsung/samsung_drm_fb.h
> > > @@ -0,0 +1,47 @@
> > > +/*
> > > + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> > > + * Authors:
> > > + *	Inki Dae <inki.dae@samsung.com>
> > > + *	Joonyoung Shim <jy0922.shim@samsung.com>
> > > + *	SeungWoo Kim <sw0312.kim@samsung.com>
> > > + *
> > > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > > + * copy of this software and associated documentation files (the
> > "Software"),
> > > + * to deal in the Software without restriction, including without
> > limitation
> > > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > > + * and/or sell copies of the Software, and to permit persons to whom
> > the
> > > + * Software is furnished to do so, subject to the following conditions:
> > > + *
> > > + * The above copyright notice and this permission notice (including the
> > next
> > > + * paragraph) shall be included in all copies or substantial portions
> > of the
> > > + * Software.
> > > + *
> > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
> > SHALL
> > > + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES OR
> > > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> OTHERWISE,
> > > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
> > OR
> > > + * OTHER DEALINGS IN THE SOFTWARE.
> > > + */
> > > +
> > > +#ifndef _SAMSUNG_DRM_FB_H_
> > > +#define _SAMSUNG_DRM_FB_H
> > > +
> > > +struct samsung_drm_buffer_info {
> > > +	unsigned long base_addr;
> > > +	dma_addr_t paddr;
> > > +	void __iomem *vaddr;
> > > +};
> > > +
> > > +void samsung_drm_fb_update_buf_off(struct drm_framebuffer *fb,
> > > +				   unsigned int x, unsigned int y,
> > > +				   struct samsung_drm_buffer_info *info);
> > > +
> > > +struct drm_framebuffer *samsung_drm_fb_create(struct drm_device *dev,
> > > +					      struct drm_file *filp,
> > > +					      struct drm_mode_fb_cmd
> *mode_cmd);
> > > +
> > > +void samsung_drm_mode_config_init(struct drm_device *dev);
> > > +
> > > +#endif
> > > diff --git a/drivers/gpu/drm/samsung/samsung_drm_fbdev.c
> > b/drivers/gpu/drm/samsung/samsung_drm_fbdev.c
> > > new file mode 100644
> > > index 0000000..1c46bc6
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/samsung/samsung_drm_fbdev.c
> > > @@ -0,0 +1,409 @@
> > > +/*
> > > + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> > > + * Authors:
> > > + *	Inki Dae <inki.dae@samsung.com>
> > > + *	Joonyoung Shim <jy0922.shim@samsung.com>
> > > + *	SeungWoo Kim <sw0312.kim@samsung.com>
> > > + *
> > > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > > + * copy of this software and associated documentation files (the
> > "Software"),
> > > + * to deal in the Software without restriction, including without
> > limitation
> > > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > > + * and/or sell copies of the Software, and to permit persons to whom
> > the
> > > + * Software is furnished to do so, subject to the following conditions:
> > > + *
> > > + * The above copyright notice and this permission notice (including the
> > next
> > > + * paragraph) shall be included in all copies or substantial portions
> > of the
> > > + * Software.
> > > + *
> > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
> > SHALL
> > > + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES OR
> > > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> OTHERWISE,
> > > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
> > OR
> > > + * OTHER DEALINGS IN THE SOFTWARE.
> > > + */
> > > +
> > > +#include "drmP.h"
> > > +#include "drm_crtc.h"
> > > +#include "drm_fb_helper.h"
> > > +#include "drm_crtc_helper.h"
> > > +
> > > +#include "samsung_drm_drv.h"
> > > +#include "samsung_drm_fb.h"
> > > +
> > > +#define to_samsung_fbdev(x)	container_of(x, struct
> > samsung_drm_fbdev,\
> > > +				drm_fb_helper)
> > > +
> > > +struct samsung_drm_fbdev {
> > > +	struct drm_fb_helper	drm_fb_helper;
> > > +	struct drm_framebuffer	*fb;
> > > +};
> > > +
> > > +static inline unsigned int chan_to_field(unsigned int chan,
> > > +					 struct fb_bitfield *bf)
> > > +{
> > > +	chan &= 0xffff;
> > > +	chan >>= 16 - bf->length;
> > 
> > Any chance that bf->length can be bigger than 16? And cause this
> > to return um wrong vlaues?
> > 
> > perhaps chan >>= (16 - max(16,bf->length));
> > 
> 
> Ok, get it. thank you.
> 
> > ?
> > > +
> > > +	return chan << bf->offset;
> > > +}
> > > +
> > > +static int samsung_drm_fbdev_setcolreg(unsigned regno, unsigned red,
> > > +				       unsigned green, unsigned blue,
> > > +				       unsigned transp, struct fb_info
> *info)
> > > +{
> > > +	unsigned int val;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	switch (info->fix.visual) {
> > > +	case FB_VISUAL_TRUECOLOR:
> > > +		if (regno < 16) {
> > 
> > Not <=?
> 
> Ah, you are right. 16bit is high color. thank you.
> 
> > > +			u32 *pal = info->pseudo_palette;
> > > +
> > > +			val = chan_to_field(red, &info->var.red);
> > > +			val |= chan_to_field(green, &info->var.green);
> > > +			val |= chan_to_field(blue, &info->var.blue);
> > > +
> > > +			pal[regno] = val;
> > > +		}
> > 
> > so if regno > 16 then we still return 0. Should we return -EINVAL instead.
> > 
> 
> Ok, get it. thank you.
> 
> > > +		break;
> > > +	default:
> > > +		return 1;
> > 
> > -EINVAL?
> > 
> 
> Thank you.
> 
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static struct fb_ops samsung_drm_fb_ops = {
> > > +	.owner		= THIS_MODULE,
> > > +	.fb_fillrect	= cfb_fillrect,
> > > +	.fb_copyarea	= cfb_copyarea,
> > > +	.fb_imageblit	= cfb_imageblit,
> > > +	.fb_check_var	= drm_fb_helper_check_var,
> > > +	.fb_set_par	= drm_fb_helper_set_par,
> > > +	.fb_setcolreg	= samsung_drm_fbdev_setcolreg,
> > > +	.fb_blank	= drm_fb_helper_blank,
> > > +	.fb_pan_display	= drm_fb_helper_pan_display,
> > > +	.fb_setcmap	= drm_fb_helper_setcmap,
> > > +};
> > > +
> > > +static void samsung_drm_fbdev_update(struct drm_fb_helper *helper,
> > > +				     struct drm_framebuffer *fb,
> > > +				     unsigned int fb_width,
> > > +				     unsigned int fb_height)
> > > +{
> > > +	struct fb_info *fbi = helper->fbdev;
> > > +	struct drm_device *dev = helper->dev;
> > > +	struct samsung_drm_fbdev *samsung_fb = to_samsung_fbdev(helper);
> > > +	struct samsung_drm_buffer_info buffer_info;
> > > +	unsigned int size = fb_width * fb_height * (fb->bits_per_pixel >>
> > 3);
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	samsung_fb->fb = fb;
> > > +
> > > +	drm_fb_helper_fill_fix(fbi, fb->pitch, fb->depth);
> > > +	drm_fb_helper_fill_var(fbi, helper, fb_width, fb_height);
> > > +
> > > +	samsung_drm_fb_update_buf_off(fb, fbi->var.xoffset, fbi-
> > >var.yoffset,
> > > +			&buffer_info);
> > > +
> > > +	dev->mode_config.fb_base = buffer_info.base_addr;
> > > +
> > > +	fbi->screen_base = buffer_info.vaddr;
> > > +	fbi->screen_size = size;
> > > +	fbi->fix.smem_start = buffer_info.paddr;
> > > +	fbi->fix.smem_len = size;
> > > +}
> > > +
> > > +static int samsung_drm_fbdev_create(struct drm_fb_helper *helper,
> > > +				    struct drm_fb_helper_surface_size
> *sizes)
> > > +{
> > > +	struct samsung_drm_fbdev *samsung_fbdev = to_samsung_fbdev(helper);
> > > +	struct drm_device *dev = helper->dev;
> > > +	struct fb_info *fbi;
> > > +	struct drm_mode_fb_cmd mode_cmd = { 0 };
> > > +	struct platform_device *pdev = dev->platformdev;
> > > +	int ret;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d\n",
> > > +			sizes->surface_width, sizes->surface_height,
> > > +			sizes->surface_bpp);
> > > +
> > > +	mode_cmd.width = sizes->surface_width;
> > > +	mode_cmd.height = sizes->surface_height;
> > > +	mode_cmd.bpp = sizes->surface_bpp;
> > > +	mode_cmd.depth = sizes->surface_depth;
> > > +
> > > +	mutex_lock(&dev->struct_mutex);
> > > +
> > > +	fbi = framebuffer_alloc(0, &pdev->dev);
> > > +	if (!fbi) {
> > > +		DRM_ERROR("failed to allocate fb info.\n");
> > > +		ret = -ENOMEM;
> > > +		goto out;
> > > +	}
> > > +
> > > +	samsung_fbdev->fb = samsung_drm_fb_create(dev, NULL, &mode_cmd);
> > > +	if (IS_ERR(samsung_fbdev->fb)) {
> > 
> > You probably want to do IS_ERR_OR_NULL?
> > 
> 
> Ok, that's more safe. thank you.
> 
> > > +		DRM_ERROR("failed to create drm dramebuffer.\n");
> > > +		ret = PTR_ERR(samsung_fbdev->fb);
> > 
> > framebuffer_release ?
> > > +		goto out;
> > > +	}
> > > +
> 
> I missed it. thank you.
> 
> > > +	helper->fb = samsung_fbdev->fb;
> > > +	helper->fbdev = fbi;
> > > +
> > > +	fbi->par = helper;
> > > +	fbi->flags = FBINFO_FLAG_DEFAULT;
> > > +	fbi->fbops = &samsung_drm_fb_ops;
> > > +
> > > +	ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
> > > +	if (ret) {
> > 
> > framebuffer_release ?
> > 
> 
> Also. Thank you.
> 
> > Or just add a new label that will make that call.
> > 
> > > +		DRM_ERROR("failed to allocate cmap.\n");
> > > +		goto out;
> > > +	}
> > > +
> > > +	samsung_drm_fbdev_update(helper, helper->fb, sizes->fb_width,
> > > +			sizes->fb_height);
> > > +
> > > +out:
> > > +	mutex_unlock(&dev->struct_mutex);
> > > +	return ret;
> > > +}
> > > +
> > > +static bool
> > > +samsung_drm_fbdev_is_samefb(struct drm_framebuffer *fb,
> > > +			    struct drm_fb_helper_surface_size *sizes)
> > > +{
> > > +	if (fb->width != sizes->surface_width)
> > > +		return false;
> > > +	if (fb->height != sizes->surface_height)
> > > +		return false;
> > > +	if (fb->bits_per_pixel != sizes->surface_bpp)
> > > +		return false;
> > > +	if (fb->depth != sizes->surface_depth)
> > > +		return false;
> > > +
> > > +	return true;
> > > +}
> > > +
> > > +static int samsung_drm_fbdev_recreate(struct drm_fb_helper *helper,
> > > +				      struct drm_fb_helper_surface_size
> *sizes)
> > > +{
> > > +	struct drm_device *dev = helper->dev;
> > > +	struct samsung_drm_fbdev *samsung_fbdev = to_samsung_fbdev(helper);
> > > +	struct drm_framebuffer *fb = samsung_fbdev->fb;
> > > +	struct drm_mode_fb_cmd mode_cmd = { 0 };
> > > +
> > > +	if (helper->fb != fb) {
> > > +		DRM_ERROR("drm framebuffer is different\n");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	if (samsung_drm_fbdev_is_samefb(fb, sizes))
> > > +		return 0;
> > > +
> > > +	mode_cmd.width = sizes->surface_width;
> > > +	mode_cmd.height = sizes->surface_height;
> > > +	mode_cmd.bpp = sizes->surface_bpp;
> > > +	mode_cmd.depth = sizes->surface_depth;
> > > +
> > > +	if (fb->funcs->destroy)
> > > +		fb->funcs->destroy(fb);
> > > +
> > > +	samsung_fbdev->fb = samsung_drm_fb_create(dev, NULL, &mode_cmd);
> > > +	if (IS_ERR(samsung_fbdev->fb)) {
> > > +		DRM_ERROR("failed to allocate fb.\n");
> > > +		return PTR_ERR(samsung_fbdev->fb);
> > > +	}
> > > +
> > > +	helper->fb = samsung_fbdev->fb;
> > > +	samsung_drm_fbdev_update(helper, helper->fb, sizes->fb_width,
> > > +			sizes->fb_height);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int samsung_drm_fbdev_probe(struct drm_fb_helper *helper,
> > > +				   struct drm_fb_helper_surface_size *sizes)
> > > +{
> > > +	int ret = 0;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	if (!helper->fb) {
> > > +		ret = samsung_drm_fbdev_create(helper, sizes);
> > > +		if (ret < 0) {
> > > +			DRM_ERROR("failed to create fbdev.\n");
> > > +			return ret;
> > > +		}
> > > +
> > > +		/*
> > > +		 * fb_helper expects a value more than 1 if succeed
> > > +		 * because register_framebuffer() should be called.
> > > +		 */
> > > +		ret = 1;
> > > +	} else {
> > > +		ret = samsung_drm_fbdev_recreate(helper, sizes);
> > > +		if (ret < 0) {
> > > +			DRM_ERROR("failed to reconfigure fbdev\n");
> > > +			return ret;
> > > +		}
> > 
> > No need to do the same thing you did before?
> > 
> 
> Ah, I will correct it. thank you.
> 
> >  ret = 1?
> > 
> 
> This code must be strange. please, see new_fb =
> (*fb_helper->funcs->fb_prob)(fb_helper, &sizes) of
> drm_fb_helper_single_fb_probe(). drm_fb_helper.c requires three return
> values.

So confusing...
> 
> > > +	}
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +static struct drm_fb_helper_funcs samsung_drm_fb_helper_funcs = {
> > > +	.fb_probe =	samsung_drm_fbdev_probe,
> > > +};
> > > +
> > > +int samsung_drm_fbdev_init(struct drm_device *dev)
> > > +{
> > > +	struct samsung_drm_fbdev *fbdev;
> > > +	struct samsung_drm_private *private = dev->dev_private;
> > > +	struct drm_fb_helper *helper;
> > > +	unsigned int num_crtc;
> > > +	int ret;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
> > > +		return 0;
> > > +
> > > +	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
> > > +	if (!fbdev) {
> > > +		DRM_ERROR("failed to allocate drm fbdev.\n");
> > > +		return -ENOMEM;
> > > +	}
> > > +
> > > +	private->fb_helper = helper = &fbdev->drm_fb_helper;
> > > +	helper->funcs = &samsung_drm_fb_helper_funcs;
> > > +
> > > +	num_crtc = dev->mode_config.num_crtc;
> > > +
> > > +	ret = drm_fb_helper_init(dev, helper, num_crtc, 4);
> > 
> > Is that value '4'
> 
> Yes, this driver is going to provide maximum four connectors.
> 
> > > +	if (ret < 0) {
> > > +		DRM_ERROR("failed to initialize drm fb helper.\n");
> > > +		goto fail;
> > > +	}
> > > +
> > > +	ret = drm_fb_helper_single_add_all_connectors(helper);
> > > +	if (ret < 0) {
> > > +		DRM_ERROR("failed to register drm_fb_helper_connector.\n");
> > > +		goto fail;
> > > +
> > > +	}
> > > +
> > > +	ret = drm_fb_helper_initial_config(helper, 32);
> > 
> > and '32' should perhaps be in #defines?
> 
> Ok, get it. thank you.
> 
> > > +	if (ret < 0) {
> > > +		DRM_ERROR("failed to set up hw configuration.\n");
> > 
> > Which I think leaks memory. The drm_fb_helper_single_add_all_connectors
> > does a bunch of kzallocs. Should you free them here?
> > 
> 
> Ah, you are right. thank you.
> 
> > > +		goto fail;
> > > +	}
> > > +
> > > +	return 0;
> > > +
> > > +fail:
> > > +	private->fb_helper = NULL;
> > > +	kfree(fbdev);
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +static void samsung_drm_fbdev_destroy(struct drm_device *dev,
> > > +				      struct drm_fb_helper *fb_helper)
> > > +{
> > > +	struct drm_framebuffer *fb;
> > > +	struct fb_info *info;
> > > +
> > > +	/* release drm framebuffer and real buffer */
> > > +	if (fb_helper->fb && fb_helper->fb->funcs) {
> > > +		fb = fb_helper->fb;
> > > +		if (fb->funcs->destroy)
> > > +			fb->funcs->destroy(fb);
> > > +	}
> > > +
> > > +	/* release linux framebuffer */
> > > +	if (fb_helper->fbdev) {
> > 
> > You can declare the 'info' here.
> 
> Ok, get it. thank you.
> 
> > > +		info = fb_helper->fbdev;
> > > +		unregister_framebuffer(info);
> > > +		if (info->cmap.len)
> > > +			fb_dealloc_cmap(&info->cmap);
> > > +		framebuffer_release(info);
> > > +	}
> > > +
> > > +	drm_fb_helper_fini(fb_helper);
> > > +}
> > > +
> > > +void samsung_drm_fbdev_fini(struct drm_device *dev)
> > > +{
> > > +	struct samsung_drm_private *private = dev->dev_private;
> > > +	struct samsung_drm_fbdev *fbdev;
> > > +
> > > +	if (!private || !private->fb_helper)
> > > +		return;
> > > +
> > > +	fbdev = to_samsung_fbdev(private->fb_helper);
> > > +
> > > +	samsung_drm_fbdev_destroy(dev, private->fb_helper);
> > > +	kfree(fbdev);
> > > +	private->fb_helper = NULL;
> > > +}
> > > +
> > > +void samsung_drm_fbdev_restore_mode(struct drm_device *dev)
> > > +{
> > > +	struct samsung_drm_private *private = dev->dev_private;
> > > +
> > > +	if (!private || !private->fb_helper)
> > > +		return;
> > > +
> > > +	drm_fb_helper_restore_fbdev_mode(private->fb_helper);
> > > +}
> > > +
> > > +int samsung_drm_fbdev_reinit(struct drm_device *dev)
> > > +{
> > > +	struct samsung_drm_private *private = dev->dev_private;
> > > +	int ret;
> > > +
> > > +	if (!private)
> > > +		return -EINVAL;
> > > +
> > > +	if (!dev->mode_config.num_connector) {
> > > +		samsung_drm_fbdev_fini(dev);
> > > +		return 0;
> > > +	}
> > > +
> > > +	if (private->fb_helper) {
> > > +		struct drm_fb_helper *fb_helper = private->fb_helper;
> > > +
> > > +		drm_fb_helper_fini(fb_helper);
> > > +
> > > +		ret = drm_fb_helper_init(dev, fb_helper,
> > > +				dev->mode_config.num_crtc, 4);
> > > +		if (ret < 0) {
> > > +			DRM_ERROR("failed to initialize drm fb helper\n");
> > > +			return ret;
> > > +		}
> > > +
> > > +		ret = drm_fb_helper_single_add_all_connectors(fb_helper);
> > > +		if (ret < 0) {
> > > +			DRM_ERROR("failed to add fb helper to
> connectors\n");
> > 
> > You should free what drm_fb_helper_init allocated
> 
> Ok, get it. thank you.
> 
> > > +			return ret;
> > > +		}
> > > +
> > > +		ret = drm_fb_helper_initial_config(fb_helper, 32);
> > > +		if (ret < 0) {
> > 
> > .. and free what drm_fb_helper_single_add_all_connectors allocated too.
> > 
> 
> Ok, thank you.
> 
> > > +			DRM_ERROR("failed to set up hw configuration.\n");
> > > +			return ret;
> > > +		}
> > > +	} else
> > > +		ret = samsung_drm_fbdev_init(dev);
> > > +
> > > +	return ret;
> > > +}
> > > diff --git a/drivers/gpu/drm/samsung/samsung_drm_fbdev.h
> > b/drivers/gpu/drm/samsung/samsung_drm_fbdev.h
> > > new file mode 100644
> > > index 0000000..3ef4e0d
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/samsung/samsung_drm_fbdev.h
> > > @@ -0,0 +1,37 @@
> > > +/*
> > > + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> > > + *
> > > + * Authors:
> > > + *	Inki Dae <inki.dae@samsung.com>
> > > + *	Joonyoung Shim <jy0922.shim@samsung.com>
> > > + *	SeungWoo Kim <sw0312.kim@samsung.com>
> > > + *
> > > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > > + * copy of this software and associated documentation files (the
> > "Software"),
> > > + * to deal in the Software without restriction, including without
> > limitation
> > > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > > + * and/or sell copies of the Software, and to permit persons to whom
> > the
> > > + * Software is furnished to do so, subject to the following conditions:
> > > + *
> > > + * The above copyright notice and this permission notice (including the
> > next
> > > + * paragraph) shall be included in all copies or substantial portions
> > of the
> > > + * Software.
> > > + *
> > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
> > SHALL
> > > + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES OR
> > > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> OTHERWISE,
> > > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
> > OR
> > > + * OTHER DEALINGS IN THE SOFTWARE.
> > > + */
> > > +
> > > +#ifndef _SAMSUNG_DRM_FBDEV_H_
> > > +#define _SAMSUNG_DRM_FBDEV_H_
> > > +
> > > +int samsung_drm_fbdev_init(struct drm_device *dev);
> > > +int samsung_drm_fbdev_reinit(struct drm_device *dev);
> > > +void samsung_drm_fbdev_fini(struct drm_device *dev);
> > > +void samsung_drm_fbdev_restore_mode(struct drm_device *dev);
> > > +
> > > +#endif
> > > diff --git a/drivers/gpu/drm/samsung/samsung_drm_fimd.c
> > b/drivers/gpu/drm/samsung/samsung_drm_fimd.c
> > > new file mode 100644
> > > index 0000000..d823e19
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/samsung/samsung_drm_fimd.c
> > > @@ -0,0 +1,643 @@
> > > +/*
> > > + * Copyright (C) 2011 Samsung Electronics Co.Ltd
> > > + * Authors:
> > > + *	Joonyoung Shim <jy0922.shim@samsung.com>
> > > + *	Inki Dae <inki.dae@samsung.com>
> > > + *
> > > + * This program is free software; you can redistribute  it and/or
> > modify it
> > > + * under  the terms of  the GNU General  Public License as published by
> > the
> > > + * Free Software Foundation;  either version 2 of the  License, or (at
> > your
> > > + * option) any later version.
> > > + *
> > > + */
> > 
> > What is 'FIMD'? Is there an explanation of what that stands for?
> > 
> 
> That's Fully Interactive Mobile Display and this is display controller. 

OK, can you include that comment and perhaps a link to the specification?
(if such thing exists).
> 
> 
> > > +
> > > +/*
> > > + * TODO list
> > > + *  - Code cleanup(FIXME and TODO parts)
> > > + *  - Clock gating and Power management
> > > + *  - Writeback feature
> > > + */
> > > +
> > > +#include "drmP.h"
> > > +
> > > +#include <linux/kernel.h>
> > > +#include <linux/module.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/clk.h>
> > > +
> > > +#include <drm/samsung_drm.h>
> > > +#include <plat/regs-fb-v4.h>
> > > +
> > > +#include "samsung_drm_drv.h"
> > > +#include "samsung_drm_fbdev.h"
> > > +#include "samsung_drm_crtc.h"
> > > +
> > > +/* irq_flags bits */
> > > +#define FIMD_VSYNC_IRQ_EN	0
> > 
> > Which is just one value right? 0?
> > 
> 
> This definition isn't needed. so I will remove it and directly use 0
> instead.
> 
> > 
> > > +
> > > +#define VIDOSD_A(win)	(VIDOSD_BASE + 0x00 + (win) * 16)
> > > +#define VIDOSD_B(win)	(VIDOSD_BASE + 0x04 + (win) * 16)
> > > +#define VIDOSD_C(win)	(VIDOSD_BASE + 0x08 + (win) * 16)
> > > +#define VIDOSD_D(win)	(VIDOSD_BASE + 0x0C + (win) * 16)
> > 
> > What about a comment for these very important low-level values?
> > > +
> 
> I think it's good to leave some comments to them also. I will add some
> comments. thank you.
> 
> 
> > > +#define VIDWx_BUF_START(win, buf)	(VIDW_BUF_START(buf) + (win) * 8)
> > > +#define VIDWx_BUF_END(win, buf)		(VIDW_BUF_END(buf) + (win)
> > * 8)
> > > +#define VIDWx_BUF_SIZE(win, buf)	(VIDW_BUF_SIZE(buf) + (win) * 4)
> > > +
> > > +#define WINDOWS_NR	5
> > > +
> > > +#define get_fimd_context(dev)
> > 	platform_get_drvdata(to_platform_device(dev))
> > > +
> > > +struct fimd_win_data {
> > > +	unsigned int		offset_x;
> > > +	unsigned int		offset_y;
> > > +	unsigned int		width;
> > > +	unsigned int		height;
> > > +	unsigned int		paddr;
> > 
> > dma_addr_t ?
> > 
> 
> Get it. thank you.
> 
> > > +	void __iomem		*vaddr;
> > > +	unsigned int		end_buf_off;
> > 
> > buf_off ?
> 
> I have a feeling that this variable could be removed. thank you.
> 
> > > +	unsigned int		buf_offsize;
> > > +	unsigned int		line_size;	/* bytes */
> > > +};
> > > +
> > > +struct fimd_context {
> > > +	struct samsung_drm_subdrv	subdrv;
> > > +	int				irq_no;
> > 
> > Just 'irq'
> 
> Ok, get it.
> 
> > 
> > > +	struct drm_crtc			*crtc;
> > > +	struct clk			*bus_clk;
> > > +	struct clk			*lcd_clk;
> > > +	struct resource			*regs_res;
> > > +	void __iomem			*regs;
> > > +	struct fimd_win_data		win_data[WINDOWS_NR];
> > > +	unsigned int			clkdiv;
> > > +	unsigned int			default_win;
> > > +	unsigned int			bpp;
> > > +	unsigned long			irq_flags;
> > > +	u32				vidcon0;
> > > +	u32				vidcon1;
> > > +
> > > +	struct fb_videomode		*timing;
> > > +};
> > > +
> > > +static bool fimd_display_is_connected(struct device *dev)
> > > +{
> > > +	struct fimd_context *ctx = get_fimd_context(dev);
> > > +
> > > +	/* TODO. */
> > > +
> > > +	return true;
> > > +}
> > > +
> > > +static void *fimd_get_timing(struct device *dev)
> > > +{
> > > +	struct fimd_context *ctx = get_fimd_context(dev);
> > > +
> > > +	return ctx->timing;
> > > +}
> > > +
> > > +static int fimd_check_timing(struct device *dev, void *timing)
> > > +{
> > > +	struct fimd_context *ctx = get_fimd_context(dev);
> > > +
> > > +	/* TODO. */
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int fimd_display_power_on(struct device *dev, int mode)
> > > +{
> > > +	struct fimd_context *ctx = get_fimd_context(dev);
> > > +
> > > +	/* TODO. */
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static struct samsung_drm_display fimd_display = {
> > > +	.type = SAMSUNG_DISPLAY_TYPE_LCD,
> > > +	.is_connected = fimd_display_is_connected,
> > > +	.get_timing = fimd_get_timing,
> > > +	.check_timing = fimd_check_timing,
> > > +	.power_on = fimd_display_power_on,
> > > +};
> > > +
> > > +static void fimd_commit(struct device *dev)
> > > +{
> > > +	struct fimd_context *ctx = get_fimd_context(dev);
> > > +	void __iomem *regs = ctx->regs;
> > > +	struct fb_videomode *timing = ctx->timing;
> > > +	u32 val;
> > > +
> > > +	/* vidcon0 */
> > > +	val = ctx->vidcon0;
> > > +	val &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
> > > +
> > > +	if (ctx->clkdiv > 1)
> > > +		val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR;
> > > +	else
> > > +		val &= ~VIDCON0_CLKDIR;	/* 1:1 clock */
> > > +
> > > +	val |= VIDCON0_ENVID | VIDCON0_ENVID_F;
> > > +	writel(val, regs + VIDCON0);
> > > +
> > > +	/* vidcon1 */
> > 
> > That comment is bit useless.. It is clear what you are
> > doing.
> 
> Ok, get it. thank you.
> 
> > > +	writel(ctx->vidcon1, regs + VIDCON1);
> > > +
> > > +	/* vidtcon0 */
> > 
> > Ah, so the order is important. Perhaps you should
> > just have a comment before you do any writes that
> > enumarates in which order it should be done?
> > 
> 
> The order hasn't implications for working. no problem if this setting is
> done before dma of fimd is enabled. Ah.. such comments should be added.
> thank you.
> 
> > And why the order is important (in case the future
> > chipsets have it fixed/changed).
> > 
> 
> I understood what you mean. Thank you for your pointing.
> 
> > > +	val = VIDTCON0_VBPD(timing->upper_margin - 1) |
> > > +	       VIDTCON0_VFPD(timing->lower_margin - 1) |
> > > +	       VIDTCON0_VSPW(timing->vsync_len - 1);
> > > +	writel(val, regs + VIDTCON0);
> > > +
> > > +	/* vidtcon1 */
> > > +	val = VIDTCON1_HBPD(timing->left_margin - 1) |
> > > +	       VIDTCON1_HFPD(timing->right_margin - 1) |
> > > +	       VIDTCON1_HSPW(timing->hsync_len - 1);
> > > +	writel(val, regs + VIDTCON1);
> > > +
> > > +	/* vidtcon2 */
> > > +	val = VIDTCON2_LINEVAL(timing->yres - 1) |
> > > +	       VIDTCON2_HOZVAL(timing->xres - 1);
> > > +	writel(val, regs + VIDTCON2);
> > > +}
> > > +
> > > +static int fimd_enable_vblank(struct device *dev)
> > > +{
> > > +	struct fimd_context *ctx = get_fimd_context(dev);
> > > +	void __iomem *regs = ctx->regs;
> > > +	u32 val;
> > > +
> > > +	if (!test_and_set_bit(FIMD_VSYNC_IRQ_EN, &ctx->irq_flags)) {
> > > +		val = readl(regs + VIDINTCON0);
> > > +
> > > +		val |= VIDINTCON0_INT_ENABLE;
> > > +		val |= VIDINTCON0_INT_FRAME;
> > > +
> > > +		val &= ~VIDINTCON0_FRAMESEL0_MASK;
> > > +		val |= VIDINTCON0_FRAMESEL0_VSYNC;
> > > +		val &= ~VIDINTCON0_FRAMESEL1_MASK;
> > > +		val |= VIDINTCON0_FRAMESEL1_NONE;
> > > +
> > > +		writel(val, regs + VIDINTCON0);
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static void fimd_disable_vblank(struct device *dev)
> > > +{
> > > +	struct fimd_context *ctx = get_fimd_context(dev);
> > > +	void __iomem *regs = ctx->regs;
> > > +	u32 val;
> > > +
> > > +	if (test_and_clear_bit(FIMD_VSYNC_IRQ_EN, &ctx->irq_flags)) {
> > > +		val = readl(regs + VIDINTCON0);
> > > +
> > > +		val &= ~VIDINTCON0_INT_FRAME;
> > > +		val &= ~VIDINTCON0_INT_ENABLE;
> > > +
> > > +		writel(val, regs + VIDINTCON0);
> > > +	}
> > > +}
> > > +
> > > +static struct samsung_drm_manager_ops fimd_manager_ops = {
> > > +	.commit = fimd_commit,
> > > +	.enable_vblank = fimd_enable_vblank,
> > > +	.disable_vblank = fimd_disable_vblank,
> > > +};
> > > +
> > > +static void fimd_win_mode_set(struct device *dev,
> > > +			      struct samsung_drm_overlay *overlay)
> > > +{
> > > +	struct fimd_context *ctx = get_fimd_context(dev);
> > > +	struct fimd_win_data *win_data;
> > > +
> > > +	if (!overlay) {
> > > +		dev_err(dev, "overlay is NULL\n");
> > > +		return;
> > > +	}
> > > +
> > > +	win_data = &ctx->win_data[ctx->default_win];
> > > +
> > > +	win_data->offset_x = overlay->offset_x;
> > > +	win_data->offset_y = overlay->offset_y;
> > > +	win_data->width = overlay->width;
> > > +	win_data->height = overlay->height;
> > > +	win_data->paddr = overlay->paddr;
> > > +	win_data->vaddr = overlay->vaddr;
> > > +	win_data->end_buf_off = overlay->end_buf_off * (ctx->bpp >> 3);
> > > +	win_data->buf_offsize = overlay->buf_offsize * (ctx->bpp >> 3);
> > > +	win_data->line_size = overlay->line_size * (ctx->bpp >> 3);
> > > +}
> > > +
> > > +static void fimd_win_commit(struct device *dev)
> > > +{
> > > +	struct fimd_context *ctx = get_fimd_context(dev);
> > > +	void __iomem *regs = ctx->regs;
> > > +	struct fimd_win_data *win_data;
> > > +	int win = ctx->default_win;
> > > +	u32 val;
> > > +
> > > +	if (win < 0 || win > WINDOWS_NR)
> > > +		return;
> > > +
> > > +	win_data = &ctx->win_data[win];
> > > +
> > > +	/* protect windows */
> > > +	val = readl(regs + SHADOWCON);
> > > +	val |= SHADOWCON_WINx_PROTECT(win);
> > > +	writel(val, regs + SHADOWCON);
> > > +
> > > +	/* buffer start address */
> > > +	val = win_data->paddr;
> > > +	writel(val, regs + VIDWx_BUF_START(win, 0));
> > > +
> > > +	/* buffer end address */
> > > +	val = win_data->paddr + win_data->end_buf_off;
> > > +	writel(val, regs + VIDWx_BUF_END(win, 0));
> > > +
> > > +	/* buffer size */
> > > +	val = VIDW_BUF_SIZE_OFFSET(win_data->buf_offsize) |
> > > +		VIDW_BUF_SIZE_PAGEWIDTH(win_data->line_size);
> > > +	writel(val, regs + VIDWx_BUF_SIZE(win, 0));
> > > +
> > > +	/* OSD position */
> > > +	val = VIDOSDxA_TOPLEFT_X(win_data->offset_x) |
> > > +		VIDOSDxA_TOPLEFT_Y(win_data->offset_y);
> > > +	writel(val, regs + VIDOSD_A(win));
> > > +
> > > +	val = VIDOSDxB_BOTRIGHT_X(win_data->offset_x + win_data->width - 1)
> > |
> > > +		VIDOSDxB_BOTRIGHT_Y(win_data->offset_y + win_data->height -
> > 1);
> > > +	writel(val, regs + VIDOSD_B(win));
> > > +
> > > +	/* TODO: OSD alpha */
> > > +
> > > +	/* OSD size */
> > > +	if (win != 3 && win != 4) {
> > > +		u32 offset = VIDOSD_D(win);
> > > +		if (win == 0)
> > > +			offset = VIDOSD_C(win);
> > > +		val = win_data->width * win_data->height;
> > > +		writel(val, regs + offset);
> > > +	}
> > > +
> > > +	/* FIXME: remove fixed values */
> > 
> > <nods> Yes.
> > 
> 
> That FIXME would be updated soon. :)
> 
> > > +	val = WINCONx_ENWIN;
> > > +	val |= WINCON0_BPPMODE_24BPP_888;
> > > +	val |= WINCONx_WSWP;
> > > +	val |= WINCONx_BURSTLEN_16WORD;
> > > +	writel(val, regs + WINCON(win));
> > > +
> > > +	/* TODO: colour key */
> > > +
> > > +	/* Enable DMA channel and unprotect windows */
> > > +	val = readl(regs + SHADOWCON);
> > > +	val |= SHADOWCON_CHx_ENABLE(win);
> > > +	val &= ~SHADOWCON_WINx_PROTECT(win);
> > > +	writel(val, regs + SHADOWCON);
> > > +}
> > > +
> > > +static void fimd_win_disable(struct device *dev)
> > > +{
> > > +	struct fimd_context *ctx = get_fimd_context(dev);
> > > +	void __iomem *regs = ctx->regs;
> > > +	struct fimd_win_data *win_data;
> > > +	int win = ctx->default_win;
> > > +	u32 val;
> > > +
> > > +	if (win < 0 || win > WINDOWS_NR)
> > > +		return;
> > > +
> > > +	win_data = &ctx->win_data[win];
> > > +
> > > +	/* protect windows */
> > > +	val = readl(regs + SHADOWCON);
> > > +	val |= SHADOWCON_WINx_PROTECT(win);
> > > +	writel(val, regs + SHADOWCON);
> > > +
> > > +	/* wincon */
> > > +	val = readl(regs + WINCON(win));
> > > +	val &= ~WINCONx_ENWIN;
> > > +	writel(val, regs + WINCON(win));
> > > +
> > > +	/* unprotect windows */
> > > +	val = readl(regs + SHADOWCON);
> > > +	val &= ~SHADOWCON_CHx_ENABLE(win);
> > > +	val &= ~SHADOWCON_WINx_PROTECT(win);
> > > +	writel(val, regs + SHADOWCON);
> > > +}
> > > +
> > > +static struct samsung_drm_overlay_ops fimd_overlay_ops = {
> > > +	.mode_set = fimd_win_mode_set,
> > > +	.commit = fimd_win_commit,
> > > +	.disable = fimd_win_disable,
> > > +};
> > > +
> > > +/* for pageflip event */
> > > +static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc)
> > > +{
> > > +	struct samsung_drm_private *dev_priv = drm_dev->dev_private;
> > > +	struct drm_pending_vblank_event *e, *t;
> > > +	struct timeval now;
> > > +	unsigned long flags;
> > > +
> > > +	if (!dev_priv->pageflip_event)
> > > +		return;
> > > +
> > > +	spin_lock_irqsave(&drm_dev->event_lock, flags);
> > > +
> > > +	list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
> > > +			base.link) {
> > > +		do_gettimeofday(&now);
> > > +		e->event.sequence = 0;
> > > +		e->event.tv_sec = now.tv_sec;
> > > +		e->event.tv_usec = now.tv_usec;
> > > +
> > > +		list_move_tail(&e->base.link, &e->base.file_priv-
> > >event_list);
> > > +		wake_up_interruptible(&e->base.file_priv->event_wait);
> > > +	}
> > > +
> > > +	drm_vblank_put(drm_dev, crtc);
> > 
> > You can make this call outside the spinlock. But it looks like pretty
> > much everybody is doing it this way?
> > 
> 
> No problem to move it outside(to fimd_irq_handler) and spinlock is used only
> here. thank you.
> 
> > > +	dev_priv->pageflip_event = false;
> > > +
> > > +	spin_unlock_irqrestore(&drm_dev->event_lock, flags);
> > > +}
> > > +
> > > +static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
> > > +{
> > > +	struct fimd_context *ctx = (struct fimd_context *)dev_id;
> > > +	struct samsung_drm_subdrv *subdrv = &ctx->subdrv;
> > > +	struct drm_device *drm_dev = subdrv->drm_dev;
> > > +	struct device *dev = subdrv->manager.dev;
> > > +	struct samsung_drm_manager *manager = &subdrv->manager;
> > > +	void __iomem *regs = ctx->regs;
> > > +	u32 val;
> > > +
> > > +	val = readl(regs + VIDINTCON1);
> > > +
> > > +	if (val & VIDINTCON1_INT_FRAME)
> > > +		/* VSYNC interrupt */
> > > +		writel(VIDINTCON1_INT_FRAME, regs + VIDINTCON1);
> > > +
> > > +	drm_handle_vblank(drm_dev, manager->pipe);
> > > +	fimd_finish_pageflip(drm_dev, manager->pipe);
> > > +
> > > +	return IRQ_HANDLED;
> > > +}
> > > +
> > > +static int fimd_subdrv_probe(struct drm_device *drm_dev)
> > > +{
> > > +	struct drm_driver *drm_driver = drm_dev->driver;
> > > +
> > > +	drm_dev->irq_enabled = 1;
> > 
> > Hehe.. Just like that ,eh?
> > 
> 
> I will add some comments. :)
> 
> > > +
> > > +	/* TODO. */
> > > +
> > > +	/* FIXME */
> > > +	drm_dev->vblank_disable_allowed = 1;
> > > +
> 
> Ditto.
> 
> > > +	return 0;
> > > +}
> > > +
> > > +static void fimd_subdrv_remove(struct drm_device *drm_dev)
> > > +{
> > > +	struct drm_driver *drm_driver = drm_dev->driver;
> > > +
> > > +	/* TODO. */
> > > +}
> > > +
> > > +static int fimd_calc_clkdiv(struct fimd_context *ctx,
> > > +			    struct fb_videomode *timing)
> > > +{
> > > +	unsigned long clk = clk_get_rate(ctx->lcd_clk);
> > > +	u32 retrace;
> > > +	u32 clkdiv;
> > > +	u32 best_framerate = 0;
> > > +	u32 framerate;
> > > +
> > > +	retrace = timing->left_margin + timing->hsync_len +
> > > +				timing->right_margin + timing->xres;
> > > +	retrace *= timing->upper_margin + timing->vsync_len +
> > > +				timing->lower_margin + timing->yres;
> > > +
> > > +	/* default framerate is 60Hz */
> > > +	if (!timing->refresh)
> > > +		timing->refresh = 60;
> > > +
> > > +	clk /= retrace;
> > > +
> > > +	for (clkdiv = 1; clkdiv < 0x100; clkdiv++) {
> > > +		int tmp;
> > > +
> > > +		/* get best framerate */
> > > +		framerate = clk / clkdiv;
> > > +		tmp = timing->refresh - framerate;
> > > +		if (tmp < 0) {
> > > +			best_framerate = framerate;
> > > +			continue;
> > > +		} else {
> > > +			if (!best_framerate)
> > > +				best_framerate = framerate;
> > > +			else if (tmp < (best_framerate - framerate))
> > > +				best_framerate = framerate ;
> > 
> > The ';' at the end should be moved.
> 
> Ah, get it. thank you.
> 
> > > +			break;
> > > +		}
> > > +	}
> > > +
> > > +	return clkdiv;
> > > +}
> > > +
> > > +static void fimd_clear_win(struct fimd_context *ctx, int win)
> > > +{
> > > +	void __iomem *regs = ctx->regs;
> > > +	u32 val;
> > > +
> > > +	writel(0, regs + WINCON(win));
> > > +	writel(0, regs + VIDOSD_A(win));
> > > +	writel(0, regs + VIDOSD_B(win));
> > > +	writel(0, regs + VIDOSD_C(win));
> > > +
> > > +	if (win == 1 || win == 2)
> > > +		writel(0, regs + VIDOSD_D(win));
> > > +
> > > +	val = readl(regs + SHADOWCON);
> > > +	val &= ~SHADOWCON_WINx_PROTECT(win);
> > > +	writel(val, regs + SHADOWCON);
> > > +}
> > > +
> > > +static int __devinit fimd_probe(struct platform_device *pdev)
> > > +{
> > > +	struct device *dev = &pdev->dev;
> > > +	struct fimd_context *ctx;
> > > +	struct samsung_drm_subdrv *subdrv;
> > > +	struct samsung_drm_fimd_pdata *pdata;
> > > +	struct fb_videomode *timing;
> > > +	struct resource *res;
> > > +	int win;
> > > +	int ret = -EINVAL;
> > > +
> > > +	printk(KERN_DEBUG "[%d] %s\n", __LINE__, __func__);
> > 
> > Hm printk? Use pr_dbg instead.
> > 
> 
> Ok, get it. thank you.
> 
> > > +
> > > +	pdata = pdev->dev.platform_data;
> > > +	if (!pdata) {
> > > +		dev_err(dev, "no platform data specified\n");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	timing = &pdata->timing;
> > > +	if (!timing) {
> > > +		dev_err(dev, "timing is null.\n");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> > > +	if (!ctx)
> > > +		return -ENOMEM;
> > > +
> > > +	ctx->bus_clk = clk_get(dev, "fimd");
> > > +	if (IS_ERR(ctx->bus_clk)) {
> > > +		dev_err(dev, "failed to get bus clock\n");
> > > +		ret = PTR_ERR(ctx->bus_clk);
> > > +		goto err_clk_get;
> > > +	}
> > > +
> > > +	clk_enable(ctx->bus_clk);
> > > +
> > > +	ctx->lcd_clk = clk_get(dev, "sclk_fimd");
> > > +	if (IS_ERR(ctx->lcd_clk)) {
> > > +		dev_err(dev, "failed to get lcd clock\n");
> > > +		ret = PTR_ERR(ctx->lcd_clk);
> > > +		goto err_bus_clk;
> > > +	}
> > > +
> > > +	clk_enable(ctx->lcd_clk);
> > > +
> > > +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > > +	if (!res) {
> > > +		dev_err(dev, "failed to find registers\n");
> > > +		ret = -ENOENT;
> > > +		goto err_clk;
> > > +	}
> > > +
> > > +	ctx->regs_res = request_mem_region(res->start, resource_size(res),
> > > +					   dev_name(dev));
> > > +	if (!ctx->regs_res) {
> > > +		dev_err(dev, "failed to claim register region\n");
> > > +		ret = -ENOENT;
> > > +		goto err_clk;
> > > +	}
> > > +
> > > +	ctx->regs = ioremap(res->start, resource_size(res));
> > > +	if (!ctx->regs) {
> > > +		dev_err(dev, "failed to map registers\n");
> > > +		ret = -ENXIO;
> > > +		goto err_req_region_io;
> > > +	}
> > > +
> > > +	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> > > +	if (!res) {
> > > +		dev_err(dev, "irq request failed.\n");
> > > +		goto err_req_region_irq;
> > > +	}
> > > +
> > > +	ctx->irq_no = res->start;
> > > +
> > > +	for (win = 0; win < WINDOWS_NR; win++)
> > > +		fimd_clear_win(ctx, win);
> > > +
> > > +	ret = request_irq(ctx->irq_no, fimd_irq_handler, 0, "drm_fimd",
> > ctx);
> > > +	if (ret < 0) {
> > > +		dev_err(dev, "irq request failed.\n");
> > > +		goto err_req_irq;
> > > +	}
> > > +
> > > +	ctx->clkdiv = fimd_calc_clkdiv(ctx, timing);
> > > +	ctx->vidcon0 = pdata->vidcon0;
> > > +	ctx->vidcon1 = pdata->vidcon1;
> > > +	ctx->default_win = pdata->default_win;
> > > +	ctx->bpp = pdata->bpp;
> > > +	ctx->timing = timing;
> > > +
> > > +	timing->pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv;
> > > +
> > > +	subdrv = &ctx->subdrv;
> > > +
> > > +	subdrv->probe = fimd_subdrv_probe;
> > > +	subdrv->remove = fimd_subdrv_remove;
> > > +	subdrv->manager.pipe = -1;
> > > +	subdrv->manager.ops = &fimd_manager_ops;
> > > +	subdrv->manager.overlay_ops = &fimd_overlay_ops;
> > > +	subdrv->manager.display = &fimd_display;
> > > +	subdrv->manager.dev = dev;
> > > +
> > > +	platform_set_drvdata(pdev, ctx);
> > > +	samsung_drm_subdrv_register(subdrv);
> > > +
> > > +	return 0;
> > > +
> > > +err_req_irq:
> > > +err_req_region_irq:
> > > +	iounmap(ctx->regs);
> > > +
> > > +err_req_region_io:
> > > +	release_resource(ctx->regs_res);
> > > +	kfree(ctx->regs_res);
> > > +
> > > +err_clk:
> > > +	clk_disable(ctx->lcd_clk);
> > > +	clk_put(ctx->lcd_clk);
> > > +
> > > +err_bus_clk:
> > > +	clk_disable(ctx->bus_clk);
> > > +	clk_put(ctx->bus_clk);
> > > +
> > > +err_clk_get:
> > > +	kfree(ctx);
> > > +	return ret;
> > > +}
> > > +
> > > +static int __devexit fimd_remove(struct platform_device *pdev)
> > > +{
> > > +	struct fimd_context *ctx = platform_get_drvdata(pdev);
> > > +
> > > +	samsung_drm_subdrv_unregister(&ctx->subdrv);
> > > +
> > > +	clk_disable(ctx->lcd_clk);
> > > +	clk_disable(ctx->bus_clk);
> > > +	clk_put(ctx->lcd_clk);
> > > +	clk_put(ctx->bus_clk);
> > > +
> > 
> > free_irq ?
> 
> Ah , I missed it. thank you.
> 
> > > +	iounmap(ctx->regs);
> > > +	release_resource(ctx->regs_res);
> > > +	kfree(ctx->regs_res);
> > > +
> > > +	kfree(ctx);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static struct platform_driver fimd_driver = {
> > > +	.probe		= fimd_probe,
> > > +	.remove		= __devexit_p(fimd_remove),
> > > +	.driver		= {
> > > +		.name	= "exynos4-fb",
> > > +		.owner	= THIS_MODULE,
> > > +	},
> > > +};
> > > +
> > > +static int __init fimd_init(void)
> > > +{
> > > +	return platform_driver_register(&fimd_driver);
> > > +}
> > > +
> > > +static void __exit fimd_exit(void)
> > > +{
> > > +	platform_driver_unregister(&fimd_driver);
> > > +}
> > > +
> > > +module_init(fimd_init);
> > > +module_exit(fimd_exit);
> > > +
> > > +MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
> > > +MODULE_DESCRIPTION("Samsung DRM FIMD Driver");
> > > +MODULE_LICENSE("GPL");
> > > diff --git a/drivers/gpu/drm/samsung/samsung_drm_gem.c
> > b/drivers/gpu/drm/samsung/samsung_drm_gem.c
> > > new file mode 100644
> > > index 0000000..8f71ef0
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/samsung/samsung_drm_gem.c
> > > @@ -0,0 +1,492 @@
> > > +/* samsung_drm_gem.c
> > > + *
> > > + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> > > + * Author: Inki Dae <inki.dae@samsung.com>
> > > + *
> > > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > > + * copy of this software and associated documentation files (the
> > "Software"),
> > > + * to deal in the Software without restriction, including without
> > limitation
> > > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > > + * and/or sell copies of the Software, and to permit persons to whom
> > the
> > > + * Software is furnished to do so, subject to the following conditions:
> > > + *
> > > + * The above copyright notice and this permission notice (including the
> > next
> > > + * paragraph) shall be included in all copies or substantial portions
> > of the
> > > + * Software.
> > > + *
> > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
> > SHALL
> > > + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES OR
> > > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> OTHERWISE,
> > > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
> > OR
> > > + * OTHER DEALINGS IN THE SOFTWARE.
> > > + */
> > > +
> > > +#include "drmP.h"
> > > +#include "drm.h"
> > > +
> > > +#include <drm/samsung_drm.h>
> > > +
> > > +#include "samsung_drm_drv.h"
> > > +#include "samsung_drm_gem.h"
> > > +#include "samsung_drm_buf.h"
> > > +
> > > +static unsigned int convert_to_vm_err_msg(int msg)
> > > +{
> > > +	unsigned int out_msg;
> > > +
> > > +	switch (msg) {
> > > +	case 0:
> > > +	case -ERESTARTSYS:
> > > +	case -EINTR:
> > > +		out_msg = VM_FAULT_NOPAGE;
> > > +		break;
> > > +
> > > +	case -ENOMEM:
> > > +		out_msg = VM_FAULT_OOM;
> > > +		break;
> > > +
> > > +	default:
> > > +		out_msg = VM_FAULT_SIGBUS;
> > > +		break;
> > > +	}
> > > +
> > > +	return out_msg;
> > > +}
> > > +
> > > +static unsigned int get_gem_mmap_offset(struct drm_gem_object *obj)
> > > +{
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT;
> > > +}
> > > +
> > > +/**
> > > + * samsung_drm_gem_create_mmap_offset - create a fake mmap offset for
> > an object
> > > + * @obj: obj in question
> > > + *
> > > + * GEM memory mapping works by handing back to userspace a fake mmap
> > offset
> > > + * it can use in a subsequent mmap(2) call.  The DRM core code then
> > looks
> > > + * up the object based on the offset and sets up the various memory
> > mapping
> > > + * structures.
> > > + *
> > > + * This routine allocates and attaches a fake offset for @obj.
> > > + */
> > > +static int
> > > +samsung_drm_gem_create_mmap_offset(struct drm_gem_object *obj)
> > > +{
> > > +	struct drm_device *dev = obj->dev;
> > > +	struct drm_gem_mm *mm = dev->mm_private;
> > > +	struct drm_map_list *list;
> > > +	struct drm_local_map *map;
> > > +	int ret = 0;
> > > +
> > > +	/* Set the object up for mmap'ing */
> > > +	list = &obj->map_list;
> > > +	list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL);
> > > +	if (!list->map)
> > > +		return -ENOMEM;
> > > +
> > > +	map = list->map;
> > > +	map->type = _DRM_GEM;
> > > +	map->size = obj->size;
> > > +	map->handle = obj;
> > > +
> > > +	/* Get a DRM GEM mmap offset allocated... */
> > > +	list->file_offset_node = drm_mm_search_free(&mm->offset_manager,
> > > +						    obj->size / PAGE_SIZE,
> > > +						    0, 0);
> > > +	if (!list->file_offset_node) {
> > > +		DRM_ERROR("failed to allocate offset for bo %d\n",
> > > +			  obj->name);
> > > +		ret = -ENOSPC;
> > > +		goto out_free_list;
> > > +	}
> > > +
> > > +	list->file_offset_node = drm_mm_get_block(list->file_offset_node,
> > > +						  obj->size / PAGE_SIZE,
> > > +						  0);
> > > +	if (!list->file_offset_node) {
> > > +		ret = -ENOMEM;
> > > +		goto out_free_list;
> > > +	}
> > > +
> > > +	list->hash.key = list->file_offset_node->start;
> > > +	ret = drm_ht_insert_item(&mm->offset_hash, &list->hash);
> > > +	if (ret) {
> > > +		DRM_ERROR("failed to add to map hash\n");
> > > +		goto out_free_mm;
> > > +	}
> > > +
> > > +	return 0;
> > > +
> > > +out_free_mm:
> > > +	drm_mm_put_block(list->file_offset_node);
> > > +out_free_list:
> > > +	kfree(list->map);
> > > +	list->map = NULL;
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +static void
> > > +samsung_drm_gem_free_mmap_offset(struct drm_gem_object *obj)
> > > +{
> > > +	struct drm_device *dev = obj->dev;
> > > +	struct drm_gem_mm *mm = dev->mm_private;
> > > +	struct drm_map_list *list = &obj->map_list;
> > > +
> > > +	drm_ht_remove_item(&mm->offset_hash, &list->hash);
> > > +	drm_mm_put_block(list->file_offset_node);
> > > +	kfree(list->map);
> > > +	list->map = NULL;
> > > +}
> > > +
> > > +struct samsung_drm_gem_obj *samsung_drm_gem_create(struct drm_file
> > *file_priv,
> > > +		struct drm_device *dev, unsigned int size,
> > > +		unsigned int *handle)
> > > +{
> > > +	struct samsung_drm_gem_obj *samsung_gem_obj;
> > > +	struct samsung_drm_buf_entry *entry;
> > > +	struct drm_gem_object *obj;
> > > +	int ret;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	size = roundup(size, PAGE_SIZE);
> > > +
> > > +	samsung_gem_obj = kzalloc(sizeof(*samsung_gem_obj), GFP_KERNEL);
> > > +	if (!samsung_gem_obj) {
> > > +		DRM_ERROR("failed to allocate samsung gem object.\n");
> > > +		return ERR_PTR(-ENOMEM);
> > > +	}
> > > +
> > > +	/* allocate the new buffer object and memory region. */
> > > +	entry = samsung_drm_buf_create(dev, size);
> > > +	if (!entry) {
> > > +		kfree(samsung_gem_obj);
> > > +		return ERR_PTR(-ENOMEM);
> > > +	}
> > > +
> > > +	samsung_gem_obj->entry = entry;
> > > +
> > > +	obj = &samsung_gem_obj->base;
> > > +
> > > +	ret = drm_gem_object_init(dev, obj, size);
> > > +	if (ret < 0) {
> > > +		DRM_ERROR("failed to initailize gem object.\n");
> > > +		goto err_obj_init;
> > > +	}
> > > +
> > > +	DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj-
> > >filp);
> > > +
> > > +	ret = samsung_drm_gem_create_mmap_offset(obj);
> > > +	if (ret < 0) {
> > > +		DRM_ERROR("failed to allocate mmap offset.\n");
> > > +		goto err_create_mmap_offset;
> > > +	}
> > > +
> > > +	/**
> > > +	 * allocate a id of idr table where the obj is registered
> > > +	 * and handle has the id what user can see.
> > > +	 */
> > > +	ret = drm_gem_handle_create(file_priv, obj, handle);
> > > +	if (ret)
> > > +		goto err_handle_create;
> > > +
> > > +	DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle);
> > > +
> > > +	/* drop reference from allocate - handle holds it now. */
> > > +	drm_gem_object_unreference_unlocked(obj);
> > > +
> > > +	return samsung_gem_obj;
> > > +
> > > +err_handle_create:
> > > +	samsung_drm_gem_free_mmap_offset(obj);
> > > +	drm_gem_object_release(obj);
> > > +
> > > +err_create_mmap_offset:
> > > +	/* add exception. FIXME. */
> > > +
> > > +err_obj_init:
> > > +	samsung_drm_buf_destroy(dev, samsung_gem_obj->entry);
> > > +
> > > +	kfree(samsung_gem_obj);
> > > +
> > > +	return ERR_PTR(ret);
> > > +}
> > > +
> > > +int samsung_drm_gem_create_ioctl(struct drm_device *dev, void *data,
> > > +		struct drm_file *file_priv)
> > > +{
> > > +	struct drm_samsung_gem_create *args = data;
> > > +	struct samsung_drm_gem_obj *samsung_gem_obj;
> > > +
> > > +	DRM_DEBUG_KMS("%s : size = 0x%x\n", __FILE__, args->size);
> > > +
> > > +	samsung_gem_obj = samsung_drm_gem_create(file_priv, dev, args->size,
> > > +			&args->handle);
> > > +	if (IS_ERR(samsung_gem_obj))
> > > +		return PTR_ERR(samsung_gem_obj);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +int samsung_drm_gem_map_offset_ioctl(struct drm_device *dev, void
> *data,
> > > +		struct drm_file *file_priv)
> > > +{
> > > +	struct drm_samsung_gem_map_off *args = data;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	DRM_DEBUG_KMS("handle = 0x%x, offset = 0x%x\n",
> > > +			args->handle, (u32)args->offset);
> > > +
> > > +	if (!(dev->driver->driver_features & DRIVER_GEM)) {
> > > +		DRM_ERROR("not support GEM.\n");
> > 
> > Um, You can make that error read better. Perhaps
> > 
> > drv_err(dev->dev,"Does not support GEM.\n");
> > 
> 
> Ok, get it. thank you.
> 
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	return samsung_drm_gem_dumb_map_offset(file_priv, dev, args->handle,
> > > +			&args->offset);
> > > +}
> > > +
> > > +static int samsung_drm_gem_mmap_buffer(struct file *filp,
> > > +		struct vm_area_struct *vma)
> > > +{
> > > +	struct drm_gem_object *obj = filp->private_data;
> > > +	struct samsung_drm_gem_obj *samsung_gem_obj =
> > to_samsung_gem_obj(obj);
> > > +	struct samsung_drm_buf_entry *entry;
> > > +	unsigned long pfn, size;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	vma->vm_flags |= (VM_IO | VM_RESERVED);
> > > +	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
> > > +	vma->vm_file = filp;
> > > +
> > > +	size = vma->vm_end - vma->vm_start;
> > > +	entry = samsung_gem_obj->entry;
> > > +
> > > +	/* check if the region to be mapped is valid or not. */
> > > +	if ((entry->paddr + vma->vm_pgoff + size) >
> > > +			(entry->paddr + entry->size)) {
> > > +		drm_gem_object_unreference_unlocked(obj);
> > > +		DRM_ERROR("desired size is bigger then real size.\n");
> > 
> > So .. you can't continue by just using the real size instead?
> > 
> 
> I am afraid I don't understand what you mean but I think that condition is
> fine. size is a vm area to user-desired size and you could request mapping
> as specific size. so it just check user-requested virtual space region it
> bigger than allocated physical memory region to be mapped. if there is my
> missing points, I would be happy to you give me your comments. thank you.

I meant that you return -EINVAL. But I am wondering if it would be possible
to just continue on, but ignore what the user specified.

I think the issue here is that you are outputing the DRM_ERROR and
I am not sure if it is that neccessary. Perhaps DRM_DEBUG, but DRM_ERROR
just seems a bit.. heavy handed.

> 
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	pfn = (samsung_gem_obj->entry->paddr + vma->vm_pgoff) >> PAGE_SHIFT;
> > > +
> > > +	DRM_DEBUG_KMS("offset = 0x%x, pfn to be mapped = 0x%x\n",
> > > +			(u32)vma->vm_pgoff, (u32)pfn);
> > 
> > You can drop those u32 and use %lx
> 
> Thank you.
> 
> > > +
> > > +	if (remap_pfn_range(vma, vma->vm_start, pfn,
> > > +				vma->vm_end - vma->vm_start,
> > > +				vma->vm_page_prot)) {
> > > +		DRM_ERROR("failed to remap pfn range.\n");
> > 
> > Perhaps also include more details. Say the PFN in question, the offset,
> > etc.
> > Something that will help in the field?
> > 
> 
> Ok, get it. thank you.
> 
> > > +		return -EAGAIN;
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static const struct file_operations samsung_drm_gem_fops = {
> > > +	.mmap = samsung_drm_gem_mmap_buffer,
> > > +};
> > > +
> > > +int samsung_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
> > > +		struct drm_file *file_priv)
> > > +{
> > > +	struct drm_samsung_gem_mmap *args = data;
> > > +	struct drm_gem_object *obj;
> > > +	unsigned int addr;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	if (!(dev->driver->driver_features & DRIVER_GEM)) {
> > > +		DRM_ERROR("not support GEM.\n");
> > 
> > Ditto.
> 
> Thank you.
> 
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
> > > +	if (!obj) {
> > > +		DRM_ERROR("failed to lookup gem object.\n");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	obj->filp->f_op = &samsung_drm_gem_fops;
> > > +	obj->filp->private_data = obj;
> > > +
> > > +	down_write(&current->mm->mmap_sem);
> > > +	addr = do_mmap(obj->filp, 0, args->size,
> > > +			PROT_READ | PROT_WRITE, MAP_SHARED, args->offset);
> > > +	up_write(&current->mm->mmap_sem);
> > > +
> > > +	drm_gem_object_unreference_unlocked(obj);
> > > +
> > > +	if (IS_ERR((void *)addr))
> > > +		return PTR_ERR((void *)addr);
> > > +
> > > +	args->mapped = addr;
> > > +
> > > +	DRM_DEBUG_KMS("mapped = 0x%x\n", (u32)args->mapped);
> > 
> > Is all this casting to (u32) that neccessary?
> 
> Definitely no, this casting should be changed to 64bit type. thank you.
> 
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +int samsung_drm_gem_init_object(struct drm_gem_object *obj)
> > > +{
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +void samsung_drm_gem_free_object(struct drm_gem_object *gem_obj)
> > > +{
> > > +	struct samsung_drm_gem_obj *samsung_gem_obj;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	DRM_DEBUG_KMS("handle count = %d\n",
> > > +			atomic_read(&gem_obj->handle_count));
> > > +
> > > +	if (gem_obj->map_list.map)
> > > +		samsung_drm_gem_free_mmap_offset(gem_obj);
> > > +
> > > +	/* release file pointer to gem object. */
> > > +	drm_gem_object_release(gem_obj);
> > > +
> > > +	samsung_gem_obj = to_samsung_gem_obj(gem_obj);
> > > +
> > > +	samsung_drm_buf_destroy(gem_obj->dev, samsung_gem_obj->entry);
> > > +}
> > > +
> > > +int samsung_drm_gem_dumb_create(struct drm_file *file_priv,
> > > +		struct drm_device *dev, struct drm_mode_create_dumb *args)
> > > +{
> > > +	struct samsung_drm_gem_obj *samsung_gem_obj;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	/**
> > > +	 * alocate memory to be used for framebuffer.
> > > +	 * - this callback would be called by user application
> > > +	 *	with DRM_IOCTL_MODE_CREATE_DUMB command.
> > > +	 */
> > > +
> > > +	args->pitch = args->width * args->bpp >> 3;
> > > +	args->size = args->pitch * args->height;
> > > +
> > > +	samsung_gem_obj = samsung_drm_gem_create(file_priv, dev, args->size,
> > > +							&args->handle);
> > > +	if (IS_ERR(samsung_gem_obj))
> > > +		return PTR_ERR(samsung_gem_obj);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +int samsung_drm_gem_dumb_map_offset(struct drm_file *file_priv,
> > > +		struct drm_device *dev, uint32_t handle, uint64_t *offset)
> > > +{
> > > +	struct samsung_drm_gem_obj *samsung_gem_obj;
> > > +	struct drm_gem_object *obj;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	mutex_lock(&dev->struct_mutex);
> > > +
> > > +	/**
> > > +	 * get offset of memory allocated for drm framebuffer.
> > > +	 * - this callback would be called by user application
> > > +	 *	with DRM_IOCTL_MODE_MAP_DUMB command.
> > > +	 */
> > > +
> > > +	obj = drm_gem_object_lookup(dev, file_priv, handle);
> > > +	if (!obj) {
> > > +		DRM_ERROR("failed to lookup gem object.\n");
> > > +		mutex_unlock(&dev->struct_mutex);
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	samsung_gem_obj = to_samsung_gem_obj(obj);
> > > +
> > > +	*offset = get_gem_mmap_offset(&samsung_gem_obj->base);
> > > +
> > > +	drm_gem_object_unreference(obj);
> > > +
> > > +	DRM_DEBUG_KMS("offset = 0x%x\n", (unsigned int)*offset);
> > > +
> > > +	mutex_unlock(&dev->struct_mutex);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +int samsung_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault
> > *vmf)
> > > +{
> > > +	struct drm_gem_object *obj = vma->vm_private_data;
> > > +	struct samsung_drm_gem_obj *samsung_gem_obj =
> > to_samsung_gem_obj(obj);
> > > +	struct drm_device *dev = obj->dev;
> > > +	unsigned long pfn;
> > > +	pgoff_t page_offset;
> > > +	int ret;
> > > +
> > > +	page_offset = ((unsigned long)vmf->virtual_address -
> > > +			vma->vm_start) >> PAGE_SHIFT;
> > > +
> > > +	mutex_lock(&dev->struct_mutex);
> > > +
> > > +	pfn = (samsung_gem_obj->entry->paddr >> PAGE_SHIFT) + page_offset;
> > > +
> > > +	ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address,
> > pfn);
> > > +
> > > +	mutex_unlock(&dev->struct_mutex);
> > > +
> > > +	return convert_to_vm_err_msg(ret);
> > > +}
> > > +
> > > +int samsung_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
> > > +{
> > > +	int ret;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	/* set vm_area_struct. */
> > > +	ret = drm_gem_mmap(filp, vma);
> > > +	if (ret < 0) {
> > > +		DRM_ERROR("failed to mmap.\n");
> > > +		return ret;
> > > +	}
> > > +
> > > +	vma->vm_flags &= ~VM_PFNMAP;
> > > +	vma->vm_flags |= VM_MIXEDMAP;
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +
> > > +int samsung_drm_gem_dumb_destroy(struct drm_file *file_priv,
> > > +		struct drm_device *dev, unsigned int handle)
> > > +{
> > > +	int ret;
> > > +
> > > +	DRM_DEBUG_KMS("%s\n", __FILE__);
> > > +
> > > +	/**
> > > +	 * obj->refcount and obj->handle_count are decreased and
> > > +	 * if both them are 0 then samsung_drm_gem_free_object()
> > > +	 * would be called by callback to release resources.
> > > +	 */
> > > +	ret = drm_gem_handle_delete(file_priv, handle);
> > > +	if (ret < 0) {
> > > +		DRM_ERROR("failed to delete drm_gem_handle.\n");
> > > +		return ret;
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
> > > +MODULE_DESCRIPTION("Samsung SoC DRM GEM Module");
> > > +MODULE_LICENSE("GPL");
> > > diff --git a/drivers/gpu/drm/samsung/samsung_drm_gem.h
> > b/drivers/gpu/drm/samsung/samsung_drm_gem.h
> > > new file mode 100644
> > > index 0000000..c6cd5e5
> > > --- /dev/null
> > > +++ b/drivers/gpu/drm/samsung/samsung_drm_gem.h
> > > @@ -0,0 +1,98 @@
> > > +/* samsung_drm_gem.h
> > > + *
> > > + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> > > + * Authoer: Inki Dae <inki.dae@samsung.com>
> > > + *
> > > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > > + * copy of this software and associated documentation files (the
> > "Software"),
> > > + * to deal in the Software without restriction, including without
> > limitation
> > > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > > + * and/or sell copies of the Software, and to permit persons to whom
> > the
> > > + * Software is furnished to do so, subject to the following conditions:
> > > + *
> > > + * The above copyright notice and this permission notice (including the
> > next
> > > + * paragraph) shall be included in all copies or substantial portions
> > of the
> > > + * Software.
> > > + *
> > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
> > SHALL
> > > + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES OR
> > > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> OTHERWISE,
> > > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
> > OR
> > > + * OTHER DEALINGS IN THE SOFTWARE.
> > > + */
> > > +
> > > +#ifndef _SAMSUNG_DRM_GEM_H_
> > > +#define _SAMSUNG_DRM_GEM_H_
> > > +
> > > +#define to_samsung_gem_obj(x)	container_of(x,\
> > > +			struct samsung_drm_gem_obj, base)
> > > +
> > > +/**
> > > + * samsung drm buffer structure.
> > > + *
> > > + * @entry: pointer to samsung drm buffer entry object.
> > > + * @flags: it means memory type to be alloated or cache attributes.
> > 
> > Hm, that sounds like an enum? Or a candidate for enums?
> 
> 
> Yes, it's better to use enums. Thank you.
> 
> 
> > > + * @handle: gem handle.
> > 
> > You are missing @base
> > 
> 
> Yes, I missed it. thank you.
> 
> > > + *
> > > + * ps. this object would be transfered to user as kms_bo.handle so
> > 
> > It is 'P.S.'
> 
> Thank you.
> 
> > > + *	user can access to memory through kms_bo.handle.
> > > + */
> > > +struct samsung_drm_gem_obj {
> > > +	struct drm_gem_object base;
> > > +	struct samsung_drm_buf_entry *entry;
> > > +	unsigned int flags;
> > 
> > Actually, I don't think you are using this? Could it be chopped off?
> 
> Could you give me your more comments. I am afraid what is 'it'. I assume
> maybe it's flags. Yes, flags isn't used yet. I will remove it until this
> feature would be added. thank you.


Yup. That is the one I was thinking off.
> 
> > > +};
> > > +
> > > +
> > > +/* create a new buffer and get a new gem handle. */
> > > +struct samsung_drm_gem_obj *samsung_drm_gem_create(struct drm_file
> > *file_priv,
> > > +		struct drm_device *dev, unsigned int size,
> > > +		unsigned int *handle);
> > > +
> > > +/*
> > > + * request gem object creation and buffer allocation as the size
> > > + * that it is calculated with framebuffer information such as width,
> > > + * height and bpp.
> > > + */
> > > +int samsung_drm_gem_create_ioctl(struct drm_device *dev, void *data,
> > > +		struct drm_file *file_priv);
> > > +
> > > +/* get buffer offset to map to user space. */
> > > +int samsung_drm_gem_map_offset_ioctl(struct drm_device *dev, void
> *data,
> > > +		struct drm_file *file_priv);
> > > +
> > > +/* unmap a buffer from user space. */
> > > +int samsung_drm_gem_munmap_ioctl(struct drm_device *dev, void *data,
> > > +		struct drm_file *file_priv);
> > > +
> > > +/* initialize gem object. */
> > > +int samsung_drm_gem_init_object(struct drm_gem_object *obj);
> > > +
> > > +/* free gem object. */
> > > +void samsung_drm_gem_free_object(struct drm_gem_object *gem_obj);
> > > +
> > > +/* create memory region for drm framebuffer. */
> > > +int samsung_drm_gem_dumb_create(struct drm_file *file_priv,
> > > +		struct drm_device *dev, struct drm_mode_create_dumb *args);
> > > +
> > > +/* map memory region for drm framebuffer to user space. */
> > > +int samsung_drm_gem_dumb_map_offset(struct drm_file *file_priv,
> > > +		struct drm_device *dev, uint32_t handle, uint64_t *offset);
> > > +
> > > +/* page fault handler and mmap fault address(virtual) to physical
> > memory. */
> > > +int samsung_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault
> > *vmf);
> > > +
> > > +/* mmap gem object. */
> > > +int samsung_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
> > > +		struct drm_file *file_priv);
> > > +
> > > +/* set vm_flags and we can change vm attribute to other here. */
> > > +int samsung_drm_gem_mmap(struct file *filp, struct vm_area_struct
> *vma);
> > > +
> > > +/* destroy memory region allocated. */
> > > +int samsung_drm_gem_dumb_destroy(struct drm_file *file_priv,
> > > +		struct drm_device *dev, unsigned int handle);
> > > +
> > > +#endif
> > > diff --git a/include/drm/samsung_drm.h b/include/drm/samsung_drm.h
> > > new file mode 100644
> > > index 0000000..5f89cf1
> > > --- /dev/null
> > > +++ b/include/drm/samsung_drm.h
> > > @@ -0,0 +1,103 @@
> > > +/* samsung_drm.h
> > > + *
> > > + * Copyright (c) 2011 Samsung Electronics Co., Ltd.
> > > + * Authors:
> > > + *	Inki Dae <inki.dae@samsung.com>
> > > + *	Joonyoung Shim <jy0922.shim@samsung.com>
> > > + *
> > > + * Permission is hereby granted, free of charge, to any person
> > obtaining a
> > > + * copy of this software and associated documentation files (the
> > "Software"),
> > > + * to deal in the Software without restriction, including without
> > limitation
> > > + * the rights to use, copy, modify, merge, publish, distribute,
> > sublicense,
> > > + * and/or sell copies of the Software, and to permit persons to whom
> > the
> > > + * Software is furnished to do so, subject to the following conditions:
> > > + *
> > > + * The above copyright notice and this permission notice (including the
> > next
> > > + * paragraph) shall be included in all copies or substantial portions
> > of the
> > > + * Software.
> > > + *
> > > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> > EXPRESS OR
> > > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> > MERCHANTABILITY,
> > > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT
> > SHALL
> > > + * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
> > DAMAGES OR
> > > + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
> OTHERWISE,
> > > + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
> > OR
> > > + * OTHER DEALINGS IN THE SOFTWARE.
> > > + */
> > > +
> > > +#ifndef _SAMSUNG_DRM_H_
> > > +#define _SAMSUNG_DRM_H_
> > > +
> > > +/**
> > > + * User-desired buffer creation information structure.
> > > + *
> > > + * @size: requested size for the object.
> > > + *	- this size value would be page-aligned internally.
> > > + * @flags: user request for setting memory type or cache attributes.
> > > + * @handle: returned handle for the object.
> > > + */
> > > +struct drm_samsung_gem_create {
> > > +	unsigned int size;
> > > +	unsigned int flags;
> > > +
> > 
> > You can deleta that space.
> 
> Ok, get it. thank you.
> 
> > > +	unsigned int handle;
> > > +};
> > > +
> > > +/**
> > > + * A structure for getting buffer offset.
> > > + *
> > > + * @handle: a pointer to gem object created.
> > > + * @offset: relatived offset value of the memory region allocated.
> > > + *	- this value should be set by user.
> > > + */
> > > +struct drm_samsung_gem_map_off {
> > > +	unsigned int handle;
> > > +	uint64_t offset;
> > > +};
> > > +
> > > +/**
> > > + * A structure for mapping buffer.
> > > + *
> > > + * @handle: a pointer to gem object created.
> > > + * @offset: relatived offset value of the memory region allocated.
> > > + *	- this value should be set by user.
> > > + * @size: memory size to be mapped.
> > > + * @mapped: user virtual address to be mapped.
> > > + */
> > > +struct drm_samsung_gem_mmap {
> > > +	unsigned int handle;
> > > +	uint64_t offset;
> > > +	unsigned int size;
> > > +
> > 
> > Ditto
> 
> Thank you.
> 
> > > +	uint64_t mapped;
> > > +};
> > > +
> > > +#define DRM_SAMSUNG_GEM_CREATE		0x00
> > > +#define DRM_SAMSUNG_GEM_MAP_OFFSET	0x01
> > > +#define DRM_SAMSUNG_GEM_MMAP		0x02
> > > +
> > > +#define DRM_IOCTL_SAMSUNG_GEM_CREATE
> DRM_IOWR(DRM_COMMAND_BASE +
> > \
> > > +		DRM_SAMSUNG_GEM_CREATE, struct drm_samsung_gem_create)
> > > +
> > > +#define DRM_IOCTL_SAMSUNG_GEM_MAP_OFFSET	DRM_IOWR(DRM_COMMAND_BASE +
> > \
> > > +		DRM_SAMSUNG_GEM_MAP_OFFSET, struct drm_samsung_gem_map_off)
> > > +
> > > +#define DRM_IOCTL_SAMSUNG_GEM_MMAP	DRM_IOWR(DRM_COMMAND_BASE + \
> > > +		DRM_SAMSUNG_GEM_MMAP, struct drm_samsung_gem_mmap)
> > > +
> > > +/**
> > > + * Platform Specific Structure for DRM based FIMD.
> > > + *
> > > + * @timing: default video mode for initializing
> > > + * @default_win: default window layer number to be used for UI.
> > > + * @bpp: default bit per pixel.
> > > + */
> > > +struct samsung_drm_fimd_pdata {
> > > +	struct fb_videomode		timing;
> > > +	u32				vidcon0;
> > > +	u32				vidcon1;
> > > +	unsigned int			default_win;
> > > +	unsigned int			bpp;
> > > +};
> > > +
> > > +#endif
> > > --
> > > 1.7.0.4


You might also include in V5 the comments about CMA/DMA and about
exhaustion so that if somebody looks at the code in a year they
won't wonder about it anymore.

^ permalink raw reply

* [RFC PATCH 11/11] DT: regulator: register regulators as platform devices
From: Mark Brown @ 2011-09-15 14:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316085727-15023-12-git-send-email-rnayak@ti.com>

On Thu, Sep 15, 2011 at 04:52:07PM +0530, Rajendra Nayak wrote:
> of_regulator_register_devices() registers all regulators
> as platform devices. Use this to register all twl regulators
> from the twl driver probe.

Regulators can be devices of any type, not just platform devices.

>  drivers/mfd/twl-core.c       |    3 +++
>  drivers/of/of_regulator.c    |   30 ++++++++++++++++++++++++++++++
>  include/linux/of_regulator.h |    5 +++++

Again, in the regulator code not hidden away please.

> +/**
> + * of_regulator_register_devices - Register regulator devices to platform bus
> + * @np:	Parent device node with regulator child nodes
> + *
> + * Registers all the regulator and regulator-fixed nodes as platform devices
> + *
> + */
> +void of_regulator_register_devices(struct device_node *np)
> +{
> +	struct device_node *child;
> +	struct platform_device *dev;
> +
> +	for_each_child_of_node(np, child) {
> +		if (of_device_is_compatible(child, "regulator")
> +			|| of_device_is_compatible(child, "regulator-fixed")) {
> +			dev = of_device_alloc(child, NULL, NULL);
> +			if (!dev)
> +				return;
> +			dev->dev.bus = &platform_bus_type;
> +			if (of_device_add(dev) != 0) {
> +				platform_device_put(dev);
> +				return;
> +			}

I'm not entirely sure what this is for?  Surely we should be
instantiating the subdevices of the MFD in the same way we always have
done?

> +		}
> +	}
> +	return;
> +}
> +
> diff --git a/include/linux/of_regulator.h b/include/linux/of_regulator.h
> index 5fc7329..38cf7e3 100644
> --- a/include/linux/of_regulator.h
> +++ b/include/linux/of_regulator.h
> @@ -15,6 +15,7 @@ extern struct fixed_voltage_config
>  	*of_get_fixed_voltage_config(struct device_node *np);
>  extern struct device_node *of_get_regulator(struct device *dev,
>  	const char *id);
> +extern void of_regulator_register_devices(struct device_node *np);
>  #else
>  static inline struct regulator_init_data
>  	*of_get_regulator_init_data(struct device_node *np)
> @@ -31,6 +32,10 @@ static inline struct device_node *of_get_regulator(struct device *dev,
>  {
>  	return NULL;
>  }
> +static inline void of_regulator_register_devices(struct device_node *np)
> +{
> +	return NULL;
> +}
>  #endif /* CONFIG_OF_REGULATOR */
>  
>  #endif /* __LINUX_OF_REG_H */
> -- 
> 1.7.1
> 

^ permalink raw reply

* [PATCH] DaVinci: only poll EPCPR on DM644x and DM355
From: Sergei Shtylyov @ 2011-09-15 14:29 UTC (permalink / raw)
  To: linux-arm-kernel

EPCPR register and PDCTL.EPCGOOD bit exist only on DaVinci DM644x and DM35x,
so do not try to poll EPCPR and set PDCTL.EPCGOOD on the other SoCs -- it would
lead to lock up if some power domain hasn't been powered up by this time (which
hasn't happened yet on any board, it seems).

Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>

---
The patch is against the recent DaVinci tree plus this patch:

http://linux.davincidsp.com/pipermail/davinci-linux-open-source/2011-September/023308.html

Index: linux-davinci/arch/arm/mach-davinci/psc.c
===================================================================
--- linux-davinci.orig/arch/arm/mach-davinci/psc.c
+++ linux-davinci/arch/arm/mach-davinci/psc.c
@@ -88,14 +88,19 @@ void davinci_psc_config(unsigned int dom
 		ptcmd = 1 << domain;
 		__raw_writel(ptcmd, psc_base + PTCMD);
 
-		do {
-			epcpr = __raw_readl(psc_base + EPCPR);
-		} while ((((epcpr >> domain) & 1) == 0));
-
-		pdctl = __raw_readl(psc_base + PDCTL + 4 * domain);
-		pdctl |= 0x100;
-		__raw_writel(pdctl, psc_base + PDCTL + 4 * domain);
-
+		/*
+		 * EPCPR register and PDCTL.EPCGOOD bit exist only on DaVinci
+		 * DM644x and DM35x...
+		 */
+		if (cpu_is_davinci_dm644x() || cpu_is_davinci_dm355()) {
+			do {
+				epcpr = __raw_readl(psc_base + EPCPR);
+			} while (((epcpr >> domain) & 1) == 0);
+
+			pdctl = __raw_readl(psc_base + PDCTL + 4 * domain);
+			pdctl |= 0x100;
+			__raw_writel(pdctl, psc_base + PDCTL + 4 * domain);
+		}
 	} else {
 		ptcmd = 1 << domain;
 		__raw_writel(ptcmd, psc_base + PTCMD);

^ permalink raw reply

* [PATCH 2/2] ARM: mmp: add audio sram allocator
From: Jean-Christophe PLAGNIOL-VILLARD @ 2011-09-15 14:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1312167547-26740-3-git-send-email-leoy@marvell.com>

On 10:59 Mon 01 Aug     , Leo Yan wrote:
> Implement the audio sram allocator with genalloc,
> so that can dynamically allocate the buffer
> to pcm devices as need.
> 
> Signed-off-by: Leo Yan <leoy@marvell.com>
this can be more generic nad move to lib/genalloc.c

Best Regards,
J.

^ permalink raw reply

* [PATCH v2 0/6] add initial imx6q support
From: Shawn Guo @ 2011-09-15 14:45 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series adds the initial support for imx6q, which is a
Cortex-A9 Quad Core based SoC.

We chose to add imx6q support into mach-imx other than mach-mx5 or
a new mach-mx6, because we intend to merge mach-mx5 into mach-imx, so
that we have only mach-imx for imx family.

It's based on v3.1-rc6 with the patches below applied.

 * [PATCH v2 0/5] Convert DEBUG_LL UART selection to a Kconfig choice
   http://thread.gmane.org/gmane.linux.ports.arm.kernel/129702

 * [PATCH v4 2/2] ARM: l2x0: Add OF based initialization
   http://article.gmane.org/gmane.linux.kernel/1164401

 * [PATCH 1/7] ARM: l2x0: add empty l2x0_of_init
   http://article.gmane.org/gmane.linux.ports.arm.kernel/130878

 * [PATCH 0/5] GIC OF bindings
   http://thread.gmane.org/gmane.linux.drivers.devicetree/8093/

For suspend/resume support, it needs the following extra patches as the
prerequisite.

 * [PATCH 00/11] Add L2 cache cleaning to generic CPU suspend
   http://thread.gmane.org/gmane.linux.ports.arm.kernel/130957/

 * [PATCH v2 0/5] CPU PM notifiers
   http://thread.gmane.org/gmane.linux.ports.arm.kernel/131212/focus=131353

 * [PATCH v2 2/2] ARM: smp_scu: remove __init annotation from
   scu_enable()
   http://permalink.gmane.org/gmane.linux.ports.arm.kernel/131358

I hope I have made all changes I agree to change.  But please let me
know if I missed any.

Changes since v1:
 * Use the existing IMX_IO_P2V for static mapping
 * Fix the MXC_INTERNAL_IRQS breakage introduced by GIC definition
 * Retrieve clock frequency for fixed clocks from device tree
 * Drop early_initcall from imx_src_init() and call it from imx6q
   platform initialization
 * Use readl_relaxed/writel_relaxed rather than __raw_readl/__raw_writel
   as suggested by Arnd
 * Kill unnecessary imx_local_timer_pre_suspend/resume functions
 * Kill Kconfig symbol MACH_IMX6Q
 * Rebase to rmk's "Add L2 cache cleaning to generic CPU suspend" series
   so that we can retain L2 cache with necessary L2 register
   save/restore across suspend/resume cycle
 * Rebase to Rob's new "GIC OF bindings" series

Thanks.

Shawn Guo (6):
      arm/imx6q: add device tree source
      arm/imx6q: add core definitions and low-level debug uart
      arm/imx6q: add core drivers clock, gpc, mmdc and src
      arm/imx6q: add smp and cpu hotplug support
      arm/imx6q: add device tree machine support
      arm/imx6q: add suspend/resume support

 Documentation/devicetree/bindings/arm/fsl.txt |    6 +
 arch/arm/Kconfig                              |    2 +-
 arch/arm/Kconfig.debug                        |    7 +
 arch/arm/Makefile                             |    1 +
 arch/arm/boot/dts/imx6q-sabreauto.dts         |   71 +
 arch/arm/boot/dts/imx6q.dtsi                  |  547 +++++++
 arch/arm/mach-imx/Kconfig                     |   29 +-
 arch/arm/mach-imx/Makefile                    |   10 +
 arch/arm/mach-imx/Makefile.boot               |    4 +
 arch/arm/mach-imx/clock-imx6q.c               | 1997 +++++++++++++++++++++++++
 arch/arm/mach-imx/gpc.c                       |  113 ++
 arch/arm/mach-imx/head-v7.S                   |   98 ++
 arch/arm/mach-imx/hotplug.c                   |   44 +
 arch/arm/mach-imx/lluart.c                    |   32 +
 arch/arm/mach-imx/localtimer.c                |   35 +
 arch/arm/mach-imx/mach-imx6q.c                |   73 +
 arch/arm/mach-imx/mmdc.c                      |   71 +
 arch/arm/mach-imx/platsmp.c                   |   85 ++
 arch/arm/mach-imx/pm-imx6q.c                  |   88 ++
 arch/arm/mach-imx/src.c                       |   49 +
 arch/arm/mm/Kconfig                           |    2 +-
 arch/arm/plat-mxc/Kconfig                     |    5 +
 arch/arm/plat-mxc/include/mach/common.h       |   25 +
 arch/arm/plat-mxc/include/mach/debug-macro.S  |    2 +
 arch/arm/plat-mxc/include/mach/entry-macro.S  |   15 +-
 arch/arm/plat-mxc/include/mach/hardware.h     |    6 +
 arch/arm/plat-mxc/include/mach/irqs.h         |   10 +-
 arch/arm/plat-mxc/include/mach/memory.h       |    3 +
 arch/arm/plat-mxc/include/mach/mx6q.h         |   33 +
 29 files changed, 3457 insertions(+), 6 deletions(-)

^ permalink raw reply

* [PATCH v2 1/6] arm/imx6q: add device tree source
From: Shawn Guo @ 2011-09-15 14:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316097926-913-1-git-send-email-shawn.guo@linaro.org>

It adds device tree source and documentation for imx6q platform.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 Documentation/devicetree/bindings/arm/fsl.txt |    6 +
 arch/arm/boot/dts/imx6q-sabreauto.dts         |   71 ++++
 arch/arm/boot/dts/imx6q.dtsi                  |  547 +++++++++++++++++++++++++
 3 files changed, 624 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/fsl.txt
 create mode 100644 arch/arm/boot/dts/imx6q-sabreauto.dts
 create mode 100644 arch/arm/boot/dts/imx6q.dtsi

diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt
new file mode 100644
index 0000000..345bfc0
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/fsl.txt
@@ -0,0 +1,6 @@
+Freescale i.MX Platforms Device Tree Bindings
+-----------------------------------------------
+
+i.MX6 Quad SABRE Automotive Board
+Required root node properties:
+    - compatible = "fsl,imx6q-sabreauto", "fsl,imx6q";
diff --git a/arch/arm/boot/dts/imx6q-sabreauto.dts b/arch/arm/boot/dts/imx6q-sabreauto.dts
new file mode 100644
index 0000000..ad14d36
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-sabreauto.dts
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "imx6q.dtsi"
+
+/ {
+	model = "Freescale i.MX6 Quad SABRE Automotive Board";
+	compatible = "fsl,imx6q-sabreauto", "fsl,imx6q";
+
+	chosen {
+		bootargs = "console=ttymxc3,115200 root=/dev/mmcblk3p3 rootwait";
+	};
+
+	memory {
+		reg = <0x10000000 0x80000000>;
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		clkl {
+			compatible = "fsl,imx6q-clkl", "fixed-clock";
+			clock-frequency = <32768>;
+		};
+
+		clkh {
+			compatible = "fsl,imx6q-clkh", "fixed-clock";
+			clock-frequency = <0>;
+		};
+
+		osc {
+			compatible = "fsl,imx6q-osc", "fixed-clock";
+			clock-frequency = <24000000>;
+		};
+	};
+
+	soc {
+		aips-bus at 02100000 { /* AIPS2 */
+			enet at 02188000 {
+				phy-mode = "rgmii";
+				local-mac-address = [00 04 9F 01 1B 61];
+				status = "okay";
+			};
+
+			uart3: uart at 021f0000 { /* UART4 */
+				status = "okay";
+			};
+		};
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		debug-led {
+			label = "Heartbeat";
+			gpios = <&gpio2 25 0>; /* GPIO3_25 */
+			linux,default-trigger = "heartbeat";
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
new file mode 100644
index 0000000..8cc2036
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -0,0 +1,547 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+		serial3 = &uart3;
+		serial4 = &uart4;
+	};
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu at 0 {
+			compatible = "arm,cortex-a9";
+			reg = <0>;
+			next-level-cache = <&L2>;
+		};
+
+		cpu at 1 {
+			compatible = "arm,cortex-a9";
+			reg = <1>;
+			next-level-cache = <&L2>;
+		};
+
+		cpu at 2 {
+			compatible = "arm,cortex-a9";
+			reg = <2>;
+			next-level-cache = <&L2>;
+		};
+
+		cpu at 3 {
+			compatible = "arm,cortex-a9";
+			reg = <3>;
+			next-level-cache = <&L2>;
+		};
+	};
+
+	intc: interrupt-controller at 00a01000 {
+		compatible = "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		interrupt-controller;
+		reg = <0x00a01000 0x1000>,
+		      <0x00a00100 0x100>;
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "simple-bus";
+		interrupt-parent = <&intc>;
+		ranges;
+
+		timer at 00a00600 {
+			compatible = "arm,smp-twd";
+			reg = <0x00a00600 0x100>;
+			interrupts = <29 0 0xf>;
+		};
+
+		L2: l2-cache at 00a02000 {
+			compatible = "arm,pl310-cache";
+			reg = <0x00a02000 0x1000>;
+			interrupts = <124 4 0>;
+			cache-unified;
+			cache-level = <2>;
+		};
+
+		aips-bus at 02000000 { /* AIPS1 */
+			compatible = "fsl,aips-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x02000000 0x100000>;
+			ranges;
+
+			spba-bus at 02000000 {
+				compatible = "fsl,spba-bus", "simple-bus";
+				#address-cells = <1>;
+				#size-cells = <1>;
+				reg = <0x02000000 0x40000>;
+				ranges;
+
+				spdif at 02004000 {
+					reg = <0x02004000 0x4000>;
+					interrupts = <84 4 0>;
+				};
+
+				ecspi at 02008000 { /* eCSPI1 */
+					#address-cells = <1>;
+					#size-cells = <0>;
+					compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi";
+					reg = <0x02008000 0x4000>;
+					interrupts = <63 4 0>;
+					status = "disabled";
+				};
+
+				ecspi at 0200c000 { /* eCSPI2 */
+					#address-cells = <1>;
+					#size-cells = <0>;
+					compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi";
+					reg = <0x0200c000 0x4000>;
+					interrupts = <64 4 0>;
+					status = "disabled";
+				};
+
+				ecspi at 02010000 { /* eCSPI3 */
+					#address-cells = <1>;
+					#size-cells = <0>;
+					compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi";
+					reg = <0x02010000 0x4000>;
+					interrupts = <65 4 0>;
+					status = "disabled";
+				};
+
+				ecspi at 02014000 { /* eCSPI4 */
+					#address-cells = <1>;
+					#size-cells = <0>;
+					compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi";
+					reg = <0x02014000 0x4000>;
+					interrupts = <66 4 0>;
+					status = "disabled";
+				};
+
+				ecspi at 02018000 { /* eCSPI5 */
+					#address-cells = <1>;
+					#size-cells = <0>;
+					compatible = "fsl,imx6q-ecspi", "fsl,imx51-ecspi";
+					reg = <0x02018000 0x4000>;
+					interrupts = <67 4 0>;
+					status = "disabled";
+				};
+
+				uart0: uart at 02020000 { /* UART1 */
+					compatible = "fsl,imx6q-uart", "fsl,imx21-uart";
+					reg = <0x02020000 0x4000>;
+					interrupts = <58 4 0>;
+					status = "disabled";
+				};
+
+				esai at 02024000 {
+					reg = <0x02024000 0x4000>;
+					interrupts = <83 4 0>;
+				};
+
+				ssi at 02028000 { /* SSI1 */
+					reg = <0x02028000 0x4000>;
+					interrupts = <78 4 0>;
+				};
+
+				ssi at 0202c000 { /* SSI2 */
+					reg = <0x0202c000 0x4000>;
+					interrupts = <79 4 0>;
+				};
+
+				ssi at 02030000 { /* SSI3 */
+					reg = <0x02030000 0x4000>;
+					interrupts = <80 4 0>;
+				};
+
+				asrc at 02034000 {
+					reg = <0x02034000 0x4000>;
+					interrupts = <82 4 0>;
+				};
+
+				spba at 0203c000 {
+					reg = <0x0203c000 0x4000>;
+				};
+			};
+
+			vpu at 02040000 {
+				reg = <0x02040000 0x3c000>;
+				interrupts = <35 4 0 44 4 0>;
+			};
+
+			aipstz at 0207c000 { /* AIPSTZ1 */
+				reg = <0x0207c000 0x4000>;
+			};
+
+			pwm at 02080000 { /* PWM1 */
+				reg = <0x02080000 0x4000>;
+				interrupts = <115 4 0>;
+			};
+
+			pwm at 02084000 { /* PWM2 */
+				reg = <0x02084000 0x4000>;
+				interrupts = <116 4 0>;
+			};
+
+			pwm at 02088000 { /* PWM3 */
+				reg = <0x02088000 0x4000>;
+				interrupts = <117 4 0>;
+			};
+
+			pwm at 0208c000 { /* PWM4 */
+				reg = <0x0208c000 0x4000>;
+				interrupts = <118 4 0>;
+			};
+
+			flexcan at 02090000 { /* CAN1 */
+				reg = <0x02090000 0x4000>;
+				interrupts = <142 4 0>;
+			};
+
+			flexcan at 02094000 { /* CAN2 */
+				reg = <0x02094000 0x4000>;
+				interrupts = <143 4 0>;
+			};
+
+			gpt at 02098000 {
+				compatible = "fsl,imx6q-gpt";
+				reg = <0x02098000 0x4000>;
+				interrupts = <87 4 0>;
+			};
+
+			gpio0: gpio at 0209c000 { /* GPIO1 */
+				compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio";
+				reg = <0x0209c000 0x4000>;
+				interrupts = <98 4 0 99 4 0>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
+
+			gpio1: gpio at 020a0000 { /* GPIO2 */
+				compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio";
+				reg = <0x020a0000 0x4000>;
+				interrupts = <100 4 0 101 4 0>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
+
+			gpio2: gpio at 020a4000 { /* GPIO3 */
+				compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio";
+				reg = <0x020a4000 0x4000>;
+				interrupts = <102 4 0 103 4 0>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
+
+			gpio3: gpio at 020a8000 { /* GPIO4 */
+				compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio";
+				reg = <0x020a8000 0x4000>;
+				interrupts = <104 4 0 105 4 0>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
+
+			gpio4: gpio at 020ac000 { /* GPIO5 */
+				compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio";
+				reg = <0x020ac000 0x4000>;
+				interrupts = <106 4 0 107 4 0>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
+
+			gpio5: gpio at 020b0000 { /* GPIO6 */
+				compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio";
+				reg = <0x020b0000 0x4000>;
+				interrupts = <108 4 0 109 4 0>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
+
+			gpio6: gpio at 020b4000 { /* GPIO7 */
+				compatible = "fsl,imx6q-gpio", "fsl,imx31-gpio";
+				reg = <0x020b4000 0x4000>;
+				interrupts = <110 4 0 111 4 0>;
+				gpio-controller;
+				#gpio-cells = <2>;
+				interrupt-controller;
+				#interrupt-cells = <1>;
+			};
+
+			kpp at 020b8000 {
+				reg = <0x020b8000 0x4000>;
+				interrupts = <114 4 0>;
+			};
+
+			wdog at 020bc000 { /* WDOG1 */
+				compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt";
+				reg = <0x020bc000 0x4000>;
+				interrupts = <112 4 0>;
+				status = "disabled";
+			};
+
+			wdog at 020c0000 { /* WDOG2 */
+				compatible = "fsl,imx6q-wdt", "fsl,imx21-wdt";
+				reg = <0x020c0000 0x4000>;
+				interrupts = <113 4 0>;
+				status = "disabled";
+			};
+
+			ccm at 020c4000 {
+				compatible = "fsl,imx6q-ccm";
+				reg = <0x020c4000 0x4000>;
+				interrupts = <119 4 0 120 4 0>;
+			};
+
+			anatop at 020c8000 {
+				compatible = "fsl,imx6q-anatop";
+				reg = <0x020c8000 0x1000>;
+				interrupts = <81 4 0 86 4 0 159 4 0>;
+			};
+
+			usbphy at 020c9000 { /* USBPHY1 */
+				reg = <0x020c9000 0x1000>;
+				interrupts = <76 4 0>;
+			};
+
+			usbphy at 020ca000 { /* USBPHY2 */
+				reg = <0x020ca000 0x1000>;
+				interrupts = <77 4 0>;
+			};
+
+			snvs at 020cc000 {
+				reg = <0x020cc000 0x4000>;
+				interrupts = <51 4 0 52 4 0>;
+			};
+
+			epit at 020d0000 { /* EPIT1 */
+				reg = <0x020d0000 0x4000>;
+				interrupts = <88 4 0>;
+			};
+
+			epit at 020d4000 { /* EPIT2 */
+				reg = <0x020d4000 0x4000>;
+				interrupts = <89 4 0>;
+			};
+
+			src at 020d8000 {
+				compatible = "fsl,imx6q-src";
+				reg = <0x020d8000 0x4000>;
+				interrupts = <123 4 0 128 4 0>;
+			};
+
+			gpc at 020dc000 {
+				compatible = "fsl,imx6q-gpc";
+				reg = <0x020dc000 0x4000>;
+				interrupts = <121 4 0 122 4 0>;
+			};
+
+			iomuxc at 020e0000 {
+				reg = <0x020e0000 0x4000>;
+			};
+
+			dcic at 020e4000 { /* DCIC1 */
+				reg = <0x020e4000 0x4000>;
+				interrupts = <156 4 0>;
+			};
+
+			dcic at 020e8000 { /* DCIC2 */
+				reg = <0x020e8000 0x4000>;
+				interrupts = <157 4 0>;
+			};
+
+			sdma at 020ec000 {
+				compatible = "fsl,imx6q-sdma", "fsl,imx35-sdma";
+				reg = <0x020ec000 0x4000>;
+				interrupts = <34 4 0>;
+			};
+		};
+
+		aips-bus at 02100000 { /* AIPS2 */
+			compatible = "fsl,aips-bus", "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x02100000 0x100000>;
+			ranges;
+
+			caam at 02100000 {
+				reg = <0x02100000 0x40000>;
+				interrupts = <137 4 0 138 4 0>;
+			};
+
+			aipstz at 0217c000 { /* AIPSTZ2 */
+				reg = <0x0217c000 0x4000>;
+			};
+
+			enet at 02188000 {
+				compatible = "fsl,imx6q-fec";
+				reg = <0x02188000 0x4000>;
+				interrupts = <150 4 0 151 4 0>;
+				status = "disabled";
+			};
+
+			mlb at 0218c000 {
+				reg = <0x0218c000 0x4000>;
+				interrupts = <85 4 0 149 4 0 158 4 0>;
+			};
+
+			usdhc at 02190000 { /* uSDHC1 */
+				reg = <0x02190000 0x4000>;
+				interrupts = <54 4 0>;
+			};
+
+			usdhc at 02194000 { /* uSDHC2 */
+				reg = <0x02194000 0x4000>;
+				interrupts = <55 4 0>;
+			};
+
+			usdhc at 02198000 { /* uSDHC3 */
+				reg = <0x02198000 0x4000>;
+				interrupts = <56 4 0>;
+			};
+
+			usdhc at 0219c000 { /* uSDHC4 */
+				reg = <0x0219c000 0x4000>;
+				interrupts = <57 4 0>;
+			};
+
+			i2c at 021a0000 { /* I2C1 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,imx6q-i2c", "fsl,imx1-i2c";
+				reg = <0x021a0000 0x4000>;
+				interrupts = <68 4 0>;
+				status = "disabled";
+			};
+
+			i2c at 021a4000 { /* I2C2 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,imx6q-i2c", "fsl,imx1-i2c";
+				reg = <0x021a4000 0x4000>;
+				interrupts = <69 4 0>;
+				status = "disabled";
+			};
+
+			i2c at 021a8000 { /* I2C3 */
+				#address-cells = <1>;
+				#size-cells = <0>;
+				compatible = "fsl,imx6q-i2c", "fsl,imx1-i2c";
+				reg = <0x021a8000 0x4000>;
+				interrupts = <70 4 0>;
+				status = "disabled";
+			};
+
+			romcp at 021ac000 {
+				reg = <0x021ac000 0x4000>;
+			};
+
+			mmdc at 021b0000 { /* MMDC0 */
+				compatible = "fsl,imx6q-mmdc";
+				reg = <0x021b0000 0x4000>;
+			};
+
+			mmdc at 021b4000 { /* MMDC1 */
+				reg = <0x021b4000 0x4000>;
+			};
+
+			weim at 021b8000 {
+				reg = <0x021b8000 0x4000>;
+				interrupts = <46 4 0>;
+			};
+
+			ocotp at 021bc000 {
+				reg = <0x021bc000 0x4000>;
+			};
+
+			ocotp at 021c0000 {
+				reg = <0x021c0000 0x4000>;
+				interrupts = <53 4 0>;
+			};
+
+			tzasc at 021d0000 { /* TZASC1 */
+				reg = <0x021d0000 0x4000>;
+				interrupts = <140 4 0>;
+			};
+
+			tzasc at 021d4000 { /* TZASC2 */
+				reg = <0x021d4000 0x4000>;
+				interrupts = <141 4 0>;
+			};
+
+			audmux at 021d8000 {
+				reg = <0x021d8000 0x4000>;
+			};
+
+			mipi at 021dc000 { /* MIPI-CSI */
+				reg = <0x021dc000 0x4000>;
+			};
+
+			mipi at 021e0000 { /* MIPI-DSI */
+				reg = <0x021e0000 0x4000>;
+			};
+
+			vdoa at 021e4000 {
+				reg = <0x021e4000 0x4000>;
+				interrupts = <50 4 0>;
+			};
+
+			uart1: uart at 021e8000 { /* UART2 */
+				compatible = "fsl,imx6q-uart", "fsl,imx21-uart";
+				reg = <0x021e8000 0x4000>;
+				interrupts = <59 4 0>;
+				status = "disabled";
+			};
+
+			uart2: uart at 021ec000 { /* UART3 */
+				compatible = "fsl,imx6q-uart", "fsl,imx21-uart";
+				reg = <0x021ec000 0x4000>;
+				interrupts = <60 4 0>;
+				status = "disabled";
+			};
+
+			uart3: uart at 021f0000 { /* UART4 */
+				compatible = "fsl,imx6q-uart", "fsl,imx21-uart";
+				reg = <0x021f0000 0x4000>;
+				interrupts = <61 4 0>;
+				status = "disabled";
+			};
+
+			uart4: uart at 021f4000 { /* UART5 */
+				compatible = "fsl,imx6q-uart", "fsl,imx21-uart";
+				reg = <0x021f4000 0x4000>;
+				interrupts = <62 4 0>;
+				status = "disabled";
+			};
+		};
+	};
+};
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH v2 2/6] arm/imx6q: add core definitions and low-level debug uart
From: Shawn Guo @ 2011-09-15 14:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316097926-913-1-git-send-email-shawn.guo@linaro.org>

It adds the core definitions and low-level debug uart support
for imx6q.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/Kconfig                             |    2 +-
 arch/arm/Kconfig.debug                       |    7 +++++
 arch/arm/Makefile                            |    1 +
 arch/arm/mach-imx/Kconfig                    |   15 +++++++++++-
 arch/arm/mach-imx/Makefile                   |    2 +
 arch/arm/mach-imx/Makefile.boot              |    4 +++
 arch/arm/mach-imx/lluart.c                   |   32 +++++++++++++++++++++++++
 arch/arm/plat-mxc/Kconfig                    |    5 ++++
 arch/arm/plat-mxc/include/mach/debug-macro.S |    2 +
 arch/arm/plat-mxc/include/mach/entry-macro.S |   15 +++++++++++-
 arch/arm/plat-mxc/include/mach/hardware.h    |    6 ++++
 arch/arm/plat-mxc/include/mach/irqs.h        |   10 ++++++-
 arch/arm/plat-mxc/include/mach/memory.h      |    3 ++
 arch/arm/plat-mxc/include/mach/mx6q.h        |   33 ++++++++++++++++++++++++++
 14 files changed, 132 insertions(+), 5 deletions(-)
 create mode 100644 arch/arm/mach-imx/lluart.c
 create mode 100644 arch/arm/plat-mxc/include/mach/mx6q.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index bc9981b..415a954 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1360,7 +1360,7 @@ config SMP
 	depends on REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || \
 		 MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \
 		 ARCH_EXYNOS4 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \
-		 ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE
+		 ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE || SOC_IMX6Q
 	select USE_GENERIC_SMP_HELPERS
 	select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP
 	help
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 965d59a..68fc155 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -155,6 +155,13 @@ choice
 		  Say Y here if you want kernel low-level debugging support
 		  on i.MX50 or i.MX53.
 
+	config DEBUG_IMX6Q_UART
+		bool "i.MX6Q Debug UART"
+		depends on SOC_IMX6Q
+		help
+		  Say Y here if you want kernel low-level debugging support
+		  on i.MX6Q.
+
 	config DEBUG_S3C_UART0
 		depends on PLAT_SAMSUNG
 		bool "Use S3C UART 0 for low-level debug"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 70c424e..3a0bbe4 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -159,6 +159,7 @@ machine-$(CONFIG_ARCH_MX2)		:= imx
 machine-$(CONFIG_ARCH_MX25)		:= imx
 machine-$(CONFIG_ARCH_MX3)		:= imx
 machine-$(CONFIG_ARCH_MX5)		:= mx5
+machine-$(CONFIG_ARCH_MX6)		:= imx
 machine-$(CONFIG_ARCH_MXS)		:= mxs
 machine-$(CONFIG_ARCH_NETX)		:= netx
 machine-$(CONFIG_ARCH_NOMADIK)		:= nomadik
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 0519dd7..e88e366 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -58,7 +58,6 @@ config SOC_IMX35
 	select ARCH_MX35
 	select MXC_AVIC
 
-
 if ARCH_MX1
 
 comment "MX1 platforms:"
@@ -606,3 +605,17 @@ config MACH_VPR200
 	  configurations for the board and its peripherals.
 
 endif
+
+if ARCH_MX6
+comment "i.MX6 family:"
+
+config SOC_IMX6Q
+	bool "i.MX6 Quad support"
+	select ARM_GIC
+	select CPU_V7
+	select USE_OF
+
+	help
+	  This enables support for Freescale i.MX6 Quad processor.
+
+endif
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index e9eb36d..96ecc96 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -61,3 +61,5 @@ obj-$(CONFIG_MACH_MX35_3DS) += mach-mx35_3ds.o
 obj-$(CONFIG_MACH_EUKREA_CPUIMX35) += mach-cpuimx35.o
 obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd35-baseboard.o
 obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o
+
+obj-$(CONFIG_DEBUG_LL) += lluart.o
diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot
index ebee18b..389a0e3 100644
--- a/arch/arm/mach-imx/Makefile.boot
+++ b/arch/arm/mach-imx/Makefile.boot
@@ -17,3 +17,7 @@ initrd_phys-$(CONFIG_MACH_MX27)	:= 0xA0800000
 zreladdr-$(CONFIG_ARCH_MX3)	:= 0x80008000
 params_phys-$(CONFIG_ARCH_MX3)	:= 0x80000100
 initrd_phys-$(CONFIG_ARCH_MX3)	:= 0x80800000
+
+zreladdr-$(CONFIG_SOC_IMX6Q)	:= 0x10008000
+params_phys-$(CONFIG_SOC_IMX6Q)	:= 0x10000100
+initrd_phys-$(CONFIG_SOC_IMX6Q)	:= 0x10800000
diff --git a/arch/arm/mach-imx/lluart.c b/arch/arm/mach-imx/lluart.c
new file mode 100644
index 0000000..d4ab6f2
--- /dev/null
+++ b/arch/arm/mach-imx/lluart.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <asm/page.h>
+#include <asm/sizes.h>
+#include <asm/mach/map.h>
+#include <mach/hardware.h>
+
+static struct map_desc imx_lluart_desc = {
+#ifdef CONFIG_DEBUG_IMX6Q_UART
+	.virtual	= MX6Q_IO_P2V(MX6Q_UART4_BASE_ADDR),
+	.pfn		= __phys_to_pfn(MX6Q_UART4_BASE_ADDR),
+	.length		= MX6Q_UART4_SIZE,
+	.type		= MT_DEVICE,
+#endif
+};
+
+void __init imx_lluart_map_io(void)
+{
+	if (imx_lluart_desc.virtual)
+		iotable_init(&imx_lluart_desc, 1);
+}
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
index a5353fc..e548f9b 100644
--- a/arch/arm/plat-mxc/Kconfig
+++ b/arch/arm/plat-mxc/Kconfig
@@ -48,6 +48,11 @@ config ARCH_MX51
 	help
 	  This enables support for systems based on the Freescale i.MX51 family
 
+config ARCH_MX6
+	bool "i.MX6"
+	help
+	  This enables support for systems based on the Freescale i.MX6 family
+
 endchoice
 
 source "arch/arm/mach-imx/Kconfig"
diff --git a/arch/arm/plat-mxc/include/mach/debug-macro.S b/arch/arm/plat-mxc/include/mach/debug-macro.S
index 07cfdbe..f2ce2cb 100644
--- a/arch/arm/plat-mxc/include/mach/debug-macro.S
+++ b/arch/arm/plat-mxc/include/mach/debug-macro.S
@@ -24,6 +24,8 @@
 #define UART_PADDR	MX51_UART1_BASE_ADDR
 #elif defined (CONFIG_DEBUG_IMX50_IMX53_UART)
 #define UART_PADDR	MX53_UART1_BASE_ADDR
+#elif defined (CONFIG_DEBUG_IMX6Q_UART)
+#define UART_PADDR	MX6Q_UART4_BASE_ADDR
 #endif
 
 #define UART_VADDR	IMX_IO_ADDRESS(UART_PADDR)
diff --git a/arch/arm/plat-mxc/include/mach/entry-macro.S b/arch/arm/plat-mxc/include/mach/entry-macro.S
index 066d464..341f800 100644
--- a/arch/arm/plat-mxc/include/mach/entry-macro.S
+++ b/arch/arm/plat-mxc/include/mach/entry-macro.S
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org>
- *  Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *  Copyright 2004-2011 Freescale Semiconductor, Inc. All Rights Reserved.
  */
 
 /*
@@ -11,6 +11,17 @@
 
 #include <mach/hardware.h>
 
+#ifdef CONFIG_ARM_GIC
+#include <asm/hardware/entry-macro-gic.S>
+
+	.macro	disable_fiq
+	.endm
+
+	.macro	arch_ret_to_user, tmp1, tmp2
+	.endm
+
+#else
+
 #define AVIC_NIMASK	0x04
 
 	@ this macro disables fast irq (not implemented)
@@ -78,3 +89,5 @@
 	movs \irqnr, \irqnr
 #endif
 	.endm
+
+#endif /* CONFIG_ARM_GIC */
diff --git a/arch/arm/plat-mxc/include/mach/hardware.h b/arch/arm/plat-mxc/include/mach/hardware.h
index a8bfd56..ee28c56 100644
--- a/arch/arm/plat-mxc/include/mach/hardware.h
+++ b/arch/arm/plat-mxc/include/mach/hardware.h
@@ -86,6 +86,11 @@
  *	SPBA0	0x70000000+0x100000	->	0xf5400000+0x100000
  *	AIPS1	0x73f00000+0x100000	->	0xf5700000+0x100000
  *	AIPS2	0x83f00000+0x100000	->	0xf4300000+0x100000
+ * mx6q:
+ *	SCU	0x00a00000+0x001000	->	0xf4000000+0x001000
+ *	CCM	0x020c4000+0x004000	->	0xf42c4000+0x004000
+ *	ANATOP	0x020c8000+0x001000	->	0xf42c8000+0x001000
+ *	UART4	0x021f0000+0x004000	->	0xf42f0000+0x004000
  */
 #define IMX_IO_P2V(x)	(						\
 			0xf4000000 +					\
@@ -97,6 +102,7 @@
 
 #include <mach/mxc.h>
 
+#include <mach/mx6q.h>
 #include <mach/mx50.h>
 #include <mach/mx51.h>
 #include <mach/mx53.h>
diff --git a/arch/arm/plat-mxc/include/mach/irqs.h b/arch/arm/plat-mxc/include/mach/irqs.h
index 00e812b..fd9efb0 100644
--- a/arch/arm/plat-mxc/include/mach/irqs.h
+++ b/arch/arm/plat-mxc/include/mach/irqs.h
@@ -14,9 +14,15 @@
 #include <asm-generic/gpio.h>
 
 /*
- * SoCs with TZIC interrupt controller have 128 IRQs, those with AVIC have 64
+ * SoCs with GIC interrupt controller have 160 IRQs, those with TZIC
+ * have 128 IRQs, and those with AVIC have 64.
+ *
+ * To support single image, the biggest number should be defined on
+ * top of the list.
  */
-#ifdef CONFIG_MXC_TZIC
+#if defined CONFIG_ARM_GIC
+#define MXC_INTERNAL_IRQS	160
+#elif defined CONFIG_MXC_TZIC
 #define MXC_INTERNAL_IRQS	128
 #else
 #define MXC_INTERNAL_IRQS	64
diff --git a/arch/arm/plat-mxc/include/mach/memory.h b/arch/arm/plat-mxc/include/mach/memory.h
index 11be5cd..2b8e186 100644
--- a/arch/arm/plat-mxc/include/mach/memory.h
+++ b/arch/arm/plat-mxc/include/mach/memory.h
@@ -19,6 +19,7 @@
 #define MX50_PHYS_OFFSET	UL(0x70000000)
 #define MX51_PHYS_OFFSET	UL(0x90000000)
 #define MX53_PHYS_OFFSET	UL(0x70000000)
+#define MX6Q_PHYS_OFFSET	UL(0x10000000)
 
 #if !defined(CONFIG_RUNTIME_PHYS_OFFSET)
 # if defined CONFIG_ARCH_MX1
@@ -37,6 +38,8 @@
 #  define PLAT_PHYS_OFFSET		MX51_PHYS_OFFSET
 # elif defined CONFIG_ARCH_MX53
 #  define PLAT_PHYS_OFFSET		MX53_PHYS_OFFSET
+# elif defined CONFIG_SOC_IMX6Q
+#  define PLAT_PHYS_OFFSET		MX6Q_PHYS_OFFSET
 # endif
 #endif
 
diff --git a/arch/arm/plat-mxc/include/mach/mx6q.h b/arch/arm/plat-mxc/include/mach/mx6q.h
new file mode 100644
index 0000000..254a561
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/mx6q.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __MACH_MX6Q_H__
+#define __MACH_MX6Q_H__
+
+#define MX6Q_IO_P2V(x)			IMX_IO_P2V(x)
+#define MX6Q_IO_ADDRESS(x)		IOMEM(MX6Q_IO_P2V(x))
+
+/*
+ * The following are the blocks that need to be statically mapped.
+ * For other blocks, the base address really should be retrieved from
+ * device tree.
+ */
+#define MX6Q_SCU_BASE_ADDR		0x00a00000
+#define MX6Q_SCU_SIZE			0x1000
+#define MX6Q_CCM_BASE_ADDR		0x020c4000
+#define MX6Q_CCM_SIZE			0x4000
+#define MX6Q_ANATOP_BASE_ADDR		0x020c8000
+#define MX6Q_ANATOP_SIZE		0x1000
+#define MX6Q_UART4_BASE_ADDR		0x021f0000
+#define MX6Q_UART4_SIZE			0x4000
+
+#endif	/* __MACH_MX6Q_H__ */
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH v2 3/6] arm/imx6q: add core drivers clock, gpc, mmdc and src
From: Shawn Guo @ 2011-09-15 14:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316097926-913-1-git-send-email-shawn.guo@linaro.org>

It adds a number of core drivers support for imx6q, including clock,
General Power Controller (gpc), Multi Mode DDR Controller(mmdc) and
System Reset Controller (src).

Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/Kconfig       |   13 +
 arch/arm/mach-imx/Makefile      |    4 +
 arch/arm/mach-imx/clock-imx6q.c | 1997 +++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-imx/gpc.c         |  113 +++
 arch/arm/mach-imx/mmdc.c        |   71 ++
 arch/arm/mach-imx/src.c         |   49 +
 6 files changed, 2247 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-imx/clock-imx6q.c
 create mode 100644 arch/arm/mach-imx/gpc.c
 create mode 100644 arch/arm/mach-imx/mmdc.c
 create mode 100644 arch/arm/mach-imx/src.c

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index e88e366..af73b3e 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -1,5 +1,15 @@
 config IMX_HAVE_DMA_V1
 	bool
+
+config HAVE_IMX_GPC
+	bool
+
+config HAVE_IMX_MMDC
+	bool
+
+config HAVE_IMX_SRC
+	bool
+
 #
 # ARCH_MX31 and ARCH_MX35 are left for compatibility
 # Some usages assume that having one of them implies not having (e.g.) ARCH_MX2.
@@ -613,6 +623,9 @@ config SOC_IMX6Q
 	bool "i.MX6 Quad support"
 	select ARM_GIC
 	select CPU_V7
+	select HAVE_IMX_GPC
+	select HAVE_IMX_MMDC
+	select HAVE_IMX_SRC
 	select USE_OF
 
 	help
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 96ecc96..8c21fda 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -63,3 +63,7 @@ obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd35-baseboard.o
 obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o
 
 obj-$(CONFIG_DEBUG_LL) += lluart.o
+obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
+obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
+obj-$(CONFIG_HAVE_IMX_SRC) += src.o
+obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o
diff --git a/arch/arm/mach-imx/clock-imx6q.c b/arch/arm/mach-imx/clock-imx6q.c
new file mode 100644
index 0000000..074ba65
--- /dev/null
+++ b/arch/arm/mach-imx/clock-imx6q.c
@@ -0,0 +1,1997 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/div64.h>
+#include <asm/mach/map.h>
+#include <mach/clock.h>
+#include <mach/common.h>
+#include <mach/hardware.h>
+
+#define PLL_BASE		IMX_IO_ADDRESS(MX6Q_ANATOP_BASE_ADDR)
+#define PLL1_SYS		(PLL_BASE + 0x000)
+#define PLL2_BUS		(PLL_BASE + 0x030)
+#define PLL3_USB_OTG		(PLL_BASE + 0x010)
+#define PLL4_AUDIO		(PLL_BASE + 0x070)
+#define PLL5_VIDEO		(PLL_BASE + 0x0a0)
+#define PLL6_MLB		(PLL_BASE + 0x0d0)
+#define PLL7_USB_HOST		(PLL_BASE + 0x020)
+#define PLL8_ENET		(PLL_BASE + 0x0e0)
+#define PFD_480			(PLL_BASE + 0x0f0)
+#define PFD_528			(PLL_BASE + 0x100)
+#define PLL_NUM_OFFSET		0x010
+#define PLL_DENOM_OFFSET	0x020
+
+#define PFD0			7
+#define PFD1			15
+#define PFD2			23
+#define PFD3			31
+#define PFD_FRAC_MASK		0x3f
+
+#define BM_PLL_BYPASS			(0x1 << 16)
+#define BM_PLL_ENABLE			(0x1 << 13)
+#define BM_PLL_POWER_DOWN		(0x1 << 12)
+#define BM_PLL_LOCK			(0x1 << 31)
+#define BP_PLL_SYS_DIV_SELECT		0
+#define BM_PLL_SYS_DIV_SELECT		(0x7f << 0)
+#define BP_PLL_BUS_DIV_SELECT		0
+#define BM_PLL_BUS_DIV_SELECT		(0x1 << 0)
+#define BP_PLL_USB_DIV_SELECT		0
+#define BM_PLL_USB_DIV_SELECT		(0x3 << 0)
+#define BP_PLL_AV_DIV_SELECT		0
+#define BM_PLL_AV_DIV_SELECT		(0x7f << 0)
+#define BP_PLL_ENET_DIV_SELECT		0
+#define BM_PLL_ENET_DIV_SELECT		(0x3 << 0)
+#define BM_PLL_ENET_EN_PCIE		(0x1 << 19)
+#define BM_PLL_ENET_EN_SATA		(0x1 << 20)
+
+#define CCM_BASE	IMX_IO_ADDRESS(MX6Q_CCM_BASE_ADDR)
+#define CCR		(CCM_BASE + 0x00)
+#define CCDR		(CCM_BASE + 0x04)
+#define CSR		(CCM_BASE + 0x08)
+#define CCSR		(CCM_BASE + 0x0c)
+#define CACRR		(CCM_BASE + 0x10)
+#define CBCDR		(CCM_BASE + 0x14)
+#define CBCMR		(CCM_BASE + 0x18)
+#define CSCMR1		(CCM_BASE + 0x1c)
+#define CSCMR2		(CCM_BASE + 0x20)
+#define CSCDR1		(CCM_BASE + 0x24)
+#define CS1CDR		(CCM_BASE + 0x28)
+#define CS2CDR		(CCM_BASE + 0x2c)
+#define CDCDR		(CCM_BASE + 0x30)
+#define CHSCCDR		(CCM_BASE + 0x34)
+#define CSCDR2		(CCM_BASE + 0x38)
+#define CSCDR3		(CCM_BASE + 0x3c)
+#define CSCDR4		(CCM_BASE + 0x40)
+#define CWDR		(CCM_BASE + 0x44)
+#define CDHIPR		(CCM_BASE + 0x48)
+#define CDCR		(CCM_BASE + 0x4c)
+#define CTOR		(CCM_BASE + 0x50)
+#define CLPCR		(CCM_BASE + 0x54)
+#define CISR		(CCM_BASE + 0x58)
+#define CIMR		(CCM_BASE + 0x5c)
+#define CCOSR		(CCM_BASE + 0x60)
+#define CGPR		(CCM_BASE + 0x64)
+#define CCGR0		(CCM_BASE + 0x68)
+#define CCGR1		(CCM_BASE + 0x6c)
+#define CCGR2		(CCM_BASE + 0x70)
+#define CCGR3		(CCM_BASE + 0x74)
+#define CCGR4		(CCM_BASE + 0x78)
+#define CCGR5		(CCM_BASE + 0x7c)
+#define CCGR6		(CCM_BASE + 0x80)
+#define CCGR7		(CCM_BASE + 0x84)
+#define CMEOR		(CCM_BASE + 0x88)
+
+#define CG0		0
+#define CG1		2
+#define CG2		4
+#define CG3		6
+#define CG4		8
+#define CG5		10
+#define CG6		12
+#define CG7		14
+#define CG8		16
+#define CG9		18
+#define CG10		20
+#define CG11		22
+#define CG12		24
+#define CG13		26
+#define CG14		28
+#define CG15		30
+
+#define BM_CCSR_PLL1_SW_SEL		(0x1 << 2)
+#define BM_CCSR_STEP_SEL		(0x1 << 8)
+
+#define BP_CACRR_ARM_PODF		0
+#define BM_CACRR_ARM_PODF		(0x7 << 0)
+
+#define BP_CBCDR_PERIPH2_CLK2_PODF	0
+#define BM_CBCDR_PERIPH2_CLK2_PODF	(0x7 << 0)
+#define BP_CBCDR_MMDC_CH1_AXI_PODF	3
+#define BM_CBCDR_MMDC_CH1_AXI_PODF	(0x7 << 3)
+#define BP_CBCDR_AXI_SEL		6
+#define BM_CBCDR_AXI_SEL		(0x3 << 6)
+#define BP_CBCDR_IPG_PODF		8
+#define BM_CBCDR_IPG_PODF		(0x3 << 8)
+#define BP_CBCDR_AHB_PODF		10
+#define BM_CBCDR_AHB_PODF		(0x7 << 10)
+#define BP_CBCDR_AXI_PODF		16
+#define BM_CBCDR_AXI_PODF		(0x7 << 16)
+#define BP_CBCDR_MMDC_CH0_AXI_PODF	19
+#define BM_CBCDR_MMDC_CH0_AXI_PODF	(0x7 << 19)
+#define BP_CBCDR_PERIPH_CLK_SEL		25
+#define BM_CBCDR_PERIPH_CLK_SEL		(0x1 << 25)
+#define BP_CBCDR_PERIPH2_CLK_SEL	26
+#define BM_CBCDR_PERIPH2_CLK_SEL	(0x1 << 26)
+#define BP_CBCDR_PERIPH_CLK2_PODF	27
+#define BM_CBCDR_PERIPH_CLK2_PODF	(0x7 << 27)
+
+#define BP_CBCMR_GPU2D_AXI_SEL		0
+#define BM_CBCMR_GPU2D_AXI_SEL		(0x1 << 0)
+#define BP_CBCMR_GPU3D_AXI_SEL		1
+#define BM_CBCMR_GPU3D_AXI_SEL		(0x1 << 1)
+#define BP_CBCMR_GPU3D_CORE_SEL		4
+#define BM_CBCMR_GPU3D_CORE_SEL		(0x3 << 4)
+#define BP_CBCMR_GPU3D_SHADER_SEL	8
+#define BM_CBCMR_GPU3D_SHADER_SEL	(0x3 << 8)
+#define BP_CBCMR_PCIE_AXI_SEL		10
+#define BM_CBCMR_PCIE_AXI_SEL		(0x1 << 10)
+#define BP_CBCMR_VDO_AXI_SEL		11
+#define BM_CBCMR_VDO_AXI_SEL		(0x1 << 11)
+#define BP_CBCMR_PERIPH_CLK2_SEL	12
+#define BM_CBCMR_PERIPH_CLK2_SEL	(0x3 << 12)
+#define BP_CBCMR_VPU_AXI_SEL		14
+#define BM_CBCMR_VPU_AXI_SEL		(0x3 << 14)
+#define BP_CBCMR_GPU2D_CORE_SEL		16
+#define BM_CBCMR_GPU2D_CORE_SEL		(0x3 << 16)
+#define BP_CBCMR_PRE_PERIPH_CLK_SEL	18
+#define BM_CBCMR_PRE_PERIPH_CLK_SEL	(0x3 << 18)
+#define BP_CBCMR_PERIPH2_CLK2_SEL	20
+#define BM_CBCMR_PERIPH2_CLK2_SEL	(0x1 << 20)
+#define BP_CBCMR_PRE_PERIPH2_CLK_SEL	21
+#define BM_CBCMR_PRE_PERIPH2_CLK_SEL	(0x3 << 21)
+#define BP_CBCMR_GPU2D_CORE_PODF	23
+#define BM_CBCMR_GPU2D_CORE_PODF	(0x7 << 23)
+#define BP_CBCMR_GPU3D_CORE_PODF	26
+#define BM_CBCMR_GPU3D_CORE_PODF	(0x7 << 26)
+#define BP_CBCMR_GPU3D_SHADER_PODF	29
+#define BM_CBCMR_GPU3D_SHADER_PODF	(0x7 << 29)
+
+#define BP_CSCMR1_PERCLK_PODF		0
+#define BM_CSCMR1_PERCLK_PODF		(0x3f << 0)
+#define BP_CSCMR1_SSI1_SEL		10
+#define BM_CSCMR1_SSI1_SEL		(0x3 << 10)
+#define BP_CSCMR1_SSI2_SEL		12
+#define BM_CSCMR1_SSI2_SEL		(0x3 << 12)
+#define BP_CSCMR1_SSI3_SEL		14
+#define BM_CSCMR1_SSI3_SEL		(0x3 << 14)
+#define BP_CSCMR1_USDHC1_SEL		16
+#define BM_CSCMR1_USDHC1_SEL		(0x1 << 16)
+#define BP_CSCMR1_USDHC2_SEL		17
+#define BM_CSCMR1_USDHC2_SEL		(0x1 << 17)
+#define BP_CSCMR1_USDHC3_SEL		18
+#define BM_CSCMR1_USDHC3_SEL		(0x1 << 18)
+#define BP_CSCMR1_USDHC4_SEL		19
+#define BM_CSCMR1_USDHC4_SEL		(0x1 << 19)
+#define BP_CSCMR1_EMI_PODF		20
+#define BM_CSCMR1_EMI_PODF		(0x7 << 20)
+#define BP_CSCMR1_EMI_SLOW_PODF		23
+#define BM_CSCMR1_EMI_SLOW_PODF		(0x7 << 23)
+#define BP_CSCMR1_EMI_SEL		27
+#define BM_CSCMR1_EMI_SEL		(0x3 << 27)
+#define BP_CSCMR1_EMI_SLOW_SEL		29
+#define BM_CSCMR1_EMI_SLOW_SEL		(0x3 << 29)
+
+#define BP_CSCMR2_CAN_PODF		2
+#define BM_CSCMR2_CAN_PODF		(0x3f << 2)
+#define BM_CSCMR2_LDB_DI0_IPU_DIV	(0x1 << 10)
+#define BM_CSCMR2_LDB_DI1_IPU_DIV	(0x1 << 11)
+#define BP_CSCMR2_ESAI_SEL		19
+#define BM_CSCMR2_ESAI_SEL		(0x3 << 19)
+
+#define BP_CSCDR1_UART_PODF		0
+#define BM_CSCDR1_UART_PODF		(0x3f << 0)
+#define BP_CSCDR1_USDHC1_PODF		11
+#define BM_CSCDR1_USDHC1_PODF		(0x7 << 11)
+#define BP_CSCDR1_USDHC2_PODF		16
+#define BM_CSCDR1_USDHC2_PODF		(0x7 << 16)
+#define BP_CSCDR1_USDHC3_PODF		19
+#define BM_CSCDR1_USDHC3_PODF		(0x7 << 19)
+#define BP_CSCDR1_USDHC4_PODF		22
+#define BM_CSCDR1_USDHC4_PODF		(0x7 << 22)
+#define BP_CSCDR1_VPU_AXI_PODF		25
+#define BM_CSCDR1_VPU_AXI_PODF		(0x7 << 25)
+
+#define BP_CS1CDR_SSI1_PODF		0
+#define BM_CS1CDR_SSI1_PODF		(0x3f << 0)
+#define BP_CS1CDR_SSI1_PRED		6
+#define BM_CS1CDR_SSI1_PRED		(0x7 << 6)
+#define BP_CS1CDR_ESAI_PRED		9
+#define BM_CS1CDR_ESAI_PRED		(0x7 << 9)
+#define BP_CS1CDR_SSI3_PODF		16
+#define BM_CS1CDR_SSI3_PODF		(0x3f << 16)
+#define BP_CS1CDR_SSI3_PRED		22
+#define BM_CS1CDR_SSI3_PRED		(0x7 << 22)
+#define BP_CS1CDR_ESAI_PODF		25
+#define BM_CS1CDR_ESAI_PODF		(0x7 << 25)
+
+#define BP_CS2CDR_SSI2_PODF		0
+#define BM_CS2CDR_SSI2_PODF		(0x3f << 0)
+#define BP_CS2CDR_SSI2_PRED		6
+#define BM_CS2CDR_SSI2_PRED		(0x7 << 6)
+#define BP_CS2CDR_LDB_DI0_SEL		9
+#define BM_CS2CDR_LDB_DI0_SEL		(0x7 << 9)
+#define BP_CS2CDR_LDB_DI1_SEL		12
+#define BM_CS2CDR_LDB_DI1_SEL		(0x7 << 12)
+#define BP_CS2CDR_ENFC_SEL		16
+#define BM_CS2CDR_ENFC_SEL		(0x3 << 16)
+#define BP_CS2CDR_ENFC_PRED		18
+#define BM_CS2CDR_ENFC_PRED		(0x7 << 18)
+#define BP_CS2CDR_ENFC_PODF		21
+#define BM_CS2CDR_ENFC_PODF		(0x3f << 21)
+
+#define BP_CDCDR_ASRC_SERIAL_SEL	7
+#define BM_CDCDR_ASRC_SERIAL_SEL	(0x3 << 7)
+#define BP_CDCDR_ASRC_SERIAL_PODF	9
+#define BM_CDCDR_ASRC_SERIAL_PODF	(0x7 << 9)
+#define BP_CDCDR_ASRC_SERIAL_PRED	12
+#define BM_CDCDR_ASRC_SERIAL_PRED	(0x7 << 12)
+#define BP_CDCDR_SPDIF_SEL		20
+#define BM_CDCDR_SPDIF_SEL		(0x3 << 20)
+#define BP_CDCDR_SPDIF_PODF		22
+#define BM_CDCDR_SPDIF_PODF		(0x7 << 22)
+#define BP_CDCDR_SPDIF_PRED		25
+#define BM_CDCDR_SPDIF_PRED		(0x7 << 25)
+#define BP_CDCDR_HSI_TX_PODF		29
+#define BM_CDCDR_HSI_TX_PODF		(0x7 << 29)
+#define BP_CDCDR_HSI_TX_SEL		28
+#define BM_CDCDR_HSI_TX_SEL		(0x1 << 28)
+
+#define BP_CHSCCDR_IPU1_DI0_SEL		0
+#define BM_CHSCCDR_IPU1_DI0_SEL		(0x7 << 0)
+#define BP_CHSCCDR_IPU1_DI0_PRE_PODF	3
+#define BM_CHSCCDR_IPU1_DI0_PRE_PODF	(0x7 << 3)
+#define BP_CHSCCDR_IPU1_DI0_PRE_SEL	6
+#define BM_CHSCCDR_IPU1_DI0_PRE_SEL	(0x7 << 6)
+#define BP_CHSCCDR_IPU1_DI1_SEL		9
+#define BM_CHSCCDR_IPU1_DI1_SEL		(0x7 << 9)
+#define BP_CHSCCDR_IPU1_DI1_PRE_PODF	12
+#define BM_CHSCCDR_IPU1_DI1_PRE_PODF	(0x7 << 12)
+#define BP_CHSCCDR_IPU1_DI1_PRE_SEL	15
+#define BM_CHSCCDR_IPU1_DI1_PRE_SEL	(0x7 << 15)
+
+#define BP_CSCDR2_IPU2_DI0_SEL		0
+#define BM_CSCDR2_IPU2_DI0_SEL		(0x7)
+#define BP_CSCDR2_IPU2_DI0_PRE_PODF	3
+#define BM_CSCDR2_IPU2_DI0_PRE_PODF	(0x7 << 3)
+#define BP_CSCDR2_IPU2_DI0_PRE_SEL	6
+#define BM_CSCDR2_IPU2_DI0_PRE_SEL	(0x7 << 6)
+#define BP_CSCDR2_IPU2_DI1_SEL		9
+#define BM_CSCDR2_IPU2_DI1_SEL		(0x7 << 9)
+#define BP_CSCDR2_IPU2_DI1_PRE_PODF	12
+#define BM_CSCDR2_IPU2_DI1_PRE_PODF	(0x7 << 12)
+#define BP_CSCDR2_IPU2_DI1_PRE_SEL	15
+#define BM_CSCDR2_IPU2_DI1_PRE_SEL	(0x7 << 15)
+#define BP_CSCDR2_ECSPI_CLK_PODF	19
+#define BM_CSCDR2_ECSPI_CLK_PODF	(0x3f << 19)
+
+#define BP_CSCDR3_IPU1_HSP_SEL		9
+#define BM_CSCDR3_IPU1_HSP_SEL		(0x3 << 9)
+#define BP_CSCDR3_IPU1_HSP_PODF		11
+#define BM_CSCDR3_IPU1_HSP_PODF		(0x7 << 11)
+#define BP_CSCDR3_IPU2_HSP_SEL		14
+#define BM_CSCDR3_IPU2_HSP_SEL		(0x3 << 14)
+#define BP_CSCDR3_IPU2_HSP_PODF		16
+#define BM_CSCDR3_IPU2_HSP_PODF		(0x7 << 16)
+
+#define BM_CDHIPR_AXI_PODF_BUSY		(0x1 << 0)
+#define BM_CDHIPR_AHB_PODF_BUSY		(0x1 << 1)
+#define BM_CDHIPR_MMDC_CH1_PODF_BUSY	(0x1 << 2)
+#define BM_CDHIPR_PERIPH2_SEL_BUSY	(0x1 << 3)
+#define BM_CDHIPR_MMDC_CH0_PODF_BUSY	(0x1 << 4)
+#define BM_CDHIPR_PERIPH_SEL_BUSY	(0x1 << 5)
+#define BM_CDHIPR_ARM_PODF_BUSY		(0x1 << 16)
+
+#define BP_CLPCR_LPM			0
+#define BM_CLPCR_LPM			(0x3 << 0)
+#define BM_CLPCR_BYPASS_PMIC_READY	(0x1 << 2)
+#define BM_CLPCR_ARM_CLK_DIS_ON_LPM	(0x1 << 5)
+#define BM_CLPCR_SBYOS			(0x1 << 6)
+#define BM_CLPCR_DIS_REF_OSC		(0x1 << 7)
+#define BM_CLPCR_VSTBY			(0x1 << 8)
+#define BP_CLPCR_STBY_COUNT		9
+#define BM_CLPCR_STBY_COUNT		(0x3 << 9)
+#define BM_CLPCR_COSC_PWRDOWN		(0x1 << 11)
+#define BM_CLPCR_WB_PER_AT_LPM		(0x1 << 16)
+#define BM_CLPCR_WB_CORE_AT_LPM		(0x1 << 17)
+#define BM_CLPCR_BYP_MMDC_CH0_LPM_HS	(0x1 << 19)
+#define BM_CLPCR_BYP_MMDC_CH1_LPM_HS	(0x1 << 21)
+#define BM_CLPCR_MASK_CORE0_WFI		(0x1 << 22)
+#define BM_CLPCR_MASK_CORE1_WFI		(0x1 << 23)
+#define BM_CLPCR_MASK_CORE2_WFI		(0x1 << 24)
+#define BM_CLPCR_MASK_CORE3_WFI		(0x1 << 25)
+#define BM_CLPCR_MASK_SCU_IDLE		(0x1 << 26)
+#define BM_CLPCR_MASK_L2CC_IDLE		(0x1 << 27)
+
+#define FREQ_480M	480000000
+#define FREQ_528M	528000000
+#define FREQ_594M	594000000
+#define FREQ_650M	650000000
+#define FREQ_1300M	1300000000
+
+static struct clk pll1_sys;
+static struct clk pll2_bus;
+static struct clk pll3_usb_otg;
+static struct clk pll4_audio;
+static struct clk pll5_video;
+static struct clk pll6_mlb;
+static struct clk pll7_usb_host;
+static struct clk pll8_enet;
+static struct clk apbh_dma_clk;
+static struct clk arm_clk;
+static struct clk ipg_clk;
+static struct clk ahb_clk;
+static struct clk axi_clk;
+static struct clk mmdc_ch0_axi_clk;
+static struct clk mmdc_ch1_axi_clk;
+static struct clk periph_clk;
+static struct clk periph_pre_clk;
+static struct clk periph_clk2_clk;
+static struct clk periph2_clk;
+static struct clk periph2_pre_clk;
+static struct clk periph2_clk2_clk;
+static struct clk gpu2d_core_clk;
+static struct clk gpu3d_core_clk;
+static struct clk gpu3d_shader_clk;
+static struct clk ipg_perclk;
+static struct clk emi_clk;
+static struct clk emi_slow_clk;
+static struct clk can1_clk;
+static struct clk uart_clk;
+static struct clk usdhc1_clk;
+static struct clk usdhc2_clk;
+static struct clk usdhc3_clk;
+static struct clk usdhc4_clk;
+static struct clk vpu_clk;
+static struct clk hsi_tx_clk;
+static struct clk ipu1_di0_pre_clk;
+static struct clk ipu1_di1_pre_clk;
+static struct clk ipu2_di0_pre_clk;
+static struct clk ipu2_di1_pre_clk;
+static struct clk ipu1_clk;
+static struct clk ipu2_clk;
+static struct clk ssi1_clk;
+static struct clk ssi3_clk;
+static struct clk esai_clk;
+static struct clk ssi2_clk;
+static struct clk spdif_clk;
+static struct clk asrc_serial_clk;
+static struct clk gpu2d_axi_clk;
+static struct clk gpu3d_axi_clk;
+static struct clk pcie_clk;
+static struct clk vdo_axi_clk;
+static struct clk ldb_di0_clk;
+static struct clk ldb_di1_clk;
+static struct clk ipu1_di0_clk;
+static struct clk ipu1_di1_clk;
+static struct clk ipu2_di0_clk;
+static struct clk ipu2_di1_clk;
+static struct clk enfc_clk;
+static struct clk dummy_clk = {};
+
+static unsigned long external_high_reference;
+static unsigned long external_low_reference;
+static unsigned long oscillator_reference;
+
+static unsigned long get_oscillator_reference_clock_rate(struct clk *clk)
+{
+	return oscillator_reference;
+}
+
+static unsigned long get_high_reference_clock_rate(struct clk *clk)
+{
+	return external_high_reference;
+}
+
+static unsigned long get_low_reference_clock_rate(struct clk *clk)
+{
+	return external_low_reference;
+}
+
+static struct clk ckil_clk = {
+	.get_rate = get_low_reference_clock_rate,
+};
+
+static struct clk ckih_clk = {
+	.get_rate = get_high_reference_clock_rate,
+};
+
+static struct clk osc_clk = {
+	.get_rate = get_oscillator_reference_clock_rate,
+};
+
+static inline void __iomem *pll_get_reg_addr(struct clk *pll)
+{
+	if (pll == &pll1_sys)
+		return PLL1_SYS;
+	else if (pll == &pll2_bus)
+		return PLL2_BUS;
+	else if (pll == &pll3_usb_otg)
+		return PLL3_USB_OTG;
+	else if (pll == &pll4_audio)
+		return PLL4_AUDIO;
+	else if (pll == &pll5_video)
+		return PLL5_VIDEO;
+	else if (pll == &pll6_mlb)
+		return PLL6_MLB;
+	else if (pll == &pll7_usb_host)
+		return PLL7_USB_HOST;
+	else if (pll == &pll8_enet)
+		return PLL8_ENET;
+	else
+		BUG();
+
+	return NULL;
+}
+
+static int pll_enable(struct clk *clk)
+{
+	int timeout = 0x100000;
+	void __iomem *reg;
+	u32 val;
+
+	reg = pll_get_reg_addr(clk);
+	val = readl_relaxed(reg);
+	val &= ~BM_PLL_BYPASS;
+	val &= ~BM_PLL_POWER_DOWN;
+	/* 480MHz PLLs have the opposite definition for power bit */
+	if (clk == &pll3_usb_otg || clk == &pll7_usb_host)
+		val |= BM_PLL_POWER_DOWN;
+	writel_relaxed(val, reg);
+
+	/* Wait for PLL to lock */
+	while (!(readl_relaxed(reg) & BM_PLL_LOCK) && --timeout)
+		cpu_relax();
+
+	if (unlikely(!timeout))
+		return -EBUSY;
+
+	/* Enable the PLL output now */
+	val = readl_relaxed(reg);
+	val |= BM_PLL_ENABLE;
+	writel_relaxed(val, reg);
+
+	return 0;
+}
+
+static void pll_disable(struct clk *clk)
+{
+	void __iomem *reg;
+	u32 val;
+
+	reg = pll_get_reg_addr(clk);
+	val = readl_relaxed(reg);
+	val &= ~BM_PLL_ENABLE;
+	val |= BM_PLL_BYPASS;
+	val |= BM_PLL_POWER_DOWN;
+	if (clk == &pll3_usb_otg || clk == &pll7_usb_host)
+		val &= ~BM_PLL_POWER_DOWN;
+	writel_relaxed(val, reg);
+}
+
+static unsigned long pll1_sys_get_rate(struct clk *clk)
+{
+	u32 div = (readl_relaxed(PLL1_SYS) & BM_PLL_SYS_DIV_SELECT) >>
+		  BP_PLL_SYS_DIV_SELECT;
+
+	return clk_get_rate(clk->parent) * div / 2;
+}
+
+static int pll1_sys_set_rate(struct clk *clk, unsigned long rate)
+{
+	u32 val, div;
+
+	if (rate < FREQ_650M || rate > FREQ_1300M)
+		return -EINVAL;
+
+	div = rate * 2 / clk_get_rate(clk->parent);
+	val = readl_relaxed(PLL1_SYS);
+	val &= ~BM_PLL_SYS_DIV_SELECT;
+	val |= div << BP_PLL_SYS_DIV_SELECT;
+	writel_relaxed(val, PLL1_SYS);
+
+	return 0;
+}
+
+static unsigned long pll8_enet_get_rate(struct clk *clk)
+{
+	u32 div = (readl_relaxed(PLL8_ENET) & BM_PLL_ENET_DIV_SELECT) >>
+		  BP_PLL_ENET_DIV_SELECT;
+
+	return 500000000 / (div + 1);
+}
+
+static int pll8_enet_set_rate(struct clk *clk, unsigned long rate)
+{
+	u32 val, div;
+
+	switch (rate) {
+	case 25000000:
+		div = 0;
+		break;
+	case 50000000:
+		div = 1;
+		break;
+	case 100000000:
+		div = 2;
+		break;
+	case 125000000:
+		div = 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	val = readl_relaxed(PLL8_ENET);
+	val &= ~BM_PLL_ENET_DIV_SELECT;
+	val |= div << BP_PLL_ENET_DIV_SELECT;
+	writel_relaxed(val, PLL8_ENET);
+
+	return 0;
+}
+
+static unsigned long pll_av_get_rate(struct clk *clk)
+{
+	void __iomem *reg = (clk == &pll4_audio) ? PLL4_AUDIO : PLL5_VIDEO;
+	unsigned long parent_rate = clk_get_rate(clk->parent);
+	u32 mfn = readl_relaxed(reg + PLL_NUM_OFFSET);
+	u32 mfd = readl_relaxed(reg + PLL_DENOM_OFFSET);
+	u32 div = (readl_relaxed(reg) & BM_PLL_AV_DIV_SELECT) >>
+		  BP_PLL_AV_DIV_SELECT;
+
+	return (parent_rate * div) + ((parent_rate / mfd) * mfn);
+}
+
+static int pll_av_set_rate(struct clk *clk, unsigned long rate)
+{
+	void __iomem *reg = (clk == &pll4_audio) ? PLL4_AUDIO : PLL5_VIDEO;
+	unsigned int parent_rate = clk_get_rate(clk->parent);
+	u32 val, div;
+	u32 mfn, mfd = 1000000;
+	s64 temp64;
+
+	if (rate < FREQ_650M || rate > FREQ_1300M)
+		return -EINVAL;
+
+	div = rate / parent_rate;
+	temp64 = (u64) (rate - div * parent_rate);
+	temp64 *= mfd;
+	do_div(temp64, parent_rate);
+	mfn = temp64;
+
+	val = readl_relaxed(reg);
+	val &= ~BM_PLL_AV_DIV_SELECT;
+	val |= div << BP_PLL_AV_DIV_SELECT;
+	writel_relaxed(val, reg);
+	writel_relaxed(mfn, reg + PLL_NUM_OFFSET);
+	writel_relaxed(mfd, reg + PLL_DENOM_OFFSET);
+
+	return 0;
+}
+
+static void __iomem *pll_get_div_reg_bit(struct clk *clk, u32 *bp, u32 *bm)
+{
+	void __iomem *reg;
+
+	if (clk == &pll2_bus) {
+		reg = PLL2_BUS;
+		*bp = BP_PLL_BUS_DIV_SELECT;
+		*bm = BM_PLL_BUS_DIV_SELECT;
+	} else if (clk == &pll3_usb_otg) {
+		reg = PLL3_USB_OTG;
+		*bp = BP_PLL_USB_DIV_SELECT;
+		*bm = BM_PLL_USB_DIV_SELECT;
+	} else if (clk == &pll7_usb_host) {
+		reg = PLL7_USB_HOST;
+		*bp = BP_PLL_USB_DIV_SELECT;
+		*bm = BM_PLL_USB_DIV_SELECT;
+	} else {
+		BUG();
+	}
+
+	return reg;
+}
+
+static unsigned long pll_get_rate(struct clk *clk)
+{
+	void __iomem *reg;
+	u32 div, bp, bm;
+
+	reg = pll_get_div_reg_bit(clk, &bp, &bm);
+	div = (readl_relaxed(reg) & bm) >> bp;
+
+	return (div == 1) ? clk_get_rate(clk->parent) * 22 :
+			    clk_get_rate(clk->parent) * 20;
+}
+
+static int pll_set_rate(struct clk *clk, unsigned long rate)
+{
+	void __iomem *reg;
+	u32 val, div, bp, bm;
+
+	if (rate == FREQ_528M)
+		div = 1;
+	else if (rate == FREQ_480M)
+		div = 0;
+	else
+		return -EINVAL;
+
+	reg = pll_get_div_reg_bit(clk, &bp, &bm);
+	val = readl_relaxed(reg);
+	val &= ~bm;
+	val |= div << bp;
+	writel_relaxed(val, reg);
+
+	return 0;
+}
+
+#define pll2_bus_get_rate	pll_get_rate
+#define pll2_bus_set_rate	pll_set_rate
+#define pll3_usb_otg_get_rate	pll_get_rate
+#define pll3_usb_otg_set_rate	pll_set_rate
+#define pll7_usb_host_get_rate	pll_get_rate
+#define pll7_usb_host_set_rate	pll_set_rate
+#define pll4_audio_get_rate	pll_av_get_rate
+#define pll4_audio_set_rate	pll_av_set_rate
+#define pll5_video_get_rate	pll_av_get_rate
+#define pll5_video_set_rate	pll_av_set_rate
+#define pll6_mlb_get_rate	NULL
+#define pll6_mlb_set_rate	NULL
+
+#define DEF_PLL(name)					\
+	static struct clk name = {			\
+		.enable		= pll_enable,		\
+		.disable	= pll_disable,		\
+		.get_rate	= name##_get_rate,	\
+		.set_rate	= name##_set_rate,	\
+		.parent		= &osc_clk,		\
+	}
+
+DEF_PLL(pll1_sys);
+DEF_PLL(pll2_bus);
+DEF_PLL(pll3_usb_otg);
+DEF_PLL(pll4_audio);
+DEF_PLL(pll5_video);
+DEF_PLL(pll6_mlb);
+DEF_PLL(pll7_usb_host);
+DEF_PLL(pll8_enet);
+
+static unsigned long pfd_get_rate(struct clk *clk)
+{
+	u64 tmp = (u64) clk_get_rate(clk->parent) * 18;
+	u32 frac, bp_frac;
+
+	if (apbh_dma_clk.usecount == 0)
+		apbh_dma_clk.enable(&apbh_dma_clk);
+
+	bp_frac = clk->enable_shift - 7;
+	frac = readl_relaxed(clk->enable_reg) >> bp_frac & PFD_FRAC_MASK;
+	do_div(tmp, frac);
+
+	return tmp;
+}
+
+static int pfd_set_rate(struct clk *clk, unsigned long rate)
+{
+	u32 val, frac, bp_frac;
+	u64 tmp = (u64) clk_get_rate(clk->parent) * 18;
+
+	if (apbh_dma_clk.usecount == 0)
+		apbh_dma_clk.enable(&apbh_dma_clk);
+
+	/*
+	 * Round up the divider so that we don't set a rate
+	 * higher than what is requested
+	 */
+	tmp += rate / 2;
+	do_div(tmp, rate);
+	frac = tmp;
+	frac = (frac < 12) ? 12 : frac;
+	frac = (frac > 35) ? 35 : frac;
+
+	/*
+	 * The frac field always starts from 7 bits lower
+	 * position of enable bit
+	 */
+	bp_frac = clk->enable_shift - 7;
+	val = readl_relaxed(clk->enable_reg);
+	val &= ~(PFD_FRAC_MASK << bp_frac);
+	val |= frac << bp_frac;
+	writel_relaxed(val, clk->enable_reg);
+
+	tmp = (u64) clk_get_rate(clk->parent) * 18;
+	do_div(tmp, frac);
+
+	if (apbh_dma_clk.usecount == 0)
+		apbh_dma_clk.disable(&apbh_dma_clk);
+
+	return 0;
+}
+
+static unsigned long pfd_round_rate(struct clk *clk, unsigned long rate)
+{
+	u32 frac;
+	u64 tmp;
+
+	tmp = (u64) clk_get_rate(clk->parent) * 18;
+	tmp += rate / 2;
+	do_div(tmp, rate);
+	frac = tmp;
+	frac = (frac < 12) ? 12 : frac;
+	frac = (frac > 35) ? 35 : frac;
+	tmp = (u64) clk_get_rate(clk->parent) * 18;
+	do_div(tmp, frac);
+
+	return tmp;
+}
+
+static int pfd_enable(struct clk *clk)
+{
+	u32 val;
+
+	if (apbh_dma_clk.usecount == 0)
+		apbh_dma_clk.enable(&apbh_dma_clk);
+
+	val = readl_relaxed(clk->enable_reg);
+	val &= ~(1 << clk->enable_shift);
+	writel_relaxed(val, clk->enable_reg);
+
+	if (apbh_dma_clk.usecount == 0)
+		apbh_dma_clk.disable(&apbh_dma_clk);
+
+	return 0;
+}
+
+static void pfd_disable(struct clk *clk)
+{
+	u32 val;
+
+	if (apbh_dma_clk.usecount == 0)
+		apbh_dma_clk.enable(&apbh_dma_clk);
+
+	val = readl_relaxed(clk->enable_reg);
+	val |= 1 << clk->enable_shift;
+	writel_relaxed(val, clk->enable_reg);
+
+	if (apbh_dma_clk.usecount == 0)
+		apbh_dma_clk.disable(&apbh_dma_clk);
+}
+
+#define DEF_PFD(name, er, es, p)			\
+	static struct clk name = {			\
+		.enable_reg	= er,			\
+		.enable_shift	= es,			\
+		.enable		= pfd_enable,		\
+		.disable	= pfd_disable,		\
+		.get_rate	= pfd_get_rate,		\
+		.set_rate	= pfd_set_rate,		\
+		.round_rate	= pfd_round_rate,	\
+		.parent		= p,			\
+	}
+
+DEF_PFD(pll2_pfd_352m, PFD_528, PFD0, &pll2_bus);
+DEF_PFD(pll2_pfd_594m, PFD_528, PFD1, &pll2_bus);
+DEF_PFD(pll2_pfd_400m, PFD_528, PFD2, &pll2_bus);
+DEF_PFD(pll3_pfd_720m, PFD_480, PFD0, &pll3_usb_otg);
+DEF_PFD(pll3_pfd_540m, PFD_480, PFD1, &pll3_usb_otg);
+DEF_PFD(pll3_pfd_508m, PFD_480, PFD2, &pll3_usb_otg);
+DEF_PFD(pll3_pfd_454m, PFD_480, PFD3, &pll3_usb_otg);
+
+static unsigned long pll2_200m_get_rate(struct clk *clk)
+{
+	return clk_get_rate(clk->parent) / 2;
+}
+
+static struct clk pll2_200m = {
+	.parent = &pll2_pfd_400m,
+	.get_rate = pll2_200m_get_rate,
+};
+
+static unsigned long pll3_120m_get_rate(struct clk *clk)
+{
+	return clk_get_rate(clk->parent) / 4;
+}
+
+static struct clk pll3_120m = {
+	.parent = &pll3_usb_otg,
+	.get_rate = pll3_120m_get_rate,
+};
+
+static unsigned long pll3_80m_get_rate(struct clk *clk)
+{
+	return clk_get_rate(clk->parent) / 6;
+}
+
+static struct clk pll3_80m = {
+	.parent = &pll3_usb_otg,
+	.get_rate = pll3_80m_get_rate,
+};
+
+static unsigned long pll3_60m_get_rate(struct clk *clk)
+{
+	return clk_get_rate(clk->parent) / 8;
+}
+
+static struct clk pll3_60m = {
+	.parent = &pll3_usb_otg,
+	.get_rate = pll3_60m_get_rate,
+};
+
+static int pll1_sw_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	u32 val = readl_relaxed(CCSR);
+
+	if (parent == &pll1_sys) {
+		val &= ~BM_CCSR_PLL1_SW_SEL;
+		val &= ~BM_CCSR_STEP_SEL;
+	} else if (parent == &osc_clk) {
+		val |= BM_CCSR_PLL1_SW_SEL;
+		val &= ~BM_CCSR_STEP_SEL;
+	} else if (parent == &pll2_pfd_400m) {
+		val |= BM_CCSR_PLL1_SW_SEL;
+		val |= BM_CCSR_STEP_SEL;
+	} else {
+		return -EINVAL;
+	}
+
+	writel_relaxed(val, CCSR);
+
+	return 0;
+}
+
+static struct clk pll1_sw_clk = {
+	.parent = &pll1_sys,
+	.set_parent = pll1_sw_clk_set_parent,
+};
+
+static void calc_pred_podf_dividers(u32 div, u32 *pred, u32 *podf)
+{
+	u32 min_pred, temp_pred, old_err, err;
+
+	if (div >= 512) {
+		*pred = 8;
+		*podf = 64;
+	} else if (div >= 8) {
+		min_pred = (div - 1) / 64 + 1;
+		old_err = 8;
+		for (temp_pred = 8; temp_pred >= min_pred; temp_pred--) {
+			err = div % temp_pred;
+			if (err == 0) {
+				*pred = temp_pred;
+				break;
+			}
+			err = temp_pred - err;
+			if (err < old_err) {
+				old_err = err;
+				*pred = temp_pred;
+			}
+		}
+		*podf = (div + *pred - 1) / *pred;
+	} else if (div < 8) {
+		*pred = div;
+		*podf = 1;
+	}
+}
+
+static int _clk_enable(struct clk *clk)
+{
+	u32 reg;
+	reg = readl_relaxed(clk->enable_reg);
+	reg |= 0x3 << clk->enable_shift;
+	writel_relaxed(reg, clk->enable_reg);
+
+	return 0;
+}
+
+static void _clk_disable(struct clk *clk)
+{
+	u32 reg;
+	reg = readl_relaxed(clk->enable_reg);
+	reg &= ~(0x3 << clk->enable_shift);
+	writel_relaxed(reg, clk->enable_reg);
+}
+
+struct divider {
+	struct clk *clk;
+	void __iomem *reg;
+	u32 bp_pred;
+	u32 bm_pred;
+	u32 bp_podf;
+	u32 bm_podf;
+};
+
+#define DEF_CLK_DIV1(d, c, r, b)				\
+	static struct divider d = {				\
+		.clk = c,					\
+		.reg = r,					\
+		.bp_podf = BP_##r##_##b##_PODF,			\
+		.bm_podf = BM_##r##_##b##_PODF,			\
+	}
+
+DEF_CLK_DIV1(arm_div,		&arm_clk,		CACRR,	ARM);
+DEF_CLK_DIV1(ipg_div,		&ipg_clk,		CBCDR,	IPG);
+DEF_CLK_DIV1(ahb_div,		&ahb_clk,		CBCDR,	AHB);
+DEF_CLK_DIV1(axi_div,		&axi_clk,		CBCDR,	AXI);
+DEF_CLK_DIV1(mmdc_ch0_axi_div,	&mmdc_ch0_axi_clk,	CBCDR,	MMDC_CH0_AXI);
+DEF_CLK_DIV1(mmdc_ch1_axi_div,	&mmdc_ch1_axi_clk,	CBCDR,	MMDC_CH1_AXI);
+DEF_CLK_DIV1(periph_clk2_div,	&periph_clk2_clk,	CBCDR,	PERIPH_CLK2);
+DEF_CLK_DIV1(periph2_clk2_div,	&periph2_clk2_clk,	CBCDR,	PERIPH2_CLK2);
+DEF_CLK_DIV1(gpu2d_core_div,	&gpu2d_core_clk,	CBCMR,	GPU2D_CORE);
+DEF_CLK_DIV1(gpu3d_core_div,	&gpu3d_core_clk,	CBCMR,	GPU3D_CORE);
+DEF_CLK_DIV1(gpu3d_shader_div,	&gpu3d_shader_clk,	CBCMR,	GPU3D_SHADER);
+DEF_CLK_DIV1(ipg_perclk_div,	&ipg_perclk,		CSCMR1,	PERCLK);
+DEF_CLK_DIV1(emi_div,		&emi_clk,		CSCMR1,	EMI);
+DEF_CLK_DIV1(emi_slow_div,	&emi_slow_clk,		CSCMR1,	EMI_SLOW);
+DEF_CLK_DIV1(can_div,		&can1_clk,		CSCMR2,	CAN);
+DEF_CLK_DIV1(uart_div,		&uart_clk,		CSCDR1,	UART);
+DEF_CLK_DIV1(usdhc1_div,	&usdhc1_clk,		CSCDR1,	USDHC1);
+DEF_CLK_DIV1(usdhc2_div,	&usdhc2_clk,		CSCDR1,	USDHC2);
+DEF_CLK_DIV1(usdhc3_div,	&usdhc3_clk,		CSCDR1,	USDHC3);
+DEF_CLK_DIV1(usdhc4_div,	&usdhc4_clk,		CSCDR1,	USDHC4);
+DEF_CLK_DIV1(vpu_div,		&vpu_clk,		CSCDR1,	VPU_AXI);
+DEF_CLK_DIV1(hsi_tx_div,	&hsi_tx_clk,		CDCDR,	HSI_TX);
+DEF_CLK_DIV1(ipu1_di0_pre_div,	&ipu1_di0_pre_clk,	CHSCCDR, IPU1_DI0_PRE);
+DEF_CLK_DIV1(ipu1_di1_pre_div,	&ipu1_di1_pre_clk,	CHSCCDR, IPU1_DI1_PRE);
+DEF_CLK_DIV1(ipu2_di0_pre_div,	&ipu2_di0_pre_clk,	CSCDR2,	IPU2_DI0_PRE);
+DEF_CLK_DIV1(ipu2_di1_pre_div,	&ipu2_di1_pre_clk,	CSCDR2,	IPU2_DI1_PRE);
+DEF_CLK_DIV1(ipu1_div,		&ipu1_clk,		CSCDR3,	IPU1_HSP);
+DEF_CLK_DIV1(ipu2_div,		&ipu2_clk,		CSCDR3,	IPU2_HSP);
+
+#define DEF_CLK_DIV2(d, c, r, b)				\
+	static struct divider d = {				\
+		.clk = c,					\
+		.reg = r,					\
+		.bp_pred = BP_##r##_##b##_PRED,			\
+		.bm_pred = BM_##r##_##b##_PRED,			\
+		.bp_podf = BP_##r##_##b##_PODF,			\
+		.bm_podf = BM_##r##_##b##_PODF,			\
+	}
+
+DEF_CLK_DIV2(ssi1_div,		&ssi1_clk,		CS1CDR,	SSI1);
+DEF_CLK_DIV2(ssi3_div,		&ssi3_clk,		CS1CDR,	SSI3);
+DEF_CLK_DIV2(esai_div,		&esai_clk,		CS1CDR,	ESAI);
+DEF_CLK_DIV2(ssi2_div,		&ssi2_clk,		CS2CDR,	SSI2);
+DEF_CLK_DIV2(enfc_div,		&enfc_clk,		CS2CDR,	ENFC);
+DEF_CLK_DIV2(spdif_div,		&spdif_clk,		CDCDR,	SPDIF);
+DEF_CLK_DIV2(asrc_serial_div,	&asrc_serial_clk,	CDCDR,	ASRC_SERIAL);
+
+static struct divider *dividers[] = {
+	&arm_div,
+	&ipg_div,
+	&ahb_div,
+	&axi_div,
+	&mmdc_ch0_axi_div,
+	&mmdc_ch1_axi_div,
+	&periph_clk2_div,
+	&periph2_clk2_div,
+	&gpu2d_core_div,
+	&gpu3d_core_div,
+	&gpu3d_shader_div,
+	&ipg_perclk_div,
+	&emi_div,
+	&emi_slow_div,
+	&can_div,
+	&uart_div,
+	&usdhc1_div,
+	&usdhc2_div,
+	&usdhc3_div,
+	&usdhc4_div,
+	&vpu_div,
+	&hsi_tx_div,
+	&ipu1_di0_pre_div,
+	&ipu1_di1_pre_div,
+	&ipu2_di0_pre_div,
+	&ipu2_di1_pre_div,
+	&ipu1_div,
+	&ipu2_div,
+	&ssi1_div,
+	&ssi3_div,
+	&esai_div,
+	&ssi2_div,
+	&enfc_div,
+	&spdif_div,
+	&asrc_serial_div,
+};
+
+static unsigned long ldb_di_clk_get_rate(struct clk *clk)
+{
+	u32 val = readl_relaxed(CSCMR2);
+
+	val &= (clk == &ldb_di0_clk) ? BM_CSCMR2_LDB_DI0_IPU_DIV :
+				       BM_CSCMR2_LDB_DI1_IPU_DIV;
+	if (val)
+		return clk_get_rate(clk->parent) / 7;
+	else
+		return clk_get_rate(clk->parent) * 2 / 7;
+}
+
+static int ldb_di_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long parent_rate = clk_get_rate(clk->parent);
+	u32 val = readl_relaxed(CSCMR2);
+
+	if (rate * 7 <= parent_rate + parent_rate / 20)
+		val |= BM_CSCMR2_LDB_DI0_IPU_DIV;
+	else
+		val &= ~BM_CSCMR2_LDB_DI0_IPU_DIV;
+
+	writel_relaxed(val, CSCMR2);
+
+	return 0;
+}
+
+static unsigned long ldb_di_clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long parent_rate = clk_get_rate(clk->parent);
+
+	if (rate * 7 <= parent_rate + parent_rate / 20)
+		return parent_rate / 7;
+	else
+		return 2 * parent_rate / 7;
+}
+
+static unsigned long _clk_get_rate(struct clk *clk)
+{
+	struct divider *d;
+	u32 val, pred, podf;
+	int i, num;
+
+	if (clk == &ldb_di0_clk || clk == &ldb_di1_clk)
+		return ldb_di_clk_get_rate(clk);
+
+	num = ARRAY_SIZE(dividers);
+	for (i = 0; i < num; i++)
+		if (dividers[i]->clk == clk) {
+			d = dividers[i];
+			break;
+		}
+	if (i == num)
+		return clk_get_rate(clk->parent);
+
+	val = readl_relaxed(d->reg);
+	pred = ((val & d->bm_pred) >> d->bp_pred) + 1;
+	podf = ((val & d->bm_podf) >> d->bp_podf) + 1;
+
+	return clk_get_rate(clk->parent) / (pred * podf);
+}
+
+static int clk_busy_wait(struct clk *clk)
+{
+	int timeout = 0x100000;
+	u32 bm;
+
+	if (clk == &axi_clk)
+		bm = BM_CDHIPR_AXI_PODF_BUSY;
+	else if (clk == &ahb_clk)
+		bm = BM_CDHIPR_AHB_PODF_BUSY;
+	else if (clk == &mmdc_ch0_axi_clk)
+		bm = BM_CDHIPR_MMDC_CH0_PODF_BUSY;
+	else if (clk == &periph_clk)
+		bm = BM_CDHIPR_PERIPH_SEL_BUSY;
+	else if (clk == &arm_clk)
+		bm = BM_CDHIPR_ARM_PODF_BUSY;
+	else
+		return -EINVAL;
+
+	while ((readl_relaxed(CDHIPR) & bm) && --timeout)
+		cpu_relax();
+
+	if (unlikely(!timeout))
+		return -EBUSY;
+
+	return 0;
+}
+
+static int _clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long parent_rate = clk_get_rate(clk->parent);
+	struct divider *d;
+	u32 val, div, max_div, pred = 0, podf;
+	int i, num;
+
+	if (clk == &ldb_di0_clk || clk == &ldb_di1_clk)
+		return ldb_di_clk_set_rate(clk, rate);
+
+	num = ARRAY_SIZE(dividers);
+	for (i = 0; i < num; i++)
+		if (dividers[i]->clk == clk) {
+			d = dividers[i];
+			break;
+		}
+	if (i == num)
+		return -EINVAL;
+
+	max_div = ((d->bm_pred >> d->bp_pred) + 1) *
+		  ((d->bm_pred >> d->bp_pred) + 1);
+
+	div = parent_rate / rate;
+	if (div == 0)
+		div++;
+
+	if ((parent_rate / div != rate) || div > max_div)
+		return -EINVAL;
+
+	if (d->bm_pred) {
+		calc_pred_podf_dividers(div, &pred, &podf);
+	} else {
+		pred = 1;
+		podf = div;
+	}
+
+	val = readl_relaxed(d->reg);
+	val &= ~(d->bm_pred | d->bm_podf);
+	val |= (pred - 1) << d->bp_pred | (podf - 1) << d->bp_podf;
+	writel_relaxed(val, d->reg);
+
+	if (clk == &axi_clk || clk == &ahb_clk ||
+	    clk == &mmdc_ch0_axi_clk || clk == &arm_clk)
+		return clk_busy_wait(clk);
+
+	return 0;
+}
+
+static unsigned long _clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long parent_rate = clk_get_rate(clk->parent);
+	u32 div = parent_rate / rate;
+	u32 div_max, pred = 0, podf;
+	struct divider *d;
+	int i, num;
+
+	if (clk == &ldb_di0_clk || clk == &ldb_di1_clk)
+		return ldb_di_clk_round_rate(clk, rate);
+
+	num = ARRAY_SIZE(dividers);
+	for (i = 0; i < num; i++)
+		if (dividers[i]->clk == clk) {
+			d = dividers[i];
+			break;
+		}
+	if (i == num)
+		return -EINVAL;
+
+	if (div == 0 || parent_rate % rate)
+		div++;
+
+	if (d->bm_pred) {
+		calc_pred_podf_dividers(div, &pred, &podf);
+		div = pred * podf;
+	} else {
+		div_max = (d->bm_podf >> d->bp_podf) + 1;
+		if (div > div_max)
+			div = div_max;
+	}
+
+	return parent_rate / div;
+}
+
+struct multiplexer {
+	struct clk *clk;
+	void __iomem *reg;
+	u32 bp;
+	u32 bm;
+	int pnum;
+	struct clk *parents[];
+};
+
+static struct multiplexer axi_mux = {
+	.clk = &axi_clk,
+	.reg = CBCDR,
+	.bp = BP_CBCDR_AXI_SEL,
+	.bm = BM_CBCDR_AXI_SEL,
+	.parents = {
+		&periph_clk,
+		&pll2_pfd_400m,
+		&pll3_pfd_540m,
+		NULL
+	},
+};
+
+static struct multiplexer periph_mux = {
+	.clk = &periph_clk,
+	.reg = CBCDR,
+	.bp = BP_CBCDR_PERIPH_CLK_SEL,
+	.bm = BM_CBCDR_PERIPH_CLK_SEL,
+	.parents = {
+		&periph_pre_clk,
+		&periph_clk2_clk,
+		NULL
+	},
+};
+
+static struct multiplexer periph_pre_mux = {
+	.clk = &periph_pre_clk,
+	.reg = CBCMR,
+	.bp = BP_CBCMR_PRE_PERIPH_CLK_SEL,
+	.bm = BM_CBCMR_PRE_PERIPH_CLK_SEL,
+	.parents = {
+		&pll2_bus,
+		&pll2_pfd_400m,
+		&pll2_pfd_352m,
+		&pll2_200m,
+		NULL
+	},
+};
+
+static struct multiplexer periph_clk2_mux = {
+	.clk = &periph_clk2_clk,
+	.reg = CBCMR,
+	.bp = BP_CBCMR_PERIPH_CLK2_SEL,
+	.bm = BM_CBCMR_PERIPH_CLK2_SEL,
+	.parents = {
+		&pll3_usb_otg,
+		&osc_clk,
+		NULL
+	},
+};
+
+static struct multiplexer periph2_mux = {
+	.clk = &periph2_clk,
+	.reg = CBCDR,
+	.bp = BP_CBCDR_PERIPH2_CLK_SEL,
+	.bm = BM_CBCDR_PERIPH2_CLK_SEL,
+	.parents = {
+		&periph2_pre_clk,
+		&periph2_clk2_clk,
+		NULL
+	},
+};
+
+static struct multiplexer periph2_pre_mux = {
+	.clk = &periph2_pre_clk,
+	.reg = CBCMR,
+	.bp = BP_CBCMR_PRE_PERIPH2_CLK_SEL,
+	.bm = BM_CBCMR_PRE_PERIPH2_CLK_SEL,
+	.parents = {
+		&pll2_bus,
+		&pll2_pfd_400m,
+		&pll2_pfd_352m,
+		&pll2_200m,
+		NULL
+	},
+};
+
+static struct multiplexer periph2_clk2_mux = {
+	.clk = &periph2_clk2_clk,
+	.reg = CBCMR,
+	.bp = BP_CBCMR_PERIPH2_CLK2_SEL,
+	.bm = BM_CBCMR_PERIPH2_CLK2_SEL,
+	.parents = {
+		&pll3_usb_otg,
+		&osc_clk,
+		NULL
+	},
+};
+
+static struct multiplexer gpu2d_axi_mux = {
+	.clk = &gpu2d_axi_clk,
+	.reg = CBCMR,
+	.bp = BP_CBCMR_GPU2D_AXI_SEL,
+	.bm = BM_CBCMR_GPU2D_AXI_SEL,
+	.parents = {
+		&axi_clk,
+		&ahb_clk,
+		NULL
+	},
+};
+
+static struct multiplexer gpu3d_axi_mux = {
+	.clk = &gpu3d_axi_clk,
+	.reg = CBCMR,
+	.bp = BP_CBCMR_GPU3D_AXI_SEL,
+	.bm = BM_CBCMR_GPU3D_AXI_SEL,
+	.parents = {
+		&axi_clk,
+		&ahb_clk,
+		NULL
+	},
+};
+
+static struct multiplexer gpu3d_core_mux = {
+	.clk = &gpu3d_core_clk,
+	.reg = CBCMR,
+	.bp = BP_CBCMR_GPU3D_CORE_SEL,
+	.bm = BM_CBCMR_GPU3D_CORE_SEL,
+	.parents = {
+		&mmdc_ch0_axi_clk,
+		&pll3_usb_otg,
+		&pll2_pfd_594m,
+		&pll2_pfd_400m,
+		NULL
+	},
+};
+
+static struct multiplexer gpu3d_shader_mux = {
+	.clk = &gpu3d_shader_clk,
+	.reg = CBCMR,
+	.bp = BP_CBCMR_GPU3D_SHADER_SEL,
+	.bm = BM_CBCMR_GPU3D_SHADER_SEL,
+	.parents = {
+		&mmdc_ch0_axi_clk,
+		&pll3_usb_otg,
+		&pll2_pfd_594m,
+		&pll3_pfd_720m,
+		NULL
+	},
+};
+
+static struct multiplexer pcie_axi_mux = {
+	.clk = &pcie_clk,
+	.reg = CBCMR,
+	.bp = BP_CBCMR_PCIE_AXI_SEL,
+	.bm = BM_CBCMR_PCIE_AXI_SEL,
+	.parents = {
+		&axi_clk,
+		&ahb_clk,
+		NULL
+	},
+};
+
+static struct multiplexer vdo_axi_mux = {
+	.clk = &vdo_axi_clk,
+	.reg = CBCMR,
+	.bp = BP_CBCMR_VDO_AXI_SEL,
+	.bm = BM_CBCMR_VDO_AXI_SEL,
+	.parents = {
+		&axi_clk,
+		&ahb_clk,
+		NULL
+	},
+};
+
+static struct multiplexer vpu_axi_mux = {
+	.clk = &vpu_clk,
+	.reg = CBCMR,
+	.bp = BP_CBCMR_VPU_AXI_SEL,
+	.bm = BM_CBCMR_VPU_AXI_SEL,
+	.parents = {
+		&axi_clk,
+		&pll2_pfd_400m,
+		&pll2_pfd_352m,
+		NULL
+	},
+};
+
+static struct multiplexer gpu2d_core_mux = {
+	.clk = &gpu2d_core_clk,
+	.reg = CBCMR,
+	.bp = BP_CBCMR_GPU2D_CORE_SEL,
+	.bm = BM_CBCMR_GPU2D_CORE_SEL,
+	.parents = {
+		&axi_clk,
+		&pll3_usb_otg,
+		&pll2_pfd_352m,
+		&pll2_pfd_400m,
+		NULL
+	},
+};
+
+#define DEF_SSI_MUX(id)							\
+	static struct multiplexer ssi##id##_mux = {			\
+		.clk = &ssi##id##_clk,					\
+		.reg = CSCMR1,						\
+		.bp = BP_CSCMR1_SSI##id##_SEL,				\
+		.bm = BM_CSCMR1_SSI##id##_SEL,				\
+		.parents = {						\
+			&pll3_pfd_508m,					\
+			&pll3_pfd_454m,					\
+			&pll4_audio,					\
+			NULL						\
+		},							\
+	}
+
+DEF_SSI_MUX(1);
+DEF_SSI_MUX(2);
+DEF_SSI_MUX(3);
+
+#define DEF_USDHC_MUX(id)						\
+	static struct multiplexer usdhc##id##_mux = {			\
+		.clk = &usdhc##id##_clk,				\
+		.reg = CSCMR1,						\
+		.bp = BP_CSCMR1_USDHC##id##_SEL,			\
+		.bm = BM_CSCMR1_USDHC##id##_SEL,			\
+		.parents = {						\
+			&pll2_pfd_400m,					\
+			&pll2_pfd_352m,					\
+			NULL						\
+		},							\
+	}
+
+DEF_USDHC_MUX(1);
+DEF_USDHC_MUX(2);
+DEF_USDHC_MUX(3);
+DEF_USDHC_MUX(4);
+
+static struct multiplexer emi_mux = {
+	.clk = &emi_clk,
+	.reg = CSCMR1,
+	.bp = BP_CSCMR1_EMI_SEL,
+	.bm = BM_CSCMR1_EMI_SEL,
+	.parents = {
+		&axi_clk,
+		&pll3_usb_otg,
+		&pll2_pfd_400m,
+		&pll2_pfd_352m,
+		NULL
+	},
+};
+
+static struct multiplexer emi_slow_mux = {
+	.clk = &emi_slow_clk,
+	.reg = CSCMR1,
+	.bp = BP_CSCMR1_EMI_SLOW_SEL,
+	.bm = BM_CSCMR1_EMI_SLOW_SEL,
+	.parents = {
+		&axi_clk,
+		&pll3_usb_otg,
+		&pll2_pfd_400m,
+		&pll2_pfd_352m,
+		NULL
+	},
+};
+
+static struct multiplexer esai_mux = {
+	.clk = &esai_clk,
+	.reg = CSCMR2,
+	.bp = BP_CSCMR2_ESAI_SEL,
+	.bm = BM_CSCMR2_ESAI_SEL,
+	.parents = {
+		&pll4_audio,
+		&pll3_pfd_508m,
+		&pll3_pfd_454m,
+		&pll3_usb_otg,
+		NULL
+	},
+};
+
+#define DEF_LDB_DI_MUX(id)						\
+	static struct multiplexer ldb_di##id##_mux = {			\
+		.clk = &ldb_di##id##_clk,				\
+		.reg = CS2CDR,						\
+		.bp = BP_CS2CDR_LDB_DI##id##_SEL,			\
+		.bm = BM_CS2CDR_LDB_DI##id##_SEL,			\
+		.parents = {						\
+			&pll5_video,					\
+			&pll2_pfd_352m,					\
+			&pll2_pfd_400m,					\
+			&pll3_pfd_540m,					\
+			&pll3_usb_otg,					\
+			NULL						\
+		},							\
+	}
+
+DEF_LDB_DI_MUX(0);
+DEF_LDB_DI_MUX(1);
+
+static struct multiplexer enfc_mux = {
+	.clk = &enfc_clk,
+	.reg = CS2CDR,
+	.bp = BP_CS2CDR_ENFC_SEL,
+	.bm = BM_CS2CDR_ENFC_SEL,
+	.parents = {
+		&pll2_pfd_352m,
+		&pll2_bus,
+		&pll3_usb_otg,
+		&pll2_pfd_400m,
+		NULL
+	},
+};
+
+static struct multiplexer spdif_mux = {
+	.clk = &spdif_clk,
+	.reg = CDCDR,
+	.bp = BP_CDCDR_SPDIF_SEL,
+	.bm = BM_CDCDR_SPDIF_SEL,
+	.parents = {
+		&pll4_audio,
+		&pll3_pfd_508m,
+		&pll3_pfd_454m,
+		&pll3_usb_otg,
+		NULL
+	},
+};
+
+static struct multiplexer asrc_serial_mux = {
+	.clk = &asrc_serial_clk,
+	.reg = CDCDR,
+	.bp = BP_CDCDR_ASRC_SERIAL_SEL,
+	.bm = BM_CDCDR_ASRC_SERIAL_SEL,
+	.parents = {
+		&pll4_audio,
+		&pll3_pfd_508m,
+		&pll3_pfd_454m,
+		&pll3_usb_otg,
+		NULL
+	},
+};
+
+static struct multiplexer hsi_tx_mux = {
+	.clk = &hsi_tx_clk,
+	.reg = CDCDR,
+	.bp = BP_CDCDR_HSI_TX_SEL,
+	.bm = BM_CDCDR_HSI_TX_SEL,
+	.parents = {
+		&pll3_120m,
+		&pll2_pfd_400m,
+		NULL
+	},
+};
+
+#define DEF_IPU_DI_PRE_MUX(r, i, d)					\
+	static struct multiplexer ipu##i##_di##d##_pre_mux = {		\
+		.clk = &ipu##i##_di##d##_pre_clk,			\
+		.reg = r,						\
+		.bp = BP_##r##_IPU##i##_DI##d##_PRE_SEL,		\
+		.bm = BM_##r##_IPU##i##_DI##d##_PRE_SEL,		\
+		.parents = {						\
+			&mmdc_ch0_axi_clk,				\
+			&pll3_usb_otg,					\
+			&pll5_video,					\
+			&pll2_pfd_352m,					\
+			&pll2_pfd_400m,					\
+			&pll3_pfd_540m,					\
+			NULL						\
+		},							\
+	}
+
+DEF_IPU_DI_PRE_MUX(CHSCCDR, 1, 0);
+DEF_IPU_DI_PRE_MUX(CHSCCDR, 1, 1);
+DEF_IPU_DI_PRE_MUX(CSCDR2, 2, 0);
+DEF_IPU_DI_PRE_MUX(CSCDR2, 2, 1);
+
+#define DEF_IPU_DI_MUX(r, i, d)						\
+	static struct multiplexer ipu##i##_di##d##_mux = {		\
+		.clk = &ipu##i##_di##d##_clk,				\
+		.reg = r,						\
+		.bp = BP_##r##_IPU##i##_DI##d##_SEL,			\
+		.bm = BM_##r##_IPU##i##_DI##d##_SEL,			\
+		.parents = {						\
+			&ipu##i##_di##d##_pre_clk,			\
+			&dummy_clk,					\
+			&dummy_clk,					\
+			&ldb_di0_clk,					\
+			&ldb_di1_clk,					\
+			NULL						\
+		},							\
+	}
+
+DEF_IPU_DI_MUX(CHSCCDR, 1, 0);
+DEF_IPU_DI_MUX(CHSCCDR, 1, 1);
+DEF_IPU_DI_MUX(CSCDR2, 2, 0);
+DEF_IPU_DI_MUX(CSCDR2, 2, 1);
+
+#define DEF_IPU_MUX(id)							\
+	static struct multiplexer ipu##id##_mux = {			\
+		.clk = &ipu##id##_clk,					\
+		.reg = CSCDR3,						\
+		.bp = BP_CSCDR3_IPU##id##_HSP_SEL,			\
+		.bm = BM_CSCDR3_IPU##id##_HSP_SEL,			\
+		.parents = {						\
+			&mmdc_ch0_axi_clk,				\
+			&pll2_pfd_400m,					\
+			&pll3_120m,					\
+			&pll3_pfd_540m,					\
+			NULL						\
+		},							\
+	}
+
+DEF_IPU_MUX(1);
+DEF_IPU_MUX(2);
+
+static struct multiplexer *multiplexers[] = {
+	&axi_mux,
+	&periph_mux,
+	&periph_pre_mux,
+	&periph_clk2_mux,
+	&periph2_mux,
+	&periph2_pre_mux,
+	&periph2_clk2_mux,
+	&gpu2d_axi_mux,
+	&gpu3d_axi_mux,
+	&gpu3d_core_mux,
+	&gpu3d_shader_mux,
+	&pcie_axi_mux,
+	&vdo_axi_mux,
+	&vpu_axi_mux,
+	&gpu2d_core_mux,
+	&ssi1_mux,
+	&ssi2_mux,
+	&ssi3_mux,
+	&usdhc1_mux,
+	&usdhc2_mux,
+	&usdhc3_mux,
+	&usdhc4_mux,
+	&emi_mux,
+	&emi_slow_mux,
+	&esai_mux,
+	&ldb_di0_mux,
+	&ldb_di1_mux,
+	&enfc_mux,
+	&spdif_mux,
+	&asrc_serial_mux,
+	&hsi_tx_mux,
+	&ipu1_di0_pre_mux,
+	&ipu1_di0_mux,
+	&ipu1_di1_pre_mux,
+	&ipu1_di1_mux,
+	&ipu2_di0_pre_mux,
+	&ipu2_di0_mux,
+	&ipu2_di1_pre_mux,
+	&ipu2_di1_mux,
+	&ipu1_mux,
+	&ipu2_mux,
+};
+
+static int _clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	struct multiplexer *m;
+	int i, num;
+	u32 val;
+
+	num = ARRAY_SIZE(multiplexers);
+	for (i = 0; i < num; i++)
+		if (multiplexers[i]->clk == clk) {
+			m = multiplexers[i];
+			break;
+		}
+	if (i == num)
+		return -EINVAL;
+
+	i = 0;
+	while (m->parents[i]) {
+		if (parent == m->parents[i])
+			break;
+		i++;
+	}
+	if (!m->parents[i])
+		return -EINVAL;
+
+	val = readl_relaxed(m->reg);
+	val &= ~m->bm;
+	val |= i << m->bp;
+	writel_relaxed(val, m->reg);
+
+	if (clk == &periph_clk)
+		return clk_busy_wait(clk);
+
+	return 0;
+}
+
+#define DEF_NG_CLK(name, p)				\
+	static struct clk name = {			\
+		.get_rate	= _clk_get_rate,	\
+		.set_rate	= _clk_set_rate,	\
+		.round_rate	= _clk_round_rate,	\
+		.set_parent	= _clk_set_parent,	\
+		.parent		= p,			\
+	}
+
+DEF_NG_CLK(periph_clk2_clk,	&osc_clk);
+DEF_NG_CLK(periph_pre_clk,	&pll2_bus);
+DEF_NG_CLK(periph_clk,		&periph_pre_clk);
+DEF_NG_CLK(periph2_clk2_clk,	&osc_clk);
+DEF_NG_CLK(periph2_pre_clk,	&pll2_bus);
+DEF_NG_CLK(periph2_clk,		&periph2_pre_clk);
+DEF_NG_CLK(axi_clk,		&periph_clk);
+DEF_NG_CLK(emi_clk,		&axi_clk);
+DEF_NG_CLK(arm_clk,		&pll1_sw_clk);
+DEF_NG_CLK(ahb_clk,		&periph_clk);
+DEF_NG_CLK(ipg_clk,		&ahb_clk);
+DEF_NG_CLK(ipg_perclk,		&ipg_clk);
+DEF_NG_CLK(ipu1_di0_pre_clk,	&pll3_pfd_540m);
+DEF_NG_CLK(ipu1_di1_pre_clk,	&pll3_pfd_540m);
+DEF_NG_CLK(ipu2_di0_pre_clk,	&pll3_pfd_540m);
+DEF_NG_CLK(ipu2_di1_pre_clk,	&pll3_pfd_540m);
+DEF_NG_CLK(asrc_serial_clk,	&pll3_usb_otg);
+
+#define DEF_CLK(name, er, es, p, s)			\
+	static struct clk name = {			\
+		.enable_reg	= er,			\
+		.enable_shift	= es,			\
+		.enable		= _clk_enable,		\
+		.disable	= _clk_disable,		\
+		.get_rate	= _clk_get_rate,	\
+		.set_rate	= _clk_set_rate,	\
+		.round_rate	= _clk_round_rate,	\
+		.set_parent	= _clk_set_parent,	\
+		.parent		= p,			\
+		.secondary	= s,			\
+	}
+
+DEF_CLK(aips_tz1_clk,	  CCGR0, CG0,  &ahb_clk,	  NULL);
+DEF_CLK(aips_tz2_clk,	  CCGR0, CG1,  &ahb_clk,	  NULL);
+DEF_CLK(apbh_dma_clk,	  CCGR0, CG2,  &ahb_clk,	  NULL);
+DEF_CLK(asrc_clk,	  CCGR0, CG3,  &pll4_audio,	  NULL);
+DEF_CLK(can1_serial_clk,  CCGR0, CG8,  &pll3_usb_otg,	  NULL);
+DEF_CLK(can1_clk,	  CCGR0, CG7,  &pll3_usb_otg,	  &can1_serial_clk);
+DEF_CLK(can2_serial_clk,  CCGR0, CG10, &pll3_usb_otg,	  NULL);
+DEF_CLK(can2_clk,	  CCGR0, CG9,  &pll3_usb_otg,	  &can2_serial_clk);
+DEF_CLK(ecspi1_clk,	  CCGR1, CG0,  &pll3_60m,	  NULL);
+DEF_CLK(ecspi2_clk,	  CCGR1, CG1,  &pll3_60m,	  NULL);
+DEF_CLK(ecspi3_clk,	  CCGR1, CG2,  &pll3_60m,	  NULL);
+DEF_CLK(ecspi4_clk,	  CCGR1, CG3,  &pll3_60m,	  NULL);
+DEF_CLK(ecspi5_clk,	  CCGR1, CG4,  &pll3_60m,	  NULL);
+DEF_CLK(enet_clk,	  CCGR1, CG5,  &pll8_enet,	  NULL);
+DEF_CLK(esai_clk,	  CCGR1, CG8,  &pll3_usb_otg,	  NULL);
+DEF_CLK(gpt_serial_clk,	  CCGR1, CG11, &ipg_perclk,	  NULL);
+DEF_CLK(gpt_clk,	  CCGR1, CG10, &ipg_perclk,	  &gpt_serial_clk);
+DEF_CLK(gpu2d_core_clk,	  CCGR1, CG12, &pll2_pfd_352m,	  &gpu2d_axi_clk);
+DEF_CLK(gpu3d_core_clk,	  CCGR1, CG13, &pll2_pfd_594m,	  &gpu3d_axi_clk);
+DEF_CLK(gpu3d_shader_clk, CCGR1, CG13, &pll3_pfd_720m,	  &gpu3d_axi_clk);
+DEF_CLK(hdmi_iahb_clk,	  CCGR2, CG0,  &ahb_clk,	  NULL);
+DEF_CLK(hdmi_isfr_clk,	  CCGR2, CG2,  &pll3_pfd_540m,	  &hdmi_iahb_clk);
+DEF_CLK(i2c1_clk,	  CCGR2, CG3,  &ipg_perclk,	  NULL);
+DEF_CLK(i2c2_clk,	  CCGR2, CG4,  &ipg_perclk,	  NULL);
+DEF_CLK(i2c3_clk,	  CCGR2, CG5,  &ipg_perclk,	  NULL);
+DEF_CLK(iim_clk,	  CCGR2, CG6,  &ipg_clk,	  NULL);
+DEF_CLK(enfc_clk,	  CCGR2, CG7,  &pll2_pfd_352m,	  NULL);
+DEF_CLK(ipu1_clk,	  CCGR3, CG0,  &mmdc_ch0_axi_clk, NULL);
+DEF_CLK(ipu1_di0_clk,	  CCGR3, CG1,  &ipu1_di0_pre_clk, NULL);
+DEF_CLK(ipu1_di1_clk,	  CCGR3, CG2,  &ipu1_di1_pre_clk, NULL);
+DEF_CLK(ipu2_clk,	  CCGR3, CG3,  &mmdc_ch0_axi_clk, NULL);
+DEF_CLK(ipu2_di0_clk,	  CCGR3, CG4,  &ipu2_di0_pre_clk, NULL);
+DEF_CLK(ipu2_di1_clk,	  CCGR3, CG5,  &ipu2_di1_pre_clk, NULL);
+DEF_CLK(ldb_di0_clk,	  CCGR3, CG6,  &pll3_pfd_540m,	  NULL);
+DEF_CLK(ldb_di1_clk,	  CCGR3, CG7,  &pll3_pfd_540m,	  NULL);
+DEF_CLK(hsi_tx_clk,	  CCGR3, CG8,  &pll2_pfd_400m,	  NULL);
+DEF_CLK(mlb_clk,	  CCGR3, CG9,  &pll6_mlb,	  NULL);
+DEF_CLK(mmdc_ch0_ipg_clk, CCGR3, CG12, &ipg_clk,	  NULL);
+DEF_CLK(mmdc_ch0_axi_clk, CCGR3, CG10, &periph_clk,	  &mmdc_ch0_ipg_clk);
+DEF_CLK(mmdc_ch1_ipg_clk, CCGR3, CG13, &ipg_clk,	  NULL);
+DEF_CLK(mmdc_ch1_axi_clk, CCGR3, CG11, &periph2_clk,	  &mmdc_ch1_ipg_clk);
+DEF_CLK(openvg_axi_clk,   CCGR3, CG13, &axi_clk,	  NULL);
+DEF_CLK(pwm1_clk,	  CCGR4, CG8,  &ipg_perclk,	  NULL);
+DEF_CLK(pwm2_clk,	  CCGR4, CG9,  &ipg_perclk,	  NULL);
+DEF_CLK(pwm3_clk,	  CCGR4, CG10, &ipg_perclk,	  NULL);
+DEF_CLK(pwm4_clk,	  CCGR4, CG11, &ipg_perclk,	  NULL);
+DEF_CLK(gpmi_bch_apb_clk, CCGR4, CG12, &usdhc3_clk,	  NULL);
+DEF_CLK(gpmi_bch_clk,	  CCGR4, CG13, &usdhc4_clk,	  &gpmi_bch_apb_clk);
+DEF_CLK(gpmi_apb_clk,	  CCGR4, CG15, &usdhc3_clk,	  &gpmi_bch_clk);
+DEF_CLK(gpmi_io_clk,	  CCGR4, CG14, &enfc_clk,	  &gpmi_apb_clk);
+DEF_CLK(sdma_clk,	  CCGR5, CG3,  &ahb_clk,	  NULL);
+DEF_CLK(spba_clk,	  CCGR5, CG6,  &ipg_clk,	  NULL);
+DEF_CLK(spdif_clk,	  CCGR5, CG7,  &pll3_usb_otg,	  &spba_clk);
+DEF_CLK(ssi1_clk,	  CCGR5, CG9,  &pll3_pfd_508m,	  NULL);
+DEF_CLK(ssi2_clk,	  CCGR5, CG10, &pll3_pfd_508m,	  NULL);
+DEF_CLK(ssi3_clk,	  CCGR5, CG11, &pll3_pfd_508m,	  NULL);
+DEF_CLK(uart_serial_clk,  CCGR5, CG13, &pll3_usb_otg,	  NULL);
+DEF_CLK(uart_clk,	  CCGR5, CG12, &pll3_80m,	  &uart_serial_clk);
+DEF_CLK(usboh3_clk,	  CCGR6, CG0,  &ipg_clk,	  NULL);
+DEF_CLK(usdhc1_clk,	  CCGR6, CG1,  &pll2_pfd_400m,	  NULL);
+DEF_CLK(usdhc2_clk,	  CCGR6, CG2,  &pll2_pfd_400m,	  NULL);
+DEF_CLK(usdhc3_clk,	  CCGR6, CG3,  &pll2_pfd_400m,	  NULL);
+DEF_CLK(usdhc4_clk,	  CCGR6, CG4,  &pll2_pfd_400m,	  NULL);
+DEF_CLK(emi_slow_clk,	  CCGR6, CG5,  &axi_clk,	  NULL);
+DEF_CLK(vdo_axi_clk,	  CCGR6, CG6,  &axi_clk,	  NULL);
+DEF_CLK(vpu_clk,	  CCGR6, CG7,  &axi_clk,	  NULL);
+
+static int pcie_clk_enable(struct clk *clk)
+{
+	u32 val;
+
+	val = readl_relaxed(PLL8_ENET);
+	val |= BM_PLL_ENET_EN_PCIE;
+	writel_relaxed(val, PLL8_ENET);
+
+	return _clk_enable(clk);
+}
+
+static void pcie_clk_disable(struct clk *clk)
+{
+	u32 val;
+
+	_clk_disable(clk);
+
+	val = readl_relaxed(PLL8_ENET);
+	val &= BM_PLL_ENET_EN_PCIE;
+	writel_relaxed(val, PLL8_ENET);
+}
+
+static struct clk pcie_clk = {
+	.enable_reg = CCGR4,
+	.enable_shift = CG0,
+	.enable = pcie_clk_enable,
+	.disable = pcie_clk_disable,
+	.set_parent = _clk_set_parent,
+	.parent = &axi_clk,
+	.secondary = &pll8_enet,
+};
+
+static int sata_clk_enable(struct clk *clk)
+{
+	u32 val;
+
+	val = readl_relaxed(PLL8_ENET);
+	val |= BM_PLL_ENET_EN_SATA;
+	writel_relaxed(val, PLL8_ENET);
+
+	return _clk_enable(clk);
+}
+
+static void sata_clk_disable(struct clk *clk)
+{
+	u32 val;
+
+	_clk_disable(clk);
+
+	val = readl_relaxed(PLL8_ENET);
+	val &= BM_PLL_ENET_EN_SATA;
+	writel_relaxed(val, PLL8_ENET);
+}
+
+static struct clk sata_clk = {
+	.enable_reg = CCGR5,
+	.enable_shift = CG2,
+	.enable = sata_clk_enable,
+	.disable = sata_clk_disable,
+	.parent = &ipg_clk,
+	.secondary = &pll8_enet,
+};
+
+#define _REGISTER_CLOCK(d, n, c) \
+	{ \
+		.dev_id = d, \
+		.con_id = n, \
+		.clk = &c, \
+	}
+
+static struct clk_lookup lookups[] = {
+	_REGISTER_CLOCK("2020000.uart", NULL, uart_clk),
+	_REGISTER_CLOCK("21e8000.uart", NULL, uart_clk),
+	_REGISTER_CLOCK("21ec000.uart", NULL, uart_clk),
+	_REGISTER_CLOCK("21f0000.uart", NULL, uart_clk),
+	_REGISTER_CLOCK("21f4000.uart", NULL, uart_clk),
+	_REGISTER_CLOCK("2188000.enet", NULL, enet_clk),
+	_REGISTER_CLOCK("21a0000.i2c", NULL, i2c1_clk),
+	_REGISTER_CLOCK("21a4000.i2c", NULL, i2c2_clk),
+	_REGISTER_CLOCK("21a8000.i2c", NULL, i2c3_clk),
+	_REGISTER_CLOCK("2008000.ecspi", NULL, ecspi1_clk),
+	_REGISTER_CLOCK("200c000.ecspi", NULL, ecspi2_clk),
+	_REGISTER_CLOCK("2010000.ecspi", NULL, ecspi3_clk),
+	_REGISTER_CLOCK("2014000.ecspi", NULL, ecspi4_clk),
+	_REGISTER_CLOCK("2018000.ecspi", NULL, ecspi5_clk),
+	_REGISTER_CLOCK("20ec000.sdma", NULL, sdma_clk),
+	_REGISTER_CLOCK("20bc000.wdog", NULL, dummy_clk),
+	_REGISTER_CLOCK("20c0000.wdog", NULL, dummy_clk),
+	_REGISTER_CLOCK(NULL, "ckih", ckih_clk),
+	_REGISTER_CLOCK(NULL, "ckil_clk", ckil_clk),
+	_REGISTER_CLOCK(NULL, "aips_tz1_clk", aips_tz1_clk),
+	_REGISTER_CLOCK(NULL, "aips_tz2_clk", aips_tz2_clk),
+	_REGISTER_CLOCK(NULL, "asrc_clk", asrc_clk),
+	_REGISTER_CLOCK(NULL, "can2_clk", can2_clk),
+	_REGISTER_CLOCK(NULL, "hdmi_isfr_clk", hdmi_isfr_clk),
+	_REGISTER_CLOCK(NULL, "iim_clk", iim_clk),
+	_REGISTER_CLOCK(NULL, "mlb_clk", mlb_clk),
+	_REGISTER_CLOCK(NULL, "openvg_axi_clk", openvg_axi_clk),
+	_REGISTER_CLOCK(NULL, "pwm1_clk", pwm1_clk),
+	_REGISTER_CLOCK(NULL, "pwm2_clk", pwm2_clk),
+	_REGISTER_CLOCK(NULL, "pwm3_clk", pwm3_clk),
+	_REGISTER_CLOCK(NULL, "pwm4_clk", pwm4_clk),
+	_REGISTER_CLOCK(NULL, "gpmi_io_clk", gpmi_io_clk),
+	_REGISTER_CLOCK(NULL, "usboh3_clk", usboh3_clk),
+	_REGISTER_CLOCK(NULL, "sata_clk", sata_clk),
+};
+
+int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
+{
+	u32 val = readl_relaxed(CLPCR);
+
+	val &= ~BM_CLPCR_LPM;
+	switch (mode) {
+	case WAIT_CLOCKED:
+		break;
+	case WAIT_UNCLOCKED:
+		val |= 0x1 << BP_CLPCR_LPM;
+		break;
+	case STOP_POWER_ON:
+		val |= 0x2 << BP_CLPCR_LPM;
+		break;
+	case WAIT_UNCLOCKED_POWER_OFF:
+		val |= 0x1 << BP_CLPCR_LPM;
+		val &= ~BM_CLPCR_VSTBY;
+		val &= ~BM_CLPCR_SBYOS;
+		val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS;
+		break;
+	case STOP_POWER_OFF:
+		val |= 0x2 << BP_CLPCR_LPM;
+		val |= 0x3 << BP_CLPCR_STBY_COUNT;
+		val |= BM_CLPCR_VSTBY;
+		val |= BM_CLPCR_SBYOS;
+		val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS;
+		break;
+	default:
+		return -EINVAL;
+	}
+	writel_relaxed(val, CLPCR);
+
+	return 0;
+}
+
+static struct map_desc imx6q_clock_desc[] = {
+	imx_map_entry(MX6Q, CCM, MT_DEVICE),
+	imx_map_entry(MX6Q, ANATOP, MT_DEVICE),
+};
+
+int __init mx6q_clocks_init(void)
+{
+	struct device_node *np;
+	void __iomem *base;
+	int i, irq;
+
+	iotable_init(imx6q_clock_desc, ARRAY_SIZE(imx6q_clock_desc));
+
+	/* retrieve the freqency of fixed clocks from device tree */
+	for_each_compatible_node(np, NULL, "fixed-clock") {
+		u32 rate;
+		if (of_property_read_u32(np, "clock-frequency", &rate))
+			continue;
+
+		if (of_device_is_compatible(np, "fsl,imx6q-clkl"))
+			external_low_reference = rate;
+		else if (of_device_is_compatible(np, "fsl,imx6q-clkh"))
+			external_high_reference = rate;
+		else if (of_device_is_compatible(np, "fsl,imx6q-osc"))
+			oscillator_reference = rate;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(lookups); i++)
+		clkdev_add(&lookups[i]);
+
+	/* only keep necessary clocks on */
+	writel_relaxed(0x3 << CG0  | 0x3 << CG1  | 0x3 << CG2,	CCGR0);
+	writel_relaxed(0x3 << CG8  | 0x3 << CG9  | 0x3 << CG10,	CCGR2);
+	writel_relaxed(0x3 << CG10 | 0x3 << CG12,		CCGR3);
+	writel_relaxed(0x3 << CG4  | 0x3 << CG6  | 0x3 << CG7,	CCGR4);
+	writel_relaxed(0x3 << CG0,				CCGR5);
+	writel_relaxed(0,					CCGR6);
+	writel_relaxed(0,					CCGR7);
+
+	clk_enable(&uart_clk);
+	clk_enable(&mmdc_ch0_axi_clk);
+
+	clk_set_rate(&pll4_audio, FREQ_650M);
+	clk_set_rate(&pll5_video, FREQ_650M);
+	clk_set_parent(&ipu1_di0_clk, &ipu1_di0_pre_clk);
+	clk_set_parent(&ipu1_di0_pre_clk, &pll5_video);
+	clk_set_parent(&gpu3d_shader_clk, &pll2_pfd_594m);
+	clk_set_rate(&gpu3d_shader_clk, FREQ_594M);
+	clk_set_parent(&gpu3d_core_clk, &mmdc_ch0_axi_clk);
+	clk_set_rate(&gpu3d_core_clk, FREQ_528M);
+	clk_set_parent(&asrc_serial_clk, &pll3_usb_otg);
+	clk_set_rate(&asrc_serial_clk, 1500000);
+	clk_set_rate(&enfc_clk, 11000000);
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpt");
+	base = of_iomap(np, 0);
+	WARN_ON(!base);
+	irq = irq_of_parse_and_map(np, 0);
+	mxc_timer_init(&gpt_clk, base, irq);
+
+	return 0;
+}
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
new file mode 100644
index 0000000..e1537f9
--- /dev/null
+++ b/arch/arm/mach-imx/gpc.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later@the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/hardware/gic.h>
+
+#define GPC_IMR1		0x008
+#define GPC_PGC_CPU_PDN		0x2a0
+
+#define IMR_NUM			4
+
+static void __iomem *gpc_base;
+static u32 gpc_wake_irqs[IMR_NUM];
+static u32 gpc_saved_imrs[IMR_NUM];
+
+void imx_gpc_pre_suspend(void)
+{
+	void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
+	int i;
+
+	/* Tell GPC to power off ARM core when suspend */
+	writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_PDN);
+
+	for (i = 0; i < IMR_NUM; i++) {
+		gpc_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4);
+		writel_relaxed(~gpc_wake_irqs[i], reg_imr1 + i * 4);
+	}
+}
+
+void imx_gpc_post_resume(void)
+{
+	void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
+	int i;
+
+	/* Keep ARM core powered on for other low-power modes */
+	writel_relaxed(0x0, gpc_base + GPC_PGC_CPU_PDN);
+
+	for (i = 0; i < IMR_NUM; i++)
+		writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4);
+}
+
+static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+	unsigned int idx = d->irq / 32 - 1;
+	u32 mask;
+
+	/* Sanity check for SPI irq */
+	if (d->irq < 32)
+		return -EINVAL;
+
+	mask = 1 << d->irq % 32;
+	gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask :
+				  gpc_wake_irqs[idx] & ~mask;
+
+	return 0;
+}
+
+static void imx_gpc_irq_unmask(struct irq_data *d)
+{
+	void __iomem *reg;
+	u32 val;
+
+	/* Sanity check for SPI irq */
+	if (d->irq < 32)
+		return;
+
+	reg = gpc_base + GPC_IMR1 + (d->irq / 32 - 1) * 4;
+	val = readl_relaxed(reg);
+	val &= ~(1 << d->irq % 32);
+	writel_relaxed(val, reg);
+}
+
+static void imx_gpc_irq_mask(struct irq_data *d)
+{
+	void __iomem *reg;
+	u32 val;
+
+	/* Sanity check for SPI irq */
+	if (d->irq < 32)
+		return;
+
+	reg = gpc_base + GPC_IMR1 + (d->irq / 32 - 1) * 4;
+	val = readl_relaxed(reg);
+	val |= 1 << (d->irq % 32);
+	writel_relaxed(val, reg);
+}
+
+void __init imx_gpc_init(void)
+{
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-gpc");
+	gpc_base = of_iomap(np, 0);
+	WARN_ON(!gpc_base);
+
+	/* Register GPC as the secondary interrupt controller behind GIC */
+	gic_arch_extn.irq_mask = imx_gpc_irq_mask;
+	gic_arch_extn.irq_unmask = imx_gpc_irq_unmask;
+	gic_arch_extn.irq_set_wake = imx_gpc_irq_set_wake;
+}
diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c
new file mode 100644
index 0000000..2103a175
--- /dev/null
+++ b/arch/arm/mach-imx/mmdc.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+#define MMDC_MAPSR		0x404
+#define BP_MMDC_MAPSR_PSD	0
+#define BP_MMDC_MAPSR_PSS	4
+
+static int __devinit imx_mmdc_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	void __iomem *mmdc_base, *reg;
+	u32 val;
+	int timeout = 0x400;
+
+	mmdc_base = of_iomap(np, 0);
+	WARN_ON(!mmdc_base);
+
+	reg = mmdc_base + MMDC_MAPSR;
+
+	/* Enable automatic power saving */
+	val = readl_relaxed(reg);
+	val &= ~(1 << BP_MMDC_MAPSR_PSD);
+	writel_relaxed(val, reg);
+
+	/* Ensure it's successfully enabled */
+	while (!(readl_relaxed(reg) & 1 << BP_MMDC_MAPSR_PSS) && --timeout)
+		cpu_relax();
+
+	if (unlikely(!timeout)) {
+		pr_warn("%s: failed to enable automatic power saving\n",
+			__func__);
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static struct of_device_id imx_mmdc_dt_ids[] = {
+	{ .compatible = "fsl,imx6q-mmdc", },
+	{ /* sentinel */ }
+};
+
+static struct platform_driver imx_mmdc_driver = {
+	.driver		= {
+		.name	= "imx-mmdc",
+		.owner	= THIS_MODULE,
+		.of_match_table = imx_mmdc_dt_ids,
+	},
+	.probe		= imx_mmdc_probe,
+};
+
+static int __init imx_mmdc_init(void)
+{
+	return platform_driver_register(&imx_mmdc_driver);
+}
+postcore_initcall(imx_mmdc_init);
diff --git a/arch/arm/mach-imx/src.c b/arch/arm/mach-imx/src.c
new file mode 100644
index 0000000..36cacbd
--- /dev/null
+++ b/arch/arm/mach-imx/src.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later@the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <asm/unified.h>
+
+#define SRC_SCR				0x000
+#define SRC_GPR1			0x020
+#define BP_SRC_SCR_CORE1_RST		14
+#define BP_SRC_SCR_CORE1_ENABLE		22
+
+static void __iomem *src_base;
+
+void imx_enable_cpu(int cpu, bool enable)
+{
+	u32 mask, val;
+
+	mask = 1 << (BP_SRC_SCR_CORE1_ENABLE + cpu - 1);
+	val = readl_relaxed(src_base + SRC_SCR);
+	val = enable ? val | mask : val & ~mask;
+	writel_relaxed(val, src_base + SRC_SCR);
+}
+
+void imx_set_cpu_jump(int cpu, void *jump_addr)
+{
+	writel_relaxed(BSYM(virt_to_phys(jump_addr)),
+		       src_base + SRC_GPR1 + cpu * 8);
+}
+
+void __init imx_src_init(void)
+{
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,imx6q-src");
+	src_base = of_iomap(np, 0);
+	WARN_ON(!src_base);
+}
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH v2 4/6] arm/imx6q: add smp and cpu hotplug support
From: Shawn Guo @ 2011-09-15 14:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316097926-913-1-git-send-email-shawn.guo@linaro.org>

It adds smp and cpu hotplug support for imx6q.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/Kconfig               |    1 +
 arch/arm/mach-imx/Makefile              |    4 ++
 arch/arm/mach-imx/head-v7.S             |   71 ++++++++++++++++++++++++++
 arch/arm/mach-imx/hotplug.c             |   44 ++++++++++++++++
 arch/arm/mach-imx/localtimer.c          |   35 +++++++++++++
 arch/arm/mach-imx/platsmp.c             |   85 +++++++++++++++++++++++++++++++
 arch/arm/plat-mxc/include/mach/common.h |    6 ++
 7 files changed, 246 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-imx/head-v7.S
 create mode 100644 arch/arm/mach-imx/hotplug.c
 create mode 100644 arch/arm/mach-imx/localtimer.c
 create mode 100644 arch/arm/mach-imx/platsmp.c

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index af73b3e..6ec758d 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -623,6 +623,7 @@ config SOC_IMX6Q
 	bool "i.MX6 Quad support"
 	select ARM_GIC
 	select CPU_V7
+	select HAVE_ARM_SCU
 	select HAVE_IMX_GPC
 	select HAVE_IMX_MMDC
 	select HAVE_IMX_SRC
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 8c21fda..d46b2e7 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -66,4 +66,8 @@ obj-$(CONFIG_DEBUG_LL) += lluart.o
 obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
 obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
 obj-$(CONFIG_HAVE_IMX_SRC) += src.o
+obj-$(CONFIG_CPU_V7) += head-v7.o
+obj-$(CONFIG_SMP) += platsmp.o
+obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
+obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
 obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o
diff --git a/arch/arm/mach-imx/head-v7.S b/arch/arm/mach-imx/head-v7.S
new file mode 100644
index 0000000..ede908b
--- /dev/null
+++ b/arch/arm/mach-imx/head-v7.S
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/hardware/cache-l2x0.h>
+
+	.section ".text.head", "ax"
+	__CPUINIT
+
+/*
+ * The secondary kernel init calls v7_flush_dcache_all before it enables
+ * the L1; however, the L1 comes out of reset in an undefined state, so
+ * the clean + invalidate performed by v7_flush_dcache_all causes a bunch
+ * of cache lines with uninitialized data and uninitialized tags to get
+ * written out to memory, which does really unpleasant things to the main
+ * processor.  We fix this by performing an invalidate, rather than a
+ * clean + invalidate, before jumping into the kernel.
+ *
+ * This funciton is cloned from arch/arm/mach-tegra/headsmp.S, and needs
+ * to be called for both secondary cores startup and primary core resume
+ * procedures.  Ideally, it should be moved into arch/arm/mm/cache-v7.S.
+ */
+ENTRY(v7_invalidate_l1)
+	mov	r0, #0
+	mcr	p15, 2, r0, c0, c0, 0
+	mrc	p15, 1, r0, c0, c0, 0
+
+	ldr	r1, =0x7fff
+	and	r2, r1, r0, lsr #13
+
+	ldr	r1, =0x3ff
+
+	and	r3, r1, r0, lsr #3	@ NumWays - 1
+	add	r2, r2, #1		@ NumSets
+
+	and	r0, r0, #0x7
+	add	r0, r0, #4	@ SetShift
+
+	clz	r1, r3		@ WayShift
+	add	r4, r3, #1	@ NumWays
+1:	sub	r2, r2, #1	@ NumSets--
+	mov	r3, r4		@ Temp = NumWays
+2:	subs	r3, r3, #1	@ Temp--
+	mov	r5, r3, lsl r1
+	mov	r6, r2, lsl r0
+	orr	r5, r5, r6	@ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
+	mcr	p15, 0, r5, c7, c6, 2
+	bgt	2b
+	cmp	r2, #0
+	bgt	1b
+	dsb
+	isb
+	mov	pc, lr
+ENDPROC(v7_invalidate_l1)
+
+#ifdef CONFIG_SMP
+ENTRY(v7_secondary_startup)
+	bl	v7_invalidate_l1
+	b	secondary_startup
+ENDPROC(v7_secondary_startup)
+#endif
diff --git a/arch/arm/mach-imx/hotplug.c b/arch/arm/mach-imx/hotplug.c
new file mode 100644
index 0000000..89493ab
--- /dev/null
+++ b/arch/arm/mach-imx/hotplug.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later@the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/errno.h>
+#include <asm/cacheflush.h>
+#include <mach/common.h>
+
+int platform_cpu_kill(unsigned int cpu)
+{
+	return 1;
+}
+
+/*
+ * platform-specific code to shutdown a CPU
+ *
+ * Called with IRQs disabled
+ */
+void platform_cpu_die(unsigned int cpu)
+{
+	flush_cache_all();
+	imx_enable_cpu(cpu, false);
+	cpu_do_idle();
+
+	/* We should never return from idle */
+	panic("cpu %d unexpectedly exit from shutdown\n", cpu);
+}
+
+int platform_cpu_disable(unsigned int cpu)
+{
+	/*
+	 * we don't allow CPU 0 to be shutdown (it is still too special
+	 * e.g. clock tick interrupts)
+	 */
+	return cpu == 0 ? -EPERM : 0;
+}
diff --git a/arch/arm/mach-imx/localtimer.c b/arch/arm/mach-imx/localtimer.c
new file mode 100644
index 0000000..3a16351
--- /dev/null
+++ b/arch/arm/mach-imx/localtimer.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/clockchips.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/smp_twd.h>
+
+/*
+ * Setup the local clock events for a CPU.
+ */
+int __cpuinit local_timer_setup(struct clock_event_device *evt)
+{
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "arm,smp-twd");
+	if (!twd_base) {
+		twd_base = of_iomap(np, 0);
+		WARN_ON(!twd_base);
+	}
+	evt->irq = irq_of_parse_and_map(np, 0);
+	twd_timer_setup(evt);
+
+	return 0;
+}
diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c
new file mode 100644
index 0000000..ab98c6f
--- /dev/null
+++ b/arch/arm/mach-imx/platsmp.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <asm/page.h>
+#include <asm/smp_scu.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/map.h>
+#include <mach/common.h>
+#include <mach/hardware.h>
+
+static void __iomem *scu_base;
+
+static struct map_desc scu_io_desc __initdata = {
+	/* .virtual and .pfn are run-time assigned */
+	.length		= SZ_4K,
+	.type		= MT_DEVICE,
+};
+
+void __init imx_scu_map_io(void)
+{
+	unsigned long base;
+
+	/* Get SCU base */
+	asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));
+
+	scu_io_desc.virtual = IMX_IO_P2V(base);
+	scu_io_desc.pfn = __phys_to_pfn(base);
+	iotable_init(&scu_io_desc, 1);
+
+	scu_base = IMX_IO_ADDRESS(base);
+}
+
+void __cpuinit platform_secondary_init(unsigned int cpu)
+{
+	/*
+	 * if any interrupts are already enabled for the primary
+	 * core (e.g. timer irq), then they will not have been enabled
+	 * for us: do so
+	 */
+	gic_secondary_init(0);
+}
+
+int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	imx_set_cpu_jump(cpu, v7_secondary_startup);
+	imx_enable_cpu(cpu, true);
+	return 0;
+}
+
+/*
+ * Initialise the CPU possible map early - this describes the CPUs
+ * which may be present or become present in the system.
+ */
+void __init smp_init_cpus(void)
+{
+	int i, ncores;
+
+	ncores = scu_get_core_count(scu_base);
+
+	for (i = 0; i < ncores; i++)
+		set_cpu_possible(i, true);
+
+	set_smp_cross_call(gic_raise_softirq);
+}
+
+void imx_smp_prepare(void)
+{
+	scu_enable(scu_base);
+}
+
+void __init platform_smp_prepare_cpus(unsigned int max_cpus)
+{
+	imx_smp_prepare();
+}
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h
index 4e3d978..48dbc27 100644
--- a/arch/arm/plat-mxc/include/mach/common.h
+++ b/arch/arm/plat-mxc/include/mach/common.h
@@ -72,4 +72,10 @@ extern void mxc_arch_reset_init(void __iomem *);
 extern void mx51_efikamx_reset(void);
 extern int mx53_revision(void);
 extern int mx53_display_revision(void);
+
+extern void imx_enable_cpu(int cpu, bool enable);
+extern void imx_set_cpu_jump(int cpu, void *jump_addr);
+#ifdef CONFIG_SMP
+extern void v7_secondary_startup(void);
+#endif
 #endif
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH v2 5/6] arm/imx6q: add device tree machine support
From: Shawn Guo @ 2011-09-15 14:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316097926-913-1-git-send-email-shawn.guo@linaro.org>

It adds generic device tree based machine support for imx6q.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/Makefile              |    2 +-
 arch/arm/mach-imx/mach-imx6q.c          |   73 +++++++++++++++++++++++++++++++
 arch/arm/mm/Kconfig                     |    2 +-
 arch/arm/plat-mxc/include/mach/common.h |   15 ++++++-
 4 files changed, 88 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm/mach-imx/mach-imx6q.c

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index d46b2e7..16737ba 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -70,4 +70,4 @@ obj-$(CONFIG_CPU_V7) += head-v7.o
 obj-$(CONFIG_SMP) += platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
 obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
-obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o
+obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
new file mode 100644
index 0000000..b9b9327
--- /dev/null
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/common.h>
+#include <mach/hardware.h>
+
+static void __init imx6q_init_machine(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+	imx6q_pm_init();
+}
+
+static void __init imx6q_map_io(void)
+{
+	imx_lluart_map_io();
+	imx_scu_map_io();
+}
+
+static const struct of_device_id imx6q_irq_match[] __initconst = {
+	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+	{ .compatible = "fsl,imx6q-gpio", },
+	{ /* sentinel */ }
+};
+
+static void __init imx6q_init_irq(void)
+{
+	l2x0_of_init(0, ~0UL);
+	imx_src_init();
+	imx_gpc_init();
+	of_irq_init(imx6q_irq_match);
+}
+
+static void __init imx6q_timer_init(void)
+{
+	mx6q_clocks_init();
+}
+
+static struct sys_timer imx6q_timer = {
+	.init = imx6q_timer_init,
+};
+
+static const char *imx6q_dt_compat[] __initdata = {
+	"fsl,imx6q-sabreauto",
+	NULL,
+};
+
+DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad (Device Tree)")
+	.map_io		= imx6q_map_io,
+	.init_irq	= imx6q_init_irq,
+	.timer		= &imx6q_timer,
+	.init_machine	= imx6q_init_machine,
+	.dt_compat	= imx6q_dt_compat,
+MACHINE_END
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 88633fe..c3ce146 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -822,7 +822,7 @@ config CACHE_L2X0
 		   REALVIEW_EB_A9MP || SOC_IMX35 || SOC_IMX31 || MACH_REALVIEW_PBX || \
 		   ARCH_NOMADIK || ARCH_OMAP4 || ARCH_EXYNOS4 || ARCH_TEGRA || \
 		   ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE || \
-		   ARCH_PRIMA2 || ARCH_ZYNQ || ARCH_CNS3XXX
+		   ARCH_PRIMA2 || ARCH_ZYNQ || ARCH_CNS3XXX || ARCH_MX6
 	default y
 	select OUTER_CACHE
 	select OUTER_CACHE_SYNC
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h
index 48dbc27..9c5be7b 100644
--- a/arch/arm/plat-mxc/include/mach/common.h
+++ b/arch/arm/plat-mxc/include/mach/common.h
@@ -64,6 +64,7 @@ extern int mx51_clocks_init(unsigned long ckil, unsigned long osc,
 			unsigned long ckih1, unsigned long ckih2);
 extern int mx53_clocks_init(unsigned long ckil, unsigned long osc,
 			unsigned long ckih1, unsigned long ckih2);
+extern int mx6q_clocks_init(void);
 extern struct platform_device *mxc_register_gpio(char *name, int id,
 	resource_size_t iobase, resource_size_t iosize, int irq, int irq_high);
 extern int mxc_register_device(struct platform_device *pdev, void *data);
@@ -73,9 +74,19 @@ extern void mx51_efikamx_reset(void);
 extern int mx53_revision(void);
 extern int mx53_display_revision(void);
 
-extern void imx_enable_cpu(int cpu, bool enable);
-extern void imx_set_cpu_jump(int cpu, void *jump_addr);
+#ifdef CONFIG_DEBUG_LL
+extern void imx_lluart_map_io(void);
+#else
+static inline void imx_lluart_map_io(void) {}
+#endif
 #ifdef CONFIG_SMP
 extern void v7_secondary_startup(void);
+extern void imx_scu_map_io(void);
+#else
+static inline void imx_scu_map_io(void) {}
 #endif
+extern void imx_enable_cpu(int cpu, bool enable);
+extern void imx_set_cpu_jump(int cpu, void *jump_addr);
+extern void imx_src_init(void);
+extern void imx_gpc_init(void);
 #endif
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH v2 6/6] arm/imx6q: add suspend/resume support
From: Shawn Guo @ 2011-09-15 14:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1316097926-913-1-git-send-email-shawn.guo@linaro.org>

It adds suspend/resume support for imx6q.

Signed-off-by: Anson Huang <b20788@freescale.com>
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 arch/arm/mach-imx/Makefile              |    2 +-
 arch/arm/mach-imx/head-v7.S             |   27 +++++++++
 arch/arm/mach-imx/pm-imx6q.c            |   88 +++++++++++++++++++++++++++++++
 arch/arm/plat-mxc/include/mach/common.h |    8 +++
 4 files changed, 124 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/mach-imx/pm-imx6q.c

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 16737ba..c787151 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -70,4 +70,4 @@ obj-$(CONFIG_CPU_V7) += head-v7.o
 obj-$(CONFIG_SMP) += platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
 obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
-obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o
+obj-$(CONFIG_SOC_IMX6Q) += clock-imx6q.o mach-imx6q.o pm-imx6q.o
diff --git a/arch/arm/mach-imx/head-v7.S b/arch/arm/mach-imx/head-v7.S
index ede908b..0a86685 100644
--- a/arch/arm/mach-imx/head-v7.S
+++ b/arch/arm/mach-imx/head-v7.S
@@ -69,3 +69,30 @@ ENTRY(v7_secondary_startup)
 	b	secondary_startup
 ENDPROC(v7_secondary_startup)
 #endif
+
+ENTRY(v7_cpu_resume)
+	bl	v7_invalidate_l1
+
+	/*
+	 * Restore L2 AUX_CTRL register saved by suspend procedure
+	 * and enable L2
+	 */
+	adr	r4, 1f
+	ldmia	r4, {r5, r6, r7}
+	sub	r4, r4, r5
+	add	r6, r6, r4
+	add	r7, r7, r4
+	ldr	r0, [r6]
+	ldr	r7, [r7]
+	ldr	r1, [r7]
+	str	r1, [r0, #L2X0_AUX_CTRL]
+	ldr	r1, =0x1
+	str	r1, [r0, #L2X0_CTRL]
+
+	b	cpu_resume
+
+	.align
+1:	.long	.
+	.long	pl310_pbase
+	.long	pl310_aux_ctrl_paddr
+ENDPROC(v7_cpu_resume)
diff --git a/arch/arm/mach-imx/pm-imx6q.c b/arch/arm/mach-imx/pm-imx6q.c
new file mode 100644
index 0000000..124bcd5
--- /dev/null
+++ b/arch/arm/mach-imx/pm-imx6q.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/suspend.h>
+#include <asm/proc-fns.h>
+#include <asm/suspend.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <mach/common.h>
+#include <mach/hardware.h>
+
+static void __iomem *pl310_vbase;
+void __iomem *pl310_pbase;
+
+static volatile unsigned long pl310_aux_ctrl;
+volatile unsigned long pl310_aux_ctrl_paddr;
+
+static int imx6q_suspend_finish(unsigned long val)
+{
+	cpu_do_idle();
+	return 0;
+}
+
+static int imx6q_pm_enter(suspend_state_t state)
+{
+	switch (state) {
+	case PM_SUSPEND_MEM:
+		imx6q_set_lpm(STOP_POWER_OFF);
+		imx_gpc_pre_suspend();
+		imx_set_cpu_jump(0, v7_cpu_resume);
+		/* Zzz ... */
+		cpu_suspend(0, imx6q_suspend_finish);
+		imx_smp_prepare();
+		imx_gpc_post_resume();
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static const struct platform_suspend_ops imx6q_pm_ops = {
+	.enter = imx6q_pm_enter,
+	.valid = suspend_valid_only_mem,
+};
+
+void __init imx6q_pm_init(void)
+{
+	struct device_node *np;
+	u32 reg[2];
+
+	np = of_find_compatible_node(NULL, NULL, "arm,pl310-cache");
+	of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg));
+	pl310_vbase = ioremap(reg[0], reg[1]);
+	WARN_ON(!pl310_vbase);
+	pl310_pbase = (void __iomem *) reg[0];
+
+	/*
+	 * On imx6q, during system suspend, ARM core gets powered off,
+	 * but L2 cache is retained.  To avoid cleaning the entire L2,
+	 * we need to save L2 controller registers, and when system gets
+	 * woke up, restore the registers and re-enable L2 before
+	 * calling into cpu_resume().
+	 *
+	 * Most of pl310 configuration upon reset work just fine for
+	 * imx6q, and the only one register we actually need to save is
+	 * AUX_CTRL.  Also since pl310 configuration won't change in a
+	 * live system, we can save it here only once, and restore it
+	 * at resume entry v7_cpu_resume() which runs in physical
+	 * address space.
+	 */
+	pl310_aux_ctrl = readl_relaxed(pl310_vbase + L2X0_AUX_CTRL);
+	pl310_aux_ctrl_paddr = __pa(&pl310_aux_ctrl);
+
+	suspend_set_ops(&imx6q_pm_ops);
+}
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h
index 9c5be7b..6673d7d 100644
--- a/arch/arm/plat-mxc/include/mach/common.h
+++ b/arch/arm/plat-mxc/include/mach/common.h
@@ -13,6 +13,7 @@
 
 struct platform_device;
 struct clk;
+enum mxc_cpu_pwr_mode;
 
 extern void mx1_map_io(void);
 extern void mx21_map_io(void);
@@ -79,14 +80,21 @@ extern void imx_lluart_map_io(void);
 #else
 static inline void imx_lluart_map_io(void) {}
 #endif
+extern void v7_cpu_resume(void);
 #ifdef CONFIG_SMP
 extern void v7_secondary_startup(void);
 extern void imx_scu_map_io(void);
+extern void imx_smp_prepare(void);
 #else
 static inline void imx_scu_map_io(void) {}
+static inline void imx_smp_prepare(void) {}
 #endif
 extern void imx_enable_cpu(int cpu, bool enable);
 extern void imx_set_cpu_jump(int cpu, void *jump_addr);
 extern void imx_src_init(void);
 extern void imx_gpc_init(void);
+extern void imx_gpc_pre_suspend(void);
+extern void imx_gpc_post_resume(void);
+extern int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
+extern void imx6q_pm_init(void);
 #endif
-- 
1.7.4.1

^ permalink raw reply related

* READ THIS: the next mach-types update
From: Jean-Christophe PLAGNIOL-VILLARD @ 2011-09-15 14:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110915102528.GI6267@n2100.arm.linux.org.uk>

On 11:25 Thu 15 Sep     , Russell King - ARM Linux wrote:
> I'm going to be merging a mach-types update (the cut-down and the
> policy-conforming version) for the next merge window.  This will mean
> that things WILL BREAK, and I will not notice that things have broken.
> 
> In order to fix this, entries need to be fixed to conform to the
> requirements - where the machine_is_xxx() name is the same as the
> MACH_TYPE_xxx name and the CONFIG_MACH_xxx name too.
> 
> Moreover, entries older than 12 months which have not been merged will
> be removed.  It is not possible to automatically check for machine_is_xxx()
> usages as these could conflict with other architectures, and I'm
> certainly NOT checking for them by hand (I estimate that'd take a
> significant amount of manual effort to do.)  What that means is that it
> is _important_ to get the core platform support in _first_ before any
> drivers which may make use of this.
> 
> The following will be deleted from the file this time around are:
> -ts_x09                  MACH_TS209              TS209                   1565
> -at572d940hfek           MACH_AT572D940HFEB      AT572D940HFEB           1783
can be dropped the at572d940hfek as the at572d940hf is drop from mainline

Russell an you confirm you will re-add the usb-a9g20 and the folowing one

usb_a9g20               MACH_USB_A9G20          USB_A9G20               1841
qil_a9g20               MACH_QIL_A9G20          QIL_A9G20               1844
tny_a9260               MACH_TNY_A9260          TNY_A9260               2058
tny_a9g20               MACH_TNY_A9G20          TNY_A9G20               2059
tny_a9263               MACH_TNY_A9263          TNY_A9263               2140

I'm working on there port mainline

I add the usb_a9g20 recently and will continue in the following weeks

Best Regards,
J.

^ permalink raw reply

* [RFC 7/8] drivers: introduce rpmsg, a remote-processor messaging bus
From: Ohad Ben-Cohen @ 2011-09-15 14:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <87d3f2hdey.fsf@rustcorp.com.au>

On Thu, Sep 15, 2011 at 3:12 AM, Rusty Russell <rusty@rustcorp.com.au> wrote:
> 7... numbers are cheap :)

7 it is :)

Thanks,
Ohad.

^ permalink raw reply

* [PATCH 0/6] mc13783 cleanup
From: Samuel Ortiz @ 2011-09-15 15:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110824132740.GA28197@pengutronix.de>

Hi Uwe,

On Wed, Aug 24, 2011 at 03:27:40PM +0200, Uwe Kleine-K?nig wrote:
> Hello,
> 
> this series removes the long obsolte mc13783 API after fixing all
> remaining users.
> 
> The patches touch many subsystems and have some interdependencies:
> 
>  - patches 3 and 5 depend on patch 2
>  - patch 6 depends on patches 1-5
> 
> So we have to think about how to merge them when everyone is OK that
> they are merged.
I am merging them, unless someone objects here.
I have applied all 6 patches now.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply

* [PATCH 0/6] mc13783 cleanup
From: Samuel Ortiz @ 2011-09-15 15:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <201108250905.13168.philippe.retornaz@epfl.ch>

Hi Philippe,

On Thu, Aug 25, 2011 at 09:05:12AM +0200, Philippe R?tornaz wrote:
> Le mercredi 24 ao?t 2011 15:27:40, Uwe Kleine-K?nig a ?crit :
> > Hello,
> > 
> > this series removes the long obsolte mc13783 API after fixing all
> > remaining users.
> 
> I posted a patch last month which was touching this MFD too.
> We will need to synchronize both patch. 
I applied Uwe's patchset now. Could you please sync your code and send me a
patchset that applies on top of:

git://git.infradead.org/users/sameo/mfd-2.6.git for-next

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

^ permalink raw reply

* [PATCH v12 0/3] add the GPMI controller driver for IMX23/IMX28
From: gianluca @ 2011-09-15 15:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4E71CDB2.4000205@freescale.com>

Sorry for intrusion in this discussion, but:

Huang Shijie wrote:
>> channels are being used concurrently. The GPMI driver will bail out
>> with the timeout error while the MMC driver obviously has no timeout
>> check for this situation.
>>
>> I can mostly rule out HW problems, because the same board works
>> perfectly well with WindowsCE (tested with a copy operation between
>> flash and SD card).
>>
>>
>> Lothar Wa?mann

@Lothar: Probably WinCE with a copy operation between flash and SD is 
not reliable as synchronous as opposed dd command in the previous mail.

dd is sync when: dd if=/dev/mtd... of=/dev/mmc...

dd is async when:

# dd if=/dev/mtd of=/mnt/somewhere/file1 &
# dd if=/mnt/somewhere/file2 of=/dev/mmc &

Or even the worst scenario:

# dd if=/dev/mtdX of=/dev/null &
# dd if=/dev/urandom of=/dev/mmcX &
# dd if=/dev/mmcX of=/dev/null &
# dd if=/dev/urandom of=/dev/mtdX &

Just my .2 cents.

Best regards,
-- 
            ,,,
           (o o)
======oOO==(_)==OOo======

Gianluca Renzi
R&D
phone: +39.0542.609120
fax:   +39.0542.609212

       .oooO  Oooo.
======(   )==(   )=======
        \ (    ) /
         \_)  (_/

^ permalink raw reply

* READ THIS: the next mach-types update
From: Arnd Bergmann @ 2011-09-15 15:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110915102528.GI6267@n2100.arm.linux.org.uk>

On Thursday 15 September 2011, Russell King - ARM Linux wrote:
> Moreover, entries older than 12 months which have not been merged will
> be removed.  It is not possible to automatically check for machine_is_xxx()
> usages as these could conflict with other architectures, and I'm
> certainly NOT checking for them by hand (I estimate that'd take a
> significant amount of manual effort to do.)  What that means is that it
> is important to get the core platform support in first before any
> drivers which may make use of this.

Hi Russell,

I've just tried checking the machine_is_xxx() values in the kernel for
the list you posted and found just two that are actually being used:

arch/arm/mach-orion5x/ts209-setup.c:    if (machine_is_ts_x09())
arch/arm/mach-kirkwood/sheevaplug-setup.c:      if (machine_is_sheeva_esata())

Would it be possible to just fix these to use the correct form instead,
along with the respective mach-types change?

	Arnd

^ permalink raw reply

* [PATCH v2] [media] at91: add code to initialize and manage the ISI_MCK for Atmel ISI driver.
From: Sylwester Nawrocki @ 2011-09-15 15:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110915132301.GK28104@game.jcrosoft.org>

On 09/15/2011 03:23 PM, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 23:08 Tue 06 Sep     , Sylwester Nawrocki wrote:
>> On 09/06/2011 10:05 PM, Jean-Christophe PLAGNIOL-VILLARD wrote:
>>>> I'm not entirely sure on this one, but as we had a similar situation with
>>>> clocks, we decided to extablish the clock hierarchy in the board code, and
>>>> only deal with the actual device clocks in the driver itself. I.e., we
>>>> moved all clk_set_parent() and setting up the parent clock into the board.
>>>> And I do think, this makes more sense, than doing this in the driver, not
>>>> all users of this driver will need to manage the parent clock, right?
>>>
>>> I don't like to manage the clock in the board except if it's manadatory otherwise
>>> we manage this at soc level

You often just can't decide about clocks hierarchy at SoC level as it
can depend on the board layout and which devices are used on it.

>>>
>>> the driver does not have to manage the clock hierachy or detail implementation
>>> but manage the clock enable/disable and speed depending on it's need

I think everyone agrees on that.

>>
>> We had a similar problem in the past and we ended up having the boot loader
>> setting up the parent clock for the device clock. The driver only controls clock
>> gating and sets its clock frequency based on an internal IP version information,
>> derived from the SoC revision.
> sorry NACK

:) When we tried to upstream the code setting up parent clocks in board files
some people disagreed on that too..

> 
> I do not want to rely on bootloader

Yeah, I don't believe this is best possible solution either..

> when we will have the DT we will pass it via it right now we need find an

I hope this can be be properly resolved with the DT. I thought there is not
much work
going on yet wrt supporting clocks hierarchy in DT though.


> other generic way
> 
> Best Regards,
> J.

-- 
Regards,
Sylwester

^ permalink raw reply

* [GIT PULL] Samsung Fixes for v3.1-rc7
From: Arnd Bergmann @ 2011-09-15 15:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <00b101cc738d$bcf46ce0$36dd46a0$%kim@samsung.com>

On Thursday 15 September 2011, Kukjin Kim wrote:
> This is Samsung fixes for v3.1
> 
> Please pull from:
>   git://github.com/kgene/linux-samsung.git samsung-fixes-2
> As you know, git.kernel.org/master.kernel.org has been down so I use
> temporary git repo. at github now.
> 
> These things are needed for v3.1 and if any problems, please let me know.
> 
> As a note, others for v3.2 will be sent in the next week...

Thanks, pulled.

Is it correct that you want none of these patches to be backported
into the stable or longterm releases? Some of these look like they
should be marked 'Cc: stable at kernel.org'.

	Arnd

^ permalink raw reply

* [PATCH v3 0/2] Add device tree probe for i2c-imx driver
From: Shawn Guo @ 2011-09-15 15:39 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Ben,

Hopefully, you can pick up this version.

Thanks.

Changes since v2:
 * Drop HS-I2C from binding document fsl-imx-i2c.txt

Changes since v1:
 * Fix a couple of typo in fsl-imx-i2c.txt

Shawn Guo (2):
      i2c-imx: remove init/exit hooks from platform data
      i2c-imx: add device tree probe support

 .../devicetree/bindings/i2c/fsl-imx-i2c.txt        |   18 ++++++++
 arch/arm/plat-mxc/include/mach/i2c.h               |    4 --
 drivers/i2c/busses/i2c-imx.c                       |   46 +++++++++----------
 3 files changed, 40 insertions(+), 28 deletions(-)

^ 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