* [PATCH 4/5] input: touchscreen: support Allwinner SoCs' touchscreen
From: Quentin Schulz @ 2016-09-24 18:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160720172532.GE25655@dtor-ws>
Hi Dimitry,
Sorry for the (long) delay, I did not have time to work on it. I'll
mainly work in my free time now.
On 20/07/2016 19:25, Dmitry Torokhov wrote:
> Hi Quentin,
>
> On Wed, Jul 20, 2016 at 10:29:10AM +0200, Quentin Schulz wrote:
>> This adds support for Allwinner SoCs' (A10, A13 and A31) resistive
>> touchscreen. This driver is probed by the MFD sunxi-gpadc-mfd.
>>
>> This driver uses ADC channels exposed through the IIO framework by
>> sunxi-gpadc-iio to get its data. When opening this input device, it will
>> start buffering in the ADC driver and enable a TP_UP_PENDING irq. The ADC
>> driver will fill in a buffer with all data and call the callback the input
>> device associated with this buffer. The input device will then read the
>> buffer two by two and send X and Y coordinates to the input framework based
>> on what it received from the ADC's buffer. When closing this input device,
>> the buffering is stopped.
>>
>> Note that locations in the first received buffer after an TP_UP_PENDING irq
>> occurred are unreliable, thus dropped.
>>
>> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
>> ---
[...]
>> + info->buffer = iio_channel_get_all_cb(&pdev->dev,
>> + &sunxi_gpadc_ts_callback,
>> + (void *)info);
>
> Any chance we could introduce devm-variant here? If you do not want to
> wait for IIO to add it you can temporarily add call
> devm_add_action_or_reset() after getting channels and remove it when IIO
> API catches up.
>
Something like:
release_iio_channels(void* data)
{
struct sunxi_gpadc_ts *info = data;
iio_channel_release_all_cb(info->buffer);
}
[...]
info->buffer = iio_channel_get_all_cb(&pdev->dev,
&sunxi_gpadc_ts_callback,
(void *)info);
ret = devm_add_action_or_reset(&pdev->dev,
release_iio_channels,
(void *)info);
if (ret)
return ret;
?
May I know why you prefer that way instead of explicit removing in
remove function of the platform device? I understand for devm-variant
already in the framework but I am curious for this one.
[...]
>> +static int sunxi_gpadc_ts_remove(struct platform_device *pdev)
>> +{
>> + struct sunxi_gpadc_ts *info = platform_get_drvdata(pdev);
>> +
>> + iio_channel_stop_all_cb(info->buffer);
>> + iio_channel_release_all_cb(info->buffer);
>> +
>> + disable_irq(info->tp_up_irq);
>
> You are mixing devm and non-devm so your unwind order is completely out
> of wack. If input device is opened while you are unloading (or
> unbinding) the dirver, then you'll release channels, then input device's
> close() will be called, which will try to stop the IIO channels again
> and disable IRQ yet again.
>
Do you mean that I should be using exclusively devm or non-devm functions?
Do you mean input device's close will always be called when
unloading/unbinding the driver?
[...]
Thanks,
Quentin
--
Quentin Schulz, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* [PATCH v2] ASoC: rk3399_gru_sound: fix recording pop at first attempt
From: Mark Brown @ 2016-09-24 18:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160923212737.GA17658@rob-hp-laptop>
On Fri, Sep 23, 2016 at 04:27:37PM -0500, Rob Herring wrote:
> On Thu, Sep 22, 2016 at 09:50:06PM +0800, Xing Zheng wrote:
> > From: Wonjoon Lee <woojoo.lee@samsung.com>
> > Pop happens when mclk applied but dmic's own boot-time
> This statement doesn't make sense.
It is very clear if you're familiar with the problem domain - because a
DMIC is digital it's got an on/off state which means that when it
transitions from off and not outputting anything to outputting something
you get a sudden DC transition which manifests as a pop in the audio
output.
> > Specify dmic delay times in dt to make sure
> > clocks are ready earlier than dmic working
> I don't think this really belongs in DT. Seems like better control of
> the init order is needed. Or why not just a fixed delay in the driver?
The changelog says this is due to the DMICs having a startup time of
their own so needing a delay after they've started. That's going to be
a system dependent thing since it'll depend on the specific component
selected and DMICs are easily interchangable.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 455 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160924/30b3993f/attachment.sig>
^ permalink raw reply
* [PATCH 3/5] iio: adc: sunxi-gpadc-iio: enable iio_buffers
From: Quentin Schulz @ 2016-09-24 17:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <ff7515ec-a064-95df-1118-93c7062c2237@kernel.org>
Hi Jonathan,
Sorry for the (long) delay, I did not have time to work on it. I'll
mainly work in my free time now.
Keep in mind this patch was proposed based on the v2 of the ADC patches.
Since then, substantial changes have been made and I'm working on
rebasing this series of patches on the v6, so comments here might
include references to code parts added later in the ADC patch series.
On 24/07/2016 13:03, Jonathan Cameron wrote:
> On 20/07/16 09:29, Quentin Schulz wrote:
>> This enables the use of buffers on ADC channels of sunxi-gpadc-iio driver.
>> It also prepares the code which will be used by the touchscreen driver
>> named sunxi-gpadc-ts.
>>
>> The GPADC on Allwinner SoCs (A10, A13 and A31) has a 12 bits register for
>> conversion's data. The GPADC uses the same ADC channels for the ADC and the
>> touchscreen therefore exposes these channels to the sunxi-gpadc-ts iio
>> consumer which will be in charge of reading data from these channels for
>> the input framework.
>>
>> The temperature can only be read when in touchscreen mode. This means if
>> the buffers are being used for the ADC, the temperature sensor cannot be
>> read.
> That may be the bizarest hardware restriction I've heard of in a while! :)
>>
>> When a FIFO_DATA_PENDING irq occurs, its handler will read the entire FIFO
>> and fill a buffer before sending it to the consumers which registered in
>> IIO for the ADC channels.
>>
>> When a consumer starts buffering ADC channels,
>> sunxi_gpadc_buffer_postenable is called and will enable FIFO_DATA_PENDING
>> irq and select the mode in which the GPADC should run (ADC or touchscreen)
>> depending on a property of the DT ("allwinner,ts-attached").
>> When the consumer stops buffering, it disables the same irq.
> Hmm. Might be possible to distinguish which consumer caused the start.
> Thus, if the touchscreen is there we would know purely based on the
> driver being the requester that we need to be in touchscreen mode.
>
As of yet, can't see in which way I can retrieve the consumer in
provider code. Maybe I'm missing something, I don't know?
>>
>> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
> You are moving fast on this - I'd have been tempted to do a mega
> series with the updated version of the basic support and this on top
> rather than a new unconnected series.
>
> (I'd forgotten that was still under review so got confused when I
> went to look something up in the files you are modifying!).
>> ---
>> drivers/iio/adc/Kconfig | 1 +
>> drivers/iio/adc/sunxi-gpadc-iio.c | 153 ++++++++++++++++++++++++++++++++++----
>> 2 files changed, 138 insertions(+), 16 deletions(-)
>>
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index 184856f..15e3b08 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -342,6 +342,7 @@ config SUNXI_ADC
>> tristate "ADC driver for sunxi platforms"
>> depends on IIO
>> depends on MFD_SUNXI_ADC
>> + depends on IIO_BUFFER_CB
>> help
>> Say yes here to build support for Allwinner (A10, A13 and A31) SoCs
>> ADC. This ADC provides 4 channels which can be used as an ADC or as a
>> diff --git a/drivers/iio/adc/sunxi-gpadc-iio.c b/drivers/iio/adc/sunxi-gpadc-iio.c
>> index 87cc913..2e44ca7 100644
>> --- a/drivers/iio/adc/sunxi-gpadc-iio.c
>> +++ b/drivers/iio/adc/sunxi-gpadc-iio.c
>> @@ -16,8 +16,9 @@
>> #include <linux/platform_device.h>
>> #include <linux/regmap.h>
>>
>> -#include <linux/iio/iio.h>
>> +#include <linux/iio/buffer.h>
>> #include <linux/iio/driver.h>
>> +#include <linux/iio/iio.h>
> Can't say I'm a particular fan of reordering headers to be in alphabetical
> order, but I suppose it doesn't really matter if you want to do it.
> (to my mind there is a tree structure implicit in these headers with iio.h
> at the top for generic support, then the various sub elements below).
>
>> #include <linux/iio/machine.h>
>> #include <linux/mfd/sunxi-gpadc-mfd.h>
>>
>> @@ -71,6 +72,7 @@
>> #define SUNXI_GPADC_TP_DATA_XY_CHANGE BIT(13)
>> #define SUNXI_GPADC_TP_FIFO_TRIG_LEVEL(x) ((x) << 8) /* 5 bits */
>> #define SUNXI_GPADC_TP_DATA_DRQ_EN BIT(7)
>> +/* Be careful, flushing FIFO spawns SUNXI_GPADC_FIFO_DATA_PENDING interrupts */
> Sounds like you learned that one the hard way ;)
>> #define SUNXI_GPADC_TP_FIFO_FLUSH BIT(4)
>> #define SUNXI_GPADC_TP_UP_IRQ_EN BIT(1)
>> #define SUNXI_GPADC_TP_DOWN_IRQ_EN BIT(0)
>> @@ -79,6 +81,7 @@
>> #define SUNXI_GPADC_TEMP_DATA_PENDING BIT(18)
>> #define SUNXI_GPADC_FIFO_OVERRUN_PENDING BIT(17)
>> #define SUNXI_GPADC_FIFO_DATA_PENDING BIT(16)
>> +#define SUNXI_GPADC_RXA_CNT GENMASK(12, 8)
>> #define SUNXI_GPADC_TP_IDLE_FLG BIT(2)
>> #define SUNXI_GPADC_TP_UP_PENDING BIT(1)
>> #define SUNXI_GPADC_TP_DOWN_PENDING BIT(0)
>> @@ -101,19 +104,43 @@ struct sunxi_gpadc_dev {
>> unsigned int fifo_data_irq;
>> unsigned int temp_data_irq;
>> unsigned int flags;
>> + struct iio_dev *indio_dev;
> I was suprised to see this as normally it is cleaner to structure
> the whole code to go in one direction through the structures (which is
> why we don't provide a generic iio_device_from_priv bit of pointer magic).
>
> Anyhow, don't htink you are actually using it ;)
>
I'm using to push to buffers from the irq handler since I pass the local
structure (sunxi_gpadc_dev) to the irq handler when registering it. But
I guess I can pass the iio_dev instead and remove this from the local
structure.
[...]
>> static int sunxi_gpadc_adc_read(struct iio_dev *indio_dev, int channel,
>> int *val)
>> {
>> struct sunxi_gpadc_dev *info = iio_priv(indio_dev);
>> + bool buffered = info->buffered;
> Not worth the local version...
>> int ret = 0;
>> + unsigned int reg;
>>
>> mutex_lock(&indio_dev->mlock);
>>
>> reinit_completion(&info->completion);
>> +
>> + reg = SUNXI_GPADC_TP_FIFO_TRIG_LEVEL(1) | SUNXI_GPADC_TP_FIFO_FLUSH;
>> + regmap_update_bits(info->regmap, SUNXI_GPADC_TP_INT_FIFOC, reg, reg);
> I'd put it in directly rahter than having a reg local variable. To mind
> mind that would be slightly easier to understand.
>> +
>> if (info->flags & SUNXI_GPADC_ARCH_SUN6I)
>> regmap_write(info->regmap, SUNXI_GPADC_TP_CTRL1,
>> SUNXI_GPADC_SUN6I_TP_MODE_EN |
>> @@ -153,9 +185,9 @@ static int sunxi_gpadc_adc_read(struct iio_dev *indio_dev, int channel,
>> SUNXI_GPADC_TP_MODE_EN |
>> SUNXI_GPADC_TP_ADC_SELECT |
>> SUNXI_GPADC_ADC_CHAN_SELECT(channel));
>> - regmap_write(info->regmap, SUNXI_GPADC_TP_INT_FIFOC,
>> - SUNXI_GPADC_TP_FIFO_TRIG_LEVEL(1) |
>> - SUNXI_GPADC_TP_FIFO_FLUSH);
> Whole load of infrastructure in place to lock buffered mode out and
> revent transitions when we can't have them.
>
> iio_claim_direct_mode etc. I think you can just use that here?
> If you need to do extra checks on it being enabled that should be
> fine too.
>
Yes, way better with iio_device_claim_direct_mode and iio_buffer_enabled!
> As a general rule, it makes sense to simply disable polled reads
> if in buffered mode. Leads to much simpler code and generally
> the data is already known to userspace anyway.
>
That's what I try to do.
However, I think the temperature of the SoC is an interesting feature to
have. Since it ("hardwarely") works while the ADC is read in touchscreen
mode (even in buffer mode), I guess it could be a good idea to allow it
in the driver. If we don't do that, boards with a touchscreen connected
to the ADC of the SoC will not get SoC temperatures and can't have
proper thermal management. We already have one board in that case: the
PocketCHIP.
Therefore, I also need to know if when the buffer is enabled, if it's
for buffering ADC data or touchscreen data. If it's for ADC data, then I
should disable temperature readings since it will return senseless
values (from memory, always 0 which means something like -144?C).
> I have been meaning to do it a bit better when we have multiple
> in kernel consumers, some expecting polled readings and some
> pushed. There some core caching magic will make sense to
> keep the polled channels as available as possible when running
> the buffers.
>
> A bit fiddly to implement + might have some slightly suprising
> results on delays on channels when say a sysfs trigger is
> being used... (not a problem here as you have a fifo and hence
> aren't using triggers).
>
> Anyhow, not really relevant here :)
>
[...]
>> case IIO_CHAN_INFO_RAW:
> Definitely use the iio_claim_direct_mode stuff here to avoid possible races
> with the buffer being enabled whilst this read is in flight.
Indeed.
>> + if (info->buffered)
>> + return -EBUSY;
>> +
>> ret = sunxi_gpadc_adc_read(indio_dev, chan->channel, val);
>> if (ret)
>> return ret;
>> @@ -261,7 +302,29 @@ static irqreturn_t sunxi_gpadc_temp_data_irq_handler(int irq, void *dev_id)
>> static irqreturn_t sunxi_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
>> {
>> struct sunxi_gpadc_dev *info = dev_id;
>> - int ret;
>> + int ret, reg, i, fifo_count;
>> +
>> + if (info->buffered) {
>> + if (regmap_read(info->regmap, SUNXI_GPADC_TP_INT_FIFOS, ®))
>> + return IRQ_HANDLED;
>> +
>> + fifo_count = (reg & SUNXI_GPADC_RXA_CNT) >> 8;
>> + /* Sometimes, the interrupt occurs when the FIFO is empty. */
>> + if (!fifo_count)
>> + return IRQ_HANDLED;
>> +
>> + for (i = 0; i < fifo_count; i++) {
>> + if (regmap_read(info->regmap, SUNXI_GPADC_TP_DATA,
>> + &info->buffer.buffer[i]))
>> + return IRQ_HANDLED;
>> + }
>> +
>> + info->buffer.buff_size = i;
>> +
>> + iio_push_to_buffers(info->indio_dev, &info->buffer);
> This is expecting a single 'scan' - e.g. set of channels read at one
> time. Here I think we could have repeated sets of channels?
> (at least that would be what is normally meant by a fifo in such
> a device).
>
> If so you need to read 'whole' scans and push them one at a time.
> We don't yet have a bulk iio_push_to_buffers, though we can add
> one if it makes sense. Care will be needed though as we'd need
> handle the case of different consumers either supporting or
> not supporting this new functionality. Not particularly hard though
> if it is worth doing.
I didn't know it was meant for only one scan. Then I need a bulk
iio_push_to_buffers.
I have a rather big problem. The whole first FIFO at each touch is
unusable so I have to drop it. I can detect the beginning of a touch
when the TP_UP irq occurs, then I know the next full FIFO the consumer
receives by callback is to be dropped. If I use push_to_buffers to send
coordinates by coordinates, the consumer has no mean to know when the
second FIFO (the first to be valid) starts and can be used. Either we
can find a way to notify the consumer of the start of a new FIFO or I
have to use a bulk iio_push_to_buffers.
The workaround would be to register the TP_UP irq in the provider (the
ADC driver) and do not send the first FIFO to the consumer. But then, we
need a way to know which consumer requests buffering to know when to
enable this irq and do all touchscreen-only logic (dropping first
frame). And I guess we don't have something like that yet. Or I could
only code a buffering in touchscreen mode and add the ADC buffering
later? But it doesn't feel right to do what I think should be handled
(TP_UP irq handler and first FIFO dropping) in the consumer, in the
provider.
So it's quiet a dead-end yet if I can't use iio_push_to_buffers with a
whole FIFO (which you told is not how it is meant to be used).
[...]
Thanks,
Quentin
--
Quentin Schulz, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* [PATCH v3] gpio: Added zynq specific check for special pins on bank zero
From: Vesa Jääskeläinen @ 2016-09-24 15:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474630018-9986-1-git-send-email-navam@xilinx.com>
On 23/09/2016 14.26, Nava kishore Manne wrote:
> From: Nava kishore Manne <nava.manne@xilinx.com>
>
> This patch adds zynq specific check for bank 0 pins 7 and 8
> are special and cannot be used as inputs
>
> Signed-off-by: Nava kishore Manne <navam@xilinx.com>
> Reported-by: Jonas Karlsson <Jonas.d.karlsson@gmail.com>
> Acked-by: S?ren Brinkmann <soren.brinkmann@xilinx.com>
> Acked-by: Michal Simek <michal.simek@xilinx.com>
> ---
> Changes for v3:
> -Fixed some minor comments.
> Changes for v2:
> -Removed un-used quirks for zynqmp.
>
> drivers/gpio/gpio-zynq.c | 15 +++++++++++++--
> 1 file changed, 13 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
> index e72794e..6b4d10d 100644
> --- a/drivers/gpio/gpio-zynq.c
> +++ b/drivers/gpio/gpio-zynq.c
> @@ -96,6 +96,9 @@
> /* GPIO upper 16 bit mask */
> #define ZYNQ_GPIO_UPPER_MASK 0xFFFF0000
>
> +/* For GPIO quirks */
> +#define ZYNQ_GPIO_QUIRK_FOO BIT(0)
Should this be a bit more descriptive than FOO?
^ permalink raw reply
* [PATCH v2 2/2] drm: zte: add initial vou drm driver
From: Shawn Guo @ 2016-09-24 14:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474727185-24180-1-git-send-email-shawn.guo@linaro.org>
It adds the initial ZTE VOU display controller DRM driver. There are
still some features to be added, like overlay plane, scaling, and more
output devices support. But it's already useful with dual CRTCs and
HDMI monitor working.
It's been tested on Debian Jessie LXDE desktop with modesetting driver.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
drivers/gpu/drm/Kconfig | 2 +
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/zte/Kconfig | 8 +
drivers/gpu/drm/zte/Makefile | 8 +
drivers/gpu/drm/zte/zx_crtc.c | 691 +++++++++++++++++++++++++++++++++++++++
drivers/gpu/drm/zte/zx_crtc.h | 47 +++
drivers/gpu/drm/zte/zx_drm_drv.c | 258 +++++++++++++++
drivers/gpu/drm/zte/zx_drm_drv.h | 22 ++
drivers/gpu/drm/zte/zx_hdmi.c | 540 ++++++++++++++++++++++++++++++
drivers/gpu/drm/zte/zx_plane.c | 362 ++++++++++++++++++++
drivers/gpu/drm/zte/zx_plane.h | 26 ++
11 files changed, 1965 insertions(+)
create mode 100644 drivers/gpu/drm/zte/Kconfig
create mode 100644 drivers/gpu/drm/zte/Makefile
create mode 100644 drivers/gpu/drm/zte/zx_crtc.c
create mode 100644 drivers/gpu/drm/zte/zx_crtc.h
create mode 100644 drivers/gpu/drm/zte/zx_drm_drv.c
create mode 100644 drivers/gpu/drm/zte/zx_drm_drv.h
create mode 100644 drivers/gpu/drm/zte/zx_hdmi.c
create mode 100644 drivers/gpu/drm/zte/zx_plane.c
create mode 100644 drivers/gpu/drm/zte/zx_plane.h
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 483059a22b1b..a91f8cecbe0f 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -223,6 +223,8 @@ source "drivers/gpu/drm/hisilicon/Kconfig"
source "drivers/gpu/drm/mediatek/Kconfig"
+source "drivers/gpu/drm/zte/Kconfig"
+
# Keep legacy drivers last
menuconfig DRM_LEGACY
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 439d89b25ae0..fe461c94d266 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -85,3 +85,4 @@ obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
obj-$(CONFIG_DRM_ARCPGU)+= arc/
obj-y += hisilicon/
+obj-$(CONFIG_DRM_ZTE) += zte/
diff --git a/drivers/gpu/drm/zte/Kconfig b/drivers/gpu/drm/zte/Kconfig
new file mode 100644
index 000000000000..4065b2840f1c
--- /dev/null
+++ b/drivers/gpu/drm/zte/Kconfig
@@ -0,0 +1,8 @@
+config DRM_ZTE
+ tristate "DRM Support for ZTE SoCs"
+ depends on DRM && ARCH_ZX
+ select DRM_KMS_CMA_HELPER
+ select DRM_KMS_FB_HELPER
+ select DRM_KMS_HELPER
+ help
+ Choose this option to enable DRM on ZTE ZX SoCs.
diff --git a/drivers/gpu/drm/zte/Makefile b/drivers/gpu/drm/zte/Makefile
new file mode 100644
index 000000000000..b40968dc749f
--- /dev/null
+++ b/drivers/gpu/drm/zte/Makefile
@@ -0,0 +1,8 @@
+zxdrm-y := \
+ zx_drm_drv.o \
+ zx_crtc.o \
+ zx_plane.o \
+ zx_hdmi.o
+
+obj-$(CONFIG_DRM_ZTE) += zxdrm.o
+
diff --git a/drivers/gpu/drm/zte/zx_crtc.c b/drivers/gpu/drm/zte/zx_crtc.c
new file mode 100644
index 000000000000..818bf9072573
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_crtc.c
@@ -0,0 +1,691 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ * Copyright 2016 ZTE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_plane_helper.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of_address.h>
+#include <video/videomode.h>
+
+#include "zx_drm_drv.h"
+#include "zx_crtc.h"
+#include "zx_plane.h"
+
+/* OSD (GPC_GLOBAL) registers */
+#define OSD_INT_STA 0x04
+#define OSD_INT_CLRSTA 0x08
+#define OSD_INT_MSK 0x0c
+#define OSD_INT_AUX_UPT BIT(14)
+#define OSD_INT_MAIN_UPT BIT(13)
+#define OSD_INT_GL1_LBW BIT(10)
+#define OSD_INT_GL0_LBW BIT(9)
+#define OSD_INT_VL2_LBW BIT(8)
+#define OSD_INT_VL1_LBW BIT(7)
+#define OSD_INT_VL0_LBW BIT(6)
+#define OSD_INT_BUS_ERR BIT(3)
+#define OSD_INT_CFG_ERR BIT(2)
+#define OSD_INT_ERROR (\
+ OSD_INT_GL1_LBW | OSD_INT_GL0_LBW | \
+ OSD_INT_VL2_LBW | OSD_INT_VL1_LBW | OSD_INT_VL0_LBW | \
+ OSD_INT_BUS_ERR | OSD_INT_CFG_ERR \
+)
+#define OSD_INT_ENABLE (OSD_INT_ERROR | OSD_INT_AUX_UPT | OSD_INT_MAIN_UPT)
+#define OSD_CTRL0 0x10
+#define OSD_CTRL0_GL0_EN BIT(7)
+#define OSD_CTRL0_GL0_SEL BIT(6)
+#define OSD_CTRL0_GL1_EN BIT(5)
+#define OSD_CTRL0_GL1_SEL BIT(4)
+#define OSD_RST_CLR 0x1c
+#define RST_PER_FRAME BIT(19)
+
+/* Main/Aux channel registers */
+#define OSD_MAIN_CHN 0x470
+#define OSD_AUX_CHN 0x4d0
+#define CHN_CTRL0 0x00
+#define CHN_ENABLE BIT(0)
+#define CHN_CTRL1 0x04
+#define CHN_SCREEN_W_SHIFT 18
+#define CHN_SCREEN_W_MASK (0x1fff << CHN_SCREEN_W_SHIFT)
+#define CHN_SCREEN_H_SHIFT 5
+#define CHN_SCREEN_H_MASK (0x1fff << CHN_SCREEN_H_SHIFT)
+#define CHN_UPDATE 0x08
+
+/* TIMING_CTRL registers */
+#define TIMING_TC_ENABLE 0x04
+#define AUX_TC_EN BIT(1)
+#define MAIN_TC_EN BIT(0)
+#define FIR_MAIN_ACTIVE 0x08
+#define FIR_AUX_ACTIVE 0x0c
+#define FIR_MAIN_H_TIMING 0x10
+#define FIR_MAIN_V_TIMING 0x14
+#define FIR_AUX_H_TIMING 0x18
+#define FIR_AUX_V_TIMING 0x1c
+#define SYNC_WIDE_SHIFT 22
+#define SYNC_WIDE_MASK (0x3ff << SYNC_WIDE_SHIFT)
+#define BACK_PORCH_SHIFT 11
+#define BACK_PORCH_MASK (0x7ff << BACK_PORCH_SHIFT)
+#define FRONT_PORCH_SHIFT 0
+#define FRONT_PORCH_MASK (0x7ff << FRONT_PORCH_SHIFT)
+#define TIMING_CTRL 0x20
+#define AUX_POL_SHIFT 3
+#define AUX_POL_MASK (0x7 << AUX_POL_SHIFT)
+#define MAIN_POL_SHIFT 0
+#define MAIN_POL_MASK (0x7 << MAIN_POL_SHIFT)
+#define POL_DE_SHIFT 2
+#define POL_VSYNC_SHIFT 1
+#define POL_HSYNC_SHIFT 0
+#define TIMING_INT_CTRL 0x24
+#define TIMING_INT_STATE 0x28
+#define TIMING_INT_AUX_FRAME BIT(3)
+#define TIMING_INT_MAIN_FRAME BIT(1)
+#define TIMING_INT_AUX_FRAME_SEL_VSW (0x2 << 10)
+#define TIMING_INT_MAIN_FRAME_SEL_VSW (0x2 << 6)
+#define TIMING_INT_ENABLE (\
+ TIMING_INT_MAIN_FRAME_SEL_VSW | TIMING_INT_AUX_FRAME_SEL_VSW | \
+ TIMING_INT_MAIN_FRAME | TIMING_INT_AUX_FRAME \
+)
+#define TIMING_MAIN_SHIFT 0x2c
+#define TIMING_AUX_SHIFT 0x30
+#define H_SHIFT_VAL 0x0048
+#define TIMING_MAIN_PI_SHIFT 0x68
+#define TIMING_AUX_PI_SHIFT 0x6c
+#define H_PI_SHIFT_VAL 0x000f
+
+/* DTRC registers */
+#define DTRC_F0_CTRL 0x2c
+#define DTRC_F1_CTRL 0x5c
+#define DTRC_DECOMPRESS_BYPASS BIT(17)
+#define DTRC_DETILE_CTRL 0x68
+#define TILE2RASTESCAN_BYPASS_MODE BIT(30)
+#define DETILE_ARIDR_MODE_MASK (0x3 << 0)
+#define DETILE_ARID_ALL 0
+#define DETILE_ARID_IN_ARIDR 1
+#define DETILE_ARID_BYP_BUT_ARIDR 2
+#define DETILE_ARID_IN_ARIDR2 3
+#define DTRC_ARID 0x6c
+#define DTRC_DEC2DDR_ARID 0x70
+
+/* VOU_CTRL registers */
+#define VOU_INF_EN 0x00
+#define VOU_INF_CH_SEL 0x04
+#define VOU_INF_DATA_SEL 0x08
+#define VOU_SOFT_RST 0x14
+#define VOU_CLK_SEL 0x18
+#define VOU_CLK_GL1_SEL BIT(5)
+#define VOU_CLK_GL0_SEL BIT(4)
+#define VOU_CLK_REQEN 0x20
+#define VOU_CLK_EN 0x24
+
+/* OTFPPU_CTRL registers */
+#define OTFPPU_RSZ_DATA_SOURCE 0x04
+
+#define GL_NUM 2
+#define VL_NUM 3
+
+enum vou_chn_type {
+ VOU_CHN_MAIN,
+ VOU_CHN_AUX,
+};
+
+struct zx_crtc {
+ struct drm_crtc crtc;
+ struct drm_plane *primary;
+ struct device *dev;
+ void __iomem *chnreg;
+ enum vou_chn_type chn_type;
+ struct clk *pixclk;
+};
+
+#define to_zx_crtc(x) container_of(crtc, struct zx_crtc, crtc)
+
+struct zx_vou_hw {
+ struct device *dev;
+ void __iomem *osd;
+ void __iomem *timing;
+ void __iomem *vouctl;
+ void __iomem *otfppu;
+ void __iomem *dtrc;
+ struct clk *axi_clk;
+ struct clk *ppu_clk;
+ struct clk *main_clk;
+ struct clk *aux_clk;
+ struct zx_crtc *main_crtc;
+ struct zx_crtc *aux_crtc;
+};
+
+static inline bool is_main_crtc(struct drm_crtc *crtc)
+{
+ struct zx_crtc *zcrtc = to_zx_crtc(crtc);
+
+ return zcrtc->chn_type == VOU_CHN_MAIN;
+}
+
+void vou_inf_enable(struct vou_inf *inf)
+{
+ struct drm_encoder *encoder = inf->encoder;
+ struct drm_device *drm = encoder->dev;
+ struct zx_drm_private *priv = drm->dev_private;
+ struct zx_vou_hw *vou = priv->vou;
+ bool is_main = is_main_crtc(encoder->crtc);
+ u32 data_sel_shift = inf->id << 1;
+ u32 val;
+
+ /* Select data format */
+ val = readl(vou->vouctl + VOU_INF_DATA_SEL);
+ val &= ~(0x3 << data_sel_shift);
+ val |= inf->data_sel << data_sel_shift;
+ writel(val, vou->vouctl + VOU_INF_DATA_SEL);
+
+ /* Select channel */
+ val = readl(vou->vouctl + VOU_INF_CH_SEL);
+ if (is_main)
+ val &= ~(1 << inf->id);
+ else
+ val |= 1 << inf->id;
+ writel(val, vou->vouctl + VOU_INF_CH_SEL);
+
+ /* Select interface clocks */
+ val = readl(vou->vouctl + VOU_CLK_SEL);
+ if (is_main)
+ val &= ~inf->clocks_sel_bits;
+ else
+ val |= inf->clocks_sel_bits;
+ writel(val, vou->vouctl + VOU_CLK_SEL);
+
+ /* Enable interface clocks */
+ val = readl(vou->vouctl + VOU_CLK_EN);
+ val |= inf->clocks_en_bits;
+ writel(val, vou->vouctl + VOU_CLK_EN);
+
+ /* Enable the device */
+ val = readl(vou->vouctl + VOU_INF_EN);
+ val |= 1 << inf->id;
+ writel(val, vou->vouctl + VOU_INF_EN);
+}
+
+void vou_inf_disable(struct vou_inf *inf)
+{
+ struct drm_encoder *encoder = inf->encoder;
+ struct drm_device *drm = encoder->dev;
+ struct zx_drm_private *priv = drm->dev_private;
+ struct zx_vou_hw *vou = priv->vou;
+ u32 val;
+
+ /* Disable the device */
+ val = readl(vou->vouctl + VOU_INF_EN);
+ val &= ~(1 << inf->id);
+ writel(val, vou->vouctl + VOU_INF_EN);
+
+ /* Disable interface clocks */
+ val = readl(vou->vouctl + VOU_CLK_EN);
+ val &= ~inf->clocks_en_bits;
+ writel(val, vou->vouctl + VOU_CLK_EN);
+}
+
+static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
+{
+ writel(1, zcrtc->chnreg + CHN_UPDATE);
+}
+
+static void zx_crtc_enable(struct drm_crtc *crtc)
+{
+ struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+ struct zx_crtc *zcrtc = to_zx_crtc(crtc);
+ struct zx_vou_hw *vou = dev_get_drvdata(zcrtc->dev);
+ bool is_main = is_main_crtc(crtc);
+ struct videomode vm;
+ u32 pol = 0;
+ u32 val;
+
+ drm_display_mode_to_videomode(mode, &vm);
+
+ /* Set up timing parameters */
+ val = (vm.vactive - 1) << 16;
+ val |= (vm.hactive - 1) & 0xffff;
+ writel(val, vou->timing + (is_main ? FIR_MAIN_ACTIVE : FIR_AUX_ACTIVE));
+
+ val = ((vm.hsync_len - 1) << SYNC_WIDE_SHIFT) & SYNC_WIDE_MASK;
+ val |= ((vm.hback_porch - 1) << BACK_PORCH_SHIFT) & BACK_PORCH_MASK;
+ val |= ((vm.hfront_porch - 1) << FRONT_PORCH_SHIFT) & FRONT_PORCH_MASK;
+ writel(val, vou->timing + (is_main ? FIR_MAIN_H_TIMING :
+ FIR_AUX_H_TIMING));
+
+ val = ((vm.vsync_len - 1) << SYNC_WIDE_SHIFT) & SYNC_WIDE_MASK;
+ val |= ((vm.vback_porch - 1) << BACK_PORCH_SHIFT) & BACK_PORCH_MASK;
+ val |= ((vm.vfront_porch - 1) << FRONT_PORCH_SHIFT) & FRONT_PORCH_MASK;
+ writel(val, vou->timing + (is_main ? FIR_MAIN_V_TIMING :
+ FIR_AUX_V_TIMING));
+
+ /* Set up polarities */
+ if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW)
+ pol |= 1 << POL_VSYNC_SHIFT;
+ if (vm.flags & DISPLAY_FLAGS_HSYNC_LOW)
+ pol |= 1 << POL_HSYNC_SHIFT;
+
+ val = readl(vou->timing + TIMING_CTRL);
+ val &= ~(is_main ? MAIN_POL_MASK : AUX_POL_MASK);
+ val |= pol << (is_main ? MAIN_POL_SHIFT : AUX_POL_SHIFT);
+ writel(val, vou->timing + TIMING_CTRL);
+
+ /* Setup SHIFT register by following what ZTE BSP does */
+ writel(H_SHIFT_VAL, vou->timing + (is_main ? TIMING_MAIN_SHIFT :
+ TIMING_AUX_SHIFT));
+ writel(H_PI_SHIFT_VAL, vou->timing + (is_main ? TIMING_MAIN_PI_SHIFT :
+ TIMING_AUX_PI_SHIFT));
+
+ /* Enable TIMING_CTRL */
+ val = readl(vou->timing + TIMING_TC_ENABLE);
+ val |= is_main ? MAIN_TC_EN : AUX_TC_EN;
+ writel(val, vou->timing + TIMING_TC_ENABLE);
+
+ /* Configure channel screen size */
+ val = readl(zcrtc->chnreg + CHN_CTRL1);
+ val &= ~(CHN_SCREEN_W_MASK | CHN_SCREEN_H_MASK);
+ val |= (vm.hactive << CHN_SCREEN_W_SHIFT) & CHN_SCREEN_W_MASK;
+ val |= (vm.vactive << CHN_SCREEN_H_SHIFT) & CHN_SCREEN_H_MASK;
+ writel(val, zcrtc->chnreg + CHN_CTRL1);
+
+ /* Update channel */
+ vou_chn_set_update(zcrtc);
+
+ /* Enable channel */
+ val = readl(zcrtc->chnreg + CHN_CTRL0);
+ val |= CHN_ENABLE;
+ writel(val, zcrtc->chnreg + CHN_CTRL0);
+
+ /* Enable Graphic Layer */
+ val = readl(vou->osd + OSD_CTRL0);
+ val |= is_main ? OSD_CTRL0_GL0_EN : OSD_CTRL0_GL1_EN;
+ writel(val, vou->osd + OSD_CTRL0);
+
+ drm_crtc_vblank_on(crtc);
+
+ /* Enable pixel clock */
+ clk_set_rate(zcrtc->pixclk, mode->clock * 1000);
+ clk_prepare_enable(zcrtc->pixclk);
+}
+
+static void zx_crtc_disable(struct drm_crtc *crtc)
+{
+ struct zx_crtc *zcrtc = to_zx_crtc(crtc);
+ struct zx_vou_hw *vou = dev_get_drvdata(zcrtc->dev);
+ bool is_main = is_main_crtc(crtc);
+ u32 val;
+
+ clk_disable_unprepare(zcrtc->pixclk);
+
+ drm_crtc_vblank_off(crtc);
+
+ /* Disable Graphic Layer */
+ val = readl(vou->osd + OSD_CTRL0);
+ val &= ~(is_main ? OSD_CTRL0_GL0_EN : OSD_CTRL0_GL1_EN);
+ writel(val, vou->osd + OSD_CTRL0);
+
+ /* Disable channel */
+ val = readl(zcrtc->chnreg + CHN_CTRL0);
+ val &= ~CHN_ENABLE;
+ writel(val, zcrtc->chnreg + CHN_CTRL0);
+
+ /* Disable TIMING_CTRL */
+ val = readl(vou->timing + TIMING_TC_ENABLE);
+ val &= ~(is_main ? MAIN_TC_EN : AUX_TC_EN);
+ writel(val, vou->timing + TIMING_TC_ENABLE);
+}
+
+static void zx_crtc_atomic_begin(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct drm_pending_vblank_event *event = crtc->state->event;
+
+ if (event) {
+ crtc->state->event = NULL;
+
+ spin_lock_irq(&crtc->dev->event_lock);
+ if (drm_crtc_vblank_get(crtc) == 0)
+ drm_crtc_arm_vblank_event(crtc, event);
+ else
+ drm_crtc_send_vblank_event(crtc, event);
+ spin_unlock_irq(&crtc->dev->event_lock);
+ }
+}
+
+static const struct drm_crtc_helper_funcs zx_crtc_helper_funcs = {
+ .enable = zx_crtc_enable,
+ .disable = zx_crtc_disable,
+ .atomic_begin = zx_crtc_atomic_begin,
+};
+
+static const struct drm_crtc_funcs zx_crtc_funcs = {
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .reset = drm_atomic_helper_crtc_reset,
+ .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+};
+
+static struct zx_crtc *zx_crtc_init(struct drm_device *drm,
+ enum vou_chn_type chn_type)
+{
+ struct zx_drm_private *priv = drm->dev_private;
+ struct zx_vou_hw *vou = priv->vou;
+ struct device *dev = vou->dev;
+ struct zx_layer_data data;
+ struct zx_crtc *zcrtc;
+ int ret;
+
+ zcrtc = devm_kzalloc(dev, sizeof(*zcrtc), GFP_KERNEL);
+ if (!zcrtc)
+ return ERR_PTR(-ENOMEM);
+
+ zcrtc->dev = dev;
+ zcrtc->chn_type = chn_type;
+
+ if (chn_type == VOU_CHN_MAIN) {
+ data.layer = vou->osd + 0x130;
+ data.csc = vou->osd + 0x580;
+ data.hbsc = vou->osd + 0x820;
+ data.rsz = vou->otfppu + 0x600;
+ zcrtc->chnreg = vou->osd + OSD_MAIN_CHN;
+ } else {
+ data.layer = vou->osd + 0x200;
+ data.csc = vou->osd + 0x5d0;
+ data.hbsc = vou->osd + 0x860;
+ data.rsz = vou->otfppu + 0x800;
+ zcrtc->chnreg = vou->osd + OSD_AUX_CHN;
+ }
+
+ zcrtc->pixclk = devm_clk_get(dev, (chn_type == VOU_CHN_MAIN) ?
+ "main_wclk" : "aux_wclk");
+ if (IS_ERR(zcrtc->pixclk))
+ return ERR_PTR(PTR_ERR(zcrtc->pixclk));
+
+ zcrtc->primary = zx_plane_init(drm, dev, &data, DRM_PLANE_TYPE_PRIMARY);
+ if (IS_ERR(zcrtc->primary))
+ return ERR_PTR(PTR_ERR(zcrtc->primary));
+
+ ret = drm_crtc_init_with_planes(drm, &zcrtc->crtc, zcrtc->primary, NULL,
+ &zx_crtc_funcs, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_crtc_helper_add(&zcrtc->crtc, &zx_crtc_helper_funcs);
+
+ return zcrtc;
+}
+
+int zx_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe)
+{
+ struct zx_drm_private *priv = drm->dev_private;
+ struct zx_vou_hw *vou = priv->vou;
+ u32 intctl;
+
+ intctl = readl(vou->timing + TIMING_INT_CTRL);
+ if (pipe == 0)
+ intctl |= TIMING_INT_MAIN_FRAME;
+ else
+ intctl |= TIMING_INT_AUX_FRAME;
+ writel(intctl, vou->timing + TIMING_INT_CTRL);
+
+ return 0;
+}
+
+void zx_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe)
+{
+ struct zx_drm_private *priv = drm->dev_private;
+ struct zx_vou_hw *vou = priv->vou;
+ u32 intctl;
+
+ intctl = readl(vou->timing + TIMING_INT_CTRL);
+ if (pipe == 0)
+ intctl &= ~TIMING_INT_MAIN_FRAME;
+ else
+ intctl &= ~TIMING_INT_AUX_FRAME;
+ writel(intctl, vou->timing + TIMING_INT_CTRL);
+}
+
+static irqreturn_t vou_irq_handler(int irq, void *dev_id)
+{
+ struct zx_vou_hw *vou = dev_id;
+ u32 state;
+
+ /* Handle TIMING_CTRL frame interrupts */
+ state = readl(vou->timing + TIMING_INT_STATE);
+ writel(state, vou->timing + TIMING_INT_STATE);
+
+ if (state & TIMING_INT_MAIN_FRAME)
+ drm_crtc_handle_vblank(&vou->main_crtc->crtc);
+
+ if (state & TIMING_INT_AUX_FRAME)
+ drm_crtc_handle_vblank(&vou->aux_crtc->crtc);
+
+ /* Handle OSD interrupts */
+ state = readl(vou->osd + OSD_INT_STA);
+ writel(state, vou->osd + OSD_INT_CLRSTA);
+
+ if (state & OSD_INT_MAIN_UPT) {
+ vou_chn_set_update(vou->main_crtc);
+ zx_plane_set_update(vou->main_crtc->primary);
+ }
+
+ if (state & OSD_INT_AUX_UPT) {
+ vou_chn_set_update(vou->aux_crtc);
+ zx_plane_set_update(vou->aux_crtc->primary);
+ }
+
+ if (state & OSD_INT_ERROR)
+ dev_err(vou->dev, "OSD ERROR: 0x%08x!\n", state);
+
+ return IRQ_HANDLED;
+}
+
+static void vou_dtrc_init(struct zx_vou_hw *vou)
+{
+ u32 val;
+
+ val = readl(vou->dtrc + DTRC_DETILE_CTRL);
+ /* Clear bit for bypass by ID */
+ val &= ~TILE2RASTESCAN_BYPASS_MODE;
+ /* Select ARIDR mode */
+ val &= ~DETILE_ARIDR_MODE_MASK;
+ val |= DETILE_ARID_IN_ARIDR;
+ writel(val, vou->dtrc + DTRC_DETILE_CTRL);
+
+ /* Bypass decompression for both frames */
+ val = readl(vou->dtrc + DTRC_F0_CTRL);
+ val |= DTRC_DECOMPRESS_BYPASS;
+ writel(val, vou->dtrc + DTRC_F0_CTRL);
+
+ val = readl(vou->dtrc + DTRC_F1_CTRL);
+ val |= DTRC_DECOMPRESS_BYPASS;
+ writel(val, vou->dtrc + DTRC_F1_CTRL);
+
+ /* Set up ARID register */
+ val = 0x0e;
+ val |= 0x0f << 8;
+ val |= 0x0e << 16;
+ val |= 0x0f << 24;
+ writel(val, vou->dtrc + DTRC_ARID);
+
+ /* Set up DEC2DDR_ARID register */
+ val = 0x0e;
+ val |= 0x0f << 8;
+ writel(val, vou->dtrc + DTRC_DEC2DDR_ARID);
+}
+
+static void vou_hw_init(struct zx_vou_hw *vou)
+{
+ u32 val;
+
+ /* Set GL0 to main channel and GL1 to aux channel */
+ val = readl(vou->osd + OSD_CTRL0);
+ val &= ~OSD_CTRL0_GL0_SEL;
+ val |= OSD_CTRL0_GL1_SEL;
+ writel(val, vou->osd + OSD_CTRL0);
+
+ /* Release reset for all VOU modules */
+ writel(~0, vou->vouctl + VOU_SOFT_RST);
+
+ /* Select main clock for GL0 and aux clock for GL1 module */
+ val = readl(vou->vouctl + VOU_CLK_SEL);
+ val &= ~VOU_CLK_GL0_SEL;
+ val |= VOU_CLK_GL1_SEL;
+ writel(val, vou->vouctl + VOU_CLK_SEL);
+
+ /* Enable clock auto-gating for all VOU modules */
+ writel(~0, vou->vouctl + VOU_CLK_REQEN);
+
+ /* Enable all VOU module clocks */
+ writel(~0, vou->vouctl + VOU_CLK_EN);
+
+ /* Clear both OSD and TIMING_CTRL interrupt state */
+ writel(~0, vou->osd + OSD_INT_CLRSTA);
+ writel(~0, vou->timing + TIMING_INT_STATE);
+
+ /* Enable OSD and TIMING_CTRL interrrupts */
+ writel(OSD_INT_ENABLE, vou->osd + OSD_INT_MSK);
+ writel(TIMING_INT_ENABLE, vou->timing + TIMING_INT_CTRL);
+
+ /* Select GPC as input to gl/vl scaler as a sane default setting */
+ writel(0x2a, vou->otfppu + OTFPPU_RSZ_DATA_SOURCE);
+
+ /*
+ * Needs to reset channel and layer logic per frame when frame starts
+ * to get VOU work properly.
+ */
+ val = readl(vou->osd + OSD_RST_CLR);
+ val |= RST_PER_FRAME;
+ writel(val, vou->osd + OSD_RST_CLR);
+
+ vou_dtrc_init(vou);
+}
+
+static int zx_crtc_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = data;
+ struct zx_drm_private *priv = drm->dev_private;
+ struct resource *res;
+ struct zx_vou_hw *vou;
+ int irq;
+ int ret;
+
+ vou = devm_kzalloc(dev, sizeof(*vou), GFP_KERNEL);
+ if (!vou)
+ return -ENOMEM;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "osd");
+ vou->osd = devm_ioremap_resource(dev, res);
+ if (IS_ERR(vou->osd))
+ return PTR_ERR(vou->osd);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "timing_ctrl");
+ vou->timing = devm_ioremap_resource(dev, res);
+ if (IS_ERR(vou->timing))
+ return PTR_ERR(vou->timing);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dtrc");
+ vou->dtrc = devm_ioremap_resource(dev, res);
+ if (IS_ERR(vou->dtrc))
+ return PTR_ERR(vou->dtrc);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vou_ctrl");
+ vou->vouctl = devm_ioremap_resource(dev, res);
+ if (IS_ERR(vou->vouctl))
+ return PTR_ERR(vou->vouctl);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otfppu");
+ vou->otfppu = devm_ioremap_resource(dev, res);
+ if (IS_ERR(vou->otfppu))
+ return PTR_ERR(vou->otfppu);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ vou->axi_clk = devm_clk_get(dev, "aclk");
+ if (IS_ERR(vou->axi_clk))
+ return PTR_ERR(vou->axi_clk);
+
+ vou->ppu_clk = devm_clk_get(dev, "ppu_wclk");
+ if (IS_ERR(vou->ppu_clk))
+ return PTR_ERR(vou->ppu_clk);
+
+ clk_prepare_enable(vou->axi_clk);
+ clk_prepare_enable(vou->ppu_clk);
+
+ vou->dev = dev;
+ priv->vou = vou;
+ dev_set_drvdata(dev, vou);
+
+ vou_hw_init(vou);
+
+ ret = devm_request_irq(dev, irq, vou_irq_handler, 0, "zx_vou", vou);
+ if (ret < 0)
+ return ret;
+
+ vou->main_crtc = zx_crtc_init(drm, VOU_CHN_MAIN);
+ if (IS_ERR(vou->main_crtc))
+ return PTR_ERR(vou->main_crtc);
+
+ vou->aux_crtc = zx_crtc_init(drm, VOU_CHN_AUX);
+ if (IS_ERR(vou->aux_crtc))
+ return PTR_ERR(vou->aux_crtc);
+
+ return 0;
+}
+
+static void zx_crtc_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct zx_vou_hw *vou = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(vou->axi_clk);
+ clk_disable_unprepare(vou->ppu_clk);
+}
+
+static const struct component_ops zx_crtc_component_ops = {
+ .bind = zx_crtc_bind,
+ .unbind = zx_crtc_unbind,
+};
+
+static int zx_crtc_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &zx_crtc_component_ops);
+}
+
+static int zx_crtc_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &zx_crtc_component_ops);
+ return 0;
+}
+
+static const struct of_device_id zx_crtc_of_match[] = {
+ { .compatible = "zte,zx296718-dpc", },
+ { /* end */ },
+};
+MODULE_DEVICE_TABLE(of, zx_crtc_of_match);
+
+struct platform_driver zx_crtc_driver = {
+ .probe = zx_crtc_probe,
+ .remove = zx_crtc_remove,
+ .driver = {
+ .name = "zx-crtc",
+ .of_match_table = zx_crtc_of_match,
+ },
+};
diff --git a/drivers/gpu/drm/zte/zx_crtc.h b/drivers/gpu/drm/zte/zx_crtc.h
new file mode 100644
index 000000000000..f889208054ce
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_crtc.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ * Copyright 2016 ZTE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ZX_CRTC_H__
+#define __ZX_CRTC_H__
+
+#define VOU_CRTC_MASK 0x3
+
+/* VOU output interfaces */
+enum vou_inf_id {
+ VOU_HDMI = 0,
+ VOU_RGB_LCD = 1,
+ VOU_TV_ENC = 2,
+ VOU_MIPI_DSI = 3,
+ VOU_LVDS = 4,
+ VOU_VGA = 5,
+};
+
+enum vou_inf_data_sel {
+ VOU_YUV444 = 0,
+ VOU_RGB_101010 = 1,
+ VOU_RGB_888 = 2,
+ VOU_RGB_666 = 3,
+};
+
+struct vou_inf {
+ struct drm_encoder *encoder;
+ enum vou_inf_id id;
+ enum vou_inf_data_sel data_sel;
+ u32 clocks_en_bits;
+ u32 clocks_sel_bits;
+};
+
+void vou_inf_enable(struct vou_inf *inf);
+void vou_inf_disable(struct vou_inf *inf);
+
+int zx_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe);
+void zx_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe);
+
+#endif /* __ZX_CRTC_H__ */
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c
new file mode 100644
index 000000000000..51fafb8e5f43
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_drm_drv.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ * Copyright 2016 ZTE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/list.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_of.h>
+
+#include "zx_drm_drv.h"
+#include "zx_crtc.h"
+
+static void zx_drm_fb_output_poll_changed(struct drm_device *drm)
+{
+ struct zx_drm_private *priv = drm->dev_private;
+
+ drm_fbdev_cma_hotplug_event(priv->fbdev);
+}
+
+static const struct drm_mode_config_funcs zx_drm_mode_config_funcs = {
+ .fb_create = drm_fb_cma_create,
+ .output_poll_changed = zx_drm_fb_output_poll_changed,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+static void zx_drm_lastclose(struct drm_device *drm)
+{
+ struct zx_drm_private *priv = drm->dev_private;
+
+ drm_fbdev_cma_restore_mode(priv->fbdev);
+}
+
+static const struct file_operations zx_drm_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
+ .poll = drm_poll,
+ .read = drm_read,
+ .llseek = noop_llseek,
+ .mmap = drm_gem_cma_mmap,
+};
+
+static struct drm_driver zx_drm_driver = {
+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
+ DRIVER_ATOMIC,
+ .lastclose = zx_drm_lastclose,
+ .get_vblank_counter = drm_vblank_no_hw_counter,
+ .enable_vblank = zx_crtc_enable_vblank,
+ .disable_vblank = zx_crtc_disable_vblank,
+ .gem_free_object = drm_gem_cma_free_object,
+ .gem_vm_ops = &drm_gem_cma_vm_ops,
+ .dumb_create = drm_gem_cma_dumb_create,
+ .dumb_map_offset = drm_gem_cma_dumb_map_offset,
+ .dumb_destroy = drm_gem_dumb_destroy,
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = drm_gem_prime_export,
+ .gem_prime_import = drm_gem_prime_import,
+ .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+ .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+ .gem_prime_vmap = drm_gem_cma_prime_vmap,
+ .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
+ .gem_prime_mmap = drm_gem_cma_prime_mmap,
+ .fops = &zx_drm_fops,
+ .name = "zx-vou",
+ .desc = "ZTE VOU Controller DRM",
+ .date = "20160811",
+ .major = 1,
+ .minor = 0,
+};
+
+static int zx_drm_bind(struct device *dev)
+{
+ struct drm_device *drm;
+ struct zx_drm_private *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ drm = drm_dev_alloc(&zx_drm_driver, dev);
+ if (!drm)
+ return -ENOMEM;
+
+ drm->dev_private = priv;
+ dev_set_drvdata(dev, drm);
+
+ drm_mode_config_init(drm);
+ drm->mode_config.min_width = 16;
+ drm->mode_config.min_height = 16;
+ drm->mode_config.max_width = 4096;
+ drm->mode_config.max_height = 4096;
+ drm->mode_config.funcs = &zx_drm_mode_config_funcs;
+
+ ret = drm_dev_register(drm, 0);
+ if (ret)
+ goto out_free;
+
+ ret = component_bind_all(dev, drm);
+ if (ret) {
+ DRM_ERROR("Failed to bind all components\n");
+ goto out_unregister;
+ }
+
+ ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ if (ret < 0) {
+ DRM_ERROR("failed to initialise vblank\n");
+ goto out_unbind;
+ }
+
+ /*
+ * We will manage irq handler on our own. In this case, irq_enabled
+ * need to be true for using vblank core support.
+ */
+ drm->irq_enabled = true;
+
+ drm_mode_config_reset(drm);
+ drm_kms_helper_poll_init(drm);
+
+ priv->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc,
+ drm->mode_config.num_connector);
+ if (IS_ERR(priv->fbdev)) {
+ ret = PTR_ERR(priv->fbdev);
+ priv->fbdev = NULL;
+ goto out_fini;
+ }
+
+ return 0;
+
+out_fini:
+ drm_kms_helper_poll_fini(drm);
+ drm_mode_config_cleanup(drm);
+ drm_vblank_cleanup(drm);
+out_unbind:
+ component_unbind_all(dev, drm);
+out_unregister:
+ drm_dev_unregister(drm);
+out_free:
+ dev_set_drvdata(dev, NULL);
+ drm_dev_unref(drm);
+ return ret;
+}
+
+static void zx_drm_unbind(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+ struct zx_drm_private *priv = drm->dev_private;
+
+ if (priv->fbdev) {
+ drm_fbdev_cma_fini(priv->fbdev);
+ priv->fbdev = NULL;
+ }
+ drm_kms_helper_poll_fini(drm);
+ component_unbind_all(dev, drm);
+ drm_vblank_cleanup(drm);
+ drm_mode_config_cleanup(drm);
+ drm_dev_unregister(drm);
+ drm_dev_unref(drm);
+ drm->dev_private = NULL;
+ dev_set_drvdata(dev, NULL);
+}
+
+static const struct component_master_ops zx_drm_master_ops = {
+ .bind = zx_drm_bind,
+ .unbind = zx_drm_unbind,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+static int zx_drm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *parent = dev->of_node;
+ struct device_node *child;
+ struct component_match *match = NULL;
+ int ret;
+
+ ret = of_platform_populate(parent, NULL, NULL, dev);
+ if (ret)
+ return ret;
+
+ for_each_available_child_of_node(parent, child) {
+ component_match_add(dev, &match, compare_of, child);
+ of_node_put(child);
+ }
+
+ return component_master_add_with_match(dev, &zx_drm_master_ops, match);
+}
+
+static int zx_drm_remove(struct platform_device *pdev)
+{
+ component_master_del(&pdev->dev, &zx_drm_master_ops);
+ return 0;
+}
+
+static const struct of_device_id zx_drm_of_match[] = {
+ { .compatible = "zte,zx296718-vou", },
+ { /* end */ },
+};
+MODULE_DEVICE_TABLE(of, zx_drm_of_match);
+
+static struct platform_driver zx_drm_platform_driver = {
+ .probe = zx_drm_probe,
+ .remove = zx_drm_remove,
+ .driver = {
+ .name = "zx-drm",
+ .of_match_table = zx_drm_of_match,
+ },
+};
+
+static struct platform_driver *drivers[] = {
+ &zx_crtc_driver,
+ &zx_hdmi_driver,
+ &zx_drm_platform_driver,
+};
+
+static int zx_drm_init(void)
+{
+ return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
+}
+module_init(zx_drm_init);
+
+static void zx_drm_exit(void)
+{
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
+}
+module_exit(zx_drm_exit);
+
+MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
+MODULE_DESCRIPTION("ZTE ZX VOU DRM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/zte/zx_drm_drv.h b/drivers/gpu/drm/zte/zx_drm_drv.h
new file mode 100644
index 000000000000..14c749949151
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_drm_drv.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ * Copyright 2016 ZTE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ZX_DRM_DRV_H__
+#define __ZX_DRM_DRV_H__
+
+struct zx_drm_private {
+ struct drm_fbdev_cma *fbdev;
+ struct zx_vou_hw *vou;
+};
+
+extern struct platform_driver zx_crtc_driver;
+extern struct platform_driver zx_hdmi_driver;
+
+#endif /* __ZX_DRM_DRV_H__ */
diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c
new file mode 100644
index 000000000000..5aaab8493b1b
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_hdmi.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ * Copyright 2016 ZTE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <drm/drm_of.h>
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hdmi.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/component.h>
+
+#include "zx_crtc.h"
+
+#define FUNC_SEL 0x000b
+#define FUNC_HDMI_EN BIT(0)
+#define CLKPWD 0x000d
+#define CLKPWD_PDIDCK BIT(2)
+#define PWD_SRST 0x0010
+#define P2T_CTRL 0x0066
+#define P2T_DC_PKT_EN BIT(7)
+#define L1_INTR_STAT 0x007e
+#define L1_INTR_STAT_INTR1 BIT(0)
+#define INTR1_STAT 0x008f
+#define INTR1_MASK 0x0095
+#define INTR1_MONITOR_DETECT (BIT(5) | BIT(6))
+#define ZX_DDC_ADDR 0x00ed
+#define ZX_DDC_SEGM 0x00ee
+#define ZX_DDC_OFFSET 0x00ef
+#define ZX_DDC_DIN_CNT1 0x00f0
+#define ZX_DDC_DIN_CNT2 0x00f1
+#define ZX_DDC_CMD 0x00f3
+#define DDC_CMD_MASK 0xf
+#define DDC_CMD_CLEAR_FIFO 0x9
+#define DDC_CMD_SEQUENTIAL_READ 0x2
+#define ZX_DDC_DATA 0x00f4
+#define ZX_DDC_DOUT_CNT 0x00f5
+#define DDC_DOUT_CNT_MASK 0x1f
+#define TEST_TXCTRL 0x00f7
+#define TEST_TXCTRL_HDMI_MODE BIT(1)
+#define HDMICTL4 0x0235
+#define TPI_HPD_RSEN 0x063b
+#define TPI_HPD_CONNECTION (BIT(1) | BIT(2))
+#define TPI_INFO_FSEL 0x06bf
+#define FSEL_AVI 0
+#define FSEL_GBD 1
+#define FSEL_AUDIO 2
+#define FSEL_SPD 3
+#define FSEL_MPEG 4
+#define FSEL_VSIF 5
+#define TPI_INFO_B0 0x06c0
+#define TPI_INFO_EN 0x06df
+#define TPI_INFO_TRANS_EN BIT(7)
+#define TPI_INFO_TRANS_RPT BIT(6)
+#define TPI_DDC_MASTER_EN 0x06f8
+#define HW_DDC_MASTER BIT(7)
+
+#define ZX_HDMI_INFOFRAME_SIZE 31
+
+struct zx_hdmi {
+ struct drm_connector connector;
+ struct drm_encoder encoder;
+ struct device *dev;
+ struct drm_device *drm;
+ void __iomem *mmio;
+ struct clk *cec_clk;
+ struct clk *osc_clk;
+ struct clk *xclk;
+ bool sink_is_hdmi;
+ bool sink_has_audio;
+ struct vou_inf *inf;
+};
+
+#define to_zx_hdmi(x) container_of(x, struct zx_hdmi, x)
+
+static struct vou_inf vou_inf_hdmi = {
+ .id = VOU_HDMI,
+ .data_sel = VOU_YUV444,
+ .clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
+ .clocks_sel_bits = BIT(13) | BIT(2),
+};
+
+static inline u8 hdmi_readb(struct zx_hdmi *hdmi, u16 offset)
+{
+ return readl_relaxed(hdmi->mmio + offset * 4);
+}
+
+static inline void hdmi_writeb(struct zx_hdmi *hdmi, u16 offset, u8 val)
+{
+ writel_relaxed(val, hdmi->mmio + offset * 4);
+}
+
+static int zx_hdmi_infoframe_trans(struct zx_hdmi *hdmi,
+ union hdmi_infoframe *frame, u8 fsel)
+{
+ u8 buffer[ZX_HDMI_INFOFRAME_SIZE];
+ u8 val;
+ ssize_t num;
+ int i;
+
+ hdmi_writeb(hdmi, TPI_INFO_FSEL, fsel);
+
+ num = hdmi_infoframe_pack(frame, buffer, ZX_HDMI_INFOFRAME_SIZE);
+ if (num < 0)
+ return num;
+
+ for (i = 0; i < num; i++)
+ hdmi_writeb(hdmi, TPI_INFO_B0 + i, buffer[i]);
+
+ val = hdmi_readb(hdmi, TPI_INFO_EN);
+ val |= TPI_INFO_TRANS_EN | TPI_INFO_TRANS_RPT;
+ hdmi_writeb(hdmi, TPI_INFO_EN, val);
+
+ return num;
+}
+
+static int zx_hdmi_config_video_vsi(struct zx_hdmi *hdmi,
+ struct drm_display_mode *mode)
+{
+ union hdmi_infoframe frame;
+ int ret;
+
+ ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
+ mode);
+ if (ret)
+ return ret;
+
+ return zx_hdmi_infoframe_trans(hdmi, &frame, FSEL_VSIF);
+}
+
+static int zx_hdmi_config_video_avi(struct zx_hdmi *hdmi,
+ struct drm_display_mode *mode)
+{
+ union hdmi_infoframe frame;
+ int ret;
+
+ ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
+ if (ret)
+ return ret;
+
+ /* We always use YUV444 for HDMI output. */
+ frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
+
+ return zx_hdmi_infoframe_trans(hdmi, &frame, FSEL_AVI);
+}
+
+static void zx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adj_mode)
+{
+ struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
+
+ if (hdmi->sink_is_hdmi) {
+ zx_hdmi_config_video_avi(hdmi, mode);
+ zx_hdmi_config_video_vsi(hdmi, mode);
+ }
+}
+
+static void zx_hdmi_encoder_enable(struct drm_encoder *encoder)
+{
+ struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
+
+ vou_inf_enable(hdmi->inf);
+}
+
+static void zx_hdmi_encoder_disable(struct drm_encoder *encoder)
+{
+ struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
+
+ vou_inf_disable(hdmi->inf);
+}
+
+static const struct drm_encoder_helper_funcs zx_hdmi_encoder_helper_funcs = {
+ .enable = zx_hdmi_encoder_enable,
+ .disable = zx_hdmi_encoder_disable,
+ .mode_set = zx_hdmi_encoder_mode_set,
+};
+
+static const struct drm_encoder_funcs zx_hdmi_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static int zx_hdmi_get_edid_block(void *data, u8 *buf, unsigned int block,
+ size_t len)
+{
+ struct zx_hdmi *hdmi = data;
+ int retry = 0;
+ int ret = 0;
+ int i = 0;
+ u8 val;
+
+ /* Enable DDC master access */
+ val = hdmi_readb(hdmi, TPI_DDC_MASTER_EN);
+ val |= HW_DDC_MASTER;
+ hdmi_writeb(hdmi, TPI_DDC_MASTER_EN, val);
+
+ hdmi_writeb(hdmi, ZX_DDC_ADDR, 0xa0);
+ hdmi_writeb(hdmi, ZX_DDC_OFFSET, block * EDID_LENGTH);
+ /* Bits [9:8] of bytes */
+ hdmi_writeb(hdmi, ZX_DDC_DIN_CNT2, (len >> 8) & 0xff);
+ /* Bits [7:0] of bytes */
+ hdmi_writeb(hdmi, ZX_DDC_DIN_CNT1, len & 0xff);
+
+ /* Clear FIFO */
+ val = hdmi_readb(hdmi, ZX_DDC_CMD);
+ val &= ~DDC_CMD_MASK;
+ val |= DDC_CMD_CLEAR_FIFO;
+ hdmi_writeb(hdmi, ZX_DDC_CMD, val);
+
+ /* Kick off the read */
+ val = hdmi_readb(hdmi, ZX_DDC_CMD);
+ val &= ~DDC_CMD_MASK;
+ val |= DDC_CMD_SEQUENTIAL_READ;
+ hdmi_writeb(hdmi, ZX_DDC_CMD, val);
+
+ while (len > 0) {
+ int cnt, j;
+
+ /* FIFO needs some time to get ready */
+ usleep_range(500, 1000);
+
+ cnt = hdmi_readb(hdmi, ZX_DDC_DOUT_CNT) & DDC_DOUT_CNT_MASK;
+ if (cnt == 0) {
+ if (++retry > 5) {
+ dev_err(hdmi->dev, "DDC read timed out!");
+ ret = -ETIMEDOUT;
+ break;
+ }
+ continue;
+ }
+
+ for (j = 0; j < cnt; j++)
+ buf[i++] = hdmi_readb(hdmi, ZX_DDC_DATA);
+ len -= cnt;
+ }
+
+ /* Disable DDC master access */
+ val = hdmi_readb(hdmi, TPI_DDC_MASTER_EN);
+ val &= ~HW_DDC_MASTER;
+ hdmi_writeb(hdmi, TPI_DDC_MASTER_EN, val);
+
+ return ret;
+}
+
+static int zx_hdmi_connector_get_modes(struct drm_connector *connector)
+{
+ struct zx_hdmi *hdmi = to_zx_hdmi(connector);
+ struct edid *edid;
+ int ret = 0;
+
+ edid = drm_do_get_edid(connector, zx_hdmi_get_edid_block, hdmi);
+ if (edid) {
+ hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid);
+ hdmi->sink_has_audio = drm_detect_monitor_audio(edid);
+ drm_mode_connector_update_edid_property(connector, edid);
+ ret = drm_add_edid_modes(connector, edid);
+ kfree(edid);
+ }
+
+ return ret;
+}
+
+static enum drm_mode_status
+zx_hdmi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ return MODE_OK;
+}
+
+static struct drm_connector_helper_funcs zx_hdmi_connector_helper_funcs = {
+ .get_modes = zx_hdmi_connector_get_modes,
+ .mode_valid = zx_hdmi_connector_mode_valid,
+};
+
+static enum drm_connector_status
+zx_hdmi_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct zx_hdmi *hdmi = to_zx_hdmi(connector);
+
+ return (hdmi_readb(hdmi, TPI_HPD_RSEN) & TPI_HPD_CONNECTION) ?
+ connector_status_connected : connector_status_disconnected;
+}
+
+static void zx_hdmi_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs zx_hdmi_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = zx_hdmi_connector_detect,
+ .destroy = zx_hdmi_connector_destroy,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int zx_hdmi_register(struct drm_device *drm, struct zx_hdmi *hdmi)
+{
+ struct drm_encoder *encoder = &hdmi->encoder;
+
+ encoder->possible_crtcs = VOU_CRTC_MASK;
+
+ drm_encoder_init(drm, encoder, &zx_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL);
+ drm_encoder_helper_add(encoder, &zx_hdmi_encoder_helper_funcs);
+
+ hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+ drm_connector_init(drm, &hdmi->connector, &zx_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+ drm_connector_helper_add(&hdmi->connector,
+ &zx_hdmi_connector_helper_funcs);
+
+ drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
+ drm_connector_register(&hdmi->connector);
+
+ return 0;
+}
+
+static irqreturn_t zx_hdmi_irq_thread(int irq, void *dev_id)
+{
+ struct zx_hdmi *hdmi = dev_id;
+
+ drm_helper_hpd_irq_event(hdmi->connector.dev);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t zx_hdmi_irq_handler(int irq, void *dev_id)
+{
+ struct zx_hdmi *hdmi = dev_id;
+ u8 lstat;
+
+ lstat = hdmi_readb(hdmi, L1_INTR_STAT);
+
+ /* Monitor detect/HPD interrupt */
+ if (lstat & L1_INTR_STAT_INTR1) {
+ u8 stat = hdmi_readb(hdmi, INTR1_STAT);
+
+ hdmi_writeb(hdmi, INTR1_STAT, stat);
+ if (stat & INTR1_MONITOR_DETECT)
+ return IRQ_WAKE_THREAD;
+ }
+
+ return IRQ_NONE;
+}
+
+static void zx_hdmi_phy_start(struct zx_hdmi *hdmi)
+{
+ /* Copy from ZTE BSP code */
+ hdmi_writeb(hdmi, 0x222, 0x0);
+ hdmi_writeb(hdmi, 0x224, 0x4);
+ hdmi_writeb(hdmi, 0x909, 0x0);
+ hdmi_writeb(hdmi, 0x7b0, 0x90);
+ hdmi_writeb(hdmi, 0x7b1, 0x00);
+ hdmi_writeb(hdmi, 0x7b2, 0xa7);
+ hdmi_writeb(hdmi, 0x7b8, 0xaa);
+ hdmi_writeb(hdmi, 0x7b2, 0xa7);
+ hdmi_writeb(hdmi, 0x7b3, 0x0f);
+ hdmi_writeb(hdmi, 0x7b4, 0x0f);
+ hdmi_writeb(hdmi, 0x7b5, 0x55);
+ hdmi_writeb(hdmi, 0x7b7, 0x03);
+ hdmi_writeb(hdmi, 0x7b9, 0x12);
+ hdmi_writeb(hdmi, 0x7ba, 0x32);
+ hdmi_writeb(hdmi, 0x7bc, 0x68);
+ hdmi_writeb(hdmi, 0x7be, 0x40);
+ hdmi_writeb(hdmi, 0x7bf, 0x84);
+ hdmi_writeb(hdmi, 0x7c1, 0x0f);
+ hdmi_writeb(hdmi, 0x7c8, 0x02);
+ hdmi_writeb(hdmi, 0x7c9, 0x03);
+ hdmi_writeb(hdmi, 0x7ca, 0x40);
+ hdmi_writeb(hdmi, 0x7dc, 0x31);
+ hdmi_writeb(hdmi, 0x7e2, 0x04);
+ hdmi_writeb(hdmi, 0x7e0, 0x06);
+ hdmi_writeb(hdmi, 0x7cb, 0x68);
+ hdmi_writeb(hdmi, 0x7f9, 0x02);
+ hdmi_writeb(hdmi, 0x7b6, 0x02);
+ hdmi_writeb(hdmi, 0x7f3, 0x0);
+}
+
+static void zx_hdmi_hw_init(struct zx_hdmi *hdmi)
+{
+ u8 val;
+
+ /* Software reset */
+ hdmi_writeb(hdmi, PWD_SRST, 1);
+
+ /* Enable pclk */
+ val = hdmi_readb(hdmi, CLKPWD);
+ val |= CLKPWD_PDIDCK;
+ hdmi_writeb(hdmi, CLKPWD, val);
+
+ /* Enable HDMI for TX */
+ val = hdmi_readb(hdmi, FUNC_SEL);
+ val |= FUNC_HDMI_EN;
+ hdmi_writeb(hdmi, FUNC_SEL, val);
+
+ /* Enable deep color packet */
+ val = hdmi_readb(hdmi, P2T_CTRL);
+ val |= P2T_DC_PKT_EN;
+ hdmi_writeb(hdmi, P2T_CTRL, val);
+
+ /* Enable HDMI/MHL mode for output */
+ val = hdmi_readb(hdmi, TEST_TXCTRL);
+ val |= TEST_TXCTRL_HDMI_MODE;
+ hdmi_writeb(hdmi, TEST_TXCTRL, val);
+
+ /* Configure reg_qc_sel */
+ hdmi_writeb(hdmi, HDMICTL4, 0x3);
+
+ /* Enable interrupt */
+ val = hdmi_readb(hdmi, INTR1_MASK);
+ val |= INTR1_MONITOR_DETECT;
+ hdmi_writeb(hdmi, INTR1_MASK, val);
+
+ /* Clear reset for normal operation */
+ hdmi_writeb(hdmi, PWD_SRST, 0);
+
+ /* Start up phy */
+ zx_hdmi_phy_start(hdmi);
+}
+
+static int zx_hdmi_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = data;
+ struct resource *res;
+ struct zx_hdmi *hdmi;
+ struct vou_inf *inf;
+ int irq;
+ int ret;
+
+ hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
+
+ hdmi->dev = dev;
+ hdmi->drm = drm;
+
+ inf = &vou_inf_hdmi;
+ inf->encoder = &hdmi->encoder;
+ hdmi->inf = inf;
+
+ dev_set_drvdata(dev, hdmi);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hdmi->mmio = devm_ioremap_resource(dev, res);
+ if (IS_ERR(hdmi->mmio))
+ return PTR_ERR(hdmi->mmio);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ hdmi->cec_clk = devm_clk_get(hdmi->dev, "osc_cec");
+ if (IS_ERR(hdmi->cec_clk))
+ return PTR_ERR(hdmi->cec_clk);
+
+ hdmi->osc_clk = devm_clk_get(hdmi->dev, "osc_clk");
+ if (IS_ERR(hdmi->osc_clk))
+ return PTR_ERR(hdmi->osc_clk);
+
+ hdmi->xclk = devm_clk_get(hdmi->dev, "xclk");
+ if (IS_ERR(hdmi->xclk))
+ return PTR_ERR(hdmi->xclk);
+
+ zx_hdmi_hw_init(hdmi);
+
+ clk_prepare_enable(hdmi->cec_clk);
+ clk_prepare_enable(hdmi->osc_clk);
+ clk_prepare_enable(hdmi->xclk);
+
+ ret = zx_hdmi_register(drm, hdmi);
+ if (ret)
+ return ret;
+
+ ret = devm_request_threaded_irq(dev, irq, zx_hdmi_irq_handler,
+ zx_hdmi_irq_thread, IRQF_SHARED,
+ dev_name(dev), hdmi);
+
+ return 0;
+}
+
+static void zx_hdmi_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct zx_hdmi *hdmi = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(hdmi->cec_clk);
+ clk_disable_unprepare(hdmi->osc_clk);
+ clk_disable_unprepare(hdmi->xclk);
+}
+
+static const struct component_ops zx_hdmi_component_ops = {
+ .bind = zx_hdmi_bind,
+ .unbind = zx_hdmi_unbind,
+};
+
+static int zx_hdmi_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &zx_hdmi_component_ops);
+}
+
+static int zx_hdmi_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &zx_hdmi_component_ops);
+ return 0;
+}
+
+static const struct of_device_id zx_hdmi_of_match[] = {
+ { .compatible = "zte,zx296718-hdmi", },
+ { /* end */ },
+};
+MODULE_DEVICE_TABLE(of, zx_hdmi_of_match);
+
+struct platform_driver zx_hdmi_driver = {
+ .probe = zx_hdmi_probe,
+ .remove = zx_hdmi_remove,
+ .driver = {
+ .name = "zx-hdmi",
+ .of_match_table = zx_hdmi_of_match,
+ },
+};
diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
new file mode 100644
index 000000000000..326cc1ff7950
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_plane.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ * Copyright 2016 ZTE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_plane_helper.h>
+
+#include "zx_crtc.h"
+#include "zx_plane.h"
+
+/* GL registers */
+#define GL_CTRL0 0x00
+#define GL_UPDATE BIT(5)
+#define GL_CTRL1 0x04
+#define GL_DATA_FMT_SHIFT 0
+#define GL_DATA_FMT_MASK (0xf << GL_DATA_FMT_SHIFT)
+#define GL_FMT_ARGB8888 0
+#define GL_FMT_RGB888 1
+#define GL_FMT_RGB565 2
+#define GL_FMT_ARGB1555 3
+#define GL_FMT_ARGB4444 4
+#define GL_CTRL2 0x08
+#define GL_GLOBAL_ALPHA_SHIFT 8
+#define GL_GLOBAL_ALPHA_MASK (0xff << GL_GLOBAL_ALPHA_SHIFT)
+#define GL_CTRL3 0x0c
+#define GL_SCALER_BYPASS_MODE BIT(0)
+#define GL_STRIDE 0x18
+#define GL_ADDR 0x1c
+#define GL_SRC_SIZE 0x38
+#define GL_SRC_W_SHIFT 16
+#define GL_SRC_W_MASK (0x3fff << GL_SRC_W_SHIFT)
+#define GL_SRC_H_SHIFT 0
+#define GL_SRC_H_MASK (0x3fff << GL_SRC_H_SHIFT)
+#define GL_POS_START 0x9c
+#define GL_POS_END 0xa0
+#define GL_POS_X_SHIFT 16
+#define GL_POS_X_MASK (0x1fff << GL_POS_X_SHIFT)
+#define GL_POS_Y_SHIFT 0
+#define GL_POS_Y_MASK (0x1fff << GL_POS_Y_SHIFT)
+
+/* CSC registers */
+#define CSC_CTRL0 0x30
+#define CSC_COV_MODE_SHIFT 16
+#define CSC_COV_MODE_MASK (0xffff << CSC_COV_MODE_SHIFT)
+#define CSC_BT601_IMAGE_RGB2YCBCR 0
+#define CSC_BT601_IMAGE_YCBCR2RGB 1
+#define CSC_BT601_VIDEO_RGB2YCBCR 2
+#define CSC_BT601_VIDEO_YCBCR2RGB 3
+#define CSC_BT709_IMAGE_RGB2YCBCR 4
+#define CSC_BT709_IMAGE_YCBCR2RGB 5
+#define CSC_BT709_VIDEO_RGB2YCBCR 6
+#define CSC_BT709_VIDEO_YCBCR2RGB 7
+#define CSC_BT2020_IMAGE_RGB2YCBCR 8
+#define CSC_BT2020_IMAGE_YCBCR2RGB 9
+#define CSC_BT2020_VIDEO_RGB2YCBCR 10
+#define CSC_BT2020_VIDEO_YCBCR2RGB 11
+#define CSC_WORK_ENABLE BIT(0)
+
+/* RSZ registers */
+#define RSZ_SRC_CFG 0x00
+#define RSZ_DEST_CFG 0x04
+#define RSZ_ENABLE_CFG 0x14
+
+/* HBSC registers */
+#define HBSC_SATURATION 0x00
+#define HBSC_HUE 0x04
+#define HBSC_BRIGHT 0x08
+#define HBSC_CONTRAST 0x0c
+#define HBSC_THRESHOLD_COL1 0x10
+#define HBSC_THRESHOLD_COL2 0x14
+#define HBSC_THRESHOLD_COL3 0x18
+#define HBSC_CTRL0 0x28
+#define HBSC_CTRL_EN BIT(2)
+
+struct zx_plane {
+ struct drm_plane plane;
+ void __iomem *layer;
+ void __iomem *csc;
+ void __iomem *hbsc;
+ void __iomem *rsz;
+};
+
+#define to_zx_plane(plane) container_of(plane, struct zx_plane, plane)
+
+static const uint32_t gl_formats[] = {
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_ARGB4444,
+};
+
+static int zx_gl_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ u32 src_w, src_h;
+
+ src_w = state->src_w >> 16;
+ src_h = state->src_h >> 16;
+
+ /* TODO: support scaling of the plane source */
+ if ((src_w != state->crtc_w) || (src_h != state->crtc_h))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int zx_gl_get_fmt(uint32_t format)
+{
+ switch (format) {
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB8888:
+ return GL_FMT_ARGB8888;
+ case DRM_FORMAT_RGB888:
+ return GL_FMT_RGB888;
+ case DRM_FORMAT_RGB565:
+ return GL_FMT_RGB565;
+ case DRM_FORMAT_ARGB1555:
+ return GL_FMT_ARGB1555;
+ case DRM_FORMAT_ARGB4444:
+ return GL_FMT_ARGB4444;
+ default:
+ WARN_ONCE(1, "invalid pixel format %d\n", format);
+ return -EINVAL;
+ }
+}
+
+static inline void zx_gl_set_update(struct zx_plane *zplane)
+{
+ void __iomem *layer = zplane->layer;
+ u32 val;
+
+ val = readl(layer + GL_CTRL0);
+ val |= GL_UPDATE;
+ writel(val, layer + GL_CTRL0);
+}
+
+static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
+{
+ writel(1, zplane->rsz + RSZ_ENABLE_CFG);
+}
+
+void zx_plane_set_update(struct drm_plane *plane)
+{
+ struct zx_plane *zplane = to_zx_plane(plane);
+
+ zx_gl_rsz_set_update(zplane);
+ zx_gl_set_update(zplane);
+}
+
+static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
+ u32 dst_w, u32 dst_h)
+{
+ void __iomem *rsz = zplane->rsz;
+ u32 val;
+
+ val = ((src_h - 1) & 0xffff) << 16;
+ val |= (src_w - 1) & 0xffff;
+ writel(val, rsz + RSZ_SRC_CFG);
+
+ val = ((dst_h - 1) & 0xffff) << 16;
+ val |= (dst_w - 1) & 0xffff;
+ writel(val, rsz + RSZ_DEST_CFG);
+
+ zx_gl_rsz_set_update(zplane);
+}
+
+static void zx_gl_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct zx_plane *zplane = to_zx_plane(plane);
+ struct drm_framebuffer *fb = plane->state->fb;
+ struct drm_gem_cma_object *cma_obj;
+ void __iomem *layer = zplane->layer;
+ void __iomem *csc = zplane->csc;
+ void __iomem *hbsc = zplane->hbsc;
+ u32 src_x, src_y, src_w, src_h;
+ u32 dst_x, dst_y, dst_w, dst_h;
+ unsigned int depth, bpp;
+ uint32_t format;
+ dma_addr_t paddr;
+ u32 stride;
+ int fmt;
+ u32 val;
+
+ if (!fb)
+ return;
+
+ format = fb->pixel_format;
+ stride = fb->pitches[0];
+
+ src_x = plane->state->src_x >> 16;
+ src_y = plane->state->src_y >> 16;
+ src_w = plane->state->src_w >> 16;
+ src_h = plane->state->src_h >> 16;
+
+ dst_x = plane->state->crtc_x;
+ dst_y = plane->state->crtc_y;
+ dst_w = plane->state->crtc_w;
+ dst_h = plane->state->crtc_h;
+
+ drm_fb_get_bpp_depth(format, &depth, &bpp);
+
+ cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+ paddr = cma_obj->paddr + fb->offsets[0];
+ paddr += src_y * stride + src_x * bpp / 8;
+ writel(paddr, layer + GL_ADDR);
+
+ /* Set up source height/width register */
+ val = (src_w << GL_SRC_W_SHIFT) & GL_SRC_W_MASK;
+ val |= (src_h << GL_SRC_H_SHIFT) & GL_SRC_H_MASK;
+ writel(val, layer + GL_SRC_SIZE);
+
+ /* Set up start position register */
+ val = (dst_x << GL_POS_X_SHIFT) & GL_POS_X_MASK;
+ val |= (dst_y << GL_POS_Y_SHIFT) & GL_POS_Y_MASK;
+ writel(val, layer + GL_POS_START);
+
+ /* Set up end position register */
+ val = ((dst_x + dst_w) << GL_POS_X_SHIFT) & GL_POS_X_MASK;
+ val |= ((dst_y + dst_h) << GL_POS_Y_SHIFT) & GL_POS_Y_MASK;
+ writel(val, layer + GL_POS_END);
+
+ /* Set up stride register */
+ writel(stride & 0xffff, layer + GL_STRIDE);
+
+ /* Set up graphic layer data format */
+ fmt = zx_gl_get_fmt(format);
+ if (fmt >= 0) {
+ val = readl(layer + GL_CTRL1);
+ val &= ~GL_DATA_FMT_MASK;
+ val |= fmt << GL_DATA_FMT_SHIFT;
+ writel(val, layer + GL_CTRL1);
+ }
+
+ /* Initialize global alpha with a sane value */
+ val = readl(layer + GL_CTRL2);
+ val &= ~GL_GLOBAL_ALPHA_MASK;
+ val |= 0xff << GL_GLOBAL_ALPHA_SHIFT;
+ writel(val, layer + GL_CTRL2);
+
+ /* Setup CSC for the GL */
+ val = readl(csc + CSC_CTRL0);
+ val &= ~CSC_COV_MODE_MASK;
+ if (dst_h > 720)
+ val |= CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT;
+ else
+ val |= CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT;
+ val |= CSC_WORK_ENABLE;
+ writel(val, csc + CSC_CTRL0);
+
+ /* Always use scaler since it exists */
+ val = readl(layer + GL_CTRL3);
+ val |= GL_SCALER_BYPASS_MODE; /* set for not bypass */
+ writel(val, layer + GL_CTRL3);
+
+ zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h);
+
+ /* Enable HBSC block */
+ val = readl(hbsc + HBSC_CTRL0);
+ val |= HBSC_CTRL_EN;
+ writel(val, hbsc + HBSC_CTRL0);
+
+ zx_gl_set_update(zplane);
+}
+
+static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
+ .atomic_check = zx_gl_plane_atomic_check,
+ .atomic_update = zx_gl_plane_atomic_update,
+};
+
+static void zx_plane_destroy(struct drm_plane *plane)
+{
+ drm_plane_helper_disable(plane);
+ drm_plane_cleanup(plane);
+}
+
+static const struct drm_plane_funcs zx_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = zx_plane_destroy,
+ .reset = drm_atomic_helper_plane_reset,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static void zx_plane_hbsc_init(struct zx_plane *zplane)
+{
+ void __iomem *hbsc = zplane->hbsc;
+
+ /*
+ * Initialize HBSC block with a sane configuration per recommedation
+ * from ZTE BSP code.
+ */
+ writel(0x200, hbsc + HBSC_SATURATION);
+ writel(0x0, hbsc + HBSC_HUE);
+ writel(0x0, hbsc + HBSC_BRIGHT);
+ writel(0x200, hbsc + HBSC_CONTRAST);
+
+ writel((0x3ac << 16) | 0x40, hbsc + HBSC_THRESHOLD_COL1);
+ writel((0x3c0 << 16) | 0x40, hbsc + HBSC_THRESHOLD_COL2);
+ writel((0x3c0 << 16) | 0x40, hbsc + HBSC_THRESHOLD_COL3);
+}
+
+struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
+ struct zx_layer_data *data,
+ enum drm_plane_type type)
+{
+ const struct drm_plane_helper_funcs *helper;
+ struct zx_plane *zplane;
+ struct drm_plane *plane;
+ const uint32_t *formats;
+ unsigned int format_count;
+ int ret;
+
+ zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
+ if (!zplane)
+ return ERR_PTR(-ENOMEM);
+
+ plane = &zplane->plane;
+
+ zplane->layer = data->layer;
+ zplane->hbsc = data->hbsc;
+ zplane->csc = data->csc;
+ zplane->rsz = data->rsz;
+
+ zx_plane_hbsc_init(zplane);
+
+ switch (type) {
+ case DRM_PLANE_TYPE_PRIMARY:
+ helper = &zx_gl_plane_helper_funcs;
+ formats = gl_formats;
+ format_count = ARRAY_SIZE(gl_formats);
+ break;
+ case DRM_PLANE_TYPE_OVERLAY:
+ /* TODO: add video layer (vl) support */
+ break;
+ default:
+ return ERR_PTR(-ENODEV);
+ }
+
+ ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
+ &zx_plane_funcs, formats, format_count,
+ type, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_plane_helper_add(plane, helper);
+
+ return plane;
+}
diff --git a/drivers/gpu/drm/zte/zx_plane.h b/drivers/gpu/drm/zte/zx_plane.h
new file mode 100644
index 000000000000..2b82cd558d9d
--- /dev/null
+++ b/drivers/gpu/drm/zte/zx_plane.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 Linaro Ltd.
+ * Copyright 2016 ZTE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ZX_PLANE_H__
+#define __ZX_PLANE_H__
+
+struct zx_layer_data {
+ void __iomem *layer;
+ void __iomem *csc;
+ void __iomem *hbsc;
+ void __iomem *rsz;
+};
+
+struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
+ struct zx_layer_data *data,
+ enum drm_plane_type type);
+void zx_plane_set_update(struct drm_plane *plane);
+
+#endif /* __ZX_PLANE_H__ */
--
1.9.1
^ permalink raw reply related
* [PATCH v2 1/2] dt-bindings: add bindings doc for ZTE VOU display controller
From: Shawn Guo @ 2016-09-24 14:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474727185-24180-1-git-send-email-shawn.guo@linaro.org>
It adds initial bindings doc for ZTE VOU display controller. HDMI is
the only supported output device right now.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
.../devicetree/bindings/display/zte,vou.txt | 86 ++++++++++++++++++++++
1 file changed, 86 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/zte,vou.txt
diff --git a/Documentation/devicetree/bindings/display/zte,vou.txt b/Documentation/devicetree/bindings/display/zte,vou.txt
new file mode 100644
index 000000000000..d03ba4c4810c
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/zte,vou.txt
@@ -0,0 +1,86 @@
+ZTE VOU Display Controller
+
+This is a display controller found on ZTE ZX296718 SoC. It includes multiple
+Graphic Layer (GL) and Video Layer (VL), two Mixers/Channels, and a few blocks
+handling scaling, color space conversion etc. VOU also integrates the support
+for typical output devices, like HDMI, TV Encoder, VGA, and RGB LCD.
+
+* Master VOU node
+
+It must be the parent node of all the sub-device nodes.
+
+Required properties:
+ - compatible: should be "zte,zx296718-vou"
+ - #address-cells: should be <1>
+ - #size-cells: should be <1>
+ - reg: Physical base address and length of the whole VOU IO region
+ - ranges: to allow probing of sub-devices
+
+* VOU DPC device
+
+Required properties:
+ - compatible: should be "zte,zx296718-dpc"
+ - reg: Physical base address and length of DPC register regions, one for each
+ entry in 'reg-names'
+ - reg-names: The names of register regions. The following regions are required:
+ "osd"
+ "timing_ctrl"
+ "dtrc"
+ "vou_ctrl"
+ "otfppu"
+ - interrupts: VOU DPC interrupt number to CPU
+ - clocks: A list of phandle + clock-specifier pairs, one for each entry
+ in 'clock-names'
+ - clock-names: A list of clock names. The following clocks are required:
+ "aclk"
+ "ppu_wclk"
+ "main_wclk"
+ "aux_wclk"
+
+* HDMI output device
+
+Required properties:
+ - compatible: should be "zte,zx296718-hdmi"
+ - reg: Physical base address and length of the HDMI device IO region
+ - interrupts : HDMI interrupt number to CPU
+ - clocks: A list of phandle + clock-specifier pairs, one for each entry
+ in 'clock-names'
+ - clock-names: A list of clock names. The following clocks are required:
+ "osc_cec"
+ "osc_clk"
+ "xclk"
+
+Example:
+
+vou: vou at 1440000 {
+ compatible = "zte,zx296718-vou";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x1440000 0x10000>;
+ ranges;
+
+ dpc: dpc at 1440000 {
+ compatible = "zte,zx296718-dpc";
+ reg = <0x1440000 0x1000>, <0x1441000 0x1000>,
+ <0x1445000 0x1000>, <0x1446000 0x1000>,
+ <0x144a000 0x1000>;
+ reg-names = "osd", "timing_ctrl",
+ "dtrc", "vou_ctrl",
+ "otfppu";
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&topcrm VOU_ACLK>, <&topcrm VOU_PPU_WCLK>,
+ <&topcrm VOU_MAIN_WCLK>, <&topcrm VOU_AUX_WCLK>;
+ clock-names = "aclk", "ppu_wclk",
+ "main_wclk", "aux_wclk";
+ };
+
+ hdmi: hdmi at 144c000 {
+ compatible = "zte,zx296718-hdmi";
+ reg = <0x144c000 0x4000>;
+ interrupts = <GIC_SPI 82 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&topcrm HDMI_OSC_CEC>,
+ <&topcrm HDMI_OSC_CLK>,
+ <&topcrm HDMI_XCLK>;
+ clock-names = "osc_cec", "osc_clk", "xclk";
+ };
+};
--
1.9.1
^ permalink raw reply related
* [PATCH v2 0/2] Add initial ZTE VOU DRM/KMS driver
From: Shawn Guo @ 2016-09-24 14:26 UTC (permalink / raw)
To: linux-arm-kernel
The series adds the initial ZTE VOU display controller DRM/KMS driver.
There are still some features to be added, like overlay plane, scaling,
and more output devices support. But it's already useful with dual
CRTCs and HDMI monitor working.
Changes for v2:
- Change device tree bindings to kill the virtual display-subsystem
node make VOU the parent node.
Shawn Guo (2):
dt-bindings: add bindings doc for ZTE VOU display controller
drm: zte: add initial vou drm driver
.../devicetree/bindings/display/zte,vou.txt | 86 +++
drivers/gpu/drm/Kconfig | 2 +
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/zte/Kconfig | 8 +
drivers/gpu/drm/zte/Makefile | 8 +
drivers/gpu/drm/zte/zx_crtc.c | 691 +++++++++++++++++++++
drivers/gpu/drm/zte/zx_crtc.h | 47 ++
drivers/gpu/drm/zte/zx_drm_drv.c | 258 ++++++++
drivers/gpu/drm/zte/zx_drm_drv.h | 22 +
drivers/gpu/drm/zte/zx_hdmi.c | 540 ++++++++++++++++
drivers/gpu/drm/zte/zx_plane.c | 362 +++++++++++
drivers/gpu/drm/zte/zx_plane.h | 26 +
12 files changed, 2051 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/zte,vou.txt
create mode 100644 drivers/gpu/drm/zte/Kconfig
create mode 100644 drivers/gpu/drm/zte/Makefile
create mode 100644 drivers/gpu/drm/zte/zx_crtc.c
create mode 100644 drivers/gpu/drm/zte/zx_crtc.h
create mode 100644 drivers/gpu/drm/zte/zx_drm_drv.c
create mode 100644 drivers/gpu/drm/zte/zx_drm_drv.h
create mode 100644 drivers/gpu/drm/zte/zx_hdmi.c
create mode 100644 drivers/gpu/drm/zte/zx_plane.c
create mode 100644 drivers/gpu/drm/zte/zx_plane.h
--
1.9.1
^ permalink raw reply
* [PATCH 1/2] dt-bindings: add bindings doc for ZTE VOU display controller
From: Shawn Guo @ 2016-09-24 14:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160923223043.GA30909@rob-hp-laptop>
On Fri, Sep 23, 2016 at 05:30:43PM -0500, Rob Herring wrote:
> > +display-subsystem {
> > + compatible = "zte,zx-display-subsystem";
> > + #address-cells = <1>;
> > + #size-cells = <1>;
> > + ranges;
> > +
> > + vou: vou at 1440000 {
> > + compatible = "zte,zx296718-vou";
> > + reg = <0x1440000 0x10000>;
> > + interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
> > + clocks = <&topcrm VOU_ACLK>, <&topcrm VOU_PPU_WCLK>,
> > + <&topcrm VOU_MAIN_WCLK>, <&topcrm VOU_AUX_WCLK>;
> > + clock-names = "aclk", "ppu_wclk",
> > + "main_wclk", "aux_wclk";
> > + };
> > +
> > + hdmi: hdmi at 144c000 {
> > + compatible = "zte,zx296718-hdmi";
> > + reg = <0x144c000 0x4000>;
>
> You have overlapping regions here. I'd suggest you kill off
> zte,zx-display-subsystem and make zte,zx296718-vou the top-level node
> with hdmi and others as the child nodes.
I was trying to make device tree simple by defining those discrete
regions in kernel driver. But honestly, I'm also unhappy about that
virtual top-level node. Version 2 Will come soon with suggested
bindings.
Shawn
^ permalink raw reply
* [PATCH 2/2] drm: zte: add initial vou drm driver
From: Shawn Guo @ 2016-09-24 14:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAKMK7uEqrGCRwC-M5daTbrqVjs54C6jC=uYshXa_ciiN7Ftmqg@mail.gmail.com>
On Fri, Sep 23, 2016 at 01:54:59PM +0200, Daniel Vetter wrote:
> Please resubmit with dri-devel on cc.
My bad. Will do shortly.
Shawn
^ permalink raw reply
* [PATCH v6 2/4] arm64: dts: Add timer erratum property for LS2080A and LS1043A
From: Shawn Guo @ 2016-09-24 14:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <57E53FBB.9090208@arm.com>
On Fri, Sep 23, 2016 at 03:44:11PM +0100, Marc Zyngier wrote:
> With a commit message along the lines of:
>
> Both the LS1043A and LS2080A platforms are affected by the Freescale
> A008585 erratum. Advertise it in their respective device trees.
<snip>
> Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Thanks, Marc. I queued up the patch with the suggested commit log
added.
Shawn
^ permalink raw reply
* [PATCH v6 2/4] arm64: dts: Add timer erratum property for LS2080A and LS1043A
From: Shawn Guo @ 2016-09-24 14:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160923162755.GG6397@arm.com>
On Fri, Sep 23, 2016 at 05:27:56PM +0100, Will Deacon wrote:
> On Thu, Sep 22, 2016 at 03:35:16AM -0500, Scott Wood wrote:
> > Signed-off-by: Scott Wood <oss@buserror.net>
> > ---
> > arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 1 +
> > arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi | 1 +
> > 2 files changed, 2 insertions(+)
>
> This patch conflicts with mainline,
Thanks for the heads-up.
> but I've queued the other three
> patches in the series in the arm64 tree.
>
> Please send the updated .dts changes via arm-soc.
I will send this to arm-soc when v4.9-rc1 comes out with driver changes
in place.
Shawn
^ permalink raw reply
* [PATCH v2 0/2] BQL support and fix for a regression issue
From: David Miller @ 2016-09-24 12:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474621948-9172-1-git-send-email-sunil.kovvuri@gmail.com>
From: sunil.kovvuri@gmail.com
Date: Fri, 23 Sep 2016 14:42:26 +0530
> From: Sunil Goutham <sgoutham@cavium.com>
>
> These patches add byte queue limit support and also fixes a regression
> issue introduced by commit
> 'net: thunderx: Use netdev's name for naming VF's interrupts'
>
> Changes from v1:
> - As suggested added 'Fixes' tag with commit id of previous commit
> which cuased issue.
> - Also fixed the missing netdev_tx_reset_queue() function call in
> byte queue limits support patch.
Series applied to net-next, thanks.
^ permalink raw reply
* [PATCH 1/1] ARM: add printf format attribute to early_print()
From: Nicolas Iooss @ 2016-09-24 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160828165815.25647-1-nicolas.iooss_linux@m4x.org>
On 28/08/16 18:58, Nicolas Iooss wrote:
> Adding such an attribute is helpful to detect errors related to printf
> formats at compile-time.
>
> Signed-off-by: Nicolas Iooss <nicolas.iooss_linux@m4x.org>
> ---
> arch/arm/include/asm/setup.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h
> index 3613d7e9fc40..797b8505b49a 100644
> --- a/arch/arm/include/asm/setup.h
> +++ b/arch/arm/include/asm/setup.h
> @@ -22,7 +22,7 @@
> static const struct tagtable __tagtable_##fn __tag = { tag, fn }
>
> extern int arm_add_memory(u64 start, u64 size);
> -extern void early_print(const char *str, ...);
> +extern __printf(1, 2) void early_print(const char *str, ...);
> extern void dump_machine_table(void);
>
> #ifdef CONFIG_ATAGS_PROC
Hello,
I sent this patch a few weeks ago and got no reply (and nothing showed
up on https://patchwork.kernel.org/patch/9302825/). Could you please
consider it for 4.9?
Thanks,
Nicolas
^ permalink raw reply
* Alignment issues with freescale FEC driver
From: Eric Nelson @ 2016-09-24 12:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160923.224305.942077200829435690.davem@davemloft.net>
Hi David,
On 09/23/2016 07:43 PM, David Miller wrote:
> From: Eric Nelson <eric@nelint.com>
> Date: Fri, 23 Sep 2016 10:33:29 -0700
>
>> Since the hardware requires longword alignment for its' DMA transfers,
>> aligning the IP header will require a memcpy, right?
>
> I wish hardware designers didn't do this.
>
> There is no conflict between DMA alignment and properly offseting
> the packet data by two bytes.
>
> All hardware designers have to do is allow 2 padding bytes to be
> emitted by the chip before the actual packet data.
>
Andrew Lunn pointed out that the hardware does support this,
and I just pushed a patch for the vendor kernel to the meta-freescale
mailing list:
https://lists.yoctoproject.org/pipermail/meta-freescale/2016-September/019228.html
> Then the longword or whatever DMA transfer alignment is met
> whilst still giving the necessary flexibility for where the
> packet data lands.
>
Right. A relatively small change fixes things right up.
Many thanks to Andrew for pointing this out and Russell for providing
the basis for my patch.
I'll re-work this for the up-stream kernel when I get out from
under a couple of unrelated things.
^ permalink raw reply
* [PATCH v2] i2c: uniphier-f: fix misdetection of incomplete STOP condition
From: Wolfram Sang @ 2016-09-24 9:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474637681-9589-1-git-send-email-yamada.masahiro@socionext.com>
On Fri, Sep 23, 2016 at 10:34:41PM +0900, Masahiro Yamada wrote:
> Currently, the status register FI2C_SR is checked immediately after
> a STOP condition is issued in case of the deferred STOP condition.
> It takes typically 5-10 usec until the corresponding bits in the
> register are set, so the error check for "stop condition was not
> completed" is very likely to be false positive.
>
> Add wait code to relax the status register check.
>
> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Applied to for-next, thanks!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160924/977ad2d7/attachment.sig>
^ permalink raw reply
* UBSAN: Undefined behaviour in ./arch/arm/include/asm/bitops.h
From: Russell King - ARM Linux @ 2016-09-24 9:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <57E604ED.6000408@samsung.com>
On Sat, Sep 24, 2016 at 01:45:33PM +0900, Seung-Woo Kim wrote:
> With the patch "arm: ubsan: select ARCH_HAS_UBSAN_SANITIZE_ALL", I got
> following UBSAN warning on Exynos5422 SoC board.
Well, the simple solution is to have fls() and ffs() take unsigned int
arguments rather than ints - but the question that brings up is: why
do both of these take signed ints? It seems at least to me that it
would be more sensible for these to take unsigned int, or even
unsigned long like the other bitops do.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
^ permalink raw reply
* [PATCH 5/5] tty: amba-pl011: Add earlycon support for SBSA UART
From: Kefeng Wang @ 2016-09-24 9:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474708465-38958-1-git-send-email-wangkefeng.wang@huawei.com>
Declare an OF early console for SBSA UART so that the early console device
can be specified via the "stdout-path" property in device-tree.
Cc: Russell King <linux@armlinux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
drivers/tty/serial/amba-pl011.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 7d9b291..3688d3b 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2330,6 +2330,7 @@ static int __init pl011_early_console_setup(struct earlycon_device *device,
return 0;
}
OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
+OF_EARLYCON_DECLARE(pl011, "arm,sbsa-uart", pl011_early_console_setup);
#else
#define AMBA_CONSOLE NULL
--
1.7.12.4
^ permalink raw reply related
* [PATCH 4/5] tty: amba-pl011: Don't complain on -EPROBE_DEFER when no irq
From: Kefeng Wang @ 2016-09-24 9:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474708465-38958-1-git-send-email-wangkefeng.wang@huawei.com>
Don't complain on -EPROBE_DEFER when attempting to get the irq.
the driver probe will be retried later.
Cc: Russell King <linux@armlinux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
drivers/tty/serial/amba-pl011.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 8a9e213..7d9b291 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2555,7 +2555,8 @@ static int sbsa_uart_probe(struct platform_device *pdev)
ret = platform_get_irq(pdev, 0);
if (ret < 0) {
- dev_err(&pdev->dev, "cannot obtain irq\n");
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "cannot obtain irq\n");
return ret;
}
uap->port.irq = ret;
--
1.7.12.4
^ permalink raw reply related
* [PATCH 3/5] arm64: dts: hisilicon: Add initial dts for Hip07 D05 board
From: Kefeng Wang @ 2016-09-24 9:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474708465-38958-1-git-send-email-wangkefeng.wang@huawei.com>
Adding initial dt file for Hip07 D05 board, it is with dual socket
and each socket has two SCCLs(supper cpu cluster), one SCCL contains
four clusters and each cluster has quard Cortex-A72.
Since each SCCL has their own DDR controller, it could be treated as
a separate numa node. Thus, there are four numa nodes(one node with
sixteen core) on Hip07 SoC.
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
arch/arm64/boot/dts/hisilicon/Makefile | 1 +
arch/arm64/boot/dts/hisilicon/hip07-d05.dts | 66 ++
arch/arm64/boot/dts/hisilicon/hip07.dtsi | 1059 +++++++++++++++++++++++++++
3 files changed, 1126 insertions(+)
create mode 100644 arch/arm64/boot/dts/hisilicon/hip07-d05.dts
create mode 100644 arch/arm64/boot/dts/hisilicon/hip07.dtsi
diff --git a/arch/arm64/boot/dts/hisilicon/Makefile b/arch/arm64/boot/dts/hisilicon/Makefile
index d5f43a0..c8b8f80 100644
--- a/arch/arm64/boot/dts/hisilicon/Makefile
+++ b/arch/arm64/boot/dts/hisilicon/Makefile
@@ -1,6 +1,7 @@
dtb-$(CONFIG_ARCH_HISI) += hi6220-hikey.dtb
dtb-$(CONFIG_ARCH_HISI) += hip05-d02.dtb
dtb-$(CONFIG_ARCH_HISI) += hip06-d03.dtb
+dtb-$(CONFIG_ARCH_HISI) += hip07-d05.dtb
always := $(dtb-y)
subdir-y := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/hisilicon/hip07-d05.dts b/arch/arm64/boot/dts/hisilicon/hip07-d05.dts
new file mode 100644
index 0000000..e058442
--- /dev/null
+++ b/arch/arm64/boot/dts/hisilicon/hip07-d05.dts
@@ -0,0 +1,66 @@
+/**
+ * dts file for Hisilicon D05 Development Board
+ *
+ * Copyright (C) 2016 Hisilicon Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * publishhed by the Free Software Foundation.
+ *
+ */
+
+/dts-v1/;
+
+#include "hip07.dtsi"
+
+/ {
+ model = "Hisilicon Hip07 D05 Development Board";
+ compatible = "hisilicon,hip07-d05";
+
+ /* the mem node will be updated by UEFI. */
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x0 0x00000000 0x0 0x40000000>;
+ numa-node-id = <0>;
+ };
+
+ distance-map {
+ compatible = "numa-distance-map-v1";
+ distance-matrix = <0 0 10>,
+ <0 1 15>,
+ <0 2 20>,
+ <0 3 25>,
+ <1 0 15>,
+ <1 1 10>,
+ <1 2 25>,
+ <1 3 30>,
+ <2 0 20>,
+ <2 1 25>,
+ <2 2 10>,
+ <2 3 15>,
+ <3 0 25>,
+ <3 1 30>,
+ <3 2 15>,
+ <3 3 10>;
+ };
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
+
+&usb_ohci {
+ status = "ok";
+};
+
+&usb_ehci {
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/hisilicon/hip07.dtsi b/arch/arm64/boot/dts/hisilicon/hip07.dtsi
new file mode 100644
index 0000000..5144eb1
--- /dev/null
+++ b/arch/arm64/boot/dts/hisilicon/hip07.dtsi
@@ -0,0 +1,1059 @@
+/**
+ * dts file for Hisilicon D05 Development Board
+ *
+ * Copyright (C) 2016 Hisilicon Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * publishhed by the Free Software Foundation.
+ *
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ compatible = "hisilicon,hip07-d05";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&cpu0>;
+ };
+ core1 {
+ cpu = <&cpu1>;
+ };
+ core2 {
+ cpu = <&cpu2>;
+ };
+ core3 {
+ cpu = <&cpu3>;
+ };
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&cpu4>;
+ };
+ core1 {
+ cpu = <&cpu5>;
+ };
+ core2 {
+ cpu = <&cpu6>;
+ };
+ core3 {
+ cpu = <&cpu7>;
+ };
+ };
+
+ cluster2 {
+ core0 {
+ cpu = <&cpu8>;
+ };
+ core1 {
+ cpu = <&cpu9>;
+ };
+ core2 {
+ cpu = <&cpu10>;
+ };
+ core3 {
+ cpu = <&cpu11>;
+ };
+ };
+
+ cluster3 {
+ core0 {
+ cpu = <&cpu12>;
+ };
+ core1 {
+ cpu = <&cpu13>;
+ };
+ core2 {
+ cpu = <&cpu14>;
+ };
+ core3 {
+ cpu = <&cpu15>;
+ };
+ };
+
+ cluster4 {
+ core0 {
+ cpu = <&cpu16>;
+ };
+ core1 {
+ cpu = <&cpu17>;
+ };
+ core2 {
+ cpu = <&cpu18>;
+ };
+ core3 {
+ cpu = <&cpu19>;
+ };
+ };
+
+ cluster5 {
+ core0 {
+ cpu = <&cpu20>;
+ };
+ core1 {
+ cpu = <&cpu21>;
+ };
+ core2 {
+ cpu = <&cpu22>;
+ };
+ core3 {
+ cpu = <&cpu23>;
+ };
+ };
+
+ cluster6 {
+ core0 {
+ cpu = <&cpu24>;
+ };
+ core1 {
+ cpu = <&cpu25>;
+ };
+ core2 {
+ cpu = <&cpu26>;
+ };
+ core3 {
+ cpu = <&cpu27>;
+ };
+ };
+
+ cluster7 {
+ core0 {
+ cpu = <&cpu28>;
+ };
+ core1 {
+ cpu = <&cpu29>;
+ };
+ core2 {
+ cpu = <&cpu30>;
+ };
+ core3 {
+ cpu = <&cpu31>;
+ };
+ };
+
+ cluster8 {
+ core0 {
+ cpu = <&cpu32>;
+ };
+ core1 {
+ cpu = <&cpu33>;
+ };
+ core2 {
+ cpu = <&cpu34>;
+ };
+ core3 {
+ cpu = <&cpu35>;
+ };
+ };
+
+ cluster9 {
+ core0 {
+ cpu = <&cpu36>;
+ };
+ core1 {
+ cpu = <&cpu37>;
+ };
+ core2 {
+ cpu = <&cpu38>;
+ };
+ core3 {
+ cpu = <&cpu39>;
+ };
+ };
+
+ cluster10 {
+ core0 {
+ cpu = <&cpu40>;
+ };
+ core1 {
+ cpu = <&cpu41>;
+ };
+ core2 {
+ cpu = <&cpu42>;
+ };
+ core3 {
+ cpu = <&cpu43>;
+ };
+ };
+
+ cluster11 {
+ core0 {
+ cpu = <&cpu44>;
+ };
+ core1 {
+ cpu = <&cpu45>;
+ };
+ core2 {
+ cpu = <&cpu46>;
+ };
+ core3 {
+ cpu = <&cpu47>;
+ };
+ };
+
+ cluster12 {
+ core0 {
+ cpu = <&cpu48>;
+ };
+ core1 {
+ cpu = <&cpu49>;
+ };
+ core2 {
+ cpu = <&cpu50>;
+ };
+ core3 {
+ cpu = <&cpu51>;
+ };
+ };
+
+ cluster13 {
+ core0 {
+ cpu = <&cpu52>;
+ };
+ core1 {
+ cpu = <&cpu53>;
+ };
+ core2 {
+ cpu = <&cpu54>;
+ };
+ core3 {
+ cpu = <&cpu55>;
+ };
+ };
+
+ cluster14 {
+ core0 {
+ cpu = <&cpu56>;
+ };
+ core1 {
+ cpu = <&cpu57>;
+ };
+ core2 {
+ cpu = <&cpu58>;
+ };
+ core3 {
+ cpu = <&cpu59>;
+ };
+ };
+
+ cluster15 {
+ core0 {
+ cpu = <&cpu60>;
+ };
+ core1 {
+ cpu = <&cpu61>;
+ };
+ core2 {
+ cpu = <&cpu62>;
+ };
+ core3 {
+ cpu = <&cpu63>;
+ };
+ };
+ };
+
+ cpu0: cpu at 10000 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10000>;
+ enable-method = "psci";
+ next-level-cache = <&cluster0_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu1: cpu at 10001 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10001>;
+ enable-method = "psci";
+ next-level-cache = <&cluster0_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu2: cpu at 10002 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10002>;
+ enable-method = "psci";
+ next-level-cache = <&cluster0_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu3: cpu at 10003 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10003>;
+ enable-method = "psci";
+ next-level-cache = <&cluster0_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu4: cpu at 10100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10100>;
+ enable-method = "psci";
+ next-level-cache = <&cluster1_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu5: cpu at 10101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10101>;
+ enable-method = "psci";
+ next-level-cache = <&cluster1_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu6: cpu at 10102 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10102>;
+ enable-method = "psci";
+ next-level-cache = <&cluster1_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu7: cpu at 10103 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10103>;
+ enable-method = "psci";
+ next-level-cache = <&cluster1_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu8: cpu at 10200 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10200>;
+ enable-method = "psci";
+ next-level-cache = <&cluster2_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu9: cpu at 10201 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10201>;
+ enable-method = "psci";
+ next-level-cache = <&cluster2_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu10: cpu at 10202 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10202>;
+ enable-method = "psci";
+ next-level-cache = <&cluster2_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu11: cpu at 10203 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10203>;
+ enable-method = "psci";
+ next-level-cache = <&cluster2_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu12: cpu at 10300 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10300>;
+ enable-method = "psci";
+ next-level-cache = <&cluster3_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu13: cpu at 10301 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10301>;
+ enable-method = "psci";
+ next-level-cache = <&cluster3_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu14: cpu at 10302 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10302>;
+ enable-method = "psci";
+ next-level-cache = <&cluster3_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu15: cpu at 10303 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x10303>;
+ enable-method = "psci";
+ next-level-cache = <&cluster3_l2>;
+ numa-node-id = <0>;
+ };
+
+ cpu16: cpu at 30000 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30000>;
+ enable-method = "psci";
+ next-level-cache = <&cluster4_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu17: cpu at 30001 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30001>;
+ enable-method = "psci";
+ next-level-cache = <&cluster4_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu18: cpu at 30002 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30002>;
+ enable-method = "psci";
+ next-level-cache = <&cluster4_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu19: cpu at 30003 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30003>;
+ enable-method = "psci";
+ next-level-cache = <&cluster4_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu20: cpu at 30100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30100>;
+ enable-method = "psci";
+ next-level-cache = <&cluster5_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu21: cpu at 30101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30101>;
+ enable-method = "psci";
+ next-level-cache = <&cluster5_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu22: cpu at 30102 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30102>;
+ enable-method = "psci";
+ next-level-cache = <&cluster5_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu23: cpu at 30103 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30103>;
+ enable-method = "psci";
+ next-level-cache = <&cluster5_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu24: cpu at 30200 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30200>;
+ enable-method = "psci";
+ next-level-cache = <&cluster6_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu25: cpu at 30201 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30201>;
+ enable-method = "psci";
+ next-level-cache = <&cluster6_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu26: cpu at 30202 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30202>;
+ enable-method = "psci";
+ next-level-cache = <&cluster6_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu27: cpu at 30203 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30203>;
+ enable-method = "psci";
+ next-level-cache = <&cluster6_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu28: cpu at 30300 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30300>;
+ enable-method = "psci";
+ next-level-cache = <&cluster7_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu29: cpu at 30301 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30301>;
+ enable-method = "psci";
+ next-level-cache = <&cluster7_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu30: cpu at 30302 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30302>;
+ enable-method = "psci";
+ next-level-cache = <&cluster7_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu31: cpu at 30303 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x30303>;
+ enable-method = "psci";
+ next-level-cache = <&cluster7_l2>;
+ numa-node-id = <1>;
+ };
+
+ cpu32: cpu at 50000 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50000>;
+ enable-method = "psci";
+ next-level-cache = <&cluster8_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu33: cpu at 50001 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50001>;
+ enable-method = "psci";
+ next-level-cache = <&cluster8_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu34: cpu at 50002 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50002>;
+ enable-method = "psci";
+ next-level-cache = <&cluster8_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu35: cpu at 50003 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50003>;
+ enable-method = "psci";
+ next-level-cache = <&cluster8_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu36: cpu at 50100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50100>;
+ enable-method = "psci";
+ next-level-cache = <&cluster9_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu37: cpu at 50101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50101>;
+ enable-method = "psci";
+ next-level-cache = <&cluster9_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu38: cpu at 50102 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50102>;
+ enable-method = "psci";
+ next-level-cache = <&cluster9_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu39: cpu at 50103 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50103>;
+ enable-method = "psci";
+ next-level-cache = <&cluster9_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu40: cpu at 50200 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50200>;
+ enable-method = "psci";
+ next-level-cache = <&cluster10_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu41: cpu at 50201 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50201>;
+ enable-method = "psci";
+ next-level-cache = <&cluster10_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu42: cpu at 50202 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50202>;
+ enable-method = "psci";
+ next-level-cache = <&cluster10_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu43: cpu at 50203 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50203>;
+ enable-method = "psci";
+ next-level-cache = <&cluster10_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu44: cpu at 50300 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50300>;
+ enable-method = "psci";
+ next-level-cache = <&cluster11_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu45: cpu at 50301 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50301>;
+ enable-method = "psci";
+ next-level-cache = <&cluster11_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu46: cpu at 50302 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50302>;
+ enable-method = "psci";
+ next-level-cache = <&cluster11_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu47: cpu at 50303 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x50303>;
+ enable-method = "psci";
+ next-level-cache = <&cluster11_l2>;
+ numa-node-id = <2>;
+ };
+
+ cpu48: cpu at 70000 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70000>;
+ enable-method = "psci";
+ next-level-cache = <&cluster12_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu49: cpu at 70001 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70001>;
+ enable-method = "psci";
+ next-level-cache = <&cluster12_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu50: cpu at 70002 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70002>;
+ enable-method = "psci";
+ next-level-cache = <&cluster12_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu51: cpu at 70003 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70003>;
+ enable-method = "psci";
+ next-level-cache = <&cluster12_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu52: cpu at 70100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70100>;
+ enable-method = "psci";
+ next-level-cache = <&cluster13_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu53: cpu at 70101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70101>;
+ enable-method = "psci";
+ next-level-cache = <&cluster13_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu54: cpu at 70102 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70102>;
+ enable-method = "psci";
+ next-level-cache = <&cluster13_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu55: cpu at 70103 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70103>;
+ enable-method = "psci";
+ next-level-cache = <&cluster13_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu56: cpu at 70200 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70200>;
+ enable-method = "psci";
+ next-level-cache = <&cluster14_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu57: cpu at 70201 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70201>;
+ enable-method = "psci";
+ next-level-cache = <&cluster14_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu58: cpu at 70202 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70202>;
+ enable-method = "psci";
+ next-level-cache = <&cluster14_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu59: cpu at 70203 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70203>;
+ enable-method = "psci";
+ next-level-cache = <&cluster14_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu60: cpu at 70300 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70300>;
+ enable-method = "psci";
+ next-level-cache = <&cluster15_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu61: cpu at 70301 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70301>;
+ enable-method = "psci";
+ next-level-cache = <&cluster15_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu62: cpu at 70302 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70302>;
+ enable-method = "psci";
+ next-level-cache = <&cluster15_l2>;
+ numa-node-id = <3>;
+ };
+
+ cpu63: cpu at 70303 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a72", "arm,armv8";
+ reg = <0x70303>;
+ enable-method = "psci";
+ next-level-cache = <&cluster15_l2>;
+ numa-node-id = <3>;
+ };
+
+ cluster0_l2: l2-cache0 {
+ compatible = "cache";
+ };
+
+ cluster1_l2: l2-cache1 {
+ compatible = "cache";
+ };
+
+ cluster2_l2: l2-cache2 {
+ compatible = "cache";
+ };
+
+ cluster3_l2: l2-cache3 {
+ compatible = "cache";
+ };
+
+ cluster4_l2: l2-cache4 {
+ compatible = "cache";
+ };
+
+ cluster5_l2: l2-cache5 {
+ compatible = "cache";
+ };
+
+ cluster6_l2: l2-cache6 {
+ compatible = "cache";
+ };
+
+ cluster7_l2: l2-cache7 {
+ compatible = "cache";
+ };
+
+ cluster8_l2: l2-cache8 {
+ compatible = "cache";
+ };
+
+ cluster9_l2: l2-cache9 {
+ compatible = "cache";
+ };
+
+ cluster10_l2: l2-cache10 {
+ compatible = "cache";
+ };
+
+ cluster11_l2: l2-cache11 {
+ compatible = "cache";
+ };
+
+ cluster12_l2: l2-cache12 {
+ compatible = "cache";
+ };
+
+ cluster13_l2: l2-cache13 {
+ compatible = "cache";
+ };
+
+ cluster14_l2: l2-cache14 {
+ compatible = "cache";
+ };
+
+ cluster15_l2: l2-cache15 {
+ compatible = "cache";
+ };
+ };
+
+ gic: interrupt-controller at 4d000000 {
+ compatible = "arm,gic-v3";
+ #interrupt-cells = <3>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ interrupt-controller;
+ #redistributor-regions = <4>;
+ redistributor-stride = <0x0 0x40000>;
+ reg = <0x0 0x4d000000 0x0 0x10000>, /* GICD */
+ <0x0 0x4d100000 0x0 0x400000>, /* p0 GICR node 0 */
+ <0x0 0x6d100000 0x0 0x400000>, /* p0 GICR node 1 */
+ <0x400 0x4d100000 0x0 0x400000>, /* p1 GICR node 2 */
+ <0x400 0x6d100000 0x0 0x400000>, /* p1 GICR node 3 */
+ <0x0 0xfe000000 0x0 0x10000>, /* GICC */
+ <0x0 0xfe010000 0x0 0x10000>, /* GICH */
+ <0x0 0xfe020000 0x0 0x10000>; /* GICV */
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+
+ p0_its_peri_a: interrupt-controller at 4c000000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x0 0x4c000000 0x0 0x40000>;
+ };
+
+ p0_its_peri_b: interrupt-controller at 6c000000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x0 0x6c000000 0x0 0x40000>;
+ };
+
+ p0_its_dsa_a: interrupt-controller at c6000000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x0 0xc6000000 0x0 0x40000>;
+ };
+
+ p0_its_dsa_b: interrupt-controller at 8,c6000000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x8 0xc6000000 0x0 0x40000>;
+ };
+
+ p1_its_peri_a: interrupt-controller at 400,4c000000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x400 0x4c000000 0x0 0x40000>;
+ };
+
+ p1_its_peri_b: interrupt-controller at 400,6c000000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x400 0x6c000000 0x0 0x40000>;
+ };
+
+ p1_its_dsa_a: interrupt-controller at 400,c6000000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x400 0xc6000000 0x0 0x40000>;
+ };
+
+ p1_its_dsa_b: interrupt-controller at 408,c6000000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ #msi-cells = <1>;
+ reg = <0x408 0xc6000000 0x0 0x40000>;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+ };
+
+ pmu {
+ compatible = "arm,cortex-a72-pmu";
+ interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ p0_mbigen_peri_b: interrupt-controller at 60080000 {
+ compatible = "hisilicon,mbigen-v2";
+ reg = <0x0 0x60080000 0x0 0x10000>;
+
+ mbigen_uart: uart_intc {
+ msi-parent = <&p0_its_peri_b 0x120c7>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ num-pins = <1>;
+ };
+ };
+
+ p0_mbigen_pcie_a: interrupt-controller at a0080000 {
+ compatible = "hisilicon,mbigen-v2";
+ reg = <0x0 0xa0080000 0x0 0x10000>;
+
+ mbigen_usb: intc_usb {
+ msi-parent = <&p0_its_dsa_a 0x40080>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ num-pins = <2>;
+ };
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ uart0: uart at 602b0000 {
+ compatible = "arm,sbsa-uart";
+ reg = <0x0 0x602b0000 0x0 0x1000>;
+ interrupt-parent = <&mbigen_uart>;
+ interrupts = <807 4>;
+ current-speed = <115200>;
+ reg-io-width = <4>;
+ status = "disabled";
+ };
+
+ usb_ohci: ohci at a7030000 {
+ compatible = "generic-ohci";
+ reg = <0x0 0xa7030000 0x0 0x10000>;
+ interrupt-parent = <&mbigen_usb>;
+ interrupts = <640 4>;
+ dma-coherent;
+ status = "disabled";
+ };
+
+ usb_ehci: ehci at a7020000 {
+ compatible = "generic-ehci";
+ reg = <0x0 0xa7020000 0x0 0x10000>;
+ interrupt-parent = <&mbigen_usb>;
+ interrupts = <641 4>;
+ dma-coherent;
+ status = "disabled";
+ };
+ };
+};
--
1.7.12.4
^ permalink raw reply related
* [PATCH 2/5] Documentation: arm64: Add Hisilicon Hip07 D05 dts binding
From: Kefeng Wang @ 2016-09-24 9:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474708465-38958-1-git-send-email-wangkefeng.wang@huawei.com>
This patch adds documentation for the devicetree bindings used by
the DT files of Hisilicon Hip07 D05 board.
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
index 3f81575..7df79a7 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
@@ -28,6 +28,10 @@ HiP06 D03 Board
Required root node properties:
- compatible = "hisilicon,hip06-d03";
+HiP07 D05 Board
+Required root node properties:
+ - compatible = "hisilicon,hip07-d05";
+
Hisilicon system controller
Required properties:
--
1.7.12.4
^ permalink raw reply related
* [PATCH 1/5] arm64: dts: hip06: Correct hardware pin number of usb node
From: Kefeng Wang @ 2016-09-24 9:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474708465-38958-1-git-send-email-wangkefeng.wang@huawei.com>
The ohci/ehci hardware pin number should be 640/641, correct them.
Fixes: commit aa8d3e74f54d ("arm64: dts: Add initial dts for Hisilicon Hip06 D03 board")
Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
arch/arm64/boot/dts/hisilicon/hip06.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/hisilicon/hip06.dtsi b/arch/arm64/boot/dts/hisilicon/hip06.dtsi
index 66b1bbf..be76f7d 100644
--- a/arch/arm64/boot/dts/hisilicon/hip06.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hip06.dtsi
@@ -322,7 +322,7 @@
compatible = "generic-ohci";
reg = <0x0 0xa7030000 0x0 0x10000>;
interrupt-parent = <&mbigen_usb>;
- interrupts = <64 4>;
+ interrupts = <640 4>;
dma-coherent;
status = "disabled";
};
@@ -331,7 +331,7 @@
compatible = "generic-ehci";
reg = <0x0 0xa7020000 0x0 0x10000>;
interrupt-parent = <&mbigen_usb>;
- interrupts = <65 4>;
+ interrupts = <641 4>;
dma-coherent;
status = "disabled";
};
--
1.7.12.4
^ permalink raw reply related
* [PATCH 0/5] arm64: dts: hisilicon: Hip06 fix and support Hip07 D05 board
From: Kefeng Wang @ 2016-09-24 9:14 UTC (permalink / raw)
To: linux-arm-kernel
1) DTs
- Fix Hip06 ehci/ohci interrupt pin number.
- Add initial support for Hip07 D05 board.
2) PL011
- The sbsa uart is used on Hip07 SoC, the interrupt is connected to mbigen,
but the uart probe(arch_init) is earlier than mbigen(module_init), so
don't complain on -EPROBE_DEFER when no irq.
- Add earlycon support for SBSA UART.
Kefeng Wang (5):
arm64: dts: hip06: Correct hardware pin number of usb node
Documentation: arm64: Add Hisilicon Hip07 D05 dts binding
arm64: dts: hisilicon: Add initial dts for Hip07 D05 board
tty: amba-pl011: Don't complain on -EPROBE_DEFER when no irq
tty: amba-pl011: Add earlycon support for SBSA UART
.../bindings/arm/hisilicon/hisilicon.txt | 4 +
arch/arm64/boot/dts/hisilicon/Makefile | 1 +
arch/arm64/boot/dts/hisilicon/hip06.dtsi | 4 +-
arch/arm64/boot/dts/hisilicon/hip07-d05.dts | 66 ++
arch/arm64/boot/dts/hisilicon/hip07.dtsi | 1059 ++++++++++++++++++++
drivers/tty/serial/amba-pl011.c | 4 +-
6 files changed, 1135 insertions(+), 3 deletions(-)
create mode 100644 arch/arm64/boot/dts/hisilicon/hip07-d05.dts
create mode 100644 arch/arm64/boot/dts/hisilicon/hip07.dtsi
--
1.7.12.4
^ permalink raw reply
* [PATCH v3 0/4] regulator: axp20x: support AXP803/AXP813 variants
From: Jean-Francois Moine @ 2016-09-24 9:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v65LjjB_vM46yurKOcw6mMaxW3pXTHwbxQO6L1BTOnTUmw@mail.gmail.com>
On Sat, 24 Sep 2016 16:35:05 +0800
Chen-Yu Tsai <wens@csie.org> wrote:
> On Fri, Sep 23, 2016 at 4:58 PM, Jean-Francois Moine <moinejf@free.fr> wrote:
> > This patch series adds support for the X-Powers AXP803 and AXP813 PMICs.
> > It is based on the previous patch series
> > regulator: axp20x: Simplify various code
> >
> > v3:
> > - put the code of the new devices in new files instead of in the common
> > axp20x file.
> > - fix errors about the regulators and interrupts
> > v2:
> > - fix lack of support of dcdc frequency
> > - notice that the AXP803 is also handled
> > - send the patch to the DT maintainers
> >
> > Jean-Francois Moine (4):
> > regulator: axp20x: move device independant parts to new files
> > regulator: axp20x: duplicate the MFD axp20x-rsb code
> > regulator: axp20x: add the AXP803
> > regulator: axp20x: add the AXP813
>
> NAK. Please follow the axp20x mfd and sub-device driver design we
> already have.
Sorry, I will not: installing a lot of useless code and tables in
permanent system memory for just one regulator is not the way I think
about a good kernel.
--
Ken ar c'henta? | ** Breizh ha Linux atav! **
Jef | http://moinejf.free.fr/
^ permalink raw reply
* [PATCH 3/3] regulator: axp20x: simplify device access
From: Jean-Francois Moine @ 2016-09-24 8:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v64ZpQ=9KUH39cFoRxU6n03cgDoUbHegjFfDWaTLQAZ2wg@mail.gmail.com>
On Sat, 24 Sep 2016 16:29:11 +0800
Chen-Yu Tsai <wens@csie.org> wrote:
[snip]
> > static int axp20x_regulator_probe(struct platform_device *pdev)
> > {
> > + struct device *dev = pdev->dev.parent;
>
> There are 2 struct device's in play in this function, 1 from the parent,
> and 1 for the platform device for this regulator sub-device.
>
> > struct regulator_dev *rdev;
> > - struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
> > + struct axp20x_dev *axp20x = dev_get_drvdata(dev);
> > const struct regulator_desc *regulators;
> > struct regulator_config config = {
> > - .dev = pdev->dev.parent,
> > + .dev = dev,
> > .regmap = axp20x->regmap,
> > .driver_data = axp20x,
> > };
> > @@ -532,7 +533,7 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
> > dcdc5_ix = AXP22X_DCDC5;
> > dc1sw_ix = AXP22X_DC1SW;
> > dc5ldo_ix = AXP22X_DC5LDO;
> > - drivevbus = of_property_read_bool(pdev->dev.parent->of_node,
> > + drivevbus = of_property_read_bool(dev->of_node,
> > "x-powers,drive-vbus-en");
> > break;
> > case AXP806_ID:
> > @@ -555,13 +556,13 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
> > dc5ldo_ix = AXP809_DC5LDO;
> > break;
> > default:
> > - dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n",
> > + dev_err(dev, "Unsupported AXP variant: %ld\n",
>
> So this one is incorrect. You should use this device's struct,
> not the parent. It's possible the mfd driver supports a PMIC,
> but the regulator driver is still missing.
Why do you need a regulator driver? The 'regulator' node in the DT is
not a real device. It is just a container and it could be removed
without any problem.
--
Ken ar c'henta? | ** Breizh ha Linux atav! **
Jef | http://moinejf.free.fr/
^ permalink raw reply
* [PATCH 0/2] i2c: meson: add gxbb compatible string
From: Wolfram Sang @ 2016-09-24 8:41 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAL_JsqJGQ2az=eO0PbfcTrAPxUsym=UaDOOy1Rsw0-AbzMjnXg@mail.gmail.com>
> I did state some reasons previously. Consistent rules for submitters
> of DT bindings and being able to trace history beyond git. Now, I
> guess you aren't changing the rules, but you probably aren't
> requesting people to split DT bindings either? You might not be aware,
> but we also generate a DT only tree with git-filter-branch[1] for
> non-kernel projects to use bindings and dts files. For that, sure they
> will only get the DT binding part of it, but what commit text do they
> get? Finally, DT maintainer acks (which from me is a review really)
> apply to the bindings only. Sometimes I review the drivers, but not
> often. So I would like the git history of my reviews to be accurate in
> terms of what I actually reviewed.
Points taken. Will keep them seperate from now on.
Thanks,
Wolfram
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160924/b82a4946/attachment-0001.sig>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox