Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 4/5] ARM: davinci: enable LEDs default-on trigger in default config
From: Sekhar Nori @ 2016-10-28  9:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <be478f0a-bd10-7241-7e9d-20dfc1beaa30@lechnology.com>

On Thursday 27 October 2016 09:19 PM, David Lechner wrote:
> Yes, module is OK here.

Here is the patch I pushed to v4.10/defconfig.

Thanks,
Sekhar

---8<---
From: David Lechner <david@lechnology.com>
Date: Fri, 21 Oct 2016 13:36:56 -0500
Subject: [PATCH] ARM: davinci_all_defconfig: enable LED default-on trigger

The LEDs default-on trigger is nice to have. For example, it can be used
to configure a LED as a power indicator.

Signed-off-by: David Lechner <david@lechnology.com>
[nsekhar at ti.com: build as module, subject line fixes]
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
 arch/arm/configs/davinci_all_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig
index 513978eaf03d..b5e978ff177f 100644
--- a/arch/arm/configs/davinci_all_defconfig
+++ b/arch/arm/configs/davinci_all_defconfig
@@ -180,6 +180,7 @@ CONFIG_LEDS_GPIO=m
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_TIMER=m
 CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_OMAP=m
 CONFIG_DMADEVICES=y
-- 
2.9.0

^ permalink raw reply related

* [PATCH] KVM: arm/arm64: Kick VCPUs when queueing already pending IRQs
From: Christoffer Dall @ 2016-10-28  8:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477580893-3479-1-git-send-email-shihwei@cs.columbia.edu>

On Thu, Oct 27, 2016 at 03:08:13PM +0000, Shih-Wei Li wrote:
> In cases like IPI, we could be queueing an interrupt for a VCPU
> that is already running and is not about to exit, because the
> VCPU has entered the VM with the interrupt pending and would
> not trap on EOI'ing that interrupt. This could result to delays
> in interrupt deliveries or even loss of interrupts.
> To guarantee prompt interrupt injection, here we have to try to
> kick the VCPU.
> 
> Signed-off-by: Shih-Wei Li <shihwei@cs.columbia.edu>
> ---
> 
> I've tested the code with an IPI test built on kvm-unit-test, which
> measures the cycles spent between one VCPU sending IPI to a target
> VCPU that busy loops in the VM, until the target VCPU ACKs and EOIs
> the IPI. The patch here can improve the performance in such case by
> more than 5000 cycles.
> 
>  virt/kvm/arm/vgic/vgic.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index b419a11..07cf239 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -273,6 +273,17 @@ retry:
>  		 * no more work for us to do.
>  		 */
>  		spin_unlock(&irq->irq_lock);
> +
> +		/*
> +		 * If the VCPU is not NULL, we could be queueing an
> +		 * edge-triggered interrupt for a VCPU which is already
> +		 * running and is not about to exit, because the VCPU has
> +		 * entered the VM with the interrupt pending and it wouldn't
> +		 * trap on EOI. To ensure prompt delivery of that interrupt,
> +		 * we have to try to kick the VCPU.
> +		 */

Perhaps the following comment is a better description:

		/*
		 * We have to kick the VCPU here, because we could be queueing
		 * an edge-triggered interrupt for which we get no EOI
		 * maintenance interrupt.  In that case, while the IRQ is
		 * already on the VCPU's AP list, the VCPU could have EOI'ed the
		 * original interrupt and won't see this one until it exits for
		 * some other reason.
		 */

> +		if (vcpu)
> +			kvm_vcpu_kick(vcpu);
>  		return false;
>  	}
>  

Otherwise:

Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>

^ permalink raw reply

* [PATCH] drm/mediatek: fix null pointer dereference
From: CK Hu @ 2016-10-28  8:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161026140904.26798-1-matthias.bgg@gmail.com>

Hi, Matthias:

Even though OVL HW would not be enabled before component_add() in
current design, your patch would be safe for any situation.

Acked-by CK Hu <ck.hu@mediatek.com>

Regards,
CK

On Wed, 2016-10-26 at 16:09 +0200, Matthias Brugger wrote:
> The probe function requests the interrupt before initializing
> the ddp component. Which leads to a null pointer dereference at boot.
> Fix this by requesting the interrput after all components got
> initialized properly.
> 
> Fixes: 119f5173628a ("drm/mediatek: Add DRM Driver for Mediatek SoC
> MT8173.")
> Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
> ---
>  drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 14 +++++++-------
>  1 file changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> index 019b7ca..1e78159 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> @@ -250,13 +250,6 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
>  	if (irq < 0)
>  		return irq;
>  
> -	ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler,
> -			       IRQF_TRIGGER_NONE, dev_name(dev), priv);
> -	if (ret < 0) {
> -		dev_err(dev, "Failed to request irq %d: %d\n", irq, ret);
> -		return ret;
> -	}
> -
>  	comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_OVL);
>  	if (comp_id < 0) {
>  		dev_err(dev, "Failed to identify by alias: %d\n", comp_id);
> @@ -272,6 +265,13 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev)
>  
>  	platform_set_drvdata(pdev, priv);
>  
> +	ret = devm_request_irq(dev, irq, mtk_disp_ovl_irq_handler,
> +			       IRQF_TRIGGER_NONE, dev_name(dev), priv);
> +	if (ret < 0) {
> +		dev_err(dev, "Failed to request irq %d: %d\n", irq, ret);
> +		return ret;
> +	}
> +
>  	ret = component_add(dev, &mtk_disp_ovl_component_ops);
>  	if (ret)
>  		dev_err(dev, "Failed to add component: %d\n", ret);

^ permalink raw reply

* [PATCH v6 4/5] ARM: DTS: da850: Add cfgchip syscon node
From: Sekhar Nori @ 2016-10-28  8:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <b9bfc4aa-ef52-53c4-dc7e-c0bc1c5969fb@lechnology.com>

On Wednesday 26 October 2016 09:38 PM, David Lechner wrote:
> On 10/25/2016 10:06 PM, David Lechner wrote:
>> Add a syscon node for the SoC CFGCHIPn registers. This is needed for
>> the new usb phy driver.
>>
>> Signed-off-by: David Lechner <david@lechnology.com>
>> ---
>>  arch/arm/boot/dts/da850.dtsi | 4 ++++
>>  1 file changed, 4 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
>> index f79e1b9..6bbf20d 100644
>> --- a/arch/arm/boot/dts/da850.dtsi
>> +++ b/arch/arm/boot/dts/da850.dtsi
>> @@ -188,6 +188,10 @@
>>              };
>>
>>          };
>> +        cfgchip: cfgchip at 1417c {
> 
> I wonder if there is a more generic name instead of cfgchip at . Is there a
> preferred generic name for syscon nodes?

I did not find anything in ePAPR, but chip-controller might be more
appropriate.

> 
>> +            compatible = "ti,da830-cfgchip", "syscon";

Looks like we need "simple-mfd" too in the compatible list?

I think we can also fold patch 5/5 into this patch and add the cfgchip
along with USB phy child node included.

If you respin the patch, I can drop 4/5 and 5/5 that I have queued and
included the updated patch instead.

Thanks,
Sekhar

^ permalink raw reply

* [PATCH v2] ASoC: hdmi-codec: Fix hdmi_of_xlate_dai_name when #sound-dai-cells = <0>
From: Jon Medhurst (Tixy) @ 2016-10-28  8:18 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161027141956.GL25322@sirena.org.uk>

If a DAI specifies "#sound-dai-cells = <0>" in device-tree then
hdmi_of_xlate_dai_name() will be called with zero args, which it isn't
implemented to cope with. The resulting use of an uninitialised variable
for the id will usually result in an error like:

  asoc-simple-card sound: parse error -11
  asoc-simple-card: probe of sound failed with error -11

Fix this by using and id of zero if no arg is provided.

Fixes: 9731f82d6016 ("ASoC: hdmi-codec: enable multi probe for same device")

Signed-off-by: Jon Medhurst <tixy@linaro.org>
---

Changes since v1
- Replace ternary ?: operator with if/else

 sound/soc/codecs/hdmi-codec.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index b904492..90b5948 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c
@@ -364,7 +364,12 @@ static int hdmi_of_xlate_dai_name(struct snd_soc_component *component,
 				  struct of_phandle_args *args,
 				  const char **dai_name)
 {
-	int id = args->args[0];
+	int id;
+
+	if (args->args_count)
+		id = args->args[0];
+	else
+		id = 0;
 
 	if (id < ARRAY_SIZE(hdmi_dai_name)) {
 		*dai_name = hdmi_dai_name[id];
-- 
2.1.4

^ permalink raw reply related

* [PATCH v3] char: hw_random: atmel-rng: disable TRNG during suspend
From: Wenyou Yang @ 2016-10-28  8:00 UTC (permalink / raw)
  To: linux-arm-kernel

To fix the over consumption on the VDDCore due to the TRNG enabled,
disable the TRNG during suspend, not only disable the user interface
clock (which is controlled by PMC). Because the user interface clock
is independent from any clock that may be used in the entropy source
logic circuitry.

Signed-off-by: Wenyou Yang <wenyou.yang@atmel.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
---

Changes in v3:
 - Add Acked-by tag.

Changes in v2:
 - Enable the user interface first, then enable the internal clock
   when resume.

 drivers/char/hw_random/atmel-rng.c | 24 +++++++++++++++++++++---
 1 file changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c
index 0fcc9e6..ae7cae5 100644
--- a/drivers/char/hw_random/atmel-rng.c
+++ b/drivers/char/hw_random/atmel-rng.c
@@ -48,6 +48,16 @@ static int atmel_trng_read(struct hwrng *rng, void *buf, size_t max,
 		return 0;
 }
 
+static void atmel_trng_enable(struct atmel_trng *trng)
+{
+	writel(TRNG_KEY | 1, trng->base + TRNG_CR);
+}
+
+static void atmel_trng_disable(struct atmel_trng *trng)
+{
+	writel(TRNG_KEY, trng->base + TRNG_CR);
+}
+
 static int atmel_trng_probe(struct platform_device *pdev)
 {
 	struct atmel_trng *trng;
@@ -71,7 +81,7 @@ static int atmel_trng_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	writel(TRNG_KEY | 1, trng->base + TRNG_CR);
+	atmel_trng_enable(trng);
 	trng->rng.name = pdev->name;
 	trng->rng.read = atmel_trng_read;
 
@@ -94,7 +104,7 @@ static int atmel_trng_remove(struct platform_device *pdev)
 
 	hwrng_unregister(&trng->rng);
 
-	writel(TRNG_KEY, trng->base + TRNG_CR);
+	atmel_trng_disable(trng);
 	clk_disable_unprepare(trng->clk);
 
 	return 0;
@@ -105,6 +115,7 @@ static int atmel_trng_suspend(struct device *dev)
 {
 	struct atmel_trng *trng = dev_get_drvdata(dev);
 
+	atmel_trng_disable(trng);
 	clk_disable_unprepare(trng->clk);
 
 	return 0;
@@ -113,8 +124,15 @@ static int atmel_trng_suspend(struct device *dev)
 static int atmel_trng_resume(struct device *dev)
 {
 	struct atmel_trng *trng = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(trng->clk);
+	if (ret)
+		return ret;
 
-	return clk_prepare_enable(trng->clk);
+	atmel_trng_enable(trng);
+
+	return 0;
 }
 
 static const struct dev_pm_ops atmel_trng_pm_ops = {
-- 
2.7.4

^ permalink raw reply related

* [PATCH] pinctrl: at91: add support for OUTPUT config
From: Wenyou Yang @ 2016-10-28  7:54 UTC (permalink / raw)
  To: linux-arm-kernel

From: Boris BREZILLON <b.brezillon@overkiz.com>

Add support for pin output control through the pinctrl config:
 - support enabling/disabling output on a given pin
 - support output level setting (high or low)

Signed-off-by: Boris BREZILLON <b.brezillon@overkiz.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Wenyou Yang <wenyou.yang@atmel.com>
---

 .../bindings/pinctrl/atmel,at91-pinctrl.txt         |  2 ++
 drivers/pinctrl/pinctrl-at91.c                      | 21 +++++++++++++++++++++
 include/dt-bindings/pinctrl/at91.h                  |  2 ++
 3 files changed, 25 insertions(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
index b7a93e8..9a8a45d 100644
--- a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
@@ -98,6 +98,8 @@ DRIVE_STRENGTH (3 << 5): indicate the drive strength of the pin using the
 				01 - Low
 				10 - Medium
 				11 - High
+OUTPUT		(1 << 7): indicate this pin need to be configured as an output.
+OUTPUT_VAL	(1 << 8): output val (1 = high, 0 = low)
 DEBOUNCE	(1 << 16): indicate this pin needs debounce.
 DEBOUNCE_VAL	(0x3fff << 17): debounce value.
 
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 9f09041..569bc28 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -56,6 +56,9 @@ static int gpio_banks;
 #define DRIVE_STRENGTH_SHIFT	5
 #define DRIVE_STRENGTH_MASK		0x3
 #define DRIVE_STRENGTH   (DRIVE_STRENGTH_MASK << DRIVE_STRENGTH_SHIFT)
+#define OUTPUT		(1 << 7)
+#define OUTPUT_VAL_SHIFT	8
+#define OUTPUT_VAL	(0x1 << OUTPUT_VAL_SHIFT)
 #define DEBOUNCE	(1 << 16)
 #define DEBOUNCE_VAL_SHIFT	17
 #define DEBOUNCE_VAL	(0x3fff << DEBOUNCE_VAL_SHIFT)
@@ -375,6 +378,19 @@ static void at91_mux_set_pullup(void __iomem *pio, unsigned mask, bool on)
 	writel_relaxed(mask, pio + (on ? PIO_PUER : PIO_PUDR));
 }
 
+static bool at91_mux_get_output(void __iomem *pio, unsigned int pin, bool *val)
+{
+	*val = (readl_relaxed(pio + PIO_ODSR) >> pin) & 0x1;
+	return (readl_relaxed(pio + PIO_OSR) >> pin) & 0x1;
+}
+
+static void at91_mux_set_output(void __iomem *pio, unsigned int mask,
+				bool is_on, bool val)
+{
+	writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR));
+	writel_relaxed(mask, pio + (is_on ? PIO_OER : PIO_ODR));
+}
+
 static unsigned at91_mux_get_multidrive(void __iomem *pio, unsigned pin)
 {
 	return (readl_relaxed(pio + PIO_MDSR) >> pin) & 0x1;
@@ -848,6 +864,7 @@ static int at91_pinconf_get(struct pinctrl_dev *pctldev,
 	void __iomem *pio;
 	unsigned pin;
 	int div;
+	bool out;
 
 	*config = 0;
 	dev_dbg(info->dev, "%s:%d, pin_id=%d", __func__, __LINE__, pin_id);
@@ -875,6 +892,8 @@ static int at91_pinconf_get(struct pinctrl_dev *pctldev,
 	if (info->ops->get_drivestrength)
 		*config |= (info->ops->get_drivestrength(pio, pin)
 				<< DRIVE_STRENGTH_SHIFT);
+	if (at91_mux_get_output(pio, pin, &out))
+		*config |= OUTPUT | (out << OUTPUT_VAL_SHIFT);
 
 	return 0;
 }
@@ -907,6 +926,8 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev,
 		if (config & PULL_UP && config & PULL_DOWN)
 			return -EINVAL;
 
+		at91_mux_set_output(pio, mask, config & OUTPUT,
+				    (config & OUTPUT_VAL) >> OUTPUT_VAL_SHIFT);
 		at91_mux_set_pullup(pio, mask, config & PULL_UP);
 		at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE);
 		if (info->ops->set_deglitch)
diff --git a/include/dt-bindings/pinctrl/at91.h b/include/dt-bindings/pinctrl/at91.h
index bbca3d0..2732d6c 100644
--- a/include/dt-bindings/pinctrl/at91.h
+++ b/include/dt-bindings/pinctrl/at91.h
@@ -15,6 +15,8 @@
 #define AT91_PINCTRL_DEGLITCH		(1 << 2)
 #define AT91_PINCTRL_PULL_DOWN		(1 << 3)
 #define AT91_PINCTRL_DIS_SCHMIT		(1 << 4)
+#define AT91_PINCTRL_OUTPUT		(1 << 7)
+#define AT91_PINCTRL_OUTPUT_VAL(x)	((x & 0x1) << 8)
 #define AT91_PINCTRL_DEBOUNCE		(1 << 16)
 #define AT91_PINCTRL_DEBOUNCE_VAL(x)	(x << 17)
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH next 1/2] media: mtk-mdp: fix video_device_release argument
From: Vincent Stehlé @ 2016-10-28  7:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161027202325.20680-1-vincent.stehle@laposte.net>

On Thu, Oct 27, 2016 at 10:23:24PM +0200, Vincent Stehl? wrote:
> video_device_release() takes a pointer to struct video_device as argument.
> Fix two call sites where the address of the pointer is passed instead.

Sorry, I messed up: please ignore that "fix". The 0day robot made me
realize this is indeed not a proper fix.

The issue remains, though: we cannot call video_device_release() on the
vdev structure member, as this will in turn call kfree(). Most probably,
vdev needs to be dynamically allocated, or the call to
video_device_release() dropped completely.

Sorry for the bad patch.

Best regards,

Vincent.

^ permalink raw reply

* [RFC][PATCH] arm64: Add support for CONFIG_DEBUG_VIRTUAL
From: Ard Biesheuvel @ 2016-10-28  7:52 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477613892-26076-1-git-send-email-labbott@redhat.com>

Hi Laura,

On 28 October 2016 at 01:18, Laura Abbott <labbott@redhat.com> wrote:
> x86 has an option CONFIG_DEBUG_VIRTUAL to do additional checks
> on virt_to_phys calls. The goal is to catch users who are calling
> virt_to_phys on non-linear addresses immediately. As features
> such as CONFIG_VMAP_STACK get enabled for arm64, this becomes
> increasingly important. Add checks to catch bad virt_to_phys
> usage.
>

I think this is a useful thing to have. However, the Kconfig
description talks about virt to page translations, not virt to phys.
Of course, this is a shift away from being equivalent on x86, but not
so much on arm64. Any concerns there?

> Signed-off-by: Laura Abbott <labbott@redhat.com>
> ---
> This has been on my TODO list for a while. It caught a few bugs with
> CONFIG_VMAP_STACK on x86 so when that eventually gets added
> for arm64 it will be useful to have. This caught one driver calling __pa on an
> ioremapped address already. RFC for a couple of reasons:
>
> 1) This is basically a direct port of the x86 approach.
> 2) I needed some #ifndef __ASSEMBLY__ which I don't like to throw around.
> 3) I'm not quite sure about the bounds check for the VIRTUAL_BUG_ON with KASLR,
> specifically the _end check.
> 4) Is it worth actually keeping this as DEBUG_VIRTUAL vs. folding it into
> another option?
>
> ---
>  arch/arm64/include/asm/memory.h | 11 ++++++++++-
>  arch/arm64/mm/Makefile          |  2 +-
>  arch/arm64/mm/physaddr.c        | 17 +++++++++++++++++
>  lib/Kconfig.debug               |  2 +-
>  mm/cma.c                        |  2 +-
>  5 files changed, 30 insertions(+), 4 deletions(-)
>  create mode 100644 arch/arm64/mm/physaddr.c
>
> diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
> index ba62df8..9805adc 100644
> --- a/arch/arm64/include/asm/memory.h
> +++ b/arch/arm64/include/asm/memory.h
> @@ -106,11 +106,19 @@
>   * private definitions which should NOT be used outside memory.h
>   * files.  Use virt_to_phys/phys_to_virt/__pa/__va instead.
>   */
> -#define __virt_to_phys(x) ({                                           \
> +#define __virt_to_phys_nodebug(x) ({                                   \
>         phys_addr_t __x = (phys_addr_t)(x);                             \
>         __x & BIT(VA_BITS - 1) ? (__x & ~PAGE_OFFSET) + PHYS_OFFSET :   \
>                                  (__x - kimage_voffset); })
>
> +#ifdef CONFIG_DEBUG_VIRTUAL
> +#ifndef __ASSEMBLY__
> +extern unsigned long __virt_to_phys(unsigned long x);
> +#endif
> +#else
> +#define __virt_to_phys(x)      __virt_to_phys_nodebug(x)
> +#endif
> +

Couldn't you move this whole block into the #ifndef __ASSEMBLY__
section lower down in the file?

>  #define __phys_to_virt(x)      ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET)
>  #define __phys_to_kimg(x)      ((unsigned long)((x) + kimage_voffset))
>
> @@ -202,6 +210,7 @@ static inline void *phys_to_virt(phys_addr_t x)
>   * Drivers should NOT use these either.
>   */
>  #define __pa(x)                        __virt_to_phys((unsigned long)(x))
> +#define __pa_nodebug(x)                __virt_to_phys_nodebug((unsigned long)(x))
>  #define __va(x)                        ((void *)__phys_to_virt((phys_addr_t)(x)))
>  #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
>  #define virt_to_pfn(x)      __phys_to_pfn(__virt_to_phys(x))
> diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
> index 54bb209..bcea84e 100644
> --- a/arch/arm64/mm/Makefile
> +++ b/arch/arm64/mm/Makefile
> @@ -5,6 +5,6 @@ obj-y                           := dma-mapping.o extable.o fault.o init.o \
>  obj-$(CONFIG_HUGETLB_PAGE)     += hugetlbpage.o
>  obj-$(CONFIG_ARM64_PTDUMP)     += dump.o
>  obj-$(CONFIG_NUMA)             += numa.o
> -
> +obj-$(CONFIG_DEBUG_VIRTUAL)    += physaddr.o
>  obj-$(CONFIG_KASAN)            += kasan_init.o
>  KASAN_SANITIZE_kasan_init.o    := n
> diff --git a/arch/arm64/mm/physaddr.c b/arch/arm64/mm/physaddr.c
> new file mode 100644
> index 0000000..6c271e2
> --- /dev/null
> +++ b/arch/arm64/mm/physaddr.c
> @@ -0,0 +1,17 @@
> +#include <linux/mm.h>
> +
> +#include <asm/memory.h>
> +
> +unsigned long __virt_to_phys(unsigned long x)
> +{
> +       phys_addr_t __x = (phys_addr_t)x;
> +
> +       if (__x & BIT(VA_BITS - 1)) {
> +               /* The bit check ensures this is the right range */

Could you expand the comment to clarify that the linear region starts
right in the middle of the kernel virtual address space, and so we
only have to test the top bit?

> +               return (__x & ~PAGE_OFFSET) + PHYS_OFFSET;
> +       } else {l
> +               VIRTUAL_BUG_ON(x < kimage_vaddr || x > (unsigned long)_end);

This looks fine. References to _end are relocated at boot to refer to
the actual runtime offset.

> +               return (__x - kimage_voffset);
> +       }
> +}
> +EXPORT_SYMBOL(__virt_to_phys);
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index 33bc56c..e5634bb 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -604,7 +604,7 @@ config DEBUG_VM_PGFLAGS
>
>  config DEBUG_VIRTUAL
>         bool "Debug VM translations"
> -       depends on DEBUG_KERNEL && X86
> +       depends on DEBUG_KERNEL && (X86 || ARM64)
>         help
>           Enable some costly sanity checks in virtual to page code. This can
>           catch mistakes with virt_to_page() and friends.
> diff --git a/mm/cma.c b/mm/cma.c
> index 384c2cb..2345803 100644
> --- a/mm/cma.c
> +++ b/mm/cma.c
> @@ -235,7 +235,7 @@ int __init cma_declare_contiguous(phys_addr_t base,
>         phys_addr_t highmem_start;
>         int ret = 0;
>
> -#ifdef CONFIG_X86
> +#if defined(CONFIG_X86) || defined(CONFIG_ARM64)
>         /*
>          * high_memory isn't direct mapped memory so retrieving its physical
>          * address isn't appropriate.  But it would be useful to check the
> --
> 2.7.4
>

^ permalink raw reply

* [PATCHv4 11/15] clk: ti: clockdomain: add clock provider support to clockdomains
From: Tero Kristo @ 2016-10-28  7:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161028005047.GQ26139@codeaurora.org>

On 28/10/16 03:50, Stephen Boyd wrote:
> On 10/18, Tero Kristo wrote:
>> Clockdomains can now be used as clock providers in the system. This
>> patch initializes the provider data during init, and parses the clocks
>> while they are being registered. An xlate function for the provider
>> is also given.
>>
>> Signed-off-by: Tero Kristo <t-kristo@ti.com>
>
> Please Cc dt reviewers on binding updates.

Sorry about missing that...

 > I suppose a PRCM is
> like an MFD that has clocks and resets under it? On other
> platforms we've combined that all into one node and just had
> #clock-cells and #reset-cells in that node. Is there any reason
> we can't do that here?

For OMAPs, there are typically multiple instances of the PRCM around; 
OMAP4 for example has:

cm1 @ 0x4a004000 (clocks + clockdomains)
cm2 @ 0x4a008000 (clocks + clockdomains)
prm @ 0x4a306000 (few clocks + resets + power state handling)
scrm @ 0x4a30a000 (few external clocks + plenty of misc stuff)

These instances are also under different power/voltage domains which 
means their PM behavior is different.

The idea behind having a clockdomain as a provider was mostly to have 
the topology visible : prcm-instance -> clockdomain -> clocks

... but basically I think it would be possible to drop the clockdomain 
representation and just mark the prcm-instance as a clock provider. 
Tony, any thoughts on that?


>
>> ---
>>  .../devicetree/bindings/arm/omap/prcm.txt          |  13 ++
>>  .../devicetree/bindings/clock/ti/clockdomain.txt   |  12 +-
>>  arch/arm/mach-omap2/io.c                           |   2 +
>>  drivers/clk/ti/clock.h                             |   1 +
>>  drivers/clk/ti/clockdomain.c                       | 147 +++++++++++++++++++++
>>  include/linux/clk/ti.h                             |   3 +
>>  6 files changed, 177 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/devicetree/bindings/arm/omap/prcm.txt b/Documentation/devicetree/bindings/arm/omap/prcm.txt
>> index 3eb6d7a..301f576 100644
>> --- a/Documentation/devicetree/bindings/arm/omap/prcm.txt
>> +++ b/Documentation/devicetree/bindings/arm/omap/prcm.txt
>> @@ -47,6 +47,19 @@ cm: cm at 48004000 {
>>  	};
>>  }
>>
>> +cm2: cm2 at 8000 {
>> +	compatible = "ti,omap4-cm2";
>> +	reg = <0x8000 0x3000>;
>> +	#address-cells = <1>;
>> +	#size-cells = <1>;
>> +	ranges = <0 0x8000 0x3000>;
>> +
>> +	l4_per_clkdm: l4_per_clkdm {
>> +		compatible = "ti,clockdomain";
>> +		reg = <0x1400 0x200>;
>
> Should there be #clock-cells = <1> here? Also node name should
> have an @1400 after it?

Yeah both should be there. I had the #clock-cells in my test data in 
place already but the address portion I seem to have completely forgot.

>
>> +	};
>> +};
>> +
>>  &cm_clocks {
>>  	omap2_32k_fck: omap_32k_fck {
>>  		#clock-cells = <0>;
>> diff --git a/Documentation/devicetree/bindings/clock/ti/clockdomain.txt b/Documentation/devicetree/bindings/clock/ti/clockdomain.txt
>> index cb76b3f..5d8ca61 100644
>> --- a/Documentation/devicetree/bindings/clock/ti/clockdomain.txt
>> +++ b/Documentation/devicetree/bindings/clock/ti/clockdomain.txt
>> @@ -14,11 +14,21 @@ hardware hierarchy.
>>
>>  Required properties:
>>  - compatible : shall be "ti,clockdomain"
>> -- #clock-cells : from common clock binding; shall be set to 0.
>> +- #clock-cells : from common clock binding; shall be set to 1 if this
>> +		 clockdomain acts as a clock provider.
>> +
>> +Optional properties:
>>  - clocks : link phandles of clocks within this domain
>> +- reg : address for the clockdomain
>>
>>  Examples:
>>  	dss_clkdm: dss_clkdm {
>>  		compatible = "ti,clockdomain";
>>  		clocks = <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>;
>>  	};
>> +
>> +	l4_per_clkdm: l4_per_clkdm {
>
> add an @1400?

Yea will do, unless we decide to go for prcm-instance provider approach.

>
>> +		compatible = "ti,clockdomain";
>> +		#clock-cells = <1>;
>> +		reg = <0x1400 0x200>;
>> +	};
>> diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
>> index 0e9acdd..c1a5cfb 100644
>> --- a/arch/arm/mach-omap2/io.c
>> +++ b/arch/arm/mach-omap2/io.c
>> @@ -794,6 +794,8 @@ int __init omap_clk_init(void)
>>  		if (ret)
>>  			return ret;
>>
>> +		ti_dt_clockdomains_early_setup();
>> +
>>  		of_clk_init(NULL);
>>
>>  		ti_dt_clk_init_retry_clks();
>> diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h
>> index 9b8a5f2..f6383ab 100644
>> --- a/drivers/clk/ti/clock.h
>> +++ b/drivers/clk/ti/clock.h
>> @@ -205,6 +205,7 @@ struct clk *ti_clk_register(struct device *dev, struct clk_hw *hw,
>>
>>  int ti_clk_get_memmap_index(struct device_node *node);
>>  void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index);
>> +void __iomem *ti_clk_get_reg_addr_clkdm(const char *clkdm_name, u16 offset);
>>  void ti_dt_clocks_register(struct ti_dt_clk *oclks);
>>  int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw,
>>  		      ti_of_clk_init_cb_t func);
>> diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c
>> index 704157d..7b0a6c3 100644
>> --- a/drivers/clk/ti/clockdomain.c
>> +++ b/drivers/clk/ti/clockdomain.c
>> @@ -28,6 +28,23 @@
>>  #define pr_fmt(fmt) "%s: " fmt, __func__
>>
>>  /**
>> + * struct ti_clkdm - TI clockdomain data structure
>> + * @name: name of the clockdomain
>> + * @index: index of the clk_iomap struct for this clkdm
>> + * @offset: clockdomain offset from the beginning of the iomap
>> + * @link: link to the list
>> + */
>> +struct ti_clkdm {
>> +	const char *name;
>> +	int index;
>> +	u32 offset;
>> +	struct list_head link;
>> +	struct list_head clocks;
>> +};
>> +
>> +static LIST_HEAD(clkdms);
>> +
>> +/**
>>   * omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw
>>   * @hw: struct clk_hw * of the clock being enabled
>>   *
>> @@ -116,6 +133,8 @@ void omap2_init_clk_clkdm(struct clk_hw *hw)
>>  	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
>>  	struct clockdomain *clkdm;
>>  	const char *clk_name;
>> +	struct ti_clkdm *ti_clkdm;
>> +	bool match = false;
>>
>>  	if (!clk->clkdm_name)
>>  		return;
>> @@ -130,7 +149,21 @@ void omap2_init_clk_clkdm(struct clk_hw *hw)
>>  	} else {
>>  		pr_debug("clock: could not associate clk %s to clkdm %s\n",
>>  			 clk_name, clk->clkdm_name);
>> +		return;
>>  	}
>> +
>> +	list_for_each_entry(ti_clkdm, &clkdms, link) {
>> +		if (!strcmp(ti_clkdm->name, clk->clkdm_name)) {
>> +			match = true;
>> +			break;
>
> Or just goto found and then drop the match bool thing.

That will be cleaner yes. Will change.

>
>> +		}
>> +	}
>> +
>> +	if (!match)
>> +		return;
>> +
>> +	/* Add clock to the list of provided clocks */
>> +	list_add(&clk->clkdm_link, &ti_clkdm->clocks);
>>  }
>>
>>  static void __init of_ti_clockdomain_setup(struct device_node *node)
>> @@ -161,11 +194,125 @@ static void __init of_ti_clockdomain_setup(struct device_node *node)
>>  	}
>>  }
>>
>> +static struct clk_hw *clkdm_clk_xlate(struct of_phandle_args *clkspec,
>> +				      void *data)
>> +{
>> +	struct ti_clkdm *clkdm = data;
>> +	struct clk_hw_omap *clk;
>> +	u16 offset = clkspec->args[0];
>> +
>> +	list_for_each_entry(clk, &clkdm->clocks, clkdm_link)
>> +		if (((u32)clk->enable_reg & 0xffff) - clkdm->offset == offset)
>
> This looks scary.

I think I need to add a separate cleanup patch for the address handling 
before this series... There are a few nasty looking address casts around 
at the moment under the TI clock driver.

>
>> +			return &clk->hw;
>> +
>> +	return ERR_PTR(-EINVAL);
>> +}
>> +
>> +static int ti_clk_register_clkdm(struct device_node *node)
>> +{
>> +	u64 clkdm_addr;
>> +	u64 inst_addr;
>> +	const __be32 *reg;
>> +	u32 offset;
>> +	int idx;
>> +	struct ti_clkdm *clkdm;
>> +	int ret;
>> +
>> +	reg = of_get_address(node, 0, NULL, NULL);
>> +	if (!reg)
>> +		return -ENOENT;
>> +
>> +	clkdm_addr = of_translate_address(node, reg);
>> +
>> +	reg = of_get_address(node->parent, 0, NULL, NULL);
>> +	if (!reg)
>> +		return -EINVAL;
>> +
>> +	inst_addr = of_translate_address(node->parent, reg);
>> +
>> +	offset = clkdm_addr - inst_addr;
>> +
>
> I guess the usual offset tricks are still going on in the TI clk
> driver? Is there a plan to stop doing that at some point?

I can have a look at that with the addressing cleanup I mentioned above. 
I'll see if I can reduce the amount of trickery involved.

>
>> +	idx = ti_clk_get_memmap_index(node->parent);
>> +
>> +	if (idx < 0) {
>> +		pr_err("bad memmap index for %s\n", node->name);
>> +		return idx;
>> +	}
>> +
>> +	clkdm = kzalloc(sizeof(*clkdm), GFP_KERNEL);
>> +	if (!clkdm)
>> +		return -ENOMEM;
>> +
>> +	clkdm->name = node->name;
>> +	clkdm->index = idx;
>> +	clkdm->offset = offset;
>> +
>> +	INIT_LIST_HEAD(&clkdm->clocks);
>> +
>> +	list_add(&clkdm->link, &clkdms);
>> +
>> +	ret = of_clk_add_hw_provider(node, clkdm_clk_xlate, clkdm);
>> +	if (ret) {
>> +		list_del(&clkdm->link);
>> +		kfree(clkdm);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * ti_clk_get_reg_addr_clkdm - get register address relative to clockdomain
>> + * @clkdm_name: parent clockdomain
>> + * @offset: offset from the clockdomain
>> + *
>> + * Gets a register address relative to parent clockdomain. Searches the
>> + * list of available clockdomain, and if match is found, calculates the
>> + * register address from the iomap relative to the clockdomain.
>> + * Returns the register address, or NULL if not found.
>> + */
>> +void __iomem *ti_clk_get_reg_addr_clkdm(const char *clkdm_name, u16 offset)
>> +{
>> +	u32 reg;
>> +	struct clk_omap_reg *reg_setup;
>> +	struct ti_clkdm *clkdm;
>> +	bool match = false;
>> +
>> +	reg_setup = (struct clk_omap_reg *)&reg;
>> +
>> +	/* XXX: get offset from clkdm, get base for instance */
>> +	list_for_each_entry(clkdm, &clkdms, link) {
>> +		if (!strcmp(clkdm->name, clkdm_name)) {
>> +			match = true;
>> +			break;
>> +		}
>> +	}
>> +
>> +	if (!match) {
>> +		pr_err("%s: no entry for %s\n", __func__, clkdm_name);
>> +		return NULL;
>> +	}
>> +
>> +	reg_setup->offset = clkdm->offset + offset;
>> +	reg_setup->index = clkdm->index;
>> +
>> +	return (void __iomem *)reg;
>> +}
>> +
>>  static const struct of_device_id ti_clkdm_match_table[] __initconst = {
>>  	{ .compatible = "ti,clockdomain" },
>>  	{ }
>>  };
>>
>> +void __init ti_dt_clockdomains_early_setup(void)
>> +{
>> +	struct device_node *np;
>> +
>> +	for_each_matching_node(np, ti_clkdm_match_table) {
>> +		ti_clk_register_clkdm(np);
>> +	}
>
> Nitpick: drop braces please.

True, will do that.

-Tero

>
>> +}
>> +
>>  /**
>>   * ti_dt_clockdomains_setup - setup device tree clockdomains
>>   *
>> diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h
>> index 626ae94..afccb48 100644
>> --- a/include/linux/clk/ti.h
>> +++ b/include/linux/clk/ti.h
>> @@ -125,6 +125,7 @@ struct clk_hw_omap_ops {
>>  /**
>>   * struct clk_hw_omap - OMAP struct clk
>>   * @node: list_head connecting this clock into the full clock list
>> + * @clkdm_link: list_head connecting this clock into the clockdomain
>>   * @enable_reg: register to write to enable the clock (see @enable_bit)
>>   * @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg)
>>   * @flags: see "struct clk.flags possibilities" above
>> @@ -137,6 +138,7 @@ struct clk_hw_omap_ops {
>>  struct clk_hw_omap {
>>  	struct clk_hw		hw;
>>  	struct list_head	node;
>> +	struct list_head	clkdm_link;
>>  	unsigned long		fixed_rate;
>>  	u8			fixed_div;
>>  	void __iomem		*enable_reg;
>> @@ -251,6 +253,7 @@ int omap2_reprogram_dpllcore(struct clk_hw *clk, unsigned long rate,
>>  unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk);
>>
>>  void ti_dt_clk_init_retry_clks(void);
>> +void ti_dt_clockdomains_early_setup(void);
>>  void ti_dt_clockdomains_setup(void);
>>  int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops);
>>
>> --
>> 1.9.1
>>
>

^ permalink raw reply

* [PATCH v2 2/2] arm64: dts: hi6220: add resets property into dwmmc nodes
From: Leo Yan @ 2016-10-28  7:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <d7993c1a-5e50-9a33-0900-5c1a79884d3c@samsung.com>

On Fri, Oct 28, 2016 at 04:33:41PM +0900, Jaehoon Chung wrote:

[...]

> >>> Guodong: Is there any bootloader dependency on that change?
> >>
> >> FYI, I use firmwares available in AOSP
> > 
> > I tried latest firmware [1], still cannot boot up until revert the
> > patch "arm64: dts: hi6220: add resets property into dwmmc nodes".
> 
> Could you share the log? Is there any log about failure?

Sure, please see below log:

EFI stub: Booting Linux Kernel...
EFI stub: Using DTB from configuration table
EFI stub: Exiting boot services and installing virtual address map...
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 4.9.0-rc1-00251-g323792f (leoy at leoy-linaro) (gcc version 4.9.2 20140904 (prerelease) (crosstool-NG linaro-1.13.1-4.9-2014.09 - Linaro GCC 4.9-2014.09) ) #589 SMP PREEMPT Fri Oct 28 15:35:15 CST 2016
[    0.000000] Boot CPU: AArch64 Processor [410fd033]
[    0.000000] efi: Getting EFI parameters from FDT:
[    0.000000] efi: EFI v2.50 by hikey EFI Oct 26 2016 15:14:29
[    0.000000] efi:  PROP=0x3d8297d8 
[    0.000000] Reserved memory: created CMA memory pool at 0x000000002d000000, size 128 MiB
[    0.000000] OF: reserved mem: initialized node linux,cma, compatible id shared-dma-pool
[    0.000000] psci: probing for conduit method from DT.
[    0.000000] psci: PSCIv1.0 detected in firmware.
[    0.000000] psci: Using standard PSCI v0.2 function IDs
[    0.000000] psci: MIGRATE_INFO_TYPE not supported.
[    0.000000] percpu: Embedded 21 pages/cpu @ffff80003df10000 s48000 r8192 d29824 u86016
[    0.000000] Detected VIPT I-cache on CPU0
[    0.000000] CPU features: enabling workaround for ARM erratum 845719
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 249229
[    0.000000] Kernel command line: BOOT_IMAGE=(hd0,gpt6)/Image console=tty0 console=ttyAMA3,115200 root=/dev/disk/by-partlabel/system rootwait rw efi=noruntime
[    0.000000] log_buf_len individual max cpu contribution: 4096 bytes
[    0.000000] log_buf_len total cpu_extra contributions: 28672 bytes
[    0.000000] log_buf_len min size: 16384 bytes
[    0.000000] log_buf_len: 65536 bytes
[    0.000000] early log buf free: 14468(88%)
[    0.000000] PID hash table entries: 4096 (order: 3, 32768 bytes)
[    0.000000] Dentry cache hash table entries: 131072 (order: 8, 1048576 bytes)
[    0.000000] Inode-cache hash table entries: 65536 (order: 7, 524288 bytes)
[    0.000000] Memory: 841572K/1012788K available (8316K kernel code, 860K rwdata, 3668K rodata, 1024K init, 283K bss, 40144K reserved, 131072K cma-reserved)
[    0.000000] Virtual kernel memory layout:
[    0.000000]     modules : 0xffff000000000000 - 0xffff000008000000   (   128 MB)
[    0.000000]     vmalloc : 0xffff000008000000 - 0xffff7dffbfff0000   (129022 GB)
[    0.000000]       .text : 0xffff000008080000 - 0xffff0000088a0000   (  8320 KB)
[    0.000000]     .rodata : 0xffff0000088a0000 - 0xffff000008c40000   (  3712 KB)
[    0.000000]       .init : 0xffff000008c40000 - 0xffff000008d40000   (  1024 KB)
[    0.000000]       .data : 0xffff000008d40000 - 0xffff000008e17200   (   861 KB)
[    0.000000]        .bss : 0xffff000008e17200 - 0xffff000008e5e0c0   (   284 KB)
[    0.000000]     fixed   : 0xffff7dfffe7fd000 - 0xffff7dfffec00000   (  4108 KB)
[    0.000000]     PCI I/O : 0xffff7dfffee00000 - 0xffff7dffffe00000   (    16 MB)
[    0.000000]     vmemmap : 0xffff7e0000000000 - 0xffff800000000000   (  2048 GB maximum)
[    0.000000]               0xffff7e0000000000 - 0xffff7e0000f80000   (    15 MB actual)
[    0.000000]     memory  : 0xffff800000000000 - 0xffff80003e000000   (   992 MB)
[    0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=8, Nodes=1
[    0.000000] Preemptible hierarchical RCU implementation.
[    0.000000] 	Build-time adjustment of leaf fanout to 64.
[    0.000000] 	RCU restricting CPUs from NR_CPUS=64 to nr_cpu_ids=8.
[    0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=64, nr_cpu_ids=8
[    0.000000] NR_IRQS:64 nr_irqs:64 0
[    0.000000] GIC: Using split EOI/Deactivate mode
[    0.000000] arm_arch_timer: Architected cp15 timer(s) running at 1.20MHz (phys).
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x11b661f8e, max_idle_ns: 1763180809113 ns
[    0.000004] sched_clock: 56 bits at 1200kHz, resolution 833ns, wraps every 4398046510838ns
[    0.000101] clocksource: arm,sp804: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 99544814920 ns
[    0.000108] sched_clock: 32 bits at 19MHz, resolution 52ns, wraps every 111848106981ns
[    0.000495] Console: colour dummy device 80x25
[    0.001193] console [tty0] enabled
[    0.001224] Calibrating delay loop (skipped), value calculated using timer frequency.. 2.40 BogoMIPS (lpj=4800)
[    0.001253] pid_max: default: 32768 minimum: 301
[    0.001331] Security Framework initialized
[    0.001373] Mount-cache hash table entries: 2048 (order: 2, 16384 bytes)
[    0.001392] Mountpoint-cache hash table entries: 2048 (order: 2, 16384 bytes)
[    0.002258] ASID allocator initialised with 65536 entries
[    0.032726] EFI runtime services will be disabled.
[    0.080274] Detected VIPT I-cache on CPU1
[    0.080323] CPU1: Booted secondary processor [410fd033]
[    0.112299] Detected VIPT I-cache on CPU2
[    0.112321] CPU2: Booted secondary processor [410fd033]
[    0.144348] Detected VIPT I-cache on CPU3
[    0.144369] CPU3: Booted secondary processor [410fd033]
[    0.176488] Detected VIPT I-cache on CPU4
[    0.176529] CPU4: Booted secondary processor [410fd033]
[    0.208479] Detected VIPT I-cache on CPU5
[    0.208501] CPU5: Booted secondary processor [410fd033]
[    0.240546] Detected VIPT I-cache on CPU6
[    0.240568] CPU6: Booted secondary processor [410fd033]
[    0.272610] Detected VIPT I-cache on CPU7
[    0.272632] CPU7: Booted secondary processor [410fd033]
[    0.272708] Brought up 8 CPUs
[    0.272887] SMP: Total of 8 processors activated.
[    0.272904] CPU features: detected feature: 32-bit EL0 Support
[    0.272975] CPU: All CPU(s) started at EL2
[    0.273028] alternatives: patching kernel code
[    0.273645] devtmpfs: initialized
[    0.278919] DMI not present or invalid.
[    0.279161] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
[    0.282522] pinctrl core: initialized pinctrl subsystem
[    0.283636] NET: Registered protocol family 16
[    0.300541] cpuidle: using governor menu
[    0.301073] vdso: 2 pages (1 code @ ffff0000088a7000, 1 data @ ffff000008d44000)
[    0.301106] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.
[    0.301863] DMA: preallocated 256 KiB pool for atomic allocations
[    0.302088] Serial: AMBA PL011 UART driver
[    0.303683] f8015000.uart: ttyAMA0 at MMIO 0xf8015000 (irq = 7, base_baud = 0) is a PL011 rev2
[    0.304121] uart-pl011 f7111000.uart: could not find pctldev for node /soc/pinmux at f7010000/uart1_pmx_func, deferring probe
[    0.304340] uart-pl011 f7112000.uart: could not find pctldev for node /soc/pinmux at f7010000/uart2_pmx_func, deferring probe
[    0.304580] uart-pl011 f7113000.uart: could not find pctldev for node /soc/pinmux at f7010000/uart3_pmx_func, deferring probe
[    0.310373] hi6220-mbox f7510000.mailbox: Mailbox enabled
[    0.341400] HugeTLB registered 2 MB page size, pre-allocated 0 pages
[    0.342257] ACPI: Interpreter disabled.
[    0.342953] vgaarb: loaded
[    0.343177] SCSI subsystem initialized
[    0.343450] ssp-pl022 f7106000.spi: could not find pctldev for node /soc/pinmux at f7010000/spi0_pmx_func, deferring probe
[    0.343955] usbcore: registered new interface driver usbfs
[    0.344042] usbcore: registered new interface driver hub
[    0.344177] usbcore: registered new device driver usb
[    0.344452] i2c_designware f7100000.i2c: could not find pctldev for node /soc/pinmux at f7010000/i2c0_pmx_func, deferring probe
[    0.344494] i2c_designware f7101000.i2c: could not find pctldev for node /soc/pinmux at f7010000/i2c1_pmx_func, deferring probe
[    0.344535] i2c_designware f7102000.i2c: could not find pctldev for node /soc/pinmux at f7010000/i2c2_pmx_func, deferring probe
[    0.344915] pps_core: LinuxPPS API ver. 1 registered
[    0.344931] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
[    0.345003] PTP clock support registered
[    0.345325] dmi: Firmware registration failed.
[    0.345408] Registered efivars operations
[    0.345580] Advanced Linux Sound Architecture Driver Initialized.
[    0.346449] clocksource: Switched to clocksource arch_sys_counter
[    0.346617] VFS: Disk quotas dquot_6.6.0
[    0.346670] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
[    0.346935] pnp: PnP ACPI: disabled
[    0.355325] NET: Registered protocol family 2
[    0.355797] TCP established hash table entries: 8192 (order: 4, 65536 bytes)
[    0.355885] TCP bind hash table entries: 8192 (order: 5, 131072 bytes)
[    0.356026] TCP: Hash tables configured (established 8192 bind 8192)
[    0.356085] UDP hash table entries: 512 (order: 2, 16384 bytes)
[    0.356120] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
[    0.356255] NET: Registered protocol family 1
[    0.356569] RPC: Registered named UNIX socket transport module.
[    0.356585] RPC: Registered udp transport module.
[    0.356599] RPC: Registered tcp transport module.
[    0.356613] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    0.356791] Unpacking initramfs...
[    0.497134] Freeing initrd memory: 3576K (ffff8000372d5000 - ffff800037653000)
[    0.497725] kvm [1]: 8-bit VMID
[    0.497744] kvm [1]: IDMAP page: 890000
[    0.497758] kvm [1]: HYP VA range: 800000000000:ffffffffffff
[    0.498691] kvm [1]: Hyp mode initialized successfully
[    0.498741] kvm [1]: vgic-v2 at f6804000
[    0.498936] kvm [1]: vgic interrupt IRQ1
[    0.498978] kvm [1]: virtual timer IRQ4
[    0.501267] futex hash table entries: 2048 (order: 6, 262144 bytes)
[    0.501394] audit: initializing netlink subsys (disabled)
[    0.501462] audit: type=2000 audit(0.495:1): initialized
[    0.501845] workingset: timestamp_bits=46 max_order=18 bucket_order=0
[    0.508960] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[    0.509596] NFS: Registering the id_resolver key type
[    0.509632] Key type id_resolver registered
[    0.509645] Key type id_legacy registered
[    0.509665] nfs4filelayout_init: NFSv4 File Layout Driver Registering...
[    0.509833] 9p: Installing v9fs 9p2000 file system support
[    0.512208] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 247)
[    0.512235] io scheduler noop registered
[    0.512349] io scheduler cfq registered (default)
[    0.513271] libphy: mdio_driver_register: phy-bcm-ns2-pci
[    0.514198] pinctrl-single f7010000.pinmux: 159 pins at pa ffff000008e81000 size 636
[    0.514612] pinctrl-single f7010800.pinmux: 163 pins at pa ffff000008e83800 size 652
[    0.514770] pinctrl-single f8001800.pinmux: 30 pins at pa ffff000008e85800 size 120
[    0.515809] pl061_gpio f8011000.gpio: PL061 GPIO chip @0x00000000f8011000 registered
[    0.516214] pl061_gpio f8012000.gpio: PL061 GPIO chip @0x00000000f8012000 registered
[    0.516610] pl061_gpio f8013000.gpio: PL061 GPIO chip @0x00000000f8013000 registered
[    0.516687] gpio gpiochip3: gpio-line-names specifies 9 line names but there are 8 lines on the chip
[    0.517038] pl061_gpio f8014000.gpio: PL061 GPIO chip @0x00000000f8014000 registered
[    0.517416] pl061_gpio f7020000.gpio: PL061 GPIO chip @0x00000000f7020000 registered
[    0.517796] pl061_gpio f7021000.gpio: PL061 GPIO chip @0x00000000f7021000 registered
[    0.518172] pl061_gpio f7022000.gpio: PL061 GPIO chip @0x00000000f7022000 registered
[    0.518577] pl061_gpio f7023000.gpio: PL061 GPIO chip @0x00000000f7023000 registered
[    0.518658] gpio gpiochip8: gpio-line-names specifies 9 line names but there are 8 lines on the chip
[    0.518999] pl061_gpio f7024000.gpio: PL061 GPIO chip @0x00000000f7024000 registered
[    0.519385] pl061_gpio f7025000.gpio: PL061 GPIO chip @0x00000000f7025000 registered
[    0.519774] pl061_gpio f7026000.gpio: PL061 GPIO chip @0x00000000f7026000 registered
[    0.520162] pl061_gpio f7027000.gpio: PL061 GPIO chip @0x00000000f7027000 registered
[    0.520550] pl061_gpio f7028000.gpio: PL061 GPIO chip @0x00000000f7028000 registered
[    0.520939] pl061_gpio f7029000.gpio: PL061 GPIO chip @0x00000000f7029000 registered
[    0.521324] pl061_gpio f702a000.gpio: PL061 GPIO chip @0x00000000f702a000 registered
[    0.521719] pl061_gpio f702b000.gpio: PL061 GPIO chip @0x00000000f702b000 registered
[    0.522107] pl061_gpio f702c000.gpio: PL061 GPIO chip @0x00000000f702c000 registered
[    0.522505] pl061_gpio f702d000.gpio: PL061 GPIO chip @0x00000000f702d000 registered
[    0.522884] pl061_gpio f702e000.gpio: PL061 GPIO chip @0x00000000f702e000 registered
[    0.523275] pl061_gpio f702f000.gpio: PL061 GPIO chip @0x00000000f702f000 registered
[    0.526086] xenfs: not registering filesystem on non-xen platform
[    0.528934] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
[    0.530124] SuperH (H)SCI(F) driver initialized
[    0.530364] msm_serial: driver initialized
[    0.536344] loop: module loaded
[    0.539526] hisi_sas: driver version v1.6
[    0.541976] libphy: Fixed MDIO Bus: probed
[    0.542702] tun: Universal TUN/TAP device driver, 1.6
[    0.542719] tun: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>
[    0.543688] e1000e: Intel(R) PRO/1000 Network Driver - 3.2.6-k
[    0.543707] e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
[    0.543804] igb: Intel(R) Gigabit Ethernet Network Driver - version 5.4.0-k
[    0.543821] igb: Copyright (c) 2007-2014 Intel Corporation.
[    0.543906] igbvf: Intel(R) Gigabit Virtual Function Network Driver - version 2.4.0-k
[    0.543930] igbvf: Copyright (c) 2009 - 2012 Intel Corporation.
[    0.544018] sky2: driver version 1.30
[    0.544551] VFIO - User Level meta-driver version: 0.3
[    0.546560] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
[    0.546590] ehci-pci: EHCI PCI platform driver
[    0.546638] ehci-platform: EHCI generic platform driver
[    0.546730] ehci-exynos: EHCI EXYNOS driver
[    0.546802] ehci-msm: Qualcomm On-Chip EHCI Host Controller
[    0.546866] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
[    0.546900] ohci-pci: OHCI PCI platform driver
[    0.546952] ohci-platform: OHCI generic platform driver
[    0.547024] ohci-exynos: OHCI EXYNOS driver
[    0.547324] usbcore: registered new interface driver usb-storage
[    0.547863] file system registered
[    0.548183] mousedev: PS/2 mouse device common for all mice
[    0.548621] input: HISI 65xx PowerOn Key as /devices/platform/f8000000.pmic/hi65xx-powerkey.0.auto/input/input0
[    0.549253] rtc-pl031 f8003000.rtc: rtc core: registered pl031 as rtc0
[    0.549459] rtc-pl031 f8004000.rtc: rtc core: registered pl031 as rtc1
[    0.549796] i2c /dev entries driver
[    0.552183] sdhci: Secure Digital Host Controller Interface driver
[    0.552207] sdhci: Copyright(c) Pierre Ossman
[    0.552403] Synopsys Designware Multimedia Card Interface Driver
[    0.553405] sdhci-pltfm: SDHCI platform and OF driver helper
[    0.554851] ledtrig-cpu: registered to indicate activity on CPUs
[    0.555695] usbcore: registered new interface driver usbhid
[    0.555717] usbhid: USB HID core driver
[    0.557233] NET: Registered protocol family 17
[    0.557320] 9pnet: Installing 9P2000 support
[    0.557383] Key type dns_resolver registered
[    0.557996] registered taskstats version 1
[    0.561690] f7111000.uart: ttyAMA1 at MMIO 0xf7111000 (irq = 8, base_baud = 0) is a PL011 rev2
[    0.562226] f7112000.uart: ttyAMA2 at MMIO 0xf7112000 (irq = 9, base_baud = 0) is a PL011 rev2
[    0.562553] f7113000.uart: ttyAMA3 at MMIO 0xf7113000 (irq = 10, base_baud = 0) is a PL011 rev2
[    1.916968] console [ttyAMA3] enabled
[    1.922080] ssp-pl022 f7106000.spi: ARM PL022 driver, device ID: 0x00041022
[    1.929144] ssp-pl022 f7106000.spi: mapped registers from 0x00000000f7106000 to ffff000008f03000
[    1.938007] ssp-pl022 f7106000.spi: Failed to work in dma mode, work without dma!
[    1.949535] f72c0000.usb supply vusb_d not found, using dummy regulator
[    1.956256] f72c0000.usb supply vusb_a not found, using dummy regulator
[    2.344873] dwc2 f72c0000.usb: EPs: 16, dedicated fifos, 1920 entries in SPRAM
[    2.353154] dwc2 f72c0000.usb: DWC OTG Controller
[    2.357891] dwc2 f72c0000.usb: new USB bus registered, assigned bus number 1
[    2.364979] dwc2 f72c0000.usb: irq 38, io mem 0x00000000
[    2.371082] hub 1-0:1.0: USB hub found
[    2.374866] hub 1-0:1.0: 1 port detected
[    2.382071] rtc-pl031 f8003000.rtc: setting system clock to 1970-01-01 00:00:19 UTC (19)
[    2.390486] LDO2_2V8: disabling
[    2.393639] LDO7_SDIO: disabling
[    2.396900] LDO10_2V85: disabling
[    2.400234] LDO13_1V8: disabling
[    2.403476] LDO14_2V8: disabling
[    2.406721] LDO17_2V5: disabling
[    2.409956] LDO19_3V0: disabling
[    2.413199] wlan-en-regulator: disabling
[    2.417135] ALSA device list:
[    2.420109]   No soundcards found.
[    2.423712] uart-pl011 f7113000.uart: no DMA platform data
[    2.429585] Freeing unused kernel memory: 1024K (ffff800000c40000 - ffff800000d40000)
Loading, please wait...
starting version 228
[    2.479981] random: systemd-udevd: uninitialized urandom read (16 bytes read)
[    2.483570] random: udevadm: uninitialized urandom read (16 bytes read)
[    2.483680] random: udevadm: uninitialized urandom read (16 bytes read)
[    2.485404] random: udevadm: uninitialized urandom read (16 bytes read)
[    2.485631] random: udevadm: uninitialized urandom read (16 bytes read)
[    2.485859] random: udevadm: uninitialized urandom read (16 bytes read)
[    2.486098] random: udevadm: uninitialized urandom read (16 bytes read)
[    2.486305] random: udevadm: uninitialized urandom read (16 bytes read)
[    2.486729] random: udevadm: uninitialized urandom read (16 bytes read)
[    2.486951] random: udevadm: uninitialized urandom read (16 bytes read)
Begin: Loading essential drivers ... done.
Begin: Running /scripts/init-premount ... done.
Begin: Mounting root file system ... Begin: Running /scripts/local-top ... done.
Begin: Running /scripts/local-premount ... modprobe: can't change directory to '4.9.0-rc1-00251-g323792f': No such file or directory
done.
Begin: Waiting for root file system ... Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.
Begin: Running /scripts/local-block ... done.

Thanks,
Leo Yan

^ permalink raw reply

* [PATCH v2 2/2] arm64: dts: hi6220: add resets property into dwmmc nodes
From: Jaehoon Chung @ 2016-10-28  7:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161028072640.GB17266@leoy-linaro>

Hi,

On 10/28/2016 04:26 PM, Leo Yan wrote:
> On Fri, Oct 28, 2016 at 08:43:51AM +0200, Vincent Guittot wrote:
> 
> [...]
> 
>>> running with? Also do you have any details about the card in case its
>>> card specific?
>>
>> The sdcard is quite common: sandisk ultra 16GB
>> and my rootfs is on the sdcard
> 
> I'm using rootfs in emmc also have same failure.
> 
>>> Guodong: Is there any bootloader dependency on that change?
>>
>> FYI, I use firmwares available in AOSP
> 
> I tried latest firmware [1], still cannot boot up until revert the
> patch "arm64: dts: hi6220: add resets property into dwmmc nodes".

Could you share the log? Is there any log about failure?

Best Regards,
Jaehoon Chung

> 
> [1] http://builds.96boards.org/snapshots/hikey/linaro/uefi-openplatformpkg/latest/
> 
> Thanks,
> Leo Yan
> 
> 
> 

^ permalink raw reply

* [PATCH v6 9/9] MAINTAINERS: Update HISILICON DRM entries
From: Rongrong Zou @ 2016-10-28  7:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477639682-22520-1-git-send-email-zourongrong@gmail.com>

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 MAINTAINERS | 1 +
 1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index c447953..cc5ee3a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4117,6 +4117,7 @@ F:	drivers/gpu/drm/gma500/
 
 DRM DRIVERS FOR HISILICON
 M:	Xinliang Liu <z.liuxinliang@hisilicon.com>
+M:	Rongrong Zou <zourongrong@gmail.com>
 R:	Xinwei Kong <kong.kongxinwei@hisilicon.com>
 R:	Chen Feng <puck.chen@hisilicon.com>
 L:	dri-devel at lists.freedesktop.org
-- 
1.9.1

^ permalink raw reply related

* [PATCH v6 8/9] drm/hisilicon/hibmc: Add vblank interruput
From: Rongrong Zou @ 2016-10-28  7:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477639682-22520-1-git-send-email-zourongrong@gmail.com>

Add vblank interrupt.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 56 ++++++++++++++++++++++++-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  1 +
 2 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 4253603..b668e3e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -40,16 +40,46 @@
 
 static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
 {
+	struct hibmc_drm_device *hidev =
+		(struct hibmc_drm_device *)dev->dev_private;
+
+	writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(1),
+	       hidev->mmio + HIBMC_RAW_INTERRUPT_EN);
+
 	return 0;
 }
 
 static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 {
+	struct hibmc_drm_device *hidev =
+		(struct hibmc_drm_device *)dev->dev_private;
+
+	writel(HIBMC_RAW_INTERRUPT_EN_VBLANK(0),
+	       hidev->mmio + HIBMC_RAW_INTERRUPT_EN);
+}
+
+irqreturn_t hibmc_drm_interrupt(int irq, void *arg)
+{
+	struct drm_device *dev = (struct drm_device *)arg;
+	struct hibmc_drm_device *hidev =
+		(struct hibmc_drm_device *)dev->dev_private;
+	struct drm_crtc *crtc = &hidev->crtc;
+	u32 status;
+
+	status = readl(hidev->mmio + HIBMC_RAW_INTERRUPT);
+
+	if (status & HIBMC_RAW_INTERRUPT_VBLANK(1)) {
+		writel(HIBMC_RAW_INTERRUPT_VBLANK(1),
+		       hidev->mmio + HIBMC_RAW_INTERRUPT);
+		drm_crtc_handle_vblank(crtc);
+	}
+
+	return IRQ_HANDLED;
 }
 
 static struct drm_driver hibmc_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET |
-				  DRIVER_ATOMIC,
+				  DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
 	.fops			= &hibmc_fops,
 	.name			= "hibmc",
 	.date			= "20160828",
@@ -63,6 +93,7 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 	.dumb_create            = hibmc_dumb_create,
 	.dumb_map_offset        = hibmc_dumb_mmap_offset,
 	.dumb_destroy           = drm_gem_dumb_destroy,
+	.irq_handler		= hibmc_drm_interrupt,
 };
 
 static int hibmc_pm_suspend(struct device *dev)
@@ -242,6 +273,13 @@ static int hibmc_unload(struct drm_device *dev)
 	struct hibmc_drm_device *hidev = dev->dev_private;
 
 	hibmc_fbdev_fini(hidev);
+
+	if (dev->irq_enabled)
+		drm_irq_uninstall(dev);
+	if (hidev->msi_enabled)
+		pci_disable_msi(dev->pdev);
+	drm_vblank_cleanup(dev);
+
 	hibmc_kms_fini(hidev);
 	hibmc_mm_fini(hidev);
 	hibmc_hw_fini(hidev);
@@ -272,6 +310,22 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
 	if (ret)
 		goto err;
 
+	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+	if (ret) {
+		DRM_ERROR("failed to initialize vblank.\n");
+		goto err;
+	}
+
+	hidev->msi_enabled = 0;
+	if (pci_enable_msi(dev->pdev)) {
+		DRM_ERROR("Enabling MSI failed!\n");
+	} else {
+		hidev->msi_enabled = 1;
+		ret = drm_irq_install(dev, dev->pdev->irq);
+		if (ret)
+			DRM_ERROR("install irq failed , ret = %d\n", ret);
+	}
+
 	/* reset all the states of crtc/plane/encoder/connector */
 	drm_mode_config_reset(dev);
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index 450247d..f1706fb 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -42,6 +42,7 @@ struct hibmc_drm_device {
 	void __iomem   *fb_map;
 	unsigned long  fb_base;
 	unsigned long  fb_size;
+	int msi_enabled;
 
 	/* drm */
 	struct drm_device  *dev;
-- 
1.9.1

^ permalink raw reply related

* [PATCH v6 7/9] drm/hisilicon/hibmc: Add connector for VDAC
From: Rongrong Zou @ 2016-10-28  7:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477639682-22520-1-git-send-email-zourongrong@gmail.com>

Add connector funcs and helper funcs for VDAC.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  |  8 +++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |  2 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 76 ++++++++++++++++++++++++
 3 files changed, 86 insertions(+)

diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index ba191e1..4253603 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -131,6 +131,14 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
 		return ret;
 	}
 
+	ret = hibmc_connector_init(hidev);
+	if (ret) {
+		DRM_ERROR("failed to init connector\n");
+		return ret;
+	}
+
+	drm_mode_connector_attach_encoder(&hidev->connector,
+					  &hidev->encoder);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index 401cea4..450247d 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -48,6 +48,7 @@ struct hibmc_drm_device {
 	struct drm_plane plane;
 	struct drm_crtc crtc;
 	struct drm_encoder encoder;
+	struct drm_connector connector;
 	bool mode_config_initialized;
 
 	/* ttm */
@@ -89,6 +90,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 int hibmc_plane_init(struct hibmc_drm_device *hidev);
 int hibmc_crtc_init(struct hibmc_drm_device *hidev);
 int hibmc_encoder_init(struct hibmc_drm_device *hidev);
+int hibmc_connector_init(struct hibmc_drm_device *hidev);
 int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
 void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
index 953f659..ebefcd1 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
@@ -87,3 +87,79 @@ int hibmc_encoder_init(struct hibmc_drm_device *hidev)
 	drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
 	return 0;
 }
+
+static int hibmc_connector_get_modes(struct drm_connector *connector)
+{
+	int count;
+
+	count = drm_add_modes_noedid(connector, 800, 600);
+	drm_set_preferred_mode(connector, defx, defy);
+	return count;
+}
+
+static int hibmc_connector_mode_valid(struct drm_connector *connector,
+				      struct drm_display_mode *mode)
+{
+	struct hibmc_drm_device *hiprivate =
+	 container_of(connector, struct hibmc_drm_device, connector);
+	unsigned long size = mode->hdisplay * mode->vdisplay * 4;
+
+	if (size * 2 > hiprivate->fb_size)
+		return MODE_BAD;
+
+	return MODE_OK;
+}
+
+static struct drm_encoder *
+hibmc_connector_best_encoder(struct drm_connector *connector)
+{
+	int enc_id = connector->encoder_ids[0];
+
+	/* pick the encoder ids */
+	if (enc_id)
+		return drm_encoder_find(connector->dev, enc_id);
+
+	return NULL;
+}
+
+static enum drm_connector_status hibmc_connector_detect(struct drm_connector
+						 *connector, bool force)
+{
+	return connector_status_connected;
+}
+
+static const struct drm_connector_helper_funcs
+	hibmc_connector_connector_helper_funcs = {
+	.get_modes = hibmc_connector_get_modes,
+	.mode_valid = hibmc_connector_mode_valid,
+	.best_encoder = hibmc_connector_best_encoder,
+};
+
+static const struct drm_connector_funcs hibmc_connector_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.detect = hibmc_connector_detect,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+int hibmc_connector_init(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct drm_connector *connector = &hidev->connector;
+	int ret;
+
+	ret = drm_connector_init(dev, connector,
+				 &hibmc_connector_connector_funcs,
+				 DRM_MODE_CONNECTOR_VGA);
+	if (ret) {
+		DRM_ERROR("failed to init connector\n");
+		return ret;
+	}
+	drm_connector_helper_add(connector,
+				 &hibmc_connector_connector_helper_funcs);
+
+	return 0;
+}
-- 
1.9.1

^ permalink raw reply related

* [PATCH v6 6/9] drm/hisilicon/hibmc: Add encoder for VDAC
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477639682-22520-1-git-send-email-zourongrong@gmail.com>

Add encoder funcs and helpers for VDAC.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/Makefile         |  2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c  |  6 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h  |  2 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 89 ++++++++++++++++++++++++
 4 files changed, 98 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index 72e107e..e04f114 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,5 +1,5 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_vdac.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
 #obj-y	+= hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 303cd36..ba191e1 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -125,6 +125,12 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
 		return ret;
 	}
 
+	ret = hibmc_encoder_init(hidev);
+	if (ret) {
+		DRM_ERROR("failed to init encoder\n");
+		return ret;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index 5731ec2..401cea4 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -47,6 +47,7 @@ struct hibmc_drm_device {
 	struct drm_device  *dev;
 	struct drm_plane plane;
 	struct drm_crtc crtc;
+	struct drm_encoder encoder;
 	bool mode_config_initialized;
 
 	/* ttm */
@@ -87,6 +88,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 
 int hibmc_plane_init(struct hibmc_drm_device *hidev);
 int hibmc_crtc_init(struct hibmc_drm_device *hidev);
+int hibmc_encoder_init(struct hibmc_drm_device *hidev);
 int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
 void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
new file mode 100644
index 0000000..953f659
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
@@ -0,0 +1,89 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "hibmc_drm_drv.h"
+#include "hibmc_drm_regs.h"
+
+static int defx = 800;
+static int defy = 600;
+
+module_param(defx, int, 0444);
+module_param(defy, int, 0444);
+MODULE_PARM_DESC(defx, "default x resolution");
+MODULE_PARM_DESC(defy, "default y resolution");
+
+static void hibmc_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static void hibmc_encoder_enable(struct drm_encoder *encoder)
+{
+}
+
+static void hibmc_encoder_mode_set(struct drm_encoder *encoder,
+				   struct drm_display_mode *mode,
+				   struct drm_display_mode *adj_mode)
+{
+	u32 reg;
+	struct drm_device *dev = encoder->dev;
+	struct hibmc_drm_device *hidev = dev->dev_private;
+
+	/* just open DISPLAY_CONTROL_HISILE register bit 3:0*/
+	reg = readl(hidev->mmio + DISPLAY_CONTROL_HISILE);
+	reg |= 0xf;
+	writel(reg, hidev->mmio + DISPLAY_CONTROL_HISILE);
+}
+
+static int hibmc_encoder_atomic_check(struct drm_encoder *encoder,
+				      struct drm_crtc_state *crtc_state,
+				      struct drm_connector_state *conn_state)
+{
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs hibmc_encoder_helper_funcs = {
+	.mode_set = hibmc_encoder_mode_set,
+	.disable = hibmc_encoder_disable,
+	.enable = hibmc_encoder_enable,
+	.atomic_check = hibmc_encoder_atomic_check,
+};
+
+static const struct drm_encoder_funcs hibmc_encoder_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+int hibmc_encoder_init(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct drm_encoder *encoder = &hidev->encoder;
+	int ret;
+
+	encoder->possible_crtcs = 0x1;
+	ret = drm_encoder_init(dev, encoder, &hibmc_encoder_encoder_funcs,
+			       DRM_MODE_ENCODER_DAC, NULL);
+	if (ret) {
+		DRM_ERROR("failed to init encoder\n");
+		return ret;
+	}
+
+	drm_encoder_helper_add(encoder, &hibmc_encoder_helper_funcs);
+	return 0;
+}
-- 
1.9.1

^ permalink raw reply related

* [PATCH v6 5/9] drm/hisilicon/hibmc: Add crtc for DE
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477639682-22520-1-git-send-email-zourongrong@gmail.com>

Add crtc funcs and helper funcs for DE.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 318 ++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |   6 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   2 +
 3 files changed, 326 insertions(+)

diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
index 9c1a68c..9b5d0d0 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
@@ -23,6 +23,7 @@
 
 #include "hibmc_drm_drv.h"
 #include "hibmc_drm_regs.h"
+#include "hibmc_drm_de.h"
 #include "hibmc_drm_power.h"
 
 /* ---------------------------------------------------------------------- */
@@ -168,3 +169,320 @@ int hibmc_plane_init(struct hibmc_drm_device *hidev)
 	drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
 	return 0;
 }
+
+static void hibmc_crtc_enable(struct drm_crtc *crtc)
+{
+	unsigned int reg;
+	/* power mode 0 is default. */
+	struct hibmc_drm_device *hidev = crtc->dev->dev_private;
+
+	hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
+	reg |= HIBMC_CURR_GATE_DISPLAY(ON);
+	hibmc_set_current_gate(hidev, reg);
+	drm_crtc_vblank_on(crtc);
+}
+
+static void hibmc_crtc_disable(struct drm_crtc *crtc)
+{
+	unsigned int reg;
+	struct hibmc_drm_device *hidev = crtc->dev->dev_private;
+
+	drm_crtc_vblank_off(crtc);
+
+	hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_SLEEP);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg |= HIBMC_CURR_GATE_LOCALMEM(OFF);
+	reg |= HIBMC_CURR_GATE_DISPLAY(OFF);
+	hibmc_set_current_gate(hidev, reg);
+}
+
+static int hibmc_crtc_atomic_check(struct drm_crtc *crtc,
+				   struct drm_crtc_state *state)
+{
+	return 0;
+}
+
+static unsigned int format_pll_reg(void)
+{
+	unsigned int pllreg = 0;
+	struct panel_pll pll = {0};
+
+	/* Note that all PLL's have the same format. Here,
+	 * we just use Panel PLL parameter to work out the bit
+	 * fields in the register.On returning a 32 bit number, the value can
+	 * be applied to any PLL in the calling function.
+	 */
+	pllreg |= HIBMC_PLL_CTRL_BYPASS(OFF) & HIBMC_PLL_CTRL_BYPASS_MASK;
+	pllreg |= HIBMC_PLL_CTRL_POWER(ON) & HIBMC_PLL_CTRL_POWER_MASK;
+	pllreg |= HIBMC_PLL_CTRL_INPUT(OSC) & HIBMC_PLL_CTRL_INPUT_MASK;
+	pllreg |= HIBMC_PLL_CTRL_POD(pll.POD) & HIBMC_PLL_CTRL_POD_MASK;
+	pllreg |= HIBMC_PLL_CTRL_OD(pll.OD) & HIBMC_PLL_CTRL_OD_MASK;
+	pllreg |= HIBMC_PLL_CTRL_N(pll.N) & HIBMC_PLL_CTRL_N_MASK;
+	pllreg |= HIBMC_PLL_CTRL_M(pll.M) & HIBMC_PLL_CTRL_M_MASK;
+
+	return pllreg;
+}
+
+static void set_vclock_hisilicon(struct drm_device *dev, unsigned long pll)
+{
+	unsigned long tmp0, tmp1;
+	struct hibmc_drm_device *hidev = dev->dev_private;
+
+	/* 1. outer_bypass_n=0 */
+	tmp0 = readl(hidev->mmio + CRT_PLL1_HS);
+	tmp0 &= 0xBFFFFFFF;
+	writel(tmp0, hidev->mmio + CRT_PLL1_HS);
+
+	/* 2. pll_pd=1?inter_bypass=1 */
+	writel(0x21000000, hidev->mmio + CRT_PLL1_HS);
+
+	/* 3. config pll */
+	writel(pll, hidev->mmio + CRT_PLL1_HS);
+
+	/* 4. delay  */
+	mdelay(1);
+
+	/* 5. pll_pd =0 */
+	tmp1 = pll & ~0x01000000;
+	writel(tmp1, hidev->mmio + CRT_PLL1_HS);
+
+	/* 6. delay  */
+	mdelay(1);
+
+	/* 7. inter_bypass=0 */
+	tmp1 &= ~0x20000000;
+	writel(tmp1, hidev->mmio + CRT_PLL1_HS);
+
+	/* 8. delay  */
+	mdelay(1);
+
+	/* 9. outer_bypass_n=1 */
+	tmp1 |= 0x40000000;
+	writel(tmp1, hidev->mmio + CRT_PLL1_HS);
+}
+
+/* This function takes care the extra registers and bit fields required to
+ *setup a mode in board.
+ *Explanation about Display Control register:
+ *FPGA only supports 7 predefined pixel clocks, and clock select is
+ *in bit 4:0 of new register 0x802a8.
+ */
+static unsigned int display_ctrl_adjust(struct drm_device *dev,
+					struct drm_display_mode *mode,
+					unsigned int ctrl)
+{
+	unsigned long x, y;
+	unsigned long pll1; /* bit[31:0] of PLL */
+	unsigned long pll2; /* bit[63:32] of PLL */
+	struct hibmc_drm_device *hidev = dev->dev_private;
+
+	x = mode->hdisplay;
+	y = mode->vdisplay;
+
+	/* Hisilicon has to set up a new register for PLL control
+	 *(CRT_PLL1_HS & CRT_PLL2_HS).
+	 */
+	if (x == 800 && y == 600) {
+		pll1 = CRT_PLL1_HS_40MHZ;
+		pll2 = CRT_PLL2_HS_40MHZ;
+	} else if (x == 1024 && y == 768) {
+		pll1 = CRT_PLL1_HS_65MHZ;
+		pll2 = CRT_PLL2_HS_65MHZ;
+	} else if (x == 1152 && y == 864) {
+		pll1 = CRT_PLL1_HS_80MHZ_1152;
+		pll2 = CRT_PLL2_HS_80MHZ;
+	} else if (x == 1280 && y == 768) {
+		pll1 = CRT_PLL1_HS_80MHZ;
+		pll2 = CRT_PLL2_HS_80MHZ;
+	} else if (x == 1280 && y == 720) {
+		pll1 = CRT_PLL1_HS_74MHZ;
+		pll2 = CRT_PLL2_HS_74MHZ;
+	} else if (x == 1280 && y == 960) {
+		pll1 = CRT_PLL1_HS_108MHZ;
+		pll2 = CRT_PLL2_HS_108MHZ;
+	} else if (x == 1280 && y == 1024) {
+		pll1 = CRT_PLL1_HS_108MHZ;
+		pll2 = CRT_PLL2_HS_108MHZ;
+	} else if (x == 1600 && y == 1200) {
+		pll1 = CRT_PLL1_HS_162MHZ;
+		pll2 = CRT_PLL2_HS_162MHZ;
+	} else if (x == 1920 && y == 1080) {
+		pll1 = CRT_PLL1_HS_148MHZ;
+		pll2 = CRT_PLL2_HS_148MHZ;
+	} else if (x == 1920 && y == 1200) {
+		pll1 = CRT_PLL1_HS_193MHZ;
+		pll2 = CRT_PLL2_HS_193MHZ;
+	} else /* default to VGA clock */ {
+		pll1 = CRT_PLL1_HS_25MHZ;
+		pll2 = CRT_PLL2_HS_25MHZ;
+	}
+
+	writel(pll2, hidev->mmio + CRT_PLL2_HS);
+	set_vclock_hisilicon(dev, pll1);
+
+	/* Hisilicon has to set up the top-left and bottom-right
+	 * registers as well.
+	 * Note that normal chip only use those two register for
+	 * auto-centering mode.
+	 */
+	writel((HIBMC_CRT_AUTO_CENTERING_TL_TOP(0) &
+		HIBMC_CRT_AUTO_CENTERING_TL_TOP_MSK) |
+	       (HIBMC_CRT_AUTO_CENTERING_TL_LEFT(0) &
+		HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK),
+	       hidev->mmio + HIBMC_CRT_AUTO_CENTERING_TL);
+
+	writel((HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(y - 1) &
+		HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
+	       (HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x - 1) &
+		HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK),
+		hidev->mmio + HIBMC_CRT_AUTO_CENTERING_BR);
+
+	/* Assume common fields in ctrl have been properly set before
+	 * calling this function.
+	 * This function only sets the extra fields in ctrl.
+	 */
+
+	/* Set bit 25 of display controller: Select CRT or VGA clock */
+	ctrl &= ~HIBMC_CRT_DISP_CTL_CRTSELECT_MASK;
+	ctrl &= ~HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK;
+
+	ctrl |= HIBMC_CRT_DISP_CTL_CRTSELECT(CRTSELECT_CRT);
+
+	/*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL, CRTSELECT, CRT);*/
+
+	/* Set bit 14 of display controller */
+	/*ctrl &= FIELD_CLEAR(HIBMC_CRT_DISP_CTL, CLOCK_PHASE);*/
+
+	/* clock_phase_polarity is 0 */
+	ctrl |= HIBMC_CRT_DISP_CTL_CLOCK_PHASE(PHASE_ACTIVE_HIGH);
+	/*ctrl = FIELD_SET(ctrl, HIBMC_CRT_DISP_CTL,*/
+	/*CLOCK_PHASE, ACTIVE_HIGH);*/
+
+	writel(ctrl, hidev->mmio + HIBMC_CRT_DISP_CTL);
+
+	return ctrl;
+}
+
+static void hibmc_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	unsigned int val;
+	struct drm_display_mode *mode = &crtc->state->mode;
+	struct drm_device *dev = crtc->dev;
+	struct hibmc_drm_device *hidev = dev->dev_private;
+
+	writel(format_pll_reg(), hidev->mmio + HIBMC_CRT_PLL_CTRL);
+	writel((HIBMC_CRT_HORZ_TOTAL_TOTAL(mode->htotal - 1) &
+		HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK) |
+		(HIBMC_CRT_HORZ_TOTAL_DISPLAY_END(mode->hdisplay - 1) &
+		HIBMC_CRT_HORZ_TOTAL_DISPLAY_END_MASK),
+		hidev->mmio + HIBMC_CRT_HORZ_TOTAL);
+
+	writel((HIBMC_CRT_HORZ_SYNC_WIDTH(mode->hsync_end - mode->hsync_start)
+		& HIBMC_CRT_HORZ_SYNC_WIDTH_MASK) |
+		(HIBMC_CRT_HORZ_SYNC_START(mode->hsync_start - 1)
+		& HIBMC_CRT_HORZ_SYNC_START_MASK),
+		hidev->mmio + HIBMC_CRT_HORZ_SYNC);
+
+	writel((HIBMC_CRT_VERT_TOTAL_TOTAL(mode->vtotal - 1) &
+		HIBMC_CRT_VERT_TOTAL_TOTAL_MASK) |
+		(HIBMC_CRT_VERT_TOTAL_DISPLAY_END(mode->vdisplay - 1) &
+		HIBMC_CRT_VERT_TOTAL_DISPLAY_END_MASK),
+		hidev->mmio + HIBMC_CRT_VERT_TOTAL);
+
+	writel((HIBMC_CRT_VERT_SYNC_HEIGHT(mode->vsync_end - mode->vsync_start)
+		& HIBMC_CRT_VERT_SYNC_HEIGHT_MASK) |
+	       (HIBMC_CRT_VERT_SYNC_START(mode->vsync_start - 1) &
+		HIBMC_CRT_VERT_SYNC_START_MASK),
+		hidev->mmio + HIBMC_CRT_VERT_SYNC);
+
+	val = HIBMC_CRT_DISP_CTL_VSYNC_PHASE(0) &
+	      HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK;
+	val |= HIBMC_CRT_DISP_CTL_HSYNC_PHASE(0) &
+	       HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK;
+	val |= HIBMC_CRT_DISP_CTL_TIMING(ENABLE);
+	val |= HIBMC_CRT_DISP_CTL_PLANE(ENABLE);
+
+	display_ctrl_adjust(dev, mode, val);
+}
+
+static void hibmc_crtc_atomic_begin(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_state)
+{
+	unsigned int reg;
+	struct drm_device *dev = crtc->dev;
+	struct hibmc_drm_device *hidev = dev->dev_private;
+
+	hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg |= HIBMC_CURR_GATE_DISPLAY(ON);
+	reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
+	hibmc_set_current_gate(hidev, reg);
+
+	/* We can add more initialization as needed. */
+}
+
+static void hibmc_crtc_atomic_flush(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_state)
+
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&crtc->dev->event_lock, flags);
+	if (crtc->state->event)
+		drm_crtc_send_vblank_event(crtc, crtc->state->event);
+	crtc->state->event = NULL;
+
+	spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+}
+
+/* These provide the minimum set of functions required to handle a CRTC */
+static const struct drm_crtc_funcs hibmc_crtc_funcs = {
+	.page_flip = drm_atomic_helper_page_flip,
+	.set_config = drm_atomic_helper_set_config,
+	.destroy = drm_crtc_cleanup,
+	.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 const struct drm_crtc_helper_funcs hibmc_crtc_helper_funcs = {
+	.enable		= hibmc_crtc_enable,
+	.disable	= hibmc_crtc_disable,
+	.mode_set_nofb	= hibmc_crtc_mode_set_nofb,
+	.atomic_check	= hibmc_crtc_atomic_check,
+	.atomic_begin	= hibmc_crtc_atomic_begin,
+	.atomic_flush	= hibmc_crtc_atomic_flush,
+};
+
+int hibmc_crtc_init(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct drm_crtc *crtc = &hidev->crtc;
+	struct drm_plane *plane = &hidev->plane;
+	int ret;
+
+	ret = drm_crtc_init_with_planes(dev, crtc, plane,
+					NULL, &hibmc_crtc_funcs, NULL);
+	if (ret) {
+		DRM_ERROR("failed to init crtc.\n");
+		return ret;
+	}
+
+	drm_mode_crtc_set_gamma_size(crtc, 256);
+	drm_crtc_helper_add(crtc, &hibmc_crtc_helper_funcs);
+	return 0;
+}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 7d96583..303cd36 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -119,6 +119,12 @@ static int hibmc_kms_init(struct hibmc_drm_device *hidev)
 		return ret;
 	}
 
+	ret = hibmc_crtc_init(hidev);
+	if (ret) {
+		DRM_ERROR("failed to init crtc.\n");
+		return ret;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index 49e39d2..5731ec2 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -46,6 +46,7 @@ struct hibmc_drm_device {
 	/* drm */
 	struct drm_device  *dev;
 	struct drm_plane plane;
+	struct drm_crtc crtc;
 	bool mode_config_initialized;
 
 	/* ttm */
@@ -85,6 +86,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
 
 int hibmc_plane_init(struct hibmc_drm_device *hidev);
+int hibmc_crtc_init(struct hibmc_drm_device *hidev);
 int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
 void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
 
-- 
1.9.1

^ permalink raw reply related

* [PATCH v6 4/9] drm/hisilicon/hibmc: Add plane for DE
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477639682-22520-1-git-send-email-zourongrong@gmail.com>

Add plane funcs and helper funcs for DE.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
 drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c  | 170 ++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h  |  29 ++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  51 ++++++-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |   5 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     |   6 +
 7 files changed, 261 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
index bcb8c18..380622a 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
+++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
@@ -1,6 +1,7 @@
 config DRM_HISI_HIBMC
 	tristate "DRM Support for Hisilicon Hibmc"
 	depends on DRM && PCI
+	select DRM_KMS_HELPER
 	select DRM_TTM
 
 	help
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index 810a37e..72e107e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,5 +1,5 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_de.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
 #obj-y	+= hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
new file mode 100644
index 0000000..9c1a68c
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
@@ -0,0 +1,170 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
+
+#include "hibmc_drm_drv.h"
+#include "hibmc_drm_regs.h"
+#include "hibmc_drm_power.h"
+
+/* ---------------------------------------------------------------------- */
+
+static int hibmc_plane_atomic_check(struct drm_plane *plane,
+				    struct drm_plane_state *state)
+{
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_crtc *crtc = state->crtc;
+	struct drm_crtc_state *crtc_state;
+	u32 src_x = state->src_x >> 16;
+	u32 src_y = state->src_y >> 16;
+	u32 src_w = state->src_w >> 16;
+	u32 src_h = state->src_h >> 16;
+	int crtc_x = state->crtc_x;
+	int crtc_y = state->crtc_y;
+	u32 crtc_w = state->crtc_w;
+	u32 crtc_h = state->crtc_h;
+
+	if (!crtc || !fb)
+		return 0;
+
+	crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
+	if (IS_ERR(crtc_state))
+		return PTR_ERR(crtc_state);
+
+	if (src_w != crtc_w || src_h != crtc_h) {
+		DRM_ERROR("Scale not support!!!\n");
+		return -EINVAL;
+	}
+
+	if (src_x + src_w > fb->width ||
+	    src_y + src_h > fb->height)
+		return -EINVAL;
+
+	if (crtc_x < 0 || crtc_y < 0)
+		return -EINVAL;
+
+	if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
+	    crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void hibmc_plane_atomic_update(struct drm_plane *plane,
+				      struct drm_plane_state *old_state)
+{
+	struct drm_plane_state	*state	= plane->state;
+	u32 reg;
+	int ret;
+	u64 gpu_addr = 0;
+	unsigned int line_l;
+	struct hibmc_drm_device *hidev =
+		(struct hibmc_drm_device *)plane->dev->dev_private;
+
+	struct hibmc_framebuffer *hibmc_fb;
+	struct hibmc_bo *bo;
+
+	hibmc_fb = to_hibmc_framebuffer(state->fb);
+	bo = gem_to_hibmc_bo(hibmc_fb->obj);
+	ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
+	if (ret)
+		return;
+
+	hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
+	if (ret) {
+		ttm_bo_unreserve(&bo->bo);
+		return;
+	}
+
+	ttm_bo_unreserve(&bo->bo);
+
+	writel(gpu_addr, hidev->mmio + HIBMC_CRT_FB_ADDRESS);
+
+	reg = state->fb->width * (state->fb->bits_per_pixel >> 3);
+	/* now line_pad is 16 */
+	reg = PADDING(16, reg);
+
+	line_l = state->fb->width * state->fb->bits_per_pixel / 8;
+	line_l = PADDING(16, line_l);
+	writel((HIBMC_CRT_FB_WIDTH_WIDTH(reg) & HIBMC_CRT_FB_WIDTH_WIDTH_MASK) |
+	       (HIBMC_CRT_FB_WIDTH_OFFS(line_l) & HIBMC_CRT_FB_WIDTH_OFFS_MASK),
+	       hidev->mmio + HIBMC_CRT_FB_WIDTH);
+
+	/* SET PIXEL FORMAT */
+	reg = readl(hidev->mmio + HIBMC_CRT_DISP_CTL);
+	reg = reg & ~HIBMC_CRT_DISP_CTL_FORMAT_MASK;
+	reg = reg | (HIBMC_CRT_DISP_CTL_FORMAT(state->fb->bits_per_pixel >> 4) &
+		     HIBMC_CRT_DISP_CTL_FORMAT_MASK);
+	writel(reg, hidev->mmio + HIBMC_CRT_DISP_CTL);
+}
+
+static void hibmc_plane_atomic_disable(struct drm_plane *plane,
+				       struct drm_plane_state *old_state)
+{
+}
+
+static const u32 channel_formats1[] = {
+	DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_ABGR8888
+};
+
+static struct drm_plane_funcs hibmc_plane_funcs = {
+	.update_plane	= drm_atomic_helper_update_plane,
+	.disable_plane	= drm_atomic_helper_disable_plane,
+	.set_property = drm_atomic_helper_plane_set_property,
+	.destroy = drm_plane_cleanup,
+	.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 const struct drm_plane_helper_funcs hibmc_plane_helper_funcs = {
+	.atomic_check = hibmc_plane_atomic_check,
+	.atomic_update = hibmc_plane_atomic_update,
+	.atomic_disable = hibmc_plane_atomic_disable,
+};
+
+int hibmc_plane_init(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct drm_plane *plane = &hidev->plane;
+	int ret = 0;
+
+	/*
+	 * plane init
+	 * TODO: Now only support primary plane, overlay planes
+	 * need to do.
+	 */
+	ret = drm_universal_plane_init(dev, plane, 1, &hibmc_plane_funcs,
+				       channel_formats1,
+				       ARRAY_SIZE(channel_formats1),
+				       DRM_PLANE_TYPE_PRIMARY,
+				       NULL);
+	if (ret) {
+		DRM_ERROR("fail to init plane!!!\n");
+		return ret;
+	}
+
+	drm_plane_helper_add(plane, &hibmc_plane_helper_funcs);
+	return 0;
+}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
new file mode 100644
index 0000000..4ce0d7b
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
@@ -0,0 +1,29 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef HIBMC_DRM_DE_H
+#define HIBMC_DRM_DE_H
+
+struct panel_pll {
+	unsigned long M;
+	unsigned long N;
+	unsigned long OD;
+	unsigned long POD;
+};
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 5ac7a7e..7d96583 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -18,6 +18,7 @@
 
 #include <linux/module.h>
 #include <linux/console.h>
+#include <drm/drm_crtc_helper.h>
 
 #include "hibmc_drm_drv.h"
 #include "hibmc_drm_regs.h"
@@ -47,8 +48,8 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 }
 
 static struct drm_driver hibmc_driver = {
-	.driver_features	= DRIVER_GEM,
-
+	.driver_features	= DRIVER_GEM | DRIVER_MODESET |
+				  DRIVER_ATOMIC,
 	.fops			= &hibmc_fops,
 	.name			= "hibmc",
 	.date			= "20160828",
@@ -70,6 +71,7 @@ static int hibmc_pm_suspend(struct device *dev)
 	struct drm_device *drm_dev = pci_get_drvdata(pdev);
 	struct hibmc_drm_device *hidev = drm_dev->dev_private;
 
+	drm_kms_helper_poll_disable(drm_dev);
 	drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
 
 	return 0;
@@ -81,7 +83,9 @@ static int hibmc_pm_resume(struct device *dev)
 	struct drm_device *drm_dev = pci_get_drvdata(pdev);
 	struct hibmc_drm_device *hidev = drm_dev->dev_private;
 
+	drm_helper_resume_force_mode(drm_dev);
 	drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
+	drm_kms_helper_poll_enable(drm_dev);
 
 	return 0;
 }
@@ -91,6 +95,41 @@ static int hibmc_pm_resume(struct device *dev)
 				hibmc_pm_resume)
 };
 
+static int hibmc_kms_init(struct hibmc_drm_device *hidev)
+{
+	int ret;
+
+	drm_mode_config_init(hidev->dev);
+	hidev->mode_config_initialized = true;
+
+	hidev->dev->mode_config.min_width = 0;
+	hidev->dev->mode_config.min_height = 0;
+	hidev->dev->mode_config.max_width = 1920;
+	hidev->dev->mode_config.max_height = 1440;
+
+	hidev->dev->mode_config.fb_base = hidev->fb_base;
+	hidev->dev->mode_config.preferred_depth = 24;
+	hidev->dev->mode_config.prefer_shadow = 0;
+
+	hidev->dev->mode_config.funcs = (void *)&hibmc_mode_funcs;
+
+	ret = hibmc_plane_init(hidev);
+	if (ret) {
+		DRM_ERROR("fail to init plane!!!\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static void hibmc_kms_fini(struct hibmc_drm_device *hidev)
+{
+	if (hidev->mode_config_initialized) {
+		drm_mode_config_cleanup(hidev->dev);
+		hidev->mode_config_initialized = false;
+	}
+}
+
 static int hibmc_hw_config(struct hibmc_drm_device *hidev)
 {
 	unsigned int reg;
@@ -183,6 +222,7 @@ static int hibmc_unload(struct drm_device *dev)
 	struct hibmc_drm_device *hidev = dev->dev_private;
 
 	hibmc_fbdev_fini(hidev);
+	hibmc_kms_fini(hidev);
 	hibmc_mm_fini(hidev);
 	hibmc_hw_fini(hidev);
 	dev->dev_private = NULL;
@@ -208,6 +248,13 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
 	if (ret)
 		goto err;
 
+	ret = hibmc_kms_init(hidev);
+	if (ret)
+		goto err;
+
+	/* reset all the states of crtc/plane/encoder/connector */
+	drm_mode_config_reset(dev);
+
 	ret = hibmc_fbdev_init(hidev);
 	if (ret)
 		goto err;
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index a40e9a7..49e39d2 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -45,6 +45,8 @@ struct hibmc_drm_device {
 
 	/* drm */
 	struct drm_device  *dev;
+	struct drm_plane plane;
+	bool mode_config_initialized;
 
 	/* ttm */
 	struct {
@@ -82,6 +84,7 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 
 #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
 
+int hibmc_plane_init(struct hibmc_drm_device *hidev);
 int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
 void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
 
@@ -102,4 +105,6 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
 			   u32 handle, u64 *offset);
 int hibmc_mmap(struct file *filp, struct vm_area_struct *vma);
 
+extern const struct drm_mode_config_funcs hibmc_mode_funcs;
+
 #endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
index 9822f62..beb4d76 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -554,3 +554,9 @@ struct hibmc_framebuffer *
 	}
 	return &hibmc_fb->fb;
 }
+
+const struct drm_mode_config_funcs hibmc_mode_funcs = {
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+	.fb_create = hibmc_user_framebuffer_create,
+};
-- 
1.9.1

^ permalink raw reply related

* [PATCH v6 3/9] drm/hisilicon/hibmc: Add support for frame buffer
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477639682-22520-1-git-send-email-zourongrong@gmail.com>

Add support for fbdev and kms fb management.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/Makefile          |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   |  17 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  24 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 255 ++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       |  66 ++++++
 5 files changed, 363 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index d5c40b8..810a37e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,5 +1,5 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_fbdev.o hibmc_drm_power.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
 #obj-y	+= hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 81f4301..5ac7a7e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -66,11 +66,23 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 
 static int hibmc_pm_suspend(struct device *dev)
 {
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct drm_device *drm_dev = pci_get_drvdata(pdev);
+	struct hibmc_drm_device *hidev = drm_dev->dev_private;
+
+	drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 1);
+
 	return 0;
 }
 
 static int hibmc_pm_resume(struct device *dev)
 {
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct drm_device *drm_dev = pci_get_drvdata(pdev);
+	struct hibmc_drm_device *hidev = drm_dev->dev_private;
+
+	drm_fb_helper_set_suspend_unlocked(&hidev->fbdev->helper, 0);
+
 	return 0;
 }
 
@@ -170,6 +182,7 @@ static int hibmc_unload(struct drm_device *dev)
 {
 	struct hibmc_drm_device *hidev = dev->dev_private;
 
+	hibmc_fbdev_fini(hidev);
 	hibmc_mm_fini(hidev);
 	hibmc_hw_fini(hidev);
 	dev->dev_private = NULL;
@@ -195,6 +208,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
 	if (ret)
 		goto err;
 
+	ret = hibmc_fbdev_init(hidev);
+	if (ret)
+		goto err;
+
 	return 0;
 
 err:
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index db8d80e..a40e9a7 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -20,9 +20,22 @@
 #define HIBMC_DRM_DRV_H
 
 #include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/ttm/ttm_bo_driver.h>
 #include <drm/drm_gem.h>
 
+struct hibmc_framebuffer {
+	struct drm_framebuffer fb;
+	struct drm_gem_object *obj;
+	bool is_fbdev_fb;
+};
+
+struct hibmc_fbdev {
+	struct drm_fb_helper helper;
+	struct hibmc_framebuffer *fb;
+	int size;
+};
+
 struct hibmc_drm_device {
 	/* hw */
 	void __iomem   *mmio;
@@ -41,9 +54,13 @@ struct hibmc_drm_device {
 		bool initialized;
 	} ttm;
 
+	/* fbdev */
+	struct hibmc_fbdev *fbdev;
 	bool mm_inited;
 };
 
+#define to_hibmc_framebuffer(x) container_of(x, struct hibmc_framebuffer, fb)
+
 struct hibmc_bo {
 	struct ttm_buffer_object bo;
 	struct ttm_placement placement;
@@ -65,8 +82,15 @@ static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
 
 #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
 
+int hibmc_fbdev_init(struct hibmc_drm_device *hidev);
+void hibmc_fbdev_fini(struct hibmc_drm_device *hidev);
+
 int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
 		     struct drm_gem_object **obj);
+struct hibmc_framebuffer *
+hibmc_framebuffer_init(struct drm_device *dev,
+		       const struct drm_mode_fb_cmd2 *mode_cmd,
+		       struct drm_gem_object *obj);
 
 int hibmc_mm_init(struct hibmc_drm_device *hibmc);
 void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
new file mode 100644
index 0000000..630124b
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
@@ -0,0 +1,255 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+
+#include "hibmc_drm_drv.h"
+
+/* ---------------------------------------------------------------------- */
+
+static int hibmcfb_create_object(
+				struct hibmc_drm_device *hidev,
+				const struct drm_mode_fb_cmd2 *mode_cmd,
+				struct drm_gem_object **gobj_p)
+{
+	struct drm_gem_object *gobj;
+	struct drm_device *dev = hidev->dev;
+	u32 size;
+	int ret = 0;
+
+	size = mode_cmd->pitches[0] * mode_cmd->height;
+	ret = hibmc_gem_create(dev, size, true, &gobj);
+	if (ret)
+		return ret;
+
+	*gobj_p = gobj;
+	return ret;
+}
+
+static struct fb_ops hibmc_drm_fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_check_var = drm_fb_helper_check_var,
+	.fb_set_par = drm_fb_helper_set_par,
+	.fb_fillrect = drm_fb_helper_sys_fillrect,
+	.fb_copyarea = drm_fb_helper_sys_copyarea,
+	.fb_imageblit = drm_fb_helper_sys_imageblit,
+	.fb_pan_display = drm_fb_helper_pan_display,
+	.fb_blank = drm_fb_helper_blank,
+	.fb_setcmap = drm_fb_helper_setcmap,
+};
+
+static int hibmc_drm_fb_create(struct drm_fb_helper *helper,
+			       struct drm_fb_helper_surface_size *sizes)
+{
+	struct hibmc_fbdev *hi_fbdev =
+		container_of(helper, struct hibmc_fbdev, helper);
+	struct hibmc_drm_device *hidev =
+		(struct hibmc_drm_device *)helper->dev->dev_private;
+	struct fb_info *info;
+	struct hibmc_framebuffer *hibmc_fb;
+	struct drm_framebuffer *fb;
+	struct drm_mode_fb_cmd2 mode_cmd;
+	struct drm_gem_object *gobj = NULL;
+	int ret = 0;
+	size_t size;
+	unsigned int bytes_per_pixel;
+	struct hibmc_bo *bo = NULL;
+
+	DRM_DEBUG_DRIVER("surface width(%d), height(%d) and bpp(%d)\n",
+			 sizes->surface_width, sizes->surface_height,
+			 sizes->surface_bpp);
+	sizes->surface_depth = 32;
+
+	bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
+
+	mode_cmd.width = sizes->surface_width;
+	mode_cmd.height = sizes->surface_height;
+	mode_cmd.pitches[0] = mode_cmd.width * bytes_per_pixel;
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+							  sizes->surface_depth);
+
+	size = roundup(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE);
+
+	ret = hibmcfb_create_object(hidev, &mode_cmd, &gobj);
+	if (ret) {
+		DRM_ERROR("failed to create fbcon backing object %d\r\n", ret);
+		return -ENOMEM;
+	}
+
+	bo = gem_to_hibmc_bo(gobj);
+
+	ret = ttm_bo_reserve(&bo->bo, true, false, NULL);
+	if (ret)
+		return ret;
+
+	ret = hibmc_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
+	if (ret) {
+		DRM_ERROR("failed to pin fbcon\n");
+		return ret;
+	}
+
+	ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+
+	if (ret) {
+		DRM_ERROR("failed to kmap fbcon\n");
+		ttm_bo_unreserve(&bo->bo);
+		return ret;
+	}
+
+	ttm_bo_unreserve(&bo->bo);
+
+	info = drm_fb_helper_alloc_fbi(helper);
+	if (IS_ERR(info))
+		return PTR_ERR(info);
+
+	info->par = hi_fbdev;
+
+	hibmc_fb = hibmc_framebuffer_init(hidev->dev, &mode_cmd, gobj);
+	if (IS_ERR(hibmc_fb)) {
+		drm_fb_helper_release_fbi(helper);
+		return PTR_ERR(hibmc_fb);
+	}
+
+	hi_fbdev->fb = hibmc_fb;
+	hidev->fbdev->size = size;
+	fb = &hibmc_fb->fb;
+	if (!fb) {
+		DRM_INFO("fb is NULL\n");
+		return -EINVAL;
+	}
+
+	hi_fbdev->helper.fb = fb;
+
+	strcpy(info->fix.id, "hibmcdrmfb");
+
+	info->flags = FBINFO_DEFAULT;
+	info->fbops = &hibmc_drm_fb_ops;
+
+	drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+	drm_fb_helper_fill_var(info, &hidev->fbdev->helper, sizes->fb_width,
+			       sizes->fb_height);
+
+	info->screen_base = bo->kmap.virtual;
+	info->screen_size = size;
+
+	info->fix.smem_start = bo->bo.mem.bus.offset + bo->bo.mem.bus.base;
+	info->fix.smem_len = size;
+
+	return 0;
+}
+
+static void hibmc_fbdev_destroy(struct hibmc_fbdev *fbdev)
+{
+	struct hibmc_framebuffer *gfb = fbdev->fb;
+	struct drm_fb_helper *fbh = &fbdev->helper;
+
+	DRM_DEBUG_DRIVER("hibmc_fbdev_destroy\n");
+
+	drm_fb_helper_unregister_fbi(fbh);
+	drm_fb_helper_release_fbi(fbh);
+
+	drm_fb_helper_fini(fbh);
+
+	if (gfb)
+		drm_framebuffer_unreference(&gfb->fb);
+
+	kfree(fbdev);
+}
+
+static const struct drm_fb_helper_funcs hibmc_fbdev_helper_funcs = {
+	.fb_probe = hibmc_drm_fb_create,
+};
+
+int hibmc_fbdev_init(struct hibmc_drm_device *hidev)
+{
+	int ret;
+	struct fb_var_screeninfo *var;
+	struct fb_fix_screeninfo *fix;
+	struct hibmc_fbdev *hifbdev;
+
+	hifbdev = kzalloc(sizeof(*hifbdev), GFP_KERNEL);
+	if (!hifbdev)
+		return -ENOMEM;
+
+	hidev->fbdev = hifbdev;
+	drm_fb_helper_prepare(hidev->dev, &hifbdev->helper,
+			      &hibmc_fbdev_helper_funcs);
+
+	/* Now just one crtc and one channel */
+	ret = drm_fb_helper_init(hidev->dev,
+				 &hifbdev->helper, 1, 1);
+
+	if (ret)
+		return ret;
+
+	ret = drm_fb_helper_single_add_all_connectors(&hifbdev->helper);
+	if (ret)
+		goto fini;
+
+	ret = drm_fb_helper_initial_config(&hifbdev->helper, 16);
+	if (ret)
+		goto fini;
+
+	var = &hifbdev->helper.fbdev->var;
+	fix = &hifbdev->helper.fbdev->fix;
+
+	DRM_DEBUG("Member of info->var is :\n"
+		 "xres=%d\n"
+		 "yres=%d\n"
+		 "xres_virtual=%d\n"
+		 "yres_virtual=%d\n"
+		 "xoffset=%d\n"
+		 "yoffset=%d\n"
+		 "bits_per_pixel=%d\n"
+		 "...\n", var->xres, var->yres, var->xres_virtual,
+		 var->yres_virtual, var->xoffset, var->yoffset,
+		 var->bits_per_pixel);
+	DRM_DEBUG("Member of info->fix is :\n"
+		 "smem_start=%lx\n"
+		 "smem_len=%d\n"
+		 "type=%d\n"
+		 "type_aux=%d\n"
+		 "visual=%d\n"
+		 "xpanstep=%d\n"
+		 "ypanstep=%d\n"
+		 "ywrapstep=%d\n"
+		 "line_length=%d\n"
+		 "accel=%d\n"
+		 "capabilities=%d\n"
+		 "...\n", fix->smem_start, fix->smem_len, fix->type,
+		 fix->type_aux, fix->visual, fix->xpanstep,
+		 fix->ypanstep, fix->ywrapstep, fix->line_length,
+		 fix->accel, fix->capabilities);
+
+	return 0;
+
+fini:
+	drm_fb_helper_fini(&hifbdev->helper);
+	return ret;
+}
+
+void hibmc_fbdev_fini(struct hibmc_drm_device *hidev)
+{
+	if (!hidev->fbdev)
+		return;
+
+	hibmc_fbdev_destroy(hidev->fbdev);
+	hidev->fbdev = NULL;
+}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
index 0802ebd..9822f62 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -488,3 +488,69 @@ int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
 	drm_gem_object_unreference_unlocked(obj);
 	return 0;
 }
+
+/* ---------------------------------------------------------------------- */
+
+static void hibmc_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+	struct hibmc_framebuffer *hibmc_fb = to_hibmc_framebuffer(fb);
+
+	drm_gem_object_unreference_unlocked(hibmc_fb->obj);
+	drm_framebuffer_cleanup(fb);
+	kfree(hibmc_fb);
+}
+
+static const struct drm_framebuffer_funcs hibmc_fb_funcs = {
+	.destroy = hibmc_user_framebuffer_destroy,
+};
+
+struct hibmc_framebuffer *
+hibmc_framebuffer_init(struct drm_device *dev,
+		       const struct drm_mode_fb_cmd2 *mode_cmd,
+		       struct drm_gem_object *obj)
+{
+	struct hibmc_framebuffer *hibmc_fb;
+	int ret;
+
+	hibmc_fb = kzalloc(sizeof(*hibmc_fb), GFP_KERNEL);
+	if (!hibmc_fb)
+		return ERR_PTR(-ENOMEM);
+
+	drm_helper_mode_fill_fb_struct(&hibmc_fb->fb, mode_cmd);
+	hibmc_fb->obj = obj;
+	ret = drm_framebuffer_init(dev, &hibmc_fb->fb, &hibmc_fb_funcs);
+	if (ret) {
+		DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
+		kfree(hibmc_fb);
+		return ERR_PTR(ret);
+	}
+
+	return hibmc_fb;
+}
+
+static struct drm_framebuffer *
+hibmc_user_framebuffer_create(struct drm_device *dev,
+			      struct drm_file *filp,
+			      const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	struct drm_gem_object *obj;
+	struct hibmc_framebuffer *hibmc_fb;
+
+	DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n",
+			 mode_cmd->width, mode_cmd->height,
+			 (mode_cmd->pixel_format) & 0xff,
+			 (mode_cmd->pixel_format >> 8)  & 0xff,
+			 (mode_cmd->pixel_format >> 16) & 0xff,
+			 (mode_cmd->pixel_format >> 24) & 0xff);
+
+	obj = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
+	if (!obj)
+		return ERR_PTR(-ENOENT);
+
+	hibmc_fb = hibmc_framebuffer_init(dev, mode_cmd, obj);
+	if (IS_ERR(hibmc_fb)) {
+		drm_gem_object_unreference_unlocked(obj);
+		return ERR_PTR((long)hibmc_fb);
+	}
+	return &hibmc_fb->fb;
+}
-- 
1.9.1

^ permalink raw reply related

* [PATCH v6 2/9] drm/hisilicon/hibmc: Add video memory management
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477639682-22520-1-git-send-email-zourongrong@gmail.com>

Hibmc have 32m video memory which can be accessed through PCIe by host,
we use ttm to manage these memory.

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/hibmc/Kconfig         |   1 +
 drivers/gpu/drm/hisilicon/hibmc/Makefile        |   2 +-
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c |  12 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h |  46 +++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c     | 490 ++++++++++++++++++++++++
 5 files changed, 550 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c

diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
index a9af90d..bcb8c18 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Kconfig
+++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
@@ -1,6 +1,7 @@
 config DRM_HISI_HIBMC
 	tristate "DRM Support for Hisilicon Hibmc"
 	depends on DRM && PCI
+	select DRM_TTM
 
 	help
 	  Choose this option if you have a Hisilicon Hibmc soc chipset.
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
index 97cf4a0..d5c40b8 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/Makefile
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -1,5 +1,5 @@
 ccflags-y := -Iinclude/drm
-hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o hibmc_ttm.o
 
 obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
 #obj-y	+= hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 4669d42..81f4301 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -31,6 +31,7 @@
 #ifdef CONFIG_COMPAT
 	.compat_ioctl	= drm_compat_ioctl,
 #endif
+	.mmap		= hibmc_mmap,
 	.poll		= drm_poll,
 	.read		= drm_read,
 	.llseek		= no_llseek,
@@ -46,6 +47,8 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 }
 
 static struct drm_driver hibmc_driver = {
+	.driver_features	= DRIVER_GEM,
+
 	.fops			= &hibmc_fops,
 	.name			= "hibmc",
 	.date			= "20160828",
@@ -55,6 +58,10 @@ static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 	.get_vblank_counter	= drm_vblank_no_hw_counter,
 	.enable_vblank		= hibmc_enable_vblank,
 	.disable_vblank		= hibmc_disable_vblank,
+	.gem_free_object_unlocked = hibmc_gem_free_object,
+	.dumb_create            = hibmc_dumb_create,
+	.dumb_map_offset        = hibmc_dumb_mmap_offset,
+	.dumb_destroy           = drm_gem_dumb_destroy,
 };
 
 static int hibmc_pm_suspend(struct device *dev)
@@ -163,6 +170,7 @@ static int hibmc_unload(struct drm_device *dev)
 {
 	struct hibmc_drm_device *hidev = dev->dev_private;
 
+	hibmc_mm_fini(hidev);
 	hibmc_hw_fini(hidev);
 	dev->dev_private = NULL;
 	return 0;
@@ -183,6 +191,10 @@ static int hibmc_load(struct drm_device *dev, unsigned long flags)
 	if (ret)
 		goto err;
 
+	ret = hibmc_mm_init(hidev);
+	if (ret)
+		goto err;
+
 	return 0;
 
 err:
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index 0037341..db8d80e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -20,6 +20,8 @@
 #define HIBMC_DRM_DRV_H
 
 #include <drm/drmP.h>
+#include <drm/ttm/ttm_bo_driver.h>
+#include <drm/drm_gem.h>
 
 struct hibmc_drm_device {
 	/* hw */
@@ -30,6 +32,50 @@ struct hibmc_drm_device {
 
 	/* drm */
 	struct drm_device  *dev;
+
+	/* ttm */
+	struct {
+		struct drm_global_reference mem_global_ref;
+		struct ttm_bo_global_ref bo_global_ref;
+		struct ttm_bo_device bdev;
+		bool initialized;
+	} ttm;
+
+	bool mm_inited;
 };
 
+struct hibmc_bo {
+	struct ttm_buffer_object bo;
+	struct ttm_placement placement;
+	struct ttm_bo_kmap_obj kmap;
+	struct drm_gem_object gem;
+	struct ttm_place placements[3];
+	int pin_count;
+};
+
+static inline struct hibmc_bo *hibmc_bo(struct ttm_buffer_object *bo)
+{
+	return container_of(bo, struct hibmc_bo, bo);
+}
+
+static inline struct hibmc_bo *gem_to_hibmc_bo(struct drm_gem_object *gem)
+{
+	return container_of(gem, struct hibmc_bo, gem);
+}
+
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+
+int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
+		     struct drm_gem_object **obj);
+
+int hibmc_mm_init(struct hibmc_drm_device *hibmc);
+void hibmc_mm_fini(struct hibmc_drm_device *hibmc);
+int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr);
+void hibmc_gem_free_object(struct drm_gem_object *obj);
+int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
+		      struct drm_mode_create_dumb *args);
+int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
+			   u32 handle, u64 *offset);
+int hibmc_mmap(struct file *filp, struct vm_area_struct *vma);
+
 #endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
new file mode 100644
index 0000000..0802ebd
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
@@ -0,0 +1,490 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include "hibmc_drm_drv.h"
+#include <ttm/ttm_page_alloc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
+
+static inline struct hibmc_drm_device *
+hibmc_bdev(struct ttm_bo_device *bd)
+{
+	return container_of(bd, struct hibmc_drm_device, ttm.bdev);
+}
+
+static int
+hibmc_ttm_mem_global_init(struct drm_global_reference *ref)
+{
+	return ttm_mem_global_init(ref->object);
+}
+
+static void
+hibmc_ttm_mem_global_release(struct drm_global_reference *ref)
+{
+	ttm_mem_global_release(ref->object);
+}
+
+static int hibmc_ttm_global_init(struct hibmc_drm_device *hibmc)
+{
+	struct drm_global_reference *global_ref;
+	int r;
+
+	global_ref = &hibmc->ttm.mem_global_ref;
+	global_ref->global_type = DRM_GLOBAL_TTM_MEM;
+	global_ref->size = sizeof(struct ttm_mem_global);
+	global_ref->init = &hibmc_ttm_mem_global_init;
+	global_ref->release = &hibmc_ttm_mem_global_release;
+	r = drm_global_item_ref(global_ref);
+	if (r != 0) {
+		DRM_ERROR("Failed setting up TTM memory accounting subsystem.\n"
+			 );
+		return r;
+	}
+
+	hibmc->ttm.bo_global_ref.mem_glob =
+		hibmc->ttm.mem_global_ref.object;
+	global_ref = &hibmc->ttm.bo_global_ref.ref;
+	global_ref->global_type = DRM_GLOBAL_TTM_BO;
+	global_ref->size = sizeof(struct ttm_bo_global);
+	global_ref->init = &ttm_bo_global_init;
+	global_ref->release = &ttm_bo_global_release;
+	r = drm_global_item_ref(global_ref);
+	if (r != 0) {
+		DRM_ERROR("Failed setting up TTM BO subsystem.\n");
+		drm_global_item_unref(&hibmc->ttm.mem_global_ref);
+		return r;
+	}
+	return 0;
+}
+
+static void
+hibmc_ttm_global_release(struct hibmc_drm_device *hibmc)
+{
+	if (!hibmc->ttm.mem_global_ref.release)
+		return;
+
+	drm_global_item_unref(&hibmc->ttm.bo_global_ref.ref);
+	drm_global_item_unref(&hibmc->ttm.mem_global_ref);
+	hibmc->ttm.mem_global_ref.release = NULL;
+}
+
+static void hibmc_bo_ttm_destroy(struct ttm_buffer_object *tbo)
+{
+	struct hibmc_bo *bo;
+
+	bo = container_of(tbo, struct hibmc_bo, bo);
+
+	drm_gem_object_release(&bo->gem);
+	kfree(bo);
+}
+
+static bool hibmc_ttm_bo_is_hibmc_bo(struct ttm_buffer_object *bo)
+{
+	if (bo->destroy == &hibmc_bo_ttm_destroy)
+		return true;
+	return false;
+}
+
+static int
+hibmc_bo_init_mem_type(struct ttm_bo_device *bdev, u32 type,
+		       struct ttm_mem_type_manager *man)
+{
+	switch (type) {
+	case TTM_PL_SYSTEM:
+		man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+		man->available_caching = TTM_PL_MASK_CACHING;
+		man->default_caching = TTM_PL_FLAG_CACHED;
+		break;
+	case TTM_PL_VRAM:
+		man->func = &ttm_bo_manager_func;
+		man->flags = TTM_MEMTYPE_FLAG_FIXED |
+			TTM_MEMTYPE_FLAG_MAPPABLE;
+		man->available_caching = TTM_PL_FLAG_UNCACHED |
+			TTM_PL_FLAG_WC;
+		man->default_caching = TTM_PL_FLAG_WC;
+		break;
+	default:
+		DRM_ERROR("Unsupported memory type %u\n", type);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+void hibmc_ttm_placement(struct hibmc_bo *bo, int domain)
+{
+	u32 c = 0;
+	u32 i;
+
+	bo->placement.placement = bo->placements;
+	bo->placement.busy_placement = bo->placements;
+	if (domain & TTM_PL_FLAG_VRAM)
+		bo->placements[c++].flags = TTM_PL_FLAG_WC |
+		TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+	if (domain & TTM_PL_FLAG_SYSTEM)
+		bo->placements[c++].flags = TTM_PL_MASK_CACHING |
+		TTM_PL_FLAG_SYSTEM;
+	if (!c)
+		bo->placements[c++].flags = TTM_PL_MASK_CACHING |
+		TTM_PL_FLAG_SYSTEM;
+
+	bo->placement.num_placement = c;
+	bo->placement.num_busy_placement = c;
+	for (i = 0; i < c; ++i) {
+		bo->placements[i].fpfn = 0;
+		bo->placements[i].lpfn = 0;
+	}
+}
+
+static void
+hibmc_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
+{
+	struct hibmc_bo *hibmcbo = hibmc_bo(bo);
+
+	if (!hibmc_ttm_bo_is_hibmc_bo(bo))
+		return;
+
+	hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_SYSTEM);
+	*pl = hibmcbo->placement;
+}
+
+static int hibmc_bo_verify_access(struct ttm_buffer_object *bo,
+				  struct file *filp)
+{
+	struct hibmc_bo *hibmcbo = hibmc_bo(bo);
+
+	return drm_vma_node_verify_access(&hibmcbo->gem.vma_node,
+					  filp->private_data);
+}
+
+static int hibmc_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
+				    struct ttm_mem_reg *mem)
+{
+	struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+	struct hibmc_drm_device *hibmc = hibmc_bdev(bdev);
+
+	mem->bus.addr = NULL;
+	mem->bus.offset = 0;
+	mem->bus.size = mem->num_pages << PAGE_SHIFT;
+	mem->bus.base = 0;
+	mem->bus.is_iomem = false;
+	if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
+		return -EINVAL;
+	switch (mem->mem_type) {
+	case TTM_PL_SYSTEM:
+		/* system memory */
+		return 0;
+	case TTM_PL_VRAM:
+		mem->bus.offset = mem->start << PAGE_SHIFT;
+		mem->bus.base = pci_resource_start(hibmc->dev->pdev, 0);
+		mem->bus.is_iomem = true;
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void hibmc_ttm_io_mem_free(struct ttm_bo_device *bdev,
+				  struct ttm_mem_reg *mem)
+{
+}
+
+static void hibmc_ttm_backend_destroy(struct ttm_tt *tt)
+{
+	ttm_tt_fini(tt);
+	kfree(tt);
+}
+
+static struct ttm_backend_func hibmc_tt_backend_func = {
+	.destroy = &hibmc_ttm_backend_destroy,
+};
+
+static struct ttm_tt *hibmc_ttm_tt_create(struct ttm_bo_device *bdev,
+					  unsigned long size,
+					  u32 page_flags,
+					  struct page *dummy_read_page)
+{
+	struct ttm_tt *tt;
+
+	tt = kzalloc(sizeof(*tt), GFP_KERNEL);
+	if (!tt)
+		return NULL;
+	tt->func = &hibmc_tt_backend_func;
+	if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
+		kfree(tt);
+		return NULL;
+	}
+	return tt;
+}
+
+static int hibmc_ttm_tt_populate(struct ttm_tt *ttm)
+{
+	return ttm_pool_populate(ttm);
+}
+
+static void hibmc_ttm_tt_unpopulate(struct ttm_tt *ttm)
+{
+	ttm_pool_unpopulate(ttm);
+}
+
+struct ttm_bo_driver hibmc_bo_driver = {
+	.ttm_tt_create		= hibmc_ttm_tt_create,
+	.ttm_tt_populate	= hibmc_ttm_tt_populate,
+	.ttm_tt_unpopulate	= hibmc_ttm_tt_unpopulate,
+	.init_mem_type		= hibmc_bo_init_mem_type,
+	.evict_flags		= hibmc_bo_evict_flags,
+	.move			= NULL,
+	.verify_access		= hibmc_bo_verify_access,
+	.io_mem_reserve		= &hibmc_ttm_io_mem_reserve,
+	.io_mem_free		= &hibmc_ttm_io_mem_free,
+	.lru_tail		= &ttm_bo_default_lru_tail,
+	.swap_lru_tail		= &ttm_bo_default_swap_lru_tail,
+};
+
+int hibmc_mm_init(struct hibmc_drm_device *hibmc)
+{
+	int ret;
+	struct drm_device *dev = hibmc->dev;
+	struct ttm_bo_device *bdev = &hibmc->ttm.bdev;
+
+	ret = hibmc_ttm_global_init(hibmc);
+	if (ret)
+		return ret;
+
+	ret = ttm_bo_device_init(&hibmc->ttm.bdev,
+				 hibmc->ttm.bo_global_ref.ref.object,
+				 &hibmc_bo_driver,
+				 dev->anon_inode->i_mapping,
+				 DRM_FILE_PAGE_OFFSET,
+				 true);
+	if (ret) {
+		DRM_ERROR("Error initialising bo driver; %d\n", ret);
+		return ret;
+	}
+
+	ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
+			     hibmc->fb_size >> PAGE_SHIFT);
+	if (ret) {
+		DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
+		return ret;
+	}
+
+	hibmc->mm_inited = true;
+	return 0;
+}
+
+void hibmc_mm_fini(struct hibmc_drm_device *hibmc)
+{
+	if (!hibmc->mm_inited)
+		return;
+
+	ttm_bo_device_release(&hibmc->ttm.bdev);
+	hibmc_ttm_global_release(hibmc);
+	hibmc->mm_inited = false;
+}
+
+int hibmc_bo_create(struct drm_device *dev, int size, int align,
+		    u32 flags, struct hibmc_bo **phibmcbo)
+{
+	struct hibmc_drm_device *hibmc = dev->dev_private;
+	struct hibmc_bo *hibmcbo;
+	size_t acc_size;
+	int ret;
+
+	hibmcbo = kzalloc(sizeof(*hibmcbo), GFP_KERNEL);
+	if (!hibmcbo)
+		return -ENOMEM;
+
+	ret = drm_gem_object_init(dev, &hibmcbo->gem, size);
+	if (ret) {
+		kfree(hibmcbo);
+		return ret;
+	}
+
+	hibmcbo->bo.bdev = &hibmc->ttm.bdev;
+
+	hibmc_ttm_placement(hibmcbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+
+	acc_size = ttm_bo_dma_acc_size(&hibmc->ttm.bdev, size,
+				       sizeof(struct hibmc_bo));
+
+	ret = ttm_bo_init(&hibmc->ttm.bdev, &hibmcbo->bo, size,
+			  ttm_bo_type_device, &hibmcbo->placement,
+			  align >> PAGE_SHIFT, false, NULL, acc_size,
+			  NULL, NULL, hibmc_bo_ttm_destroy);
+	if (ret)
+		return ret;
+
+	*phibmcbo = hibmcbo;
+	return 0;
+}
+
+static inline u64 hibmc_bo_gpu_offset(struct hibmc_bo *bo)
+{
+	return bo->bo.offset;
+}
+
+int hibmc_bo_pin(struct hibmc_bo *bo, u32 pl_flag, u64 *gpu_addr)
+{
+	int i, ret;
+
+	if (bo->pin_count) {
+		bo->pin_count++;
+		if (gpu_addr)
+			*gpu_addr = hibmc_bo_gpu_offset(bo);
+	}
+
+	hibmc_ttm_placement(bo, pl_flag);
+	for (i = 0; i < bo->placement.num_placement; i++)
+		bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
+	ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
+	if (ret)
+		return ret;
+
+	bo->pin_count = 1;
+	if (gpu_addr)
+		*gpu_addr = hibmc_bo_gpu_offset(bo);
+	return 0;
+}
+
+int hibmc_bo_push_sysram(struct hibmc_bo *bo)
+{
+	int i, ret;
+
+	if (!bo->pin_count) {
+		DRM_ERROR("unpin bad %p\n", bo);
+		return 0;
+	}
+	bo->pin_count--;
+	if (bo->pin_count)
+		return 0;
+
+	if (bo->kmap.virtual)
+		ttm_bo_kunmap(&bo->kmap);
+
+	hibmc_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
+	for (i = 0; i < bo->placement.num_placement ; i++)
+		bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
+
+	ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
+	if (ret) {
+		DRM_ERROR("pushing to VRAM failed\n");
+		return ret;
+	}
+	return 0;
+}
+
+int hibmc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct drm_file *file_priv;
+	struct hibmc_drm_device *hibmc;
+
+	if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
+		return -EINVAL;
+
+	file_priv = filp->private_data;
+	hibmc = file_priv->minor->dev->dev_private;
+	return ttm_bo_mmap(filp, vma, &hibmc->ttm.bdev);
+}
+
+int hibmc_gem_create(struct drm_device *dev, u32 size, bool iskernel,
+		     struct drm_gem_object **obj)
+{
+	struct hibmc_bo *hibmcbo;
+	int ret;
+
+	*obj = NULL;
+
+	size = PAGE_ALIGN(size);
+	if (size == 0)
+		return -EINVAL;
+
+	ret = hibmc_bo_create(dev, size, 0, 0, &hibmcbo);
+	if (ret) {
+		if (ret != -ERESTARTSYS)
+			DRM_ERROR("failed to allocate GEM object\n");
+		return ret;
+	}
+	*obj = &hibmcbo->gem;
+	return 0;
+}
+
+int hibmc_dumb_create(struct drm_file *file, struct drm_device *dev,
+		      struct drm_mode_create_dumb *args)
+{
+	struct drm_gem_object *gobj;
+	u32 handle;
+	int ret;
+
+	args->pitch = ALIGN(args->width * ((args->bpp + 7) / 8), 16);
+	args->size = args->pitch * args->height;
+
+	ret = hibmc_gem_create(dev, args->size, false,
+			       &gobj);
+	if (ret)
+		return ret;
+
+	ret = drm_gem_handle_create(file, gobj, &handle);
+	drm_gem_object_unreference_unlocked(gobj);
+	if (ret)
+		return ret;
+
+	args->handle = handle;
+	return 0;
+}
+
+static void hibmc_bo_unref(struct hibmc_bo **bo)
+{
+	struct ttm_buffer_object *tbo;
+
+	if ((*bo) == NULL)
+		return;
+
+	tbo = &((*bo)->bo);
+	ttm_bo_unref(&tbo);
+	*bo = NULL;
+}
+
+void hibmc_gem_free_object(struct drm_gem_object *obj)
+{
+	struct hibmc_bo *hibmcbo = gem_to_hibmc_bo(obj);
+
+	hibmc_bo_unref(&hibmcbo);
+}
+
+static u64 hibmc_bo_mmap_offset(struct hibmc_bo *bo)
+{
+	return drm_vma_node_offset_addr(&bo->bo.vma_node);
+}
+
+int hibmc_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
+			   u32 handle, u64 *offset)
+{
+	struct drm_gem_object *obj;
+	struct hibmc_bo *bo;
+
+	obj = drm_gem_object_lookup(file, handle);
+	if (!obj)
+		return -ENOENT;
+
+	bo = gem_to_hibmc_bo(obj);
+	*offset = hibmc_bo_mmap_offset(bo);
+
+	drm_gem_object_unreference_unlocked(obj);
+	return 0;
+}
-- 
1.9.1

^ permalink raw reply related

* [PATCH v6 1/9] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477639682-22520-1-git-send-email-zourongrong@gmail.com>

Add DRM master driver for Hisilicon Hibmc SoC which used for
Out-of-band management. Blow is the general hardware connection,
both the Hibmc and the host CPU are on the same mother board.

+----------+       +----------+
|          | PCIe  |  Hibmc   |
|host CPU( |<----->| display  |
|arm64,x86)|       |subsystem |
+----------+       +----------+

Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
---
 drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
 drivers/gpu/drm/hisilicon/Makefile                |   1 +
 drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   7 +
 drivers/gpu/drm/hisilicon/hibmc/Makefile          |   5 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 269 ++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   |  35 +++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c |  85 +++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h |  28 +++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 212 +++++++++++++++++
 9 files changed, 643 insertions(+)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h

diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
index 558c61b..2fd2724 100644
--- a/drivers/gpu/drm/hisilicon/Kconfig
+++ b/drivers/gpu/drm/hisilicon/Kconfig
@@ -2,4 +2,5 @@
 # hisilicon drm device configuration.
 # Please keep this list sorted alphabetically
 
+source "drivers/gpu/drm/hisilicon/hibmc/Kconfig"
 source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
index e3f6d49..c8155bf 100644
--- a/drivers/gpu/drm/hisilicon/Makefile
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -2,4 +2,5 @@
 # Makefile for hisilicon drm drivers.
 # Please keep this list sorted alphabetically
 
+obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc/
 obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
new file mode 100644
index 0000000..a9af90d
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
@@ -0,0 +1,7 @@
+config DRM_HISI_HIBMC
+	tristate "DRM Support for Hisilicon Hibmc"
+	depends on DRM && PCI
+
+	help
+	  Choose this option if you have a Hisilicon Hibmc soc chipset.
+	  If M is selected the module will be called hibmc-drm.
diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
new file mode 100644
index 0000000..97cf4a0
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
@@ -0,0 +1,5 @@
+ccflags-y := -Iinclude/drm
+hibmc-drm-y := hibmc_drm_drv.o hibmc_drm_power.o
+
+obj-$(CONFIG_DRM_HISI_HIBMC)	+=hibmc-drm.o
+#obj-y	+= hibmc-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
new file mode 100644
index 0000000..4669d42
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -0,0 +1,269 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/console.h>
+
+#include "hibmc_drm_drv.h"
+#include "hibmc_drm_regs.h"
+#include "hibmc_drm_power.h"
+
+static const struct file_operations hibmc_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		= no_llseek,
+};
+
+static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
+{
+	return 0;
+}
+
+static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
+{
+}
+
+static struct drm_driver hibmc_driver = {
+	.fops			= &hibmc_fops,
+	.name			= "hibmc",
+	.date			= "20160828",
+	.desc			= "hibmc drm driver",
+	.major			= 1,
+	.minor			= 0,
+	.get_vblank_counter	= drm_vblank_no_hw_counter,
+	.enable_vblank		= hibmc_enable_vblank,
+	.disable_vblank		= hibmc_disable_vblank,
+};
+
+static int hibmc_pm_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int hibmc_pm_resume(struct device *dev)
+{
+	return 0;
+}
+
+static const struct dev_pm_ops hibmc_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,
+				hibmc_pm_resume)
+};
+
+static int hibmc_hw_config(struct hibmc_drm_device *hidev)
+{
+	unsigned int reg;
+
+	/* On hardware reset, power mode 0 is default. */
+	hibmc_set_power_mode(hidev, HIBMC_PW_MODE_CTL_MODE_MODE0);
+
+	/* Enable display power gate & LOCALMEM power gate*/
+	reg = readl(hidev->mmio + HIBMC_CURRENT_GATE);
+	reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
+	reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
+	reg |= HIBMC_CURR_GATE_DISPLAY(ON);
+	reg |= HIBMC_CURR_GATE_LOCALMEM(ON);
+
+	hibmc_set_current_gate(hidev, reg);
+
+	/* Reset the memory controller. If the memory controller
+	 * is not reset in chip,the system might hang when sw accesses
+	 * the memory.The memory should be resetted after
+	 * changing the MXCLK.
+	 */
+	reg = readl(hidev->mmio + HIBMC_MISC_CTRL);
+	reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
+	reg |= HIBMC_MSCCTL_LOCALMEM_RESET(RESET);
+	writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
+
+	reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
+	reg |= HIBMC_MSCCTL_LOCALMEM_RESET(NORMAL);
+
+	writel(reg, hidev->mmio + HIBMC_MISC_CTRL);
+
+	/* We can add more initialization as needed. */
+
+	return 0;
+}
+
+static int hibmc_hw_map(struct hibmc_drm_device *hidev)
+{
+	struct drm_device *dev = hidev->dev;
+	struct pci_dev *pdev = dev->pdev;
+	resource_size_t addr, size, ioaddr, iosize;
+
+	ioaddr = pci_resource_start(pdev, 1);
+	iosize = MB(2);
+
+	hidev->mmio = ioremap_nocache(ioaddr, iosize);
+
+	if (!hidev->mmio) {
+		DRM_ERROR("Cannot map mmio region\n");
+		return -ENOMEM;
+	}
+
+	addr = pci_resource_start(pdev, 0);
+	size = MB(32);
+
+	hidev->fb_map = ioremap(addr, size);
+	if (!hidev->fb_map) {
+		DRM_ERROR("Cannot map framebuffer\n");
+		return -ENOMEM;
+	}
+	hidev->fb_base = addr;
+	hidev->fb_size = size;
+
+	return 0;
+}
+
+static void hibmc_hw_fini(struct hibmc_drm_device *hidev)
+{
+	if (hidev->mmio)
+		iounmap(hidev->mmio);
+	if (hidev->fb_map)
+		iounmap(hidev->fb_map);
+}
+
+static int hibmc_hw_init(struct hibmc_drm_device *hidev)
+{
+	int ret;
+
+	ret = hibmc_hw_map(hidev);
+	if (ret)
+		return ret;
+
+	hibmc_hw_config(hidev);
+
+	return 0;
+}
+
+static int hibmc_unload(struct drm_device *dev)
+{
+	struct hibmc_drm_device *hidev = dev->dev_private;
+
+	hibmc_hw_fini(hidev);
+	dev->dev_private = NULL;
+	return 0;
+}
+
+static int hibmc_load(struct drm_device *dev, unsigned long flags)
+{
+	struct hibmc_drm_device *hidev;
+	int ret;
+
+	hidev = devm_kzalloc(dev->dev, sizeof(*hidev), GFP_KERNEL);
+	if (!hidev)
+		return -ENOMEM;
+	dev->dev_private = hidev;
+	hidev->dev = dev;
+
+	ret = hibmc_hw_init(hidev);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	hibmc_unload(dev);
+	DRM_ERROR("failed to initialize drm driver.\n");
+	return ret;
+}
+
+static int hibmc_pci_probe(struct pci_dev *pdev,
+			   const struct pci_device_id *ent)
+{
+	struct drm_device *dev;
+	int ret;
+
+	dev = drm_dev_alloc(&hibmc_driver, &pdev->dev);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->pdev = pdev;
+	pci_set_drvdata(pdev, dev);
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		goto err_free;
+
+	ret = hibmc_load(dev, 0);
+	if (ret)
+		goto err_disable;
+
+	ret = drm_dev_register(dev, 0);
+	if (ret)
+		goto err_unload;
+
+	return 0;
+
+err_unload:
+	hibmc_unload(dev);
+err_disable:
+	pci_disable_device(pdev);
+err_free:
+	drm_dev_unref(dev);
+
+	return ret;
+}
+
+static void hibmc_pci_remove(struct pci_dev *pdev)
+{
+	struct drm_device *dev = pci_get_drvdata(pdev);
+
+	drm_dev_unregister(dev);
+	hibmc_unload(dev);
+	drm_dev_unref(dev);
+}
+
+static struct pci_device_id hibmc_pci_table[] = {
+	{0x19e5, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}
+};
+
+static struct pci_driver hibmc_pci_driver = {
+	.name =		"hibmc-drm",
+	.id_table =	hibmc_pci_table,
+	.probe =	hibmc_pci_probe,
+	.remove =	hibmc_pci_remove,
+	.driver.pm =    &hibmc_pm_ops,
+};
+
+static int __init hibmc_init(void)
+{
+	return pci_register_driver(&hibmc_pci_driver);
+}
+
+static void __exit hibmc_exit(void)
+{
+	return pci_unregister_driver(&hibmc_pci_driver);
+}
+
+module_init(hibmc_init);
+module_exit(hibmc_exit);
+
+MODULE_DEVICE_TABLE(pci, hibmc_pci_table);
+MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>");
+MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
new file mode 100644
index 0000000..0037341
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -0,0 +1,35 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef HIBMC_DRM_DRV_H
+#define HIBMC_DRM_DRV_H
+
+#include <drm/drmP.h>
+
+struct hibmc_drm_device {
+	/* hw */
+	void __iomem   *mmio;
+	void __iomem   *fb_map;
+	unsigned long  fb_base;
+	unsigned long  fb_size;
+
+	/* drm */
+	struct drm_device  *dev;
+};
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
new file mode 100644
index 0000000..1036542
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
@@ -0,0 +1,85 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include "hibmc_drm_drv.h"
+#include "hibmc_drm_regs.h"
+
+/*
+ * It can operate in one of three modes: 0, 1 or Sleep.
+ */
+void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
+			  unsigned int power_mode)
+{
+	unsigned int control_value = 0;
+	void __iomem   *mmio = hidev->mmio;
+
+	if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
+		return;
+
+	control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
+	control_value &= ~HIBMC_PW_MODE_CTL_MODE_MASK;
+
+	control_value |= HIBMC_PW_MODE_CTL_MODE(power_mode) &
+			 HIBMC_PW_MODE_CTL_MODE_MASK;
+
+    /* Set up other fields in Power Control Register */
+	if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP) {
+		control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
+		control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(0) &
+				 HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
+	} else {
+		control_value &= ~HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
+		control_value |= HIBMC_PW_MODE_CTL_OSC_INPUT(1) &
+				 HIBMC_PW_MODE_CTL_OSC_INPUT_MASK;
+	}
+	/* Program new power mode. */
+	writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
+}
+
+static unsigned int hibmc_get_power_mode(struct hibmc_drm_device *hidev)
+{
+	void __iomem   *mmio = hidev->mmio;
+
+	return (readl(mmio + HIBMC_POWER_MODE_CTRL) &
+		HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
+}
+
+void hibmc_set_current_gate(struct hibmc_drm_device *hidev, unsigned int gate)
+{
+	unsigned int gate_reg;
+	unsigned int mode;
+	void __iomem   *mmio = hidev->mmio;
+
+	/* Get current power mode. */
+	mode = hibmc_get_power_mode(hidev);
+
+	switch (mode) {
+	case HIBMC_PW_MODE_CTL_MODE_MODE0:
+		gate_reg = HIBMC_MODE0_GATE;
+		break;
+
+	case HIBMC_PW_MODE_CTL_MODE_MODE1:
+		gate_reg = HIBMC_MODE1_GATE;
+		break;
+
+	default:
+		gate_reg = HIBMC_MODE0_GATE;
+		break;
+	}
+	writel(gate, mmio + gate_reg);
+}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
new file mode 100644
index 0000000..e20e1aa
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
@@ -0,0 +1,28 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef HIBMC_DRM_POWER_H
+#define HIBMC_DRM_POWER_H
+
+#include "hibmc_drm_drv.h"
+
+void hibmc_set_power_mode(struct hibmc_drm_device *hidev,
+			  unsigned int power_mode);
+void hibmc_set_current_gate(struct hibmc_drm_device *hidev,
+			    unsigned int gate);
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
new file mode 100644
index 0000000..9c804ca
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
@@ -0,0 +1,212 @@
+/* Hisilicon Hibmc SoC drm driver
+ *
+ * Based on the bochs drm driver.
+ *
+ * Copyright (c) 2016 Huawei Limited.
+ *
+ * Author:
+ *	Rongrong Zou <zourongrong@huawei.com>
+ *	Rongrong Zou <zourongrong@gmail.com>
+ *	Jianhua Li <lijianhua@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef HIBMC_DRM_HW_H
+#define HIBMC_DRM_HW_H
+
+#define OFF 0
+#define ON  1
+#define DISABLE               0
+#define ENABLE                1
+
+/* register definition */
+#define HIBMC_MISC_CTRL				0x4
+
+#define HIBMC_MSCCTL_LOCALMEM_RESET(x)		((x) << 6)
+#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK	0x40
+
+#define RESET                0
+#define NORMAL               1
+
+#define HIBMC_CURRENT_GATE			0x000040
+#define HIBMC_CURR_GATE_DISPLAY(x)		((x) << 2)
+#define HIBMC_CURR_GATE_DISPLAY_MASK		0x4
+
+#define HIBMC_CURR_GATE_LOCALMEM(x)		((x) << 1)
+#define HIBMC_CURR_GATE_LOCALMEM_MASK		0x2
+
+#define HIBMC_MODE0_GATE			0x000044
+#define HIBMC_MODE1_GATE			0x000048
+#define HIBMC_POWER_MODE_CTRL			0x00004C
+
+#define HIBMC_PW_MODE_CTL_OSC_INPUT(x)		((x) << 3)
+#define HIBMC_PW_MODE_CTL_OSC_INPUT_MASK	0x8
+
+#define HIBMC_PW_MODE_CTL_MODE(x)		((x) << 0)
+#define HIBMC_PW_MODE_CTL_MODE_MASK		0x03
+#define HIBMC_PW_MODE_CTL_MODE_SHIFT		0
+
+#define HIBMC_PW_MODE_CTL_MODE_MODE0		0
+#define HIBMC_PW_MODE_CTL_MODE_MODE1		1
+#define HIBMC_PW_MODE_CTL_MODE_SLEEP		2
+
+#define HIBMC_PANEL_PLL_CTRL			0x00005C
+#define HIBMC_CRT_PLL_CTRL			0x000060
+
+#define HIBMC_PLL_CTRL_BYPASS(x)		((x) << 18)
+#define HIBMC_PLL_CTRL_BYPASS_MASK		0x40000
+
+#define HIBMC_PLL_CTRL_POWER(x)			((x) << 17)
+#define HIBMC_PLL_CTRL_POWER_MASK		0x20000
+
+#define HIBMC_PLL_CTRL_INPUT(x)			((x) << 16)
+#define HIBMC_PLL_CTRL_INPUT_MASK		0x10000
+
+#define OSC					0
+#define TESTCLK					1
+
+#define HIBMC_PLL_CTRL_POD(x)			((x) << 14)
+#define HIBMC_PLL_CTRL_POD_MASK			0xC000
+
+#define HIBMC_PLL_CTRL_OD(x)			((x) << 12)
+#define HIBMC_PLL_CTRL_OD_MASK			0x3000
+
+#define HIBMC_PLL_CTRL_N(x)			((x) << 8)
+#define HIBMC_PLL_CTRL_N_MASK			0xF00
+
+#define HIBMC_PLL_CTRL_M(x)			((x) << 0)
+#define HIBMC_PLL_CTRL_M_MASK			0xFF
+
+#define HIBMC_CRT_DISP_CTL			0x80200
+
+#define HIBMC_CRT_DISP_CTL_CRTSELECT(x)		((x) << 25)
+#define HIBMC_CRT_DISP_CTL_CRTSELECT_MASK	0x2000000
+
+#define CRTSELECT_VGA                0
+#define CRTSELECT_CRT                1
+
+#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x)	((x) << 14)
+#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK	0x4000
+
+#define PHASE_ACTIVE_HIGH      0
+#define PHASE_ACTIVE_LOW       1
+
+#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE(x)	((x) << 13)
+#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK	0x2000
+
+#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE(x)	((x) << 12)
+#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK	0x1000
+
+#define HIBMC_CRT_DISP_CTL_TIMING(x)		((x) << 8)
+#define HIBMC_CRT_DISP_CTL_TIMING_MASK		0x100
+
+#define HIBMC_CRT_DISP_CTL_PLANE(x)		((x) << 2)
+#define HIBMC_CRT_DISP_CTL_PLANE_MASK		4
+
+#define HIBMC_CRT_DISP_CTL_FORMAT(x)		((x) << 0)
+#define HIBMC_CRT_DISP_CTL_FORMAT_MASK		0x03
+
+#define HIBMC_CRT_FB_ADDRESS			0x080204
+
+#define HIBMC_CRT_FB_WIDTH			0x080208
+#define HIBMC_CRT_FB_WIDTH_WIDTH(x)		((x) << 16)
+#define HIBMC_CRT_FB_WIDTH_WIDTH_MASK		0x3FFF0000
+#define HIBMC_CRT_FB_WIDTH_OFFS(x)		((x) << 0)
+#define HIBMC_CRT_FB_WIDTH_OFFS_MASK		0x3FFF
+
+#define HIBMC_CRT_HORZ_TOTAL			0x08020C
+#define HIBMC_CRT_HORZ_TOTAL_TOTAL(x)		((x) << 16)
+#define HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK		0xFFF0000
+
+#define HIBMC_CRT_HORZ_TOTAL_DISPLAY_END(x)	((x) << 0)
+#define HIBMC_CRT_HORZ_TOTAL_DISPLAY_END_MASK	0xFFF
+
+#define HIBMC_CRT_HORZ_SYNC			0x080210
+#define HIBMC_CRT_HORZ_SYNC_WIDTH(x)		((x) << 16)
+#define HIBMC_CRT_HORZ_SYNC_WIDTH_MASK		0xFF0000
+
+#define HIBMC_CRT_HORZ_SYNC_START(x)		((x) << 0)
+#define HIBMC_CRT_HORZ_SYNC_START_MASK		0xFFF
+
+#define HIBMC_CRT_VERT_TOTAL			0x080214
+#define HIBMC_CRT_VERT_TOTAL_TOTAL(x)		((x) << 16)
+#define HIBMC_CRT_VERT_TOTAL_TOTAL_MASK		0x7FFF0000
+
+#define HIBMC_CRT_VERT_TOTAL_DISPLAY_END(x)	((x) << 0)
+#define HIBMC_CRT_VERT_TOTAL_DISPLAY_END_MASK	0x7FF
+
+#define HIBMC_CRT_VERT_SYNC			0x080218
+#define HIBMC_CRT_VERT_SYNC_HEIGHT(x)		((x) << 16)
+#define HIBMC_CRT_VERT_SYNC_HEIGHT_MASK		0x3F0000
+
+#define HIBMC_CRT_VERT_SYNC_START(x)		((x) << 0)
+#define HIBMC_CRT_VERT_SYNC_START_MASK		0x7FF
+
+/* Auto Centering */
+#define HIBMC_CRT_AUTO_CENTERING_TL		0x080280
+#define HIBMC_CRT_AUTO_CENTERING_TL_TOP(x)	((x) << 16)
+#define HIBMC_CRT_AUTO_CENTERING_TL_TOP_MSK	0x7FF0000
+
+#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x)	((x) << 0)
+#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MSK	0x7FF
+
+#define HIBMC_CRT_AUTO_CENTERING_BR		0x080284
+#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(x)	((x) << 16)
+#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK	0x7FF0000
+
+#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x)	((x) << 0)
+#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK	0x7FF
+
+/* register to control panel output */
+#define DISPLAY_CONTROL_HISILE			0x80288
+
+#define HIBMC_RAW_INTERRUPT			0x80290
+#define HIBMC_RAW_INTERRUPT_VBLANK(x)		((x) << 2)
+#define HIBMC_RAW_INTERRUPT_VBLANK_MASK		0x4
+
+#define HIBMC_RAW_INTERRUPT_EN			0x80298
+#define HIBMC_RAW_INTERRUPT_EN_VBLANK(x)	((x) << 2)
+#define HIBMC_RAW_INTERRUPT_EN_VBLANK_MASK	0x4
+
+/* register and values for PLL control */
+#define CRT_PLL1_HS				0x802a8
+#define CRT_PLL1_HS_25MHZ			0x23d40f02
+#define CRT_PLL1_HS_40MHZ			0x23940801
+#define CRT_PLL1_HS_65MHZ			0x23940d01
+#define CRT_PLL1_HS_78MHZ			0x23540F82
+#define CRT_PLL1_HS_74MHZ			0x23941dc2
+#define CRT_PLL1_HS_80MHZ			0x23941001
+#define CRT_PLL1_HS_80MHZ_1152			0x23540fc2
+#define CRT_PLL1_HS_108MHZ			0x23b41b01
+#define CRT_PLL1_HS_162MHZ			0x23480681
+#define CRT_PLL1_HS_148MHZ			0x23541dc2
+#define CRT_PLL1_HS_193MHZ			0x234807c1
+
+#define CRT_PLL2_HS				0x802ac
+#define CRT_PLL2_HS_25MHZ			0x206B851E
+#define CRT_PLL2_HS_40MHZ			0x30000000
+#define CRT_PLL2_HS_65MHZ			0x40000000
+#define CRT_PLL2_HS_78MHZ			0x50E147AE
+#define CRT_PLL2_HS_74MHZ			0x602B6AE7
+#define CRT_PLL2_HS_80MHZ			0x70000000
+#define CRT_PLL2_HS_108MHZ			0x80000000
+#define CRT_PLL2_HS_162MHZ			0xA0000000
+#define CRT_PLL2_HS_148MHZ			0xB0CCCCCD
+#define CRT_PLL2_HS_193MHZ			0xC0872B02
+
+/* Global macros */
+#define RGB(r, g, b) \
+( \
+	(unsigned long)(((r) << 16) | ((g) << 8) | (b)) \
+)
+
+#define PADDING(align, data) (((data) + (align) - 1) & (~((align) - 1)))
+
+#define MB(x) ((x) << 20)
+
+#endif
-- 
1.9.1

^ permalink raw reply related

* [PATCH v6 0/9] Add DRM driver for Hisilicon Hibmc
From: Rongrong Zou @ 2016-10-28  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
BMC SoC with a display controller intergrated, usually it is used on
server for Out-of-band management purpose. In this patch set, we just
support basic function for Hibmc display subsystem. Hibmc display
subsystem is connected to host CPU by PCIe as blow:

+----------+       +----------+
|          | PCIe  |  Hibmc   |
|host CPU( |<----->| display  |
|arm64,x86)|       |subsystem |
+----------+       +----------+

Hardware Detail for Hibmc display subsystem
-----------

  The display subsystem of Hibmc is show as bellow:
  +----+      +----+      +----+     +--------+
  |    |      |    |      |    |     |        |
  | FB |----->| DE |----->|VDAC|---->|external|
  |    |      |    |      |    |     | VGA    |
  +----+      +----+      +----+     +--------+

  -DE(Display Engine) is the display controller.
  -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
  stream from DE to VGA analog signals.

Change History
------------
Changes in v6:
  -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
   instead.
  -remove the deprecated drm_framebuffer_unregister_private(), 
   drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
  -uninstall irq in hibmc_unload(). 

Changes in v5:
  -rebase on v4.9-rc2.
  -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
   and remove redundant console_lock and console_unlock. 

Changes in v4:
  -remove unused include files, and include header file when it is needed.
  -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
  -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.

Changes in v3:
  -enable KMS, in v2, only fbdev is enabled.
  -management video memory with ttm.
  -add vblank interrupt.
  -remove drm_connector_register_all() and drm_connector_unregister_all().
  -I have a basic test with igt.

Changes in v2:
  -Remove self-defined macros for bit operations.
  -Remove unused register.
  -Replace those deprecated functions with new version of them.
  -use drm_connector_register_all() to register connector after
   drm_dev_register().

The patch v2 is at
https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html

Rongrong Zou (9):
  drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
  drm/hisilicon/hibmc: Add video memory management
  drm/hisilicon/hibmc: Add support for frame buffer
  drm/hisilicon/hibmc: Add plane for DE
  drm/hisilicon/hibmc: Add crtc for DE
  drm/hisilicon/hibmc: Add encoder for VDAC
  drm/hisilicon/hibmc: Add connector for VDAC
  drm/hisilicon/hibmc: Add vblank interruput
  MAINTAINERS: Update HISILICON DRM entries

 MAINTAINERS                                       |   1 +
 drivers/gpu/drm/hisilicon/Kconfig                 |   1 +
 drivers/gpu/drm/hisilicon/Makefile                |   1 +
 drivers/gpu/drm/hisilicon/hibmc/Kconfig           |   9 +
 drivers/gpu/drm/hisilicon/hibmc/Makefile          |   5 +
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c    | 488 +++++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h    |  29 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c   | 419 ++++++++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h   | 117 +++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 255 ++++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c |  85 ++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h |  28 ++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h  | 212 ++++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c  | 165 +++++++
 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c       | 562 ++++++++++++++++++++++
 15 files changed, 2377 insertions(+)
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.h
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_power.h
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
 create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c

-- 
1.9.1

^ permalink raw reply

* [PATCH v2 2/2] arm64: dts: hi6220: add resets property into dwmmc nodes
From: Leo Yan @ 2016-10-28  7:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAKfTPtAXdkKcfpHmUmQNwuJxO0PORcCf49noST_CCkZPigPwgw@mail.gmail.com>

On Fri, Oct 28, 2016 at 08:43:51AM +0200, Vincent Guittot wrote:

[...]

> > running with? Also do you have any details about the card in case its
> > card specific?
> 
> The sdcard is quite common: sandisk ultra 16GB
> and my rootfs is on the sdcard

I'm using rootfs in emmc also have same failure.

> > Guodong: Is there any bootloader dependency on that change?
> 
> FYI, I use firmwares available in AOSP

I tried latest firmware [1], still cannot boot up until revert the
patch "arm64: dts: hi6220: add resets property into dwmmc nodes".

[1] http://builds.96boards.org/snapshots/hikey/linaro/uefi-openplatformpkg/latest/

Thanks,
Leo Yan

^ permalink raw reply

* [PATCHv4 00/15] clk: ti: add support for hwmod clocks
From: Tero Kristo @ 2016-10-28  7:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161028005341.GR26139@codeaurora.org>

On 28/10/16 03:53, Stephen Boyd wrote:
> On 10/18, Tero Kristo wrote:
>> Hi,
>>
>> As a recap, this series is part of the ongoing work to get rid of the
>> hwmod database under mach-omap2 folder. This series converts the
>> existing clock related functionality to a new clock type, which will
>> allow removing all the .clkctrl related items from hwmod database.
>> This series adds sample solution for OMAP4 only, rest of the SoCs can
>> be converted automatically once the approach is acceptable.
>>
>> v4 has the following high level changes compared to v3:
>> - Clock data is now statically built-in to the driver
>> - Adds clockdomain provider support, which can be used to fetch
>>   clocks based on clockdomain relation. Only clockdomains need to be
>>   registered within DT.
>> - Added some automatic clock alias generation support to the TI clock
>>   drivers, if this is not acceptable, I can change this to add all the
>>   aliases under the individual drivers/clk/ti/clk-xyz.c files
>
> Is there a plan to get rid of the aliases entirely? Or we can't
> do that because DT is not fully supported on these platforms? I'm
> mostly wondering how long that sort of code is going to stick
> around and if it's better to fully compartmentalize it to the
> SoCs that are affected or if it should be a core feature of TI
> driver.

Eventually that should happen. However, we have plenty of legacy code 
still in place which depend on clk_get functionality within kernel. The 
major contributing factor is the hwmod codebase, for which we have plans to:

- get this clock driver merged
- implement a new interconnect driver for OMAP family SoCs
- interconnect driver will use DT handles for fetching clocks, rather 
than clock aliases
- reset handling will be implemented as part of the interconnect driver 
somehow (no prototype / clear plans for that as of yet)
- all the hwmod stuff can be dropped

The clock alias handling is still needed as a transition phase until all 
the above is done, then we can start dropping them. Basically anything 
that is using omap_hwmod depends on the clock aliases right now.

>
>> - As a sample, only omap4 clock data is available with this set
>>
>> After this series, the clock data can be dropped from the hwmod database
>> for OMAP4, I have working patches for this for anybody interested. Also,
>> the DT files require some modifications to add proper support for
>> clockdomain providers, and drop some unnecessary clock nodes.
>
> Can this be shared as a git tree on the web? Hopefully I can see
> the resulting DTS and understand what's going on better.

Sure, here is a test branch I've been using, it has some extra hacks on 
top for debugging purposes, but the DTS changes are visible also.

https://github.com/t-kristo/linux-pm/tree/4.9-rc1-hwmod-clks-w-data


>
>>
>> Boot + simple PM test seems to be working on OMAP4 with this set, and
>> boot test with other boards I have access to don't seem to cause any
>> issues. Applies on top of 4.9-rc1.
>>
>
> Awesome!
>

^ permalink raw reply

* [v13, 5/8] soc: fsl: add GUTS driver for QorIQ platforms
From: Y.B. Lu @ 2016-10-28  7:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1477629956.6812.15.camel@buserror.net>

> -----Original Message-----
> From: Y.B. Lu
> Sent: Friday, October 28, 2016 2:06 PM
> To: Y.B. Lu; 'Scott Wood'; 'linux-mmc at vger.kernel.org';
> 'ulf.hansson at linaro.org'; 'Arnd Bergmann'
> Cc: 'linuxppc-dev at lists.ozlabs.org'; 'devicetree at vger.kernel.org';
> 'linux-arm-kernel at lists.infradead.org'; 'linux-kernel at vger.kernel.org';
> 'linux-clk at vger.kernel.org'; 'linux-i2c at vger.kernel.org';
> 'iommu at lists.linux-foundation.org'; 'netdev at vger.kernel.org'; 'Greg
> Kroah-Hartman'; 'Mark Rutland'; 'Rob Herring'; 'Russell King'; 'Jochen
> Friedrich'; 'Joerg Roedel'; 'Claudiu Manoil'; 'Bhupesh Sharma'; Qiang
> Zhao; 'Kumar Gala'; 'Santosh Shilimkar'; Leo Li; X.B. Xie; M.H. Lian
> Subject: RE: [v13, 5/8] soc: fsl: add GUTS driver for QorIQ platforms
> 
> > -----Original Message-----
> > From: Y.B. Lu
> > Sent: Friday, October 28, 2016 2:00 PM
> > To: 'Scott Wood'; linux-mmc at vger.kernel.org; ulf.hansson at linaro.org;
> > Arnd Bergmann
> > Cc: linuxppc-dev at lists.ozlabs.org; devicetree at vger.kernel.org;
> > linux-arm- kernel at lists.infradead.org; linux-kernel at vger.kernel.org;
> > linux- clk at vger.kernel.org; linux-i2c at vger.kernel.org;
> > iommu at lists.linux- foundation.org; netdev at vger.kernel.org; Greg
> > Kroah-Hartman; Mark Rutland; Rob Herring; Russell King; Jochen
> > Friedrich; Joerg Roedel; Claudiu Manoil; Bhupesh Sharma; Qiang Zhao;
> Kumar Gala; Santosh Shilimkar; Leo Li; X.B.
> > Xie; M.H. Lian
> > Subject: RE: [v13, 5/8] soc: fsl: add GUTS driver for QorIQ platforms
> >
> >
> >
> > > -----Original Message-----
> > > From: linux-mmc-owner at vger.kernel.org [mailto:linux-mmc-
> > > owner at vger.kernel.org] On Behalf Of Scott Wood
> > > Sent: Friday, October 28, 2016 12:46 PM
> > > To: Y.B. Lu; linux-mmc at vger.kernel.org; ulf.hansson at linaro.org; Arnd
> > > Bergmann
> > > Cc: linuxppc-dev at lists.ozlabs.org; devicetree at vger.kernel.org;
> > > linux-arm- kernel at lists.infradead.org; linux-kernel at vger.kernel.org;
> > > linux- clk at vger.kernel.org; linux-i2c at vger.kernel.org;
> > > iommu at lists.linux- foundation.org; netdev at vger.kernel.org; Greg
> > > Kroah-Hartman; Mark Rutland; Rob Herring; Russell King; Jochen
> > > Friedrich; Joerg Roedel; Claudiu Manoil; Bhupesh Sharma; Qiang Zhao;
> > Kumar Gala; Santosh Shilimkar; Leo Li; X.B.
> > > Xie; M.H. Lian
> > > Subject: Re: [v13, 5/8] soc: fsl: add GUTS driver for QorIQ
> > > platforms
> > >
> > > On Fri, 2016-10-28 at 11:32 +0800, Yangbo Lu wrote:
> > > > +	guts->regs = of_iomap(np, 0);
> > > > +	if (!guts->regs)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	/* Register soc device */
> > > > +	machine = of_flat_dt_get_machine_name();
> > > > +	if (machine)
> > > > +		soc_dev_attr.machine = devm_kstrdup(dev, machine,
> > > > GFP_KERNEL);
> > > > +
> > > > +	svr = fsl_guts_get_svr();
> > > > +	soc_die = fsl_soc_die_match(svr, fsl_soc_die);
> > > > +	if (soc_die) {
> > > > +		soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL,
> > > > +						?????"QorIQ %s", soc_die-
> > > > >die);
> > > > +	} else {
> > > > +		soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL,
> > > > "QorIQ");
> > > > +	}
> > > > +	soc_dev_attr.soc_id = devm_kasprintf(dev, GFP_KERNEL,
> > > > +					?????"svr:0x%08x", svr);
> > > > +	soc_dev_attr.revision = devm_kasprintf(dev, GFP_KERNEL,
> "%d.%d",
> > > > +					???????SVR_MAJ(svr), SVR_MIN(svr));
> > > > +
> > > > +	soc_dev = soc_device_register(&soc_dev_attr);
> > > > +	if (IS_ERR(soc_dev))
> > > > +		return PTR_ERR(soc_dev);
> > >
> > > ioremap leaks on this error path. ?Use devm_ioremap_resource().
> > >
> >
> > [Lu Yangbo-B47093] Ok. I have fixed it in v14. Thanks :)
> 
> [Lu Yangbo-B47093] Sorry, used the wrong error code... Will resent it

[Lu Yangbo-B47093] The v15 had been sent. And dropped patch 'dt: bindings: update Freescale DCFG compatible',
since that work has been done by below patch on ShawnGuo's linux tree.
'dt-bindings: fsl: add LS1043A/LS1046A/LS2080A compatible for SCFG and DCFG'
https://git.kernel.org/cgit/linux/kernel/git/shawnguo/linux.git/commit/?h=imx/dt64&id=981034a2bfcaff5c95dafde24d7abfe7f9025c19

Thanks.

> 
> >
> > > -Scott
> > >
> > > --
> > > To unsubscribe from this list: send the line "unsubscribe linux-mmc"
> > > in the body of a message to majordomo at vger.kernel.org More majordomo
> > > info at http://vger.kernel.org/majordomo-info.html

^ permalink raw reply


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