* Re: [PATCH 1/5] misc: Beaglebone capemanager
From: Greg Kroah-Hartman @ 2015-05-13 15:36 UTC (permalink / raw)
To: Pantelis Antoniou
Cc: Matt Porter, Koen Kooi, Robert Nelson, Rob Herring, Grant Likely,
Jonathan Corbet, Srinivas Kandagatla, Guenter Roeck,
Geert Uytterhoeven, Benoît Cousso,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <67B17BCF-0489-4FD6-88F0-57B6187BEFEB-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
On Wed, May 13, 2015 at 03:10:25PM +0300, Pantelis Antoniou wrote:
> Hi Greg,
>
> > On May 13, 2015, at 14:55 , Greg Kroah-Hartman <gregkh@linuxfoundation.org> wrote:
> >
> > On Wed, May 13, 2015 at 10:59:41AM +0300, Pantelis Antoniou wrote:
> >> A cape loader based on DT overlays and DT objects.
> >>
> >> This is the beaglebone cape manager which allows capes to be automatically
> >> probed and instantiated via means of a device tree overlay deduced from
> >> the part-number and version contained on the cape's EEPROM.
> >>
> >> The reference manual contains information about the specification
> >> and the contents of the EEPROM.
> >>
> >> http://beagleboard.org/static/beaglebone/latest/Docs/Hardware/BONE_SRM.pdf
> >>
> >> Documentation about the workings of the cape manager is located
> >> in Documentation/misc-devices/bone_capemgr.txt
> >>
> >> This driver is using the EEPROM framework interface to retrieve
> >> the data stored on the baseboard and cape EEPROMs.
> >>
> >> Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
> >> ---
> >> drivers/misc/Kconfig | 10 +
> >> drivers/misc/Makefile | 1 +
> >> drivers/misc/bone_capemgr.c | 1926 +++++++++++++++++++++++++++++++++++++++++++
> >> 3 files changed, 1937 insertions(+)
> >> create mode 100644 drivers/misc/bone_capemgr.c
> >>
> >> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> >> index 006242c..f9e09e1 100644
> >> --- a/drivers/misc/Kconfig
> >> +++ b/drivers/misc/Kconfig
> >> @@ -515,6 +515,16 @@ config VEXPRESS_SYSCFG
> >> bus. System Configuration interface is one of the possible means
> >> of generating transactions on this bus.
> >>
> >> +config BONE_CAPEMGR
> >> + tristate "Beaglebone cape manager"
> >> + depends on ARCH_OMAP2PLUS && OF
> >> + select EEPROM
> >> + select OF_OVERLAY
> >> + default n
> >
> > N is always the default, please remove.
> >
>
> OK
>
> >> + help
> >> + Say Y here to include support for automatic loading of
> >> + beaglebone capes.
> >> +
> >
> > What about if it's a module?
> >
> >
>
> It should work but it’s going to be weird (i.e. no-one has used it as such).
> I’ll update the blurb.
You are saying it is a valid config option, so please test it as such,
or if it's not a valid config option, don't allow it.
> >> source "drivers/misc/c2port/Kconfig"
> >> source "drivers/misc/eeprom/Kconfig"
> >> source "drivers/misc/cb710/Kconfig"
> >> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> >> index 7d5c4cd..659b78b 100644
> >> --- a/drivers/misc/Makefile
> >> +++ b/drivers/misc/Makefile
> >> @@ -56,3 +56,4 @@ obj-$(CONFIG_GENWQE) += genwqe/
> >> obj-$(CONFIG_ECHO) += echo/
> >> obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
> >> obj-$(CONFIG_CXL_BASE) += cxl/
> >> +obj-$(CONFIG_BONE_CAPEMGR) += bone_capemgr.o
> >> diff --git a/drivers/misc/bone_capemgr.c b/drivers/misc/bone_capemgr.c
> >> new file mode 100644
> >> index 0000000..423719c
> >> --- /dev/null
> >> +++ b/drivers/misc/bone_capemgr.c
> >> @@ -0,0 +1,1926 @@
> >> +/*
> >> + * TI Beaglebone cape manager
> >> + *
> >> + * Copyright (C) 2012 Texas Instruments Inc.
> >> + * Copyright (C) 2012-2015 Konsulko Group.
> >> + * Author: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
> >> + *
> >> + * 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.
> >
> > I have to ask, do you really mean, "or any later version”?
> >
>
> Yes, this is purely a community thing. No evil vendor at play at all.
I have no idea what that means.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> >> + * GNU General Public License for more details.
> >> + */
> >> +
> >> +#include <linux/module.h>
> >> +#include <linux/delay.h>
> >> +#include <linux/err.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/completion.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/clk.h>
> >> +#include <linux/io.h>
> >> +#include <linux/of.h>
> >> +#include <linux/of_device.h>
> >> +#include <linux/of_fdt.h>
> >> +#include <linux/slab.h>
> >> +#include <linux/pm_runtime.h>
> >> +#include <linux/pinctrl/consumer.h>
> >> +#include <linux/firmware.h>
> >> +#include <linux/err.h>
> >> +#include <linux/ctype.h>
> >> +#include <linux/string.h>
> >> +#include <linux/memory.h>
> >> +#include <linux/kthread.h>
> >> +#include <linux/wait.h>
> >> +#include <linux/file.h>
> >> +#include <linux/fs.h>
> >> +#include <linux/eeprom-consumer.h>
> >> +
> >> +/* disabled capes */
> >> +static char *disable_partno;
> >> +module_param(disable_partno, charp, 0444);
> >> +MODULE_PARM_DESC(disable_partno,
> >> + "Comma delimited list of PART-NUMBER[:REV] of disabled capes");
> >> +
> >> +/* enable capes */
> >> +static char *enable_partno;
> >> +module_param(enable_partno, charp, 0444);
> >> +MODULE_PARM_DESC(enable_partno,
> >> + "Comma delimited list of PART-NUMBER[:REV] of enabled capes");
> >> +
> >> +/* delay to scan on boot until rootfs appears */
> >> +static int boot_scan_period = 1000;
> >> +module_param(boot_scan_period, int, 0444);
> >> +MODULE_PARM_DESC(boot_scan_period,
> >> + "boot scan period until rootfs firmware is available");
> >
> > Ick, no module parameters please, can't we drop these?
> >
>
> In a nutshell, no :)
>
> These has to be way to control whether a cape is disabled (if found) and enabled (if the manufacturer in it’s infinite wisdom removed the EEPROM to save $0.01 per cape).
Please line-wrap your responses.
> The easiest way to achieve this is with the kernel command line.
No it is not. You can't easily change the kernel command line for an
embedded system (or so everyone keeps telling me when I say things like
"just update your kernel command line!") So embedded people can't have
it both ways, sorry.
Can't you put these in a dt file?
> > And we have a rootfs delay option already for the whole system, this
> > module shouldn't need a special one.
> >
>
> No, that won’t work.
>
> You see the problem is as follows.
>
> The capemanager is not built as a module, it is builtin.
Not according to your Kconfig file :)
> By the time the probe method is called the rootfs has no been mounted yet.
> This is actually what we want for the cases where the rootfs resides on a cape and
> the cape’s dtbo firmware file is built-in the kernel image.
>
> This does not work when the firmware file is located in the rootfs filesystem, since
> the call to request_firmware will fail at that time.
Then you let it happen later. Or do it async. Don't create new command
line options for when we already have the same command line option!
> That option controls the polling delay until the system boot state indicates that the
> rootfs is available and the call will succeed.
If this is such an issue, just sit and spin and wait for it to show up.
> There are lots of warts in our firmware loader.
You can fix them, don't make the kernel work around the warts because
you don't want to :)
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH v8 14/16] ARM: dts: Introduce STM32F429 MCU
From: Arnd Bergmann @ 2015-05-13 15:28 UTC (permalink / raw)
To: Daniel Thompson
Cc: Maxime Coquelin, Uwe Kleine-König, Andreas Färber,
Geert Uytterhoeven, Rob Herring, Philipp Zabel, Linus Walleij,
Stefan Agner, Peter Meerwald, Paul Bolle, Peter Hurley,
Andy Shevchenko, Chanwoo Choi, Russell King, Daniel Lezcano,
Joe Perches, Vladimir Zapolskiy, Lee Jones, Jonathan Corbet,
Pawel Moll, Mark Rutland
In-Reply-To: <55536BC2.30603@linaro.org>
On Wednesday 13 May 2015 16:20:34 Daniel Thompson wrote:
> For the all reset bits:
>
> clock idx = reset idx + 256
>
> The opposite is not true; the clock bits are a superset of the reset
> bits (the reset bits act on cells but some cells have >1 clock).
Ok, in that case, I would strongly recommend subtracting that 256
offset keeping the numbers the same, to remove the function-type
macros.
> >> However there are a couple of clocks without gating just before the
> >> clock reaches the peripheral:
> >>
> >> 1. A hard coded /8. I think this will have to be given a synthetic
> >> number.
> >
> > If this is just a divider, why not use a separate DT node for that,
> > like this:
> >
> > clock {
> > compatible = "fixed-factor-clock";
> > clocks = <&parentclk>;
> > #clock-cells = <0>;
> > clock-div = <8>;
> > clock-mult = <1>;
> > };
> >
> > No need to assign a number for this.
>
> I'd wondered about doing that.
>
> It will certainly work but it seemed a bit odd to me to have one (really
> tiny) part of the RCC cell included seperately in the platform
> description whilst all the complicated bits end up aggregated into the
> RCC cell.
>
> Is there much prior art that uses this type of trick to avoid having
> magic numbers into the bindings?
Are you sure that divider is actually part of the RCC?
> >> 2. Ungated dividers. For these I am using the bit offset of the LSB of
> >> the mux field.
> >
> > Do these ones also come with resets?
>
> No. They mostly run to the core and its intimate peripherals (i.e. only
> reset line comes from WDT).
Ok.
> >> So I think there is only one value that is completely unrelated to the
> >> hardware and will use a magic constant instead.
> >>
> >> I had planned to macros similar to the STM32F4_AxB_RESET() family of
> >> macros in both clk driver and DT in order to reuse the bit layouts from
> >> dt-bindings/mfd/stm32f4-rcc.h .
> >>
> >> Normal case would have looked like this:
> >>
> >> timer3: timer@40000000 {
> >> compatible = "st,stm32-timer";
> >> reg = <0x40000000 0x400>;
> >> interrupts = <28>;
> >> resets = <&rcc STM32F4_APB1_RESET(TIM3)>;
> >> clocks = <&rcc STM32F4_APB1_CLK(TIM3)>;
> >> status = "disabled";
> >> };
> >>
> >> Without the macros it looks like this:
> >>
> >> timer3: timer@40000000 {
> >> compatible = "st,stm32-timer";
> >> reg = <0x40000000 0x400>;
> >> interrupts = <28>;
> >> resets = <&rcc 257>;
> >> clocks = <&rcc 513>;
> >> status = "disabled";
> >> };
> >>
> >> However we could perhaps be more literate even if we don't use the macros?
> >>
> >> timer3: timer@40000000 {
> >> compatible = "st,stm32-timer";
> >> reg = <0x40000000 0x400>;
> >> interrupts = <28>;
> >> resets = <&rcc ((0x20*8) + 1)>;
> >> clocks = <&rcc ((0x40*8) + 1)>;
> >> status = "disabled";
> >> };
> >
> > How about #address-cells = <2>, so you can do
> >
> > resets = <&rcc 8 1>;
> > clocks = <&rcc 8 1>;
> >
> > with the first cell being an index for the block and the second cell the
> > bit number within that block.
>
> That would suit me very well (although is the 0x20/0x40 not the 8 that
> we would need in the middle column).
We don't normally use register offsets in DT. The number 8 here instead
would indicate block 8, where each block is four bytes wide. Using the
same index here for reset and clock would also help readability.
Arnd
^ permalink raw reply
* [RFC][PATCH 2/2] drm/mediatek: Add DRM Driver for Mediatek SoC MT8173.
From: CK Hu @ 2015-05-13 15:23 UTC (permalink / raw)
To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
David Airlie, Matthias Brugger
Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
Rob Herring, Ashwin Chaugule, Catalin Marinas, Will Deacon,
Grant Likely, Graeme Gregory, dri-devel, linux-api,
srv_heupstream, Sascha Hauer, Cawa Cheng, YT Shen, Jitao Shi,
CK Hu
In-Reply-To: <1431530626-31493-1-git-send-email-ck.hu@mediatek.com>
This patch is a DRM Driver for Mediatek SoC MT8173.
Now support one crtc with MIPI DSI interface.
We used GEM framework for buffer management and use iommu for
physically non-continuous memory.
Signed-off-by: CK Hu <ck.hu@mediatek.com>
---
drivers/gpu/drm/Kconfig | 2 +
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/mediatek/Kconfig | 28 +
drivers/gpu/drm/mediatek/Makefile | 13 +
drivers/gpu/drm/mediatek/mediatek_drm_crtc.c | 246 ++++
drivers/gpu/drm/mediatek/mediatek_drm_crtc.h | 80 ++
drivers/gpu/drm/mediatek/mediatek_drm_crtc_main.c | 420 +++++++
drivers/gpu/drm/mediatek/mediatek_drm_ddp.c | 202 ++++
drivers/gpu/drm/mediatek/mediatek_drm_ddp.h | 23 +
drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.c | 346 ++++++
drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.h | 33 +
drivers/gpu/drm/mediatek/mediatek_drm_drv.c | 369 ++++++
drivers/gpu/drm/mediatek/mediatek_drm_drv.h | 37 +
drivers/gpu/drm/mediatek/mediatek_drm_dsi.c | 1333 +++++++++++++++++++++
drivers/gpu/drm/mediatek/mediatek_drm_dsi.h | 71 ++
drivers/gpu/drm/mediatek/mediatek_drm_fb.c | 339 ++++++
drivers/gpu/drm/mediatek/mediatek_drm_fb.h | 43 +
drivers/gpu/drm/mediatek/mediatek_drm_gem.c | 315 +++++
drivers/gpu/drm/mediatek/mediatek_drm_gem.h | 94 ++
include/uapi/drm/mediatek_drm.h | 59 +
20 files changed, 4054 insertions(+)
create mode 100644 drivers/gpu/drm/mediatek/Kconfig
create mode 100644 drivers/gpu/drm/mediatek/Makefile
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_crtc.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_crtc.h
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_crtc_main.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_ddp.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_ddp.h
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.h
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_drv.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_drv.h
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_dsi.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_dsi.h
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_fb.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_fb.h
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_gem.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_gem.h
create mode 100644 include/uapi/drm/mediatek_drm.h
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 47f2ce8..441be2d 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -217,3 +217,5 @@ source "drivers/gpu/drm/sti/Kconfig"
source "drivers/gpu/drm/amd/amdkfd/Kconfig"
source "drivers/gpu/drm/imx/Kconfig"
+
+source "drivers/gpu/drm/mediatek/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 7d4944e..55fe66c 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_DRM_MSM) += msm/
obj-$(CONFIG_DRM_TEGRA) += tegra/
obj-$(CONFIG_DRM_STI) += sti/
obj-$(CONFIG_DRM_IMX) += imx/
+obj-$(CONFIG_DRM_MEDIATEK) += mediatek/
obj-y += i2c/
obj-y += panel/
obj-y += bridge/
diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig
new file mode 100644
index 0000000..fa581fb
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/Kconfig
@@ -0,0 +1,28 @@
+config DRM_MEDIATEK
+ tristate "DRM Support for Mediatek SoCs"
+ depends on DRM
+ depends on ARCH_MEDIATEK || (ARM && COMPILE_TEST)
+ select MTK_SMI
+ select DRM_PANEL
+ select DRM_MIPI_DSI
+ select DRM_PANEL_SIMPLE
+ select DRM_KMS_HELPER
+ select IOMMU_DMA
+ help
+ Choose this option if you have a Mediatek SoCs.
+ The module will be called mediatek-drm
+ This driver provides kernel mode setting and
+ buffer management to userspace.
+
+config DRM_MEDIATEK_FBDEV
+ bool "Enable legacy fbdev support for Mediatek DRM"
+ depends on DRM_MEDIATEK
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select DRM_KMS_FB_HELPER
+ help
+ Choose this option if you have a need for the legacy
+ fbdev support. Note that this support also provides
+ the Linux console on top of the Mediatek DRM mode
+ setting driver.
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
new file mode 100644
index 0000000..a566a83
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -0,0 +1,13 @@
+mediatek-drm-objs := mediatek_drm_drv.o \
+ mediatek_drm_crtc.o \
+ mediatek_drm_fb.o \
+ mediatek_drm_gem.o \
+ mediatek_drm_dsi.o \
+ mediatek_drm_ddp.o \
+ mediatek_drm_ddp_comp.o \
+ mediatek_drm_crtc_main.o
+
+obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o
+
+ccflags-y += \
+ -Idrivers/gpu/drm
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_crtc.c b/drivers/gpu/drm/mediatek/mediatek_drm_crtc.c
new file mode 100644
index 0000000..e1437c6
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_crtc.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <linux/dma-buf.h>
+#include <linux/reservation.h>
+
+#include "mediatek_drm_drv.h"
+#include "mediatek_drm_crtc.h"
+#include "mediatek_drm_fb.h"
+#include "mediatek_drm_gem.h"
+
+
+void mtk_crtc_finish_page_flip(struct mtk_drm_crtc *mtk_crtc)
+{
+ struct drm_device *dev = mtk_crtc->base.dev;
+
+ drm_send_vblank_event(dev, mtk_crtc->event->pipe, mtk_crtc->event);
+ drm_crtc_vblank_put(&mtk_crtc->base);
+ mtk_crtc->event = NULL;
+}
+
+static void mediatek_drm_crtc_pending_ovl_config(struct mtk_drm_crtc *mtk_crtc,
+ bool enable, unsigned int addr)
+{
+ if (mtk_crtc->ops && mtk_crtc->ops->ovl_layer_config)
+ mtk_crtc->ops->ovl_layer_config(mtk_crtc, enable, addr);
+}
+
+static void mediatek_drm_crtc_pending_ovl_cursor_config(
+ struct mtk_drm_crtc *mtk_crtc,
+ bool enable, unsigned int addr)
+{
+ if (mtk_crtc->ops && mtk_crtc->ops->ovl_layer_config_cursor)
+ mtk_crtc->ops->ovl_layer_config_cursor(mtk_crtc, enable, addr);
+}
+
+static int mtk_drm_crtc_page_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event,
+ uint32_t page_flip_flags)
+{
+ struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+ struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
+ struct drm_device *dev = crtc->dev;
+ unsigned long flags;
+ bool busy;
+ int ret;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ busy = !!mtk_crtc->event;
+ if (!busy)
+ mtk_crtc->event = event;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ if (busy)
+ return -EBUSY;
+
+ if (fb->width != crtc->mode.hdisplay ||
+ fb->height != crtc->mode.vdisplay) {
+ DRM_ERROR("mtk_drm_crtc_page_flip width/height not match !!\n");
+ return -EINVAL;
+ }
+
+ if (event) {
+ ret = drm_crtc_vblank_get(crtc);
+ if (ret) {
+ DRM_ERROR("failed to acquire vblank events\n");
+ return ret;
+ }
+ }
+
+ /*
+ * the values related to a buffer of the drm framebuffer
+ * to be applied should be set at here. because these values
+ * first, are set to shadow registers and then to
+ * real registers at vsync front porch period.
+ */
+ crtc->primary->fb = fb;
+ mtk_crtc->flip_buffer = to_mtk_gem_obj(mtk_fb->gem_obj[0])->buffer;
+
+ mediatek_drm_crtc_pending_ovl_config(mtk_crtc, true,
+ mtk_crtc->flip_buffer->mva_addr);
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ if (mtk_crtc->event)
+ mtk_crtc->pending_needs_vblank = true;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ return ret;
+}
+
+static void mtk_drm_crtc_destroy(struct drm_crtc *crtc)
+{
+ drm_crtc_cleanup(crtc);
+}
+
+static void mtk_drm_crtc_prepare(struct drm_crtc *crtc)
+{
+ /* drm framework doesn't check NULL. */
+}
+
+static void mtk_drm_crtc_commit(struct drm_crtc *crtc)
+{
+ /*
+ * when set_crtc is requested from user or at booting time,
+ * crtc->commit would be called without dpms call so if dpms is
+ * no power on then crtc->dpms should be called
+ * with DRM_MODE_DPMS_ON for the hardware power to be on.
+ */
+}
+
+static bool mtk_drm_crtc_mode_fixup(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ /* drm framework doesn't check NULL */
+ return true;
+}
+
+static int mtk_drm_crtc_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ int x, int y, struct drm_framebuffer *old_fb)
+{
+ struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+ struct drm_framebuffer *fb;
+ struct mtk_drm_fb *mtk_fb;
+ struct mtk_drm_gem_buf *buffer;
+
+ fb = crtc->primary->fb;
+ mtk_fb = to_mtk_fb(fb);
+
+ buffer = to_mtk_gem_obj(mtk_fb->gem_obj[0])->buffer;
+
+ mediatek_drm_crtc_pending_ovl_config(mtk_crtc, true,
+ buffer->mva_addr);
+ /*
+ * copy the mode data adjusted by mode_fixup() into crtc->mode
+ * so that hardware can be seet to proper mode.
+ */
+ memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
+
+ /* Take a reference to the new fb as we're using it */
+ drm_framebuffer_reference(crtc->primary->fb);
+
+ return 0;
+}
+
+int mtk_drm_crtc_enable_vblank(struct drm_device *drm, int pipe)
+{
+ struct mtk_drm_private *priv =
+ (struct mtk_drm_private *)drm->dev_private;
+ struct mtk_drm_crtc *mtk_crtc;
+
+ if (pipe >= MAX_CRTC || pipe < 0) {
+ DRM_ERROR(" - %s: invalid crtc (%d)\n", __func__, pipe);
+ return -EINVAL;
+ }
+
+ mtk_crtc = to_mtk_crtc(priv->crtc[pipe]);
+
+ if (mtk_crtc->ops->enable_vblank)
+ mtk_crtc->ops->enable_vblank(mtk_crtc);
+
+ return 0;
+}
+
+void mtk_drm_crtc_disable_vblank(struct drm_device *drm, int pipe)
+{
+ struct mtk_drm_private *priv =
+ (struct mtk_drm_private *)drm->dev_private;
+ struct mtk_drm_crtc *mtk_crtc;
+
+ if (pipe >= MAX_CRTC || pipe < 0)
+ DRM_ERROR(" - %s: invalid crtc (%d)\n", __func__, pipe);
+
+ mtk_crtc = to_mtk_crtc(priv->crtc[pipe]);
+ if (mtk_crtc->ops->disable_vblank)
+ mtk_crtc->ops->disable_vblank(mtk_crtc);
+}
+
+static void mtk_drm_crtc_disable(struct drm_crtc *crtc)
+{
+ struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+
+ DRM_INFO("mtk_drm_crtc_disable %d\n", crtc->base.id);
+
+ mediatek_drm_crtc_pending_ovl_config(mtk_crtc, false, 0);
+ mediatek_drm_crtc_pending_ovl_cursor_config(mtk_crtc, false, 0);
+}
+
+static struct drm_crtc_funcs mediatek_crtc_funcs = {
+ .set_config = drm_crtc_helper_set_config,
+ .page_flip = mtk_drm_crtc_page_flip,
+ .destroy = mtk_drm_crtc_destroy,
+};
+
+static struct drm_crtc_helper_funcs mediatek_crtc_helper_funcs = {
+ .prepare = mtk_drm_crtc_prepare,
+ .commit = mtk_drm_crtc_commit,
+ .mode_fixup = mtk_drm_crtc_mode_fixup,
+ .mode_set = mtk_drm_crtc_mode_set,
+ .disable = mtk_drm_crtc_disable,
+};
+
+struct mtk_drm_crtc *mtk_drm_crtc_create(
+ struct drm_device *drm_dev, int pipe,
+ struct mediatek_drm_crtc_ops *ops,
+ void *ctx)
+{
+ struct mtk_drm_private *priv =
+ (struct mtk_drm_private *)drm_dev->dev_private;
+ struct mtk_drm_crtc *mtk_crtc;
+
+ mtk_crtc = devm_kzalloc(drm_dev->dev, sizeof(*mtk_crtc), GFP_KERNEL);
+ if (!mtk_crtc) {
+ DRM_ERROR("failed to allocate mtk crtc\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ mtk_crtc->pipe = pipe;
+ mtk_crtc->ops = ops;
+ mtk_crtc->ctx = ctx;
+
+ priv->crtc[pipe] = &mtk_crtc->base;
+
+ drm_crtc_init(drm_dev, &mtk_crtc->base, &mediatek_crtc_funcs);
+ drm_crtc_helper_add(&mtk_crtc->base, &mediatek_crtc_helper_funcs);
+
+ return mtk_crtc;
+}
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_crtc.h b/drivers/gpu/drm/mediatek/mediatek_drm_crtc.h
new file mode 100644
index 0000000..1732927
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_crtc.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#ifndef _MEDIATEL_DRM_CRTC_H_
+#define _MEDIATEL_DRM_CRTC_H_
+
+#include "mediatek_drm_ddp.h"
+
+
+#define MAX_FB_BUFFER 4
+#define DEFAULT_ZPOS -1
+
+struct mtk_drm_crtc;
+struct mediatek_drm_crtc_ops {
+ void (*dpms)(struct mtk_drm_crtc *crtc, int mode);
+ int (*enable_vblank)(struct mtk_drm_crtc *crtc);
+ void (*disable_vblank)(struct mtk_drm_crtc *crtc);
+ void (*ovl_layer_config)(struct mtk_drm_crtc *crtc,
+ bool enable, unsigned int addr);
+ void (*ovl_layer_config_cursor)(struct mtk_drm_crtc *crtc,
+ bool enable, unsigned int addr);
+};
+
+/*
+ * MediaTek specific crtc structure.
+ *
+ * @base: crtc object.
+ * @pipe: a crtc index created at load() with a new crtc object creation
+ * and the crtc object would be set to private->crtc array
+ * to get a crtc object corresponding to this pipe from private->crtc
+ * array when irq interrupt occurred. the reason of using this pipe is that
+ * drm framework doesn't support multiple irq yet.
+ * we can refer to the crtc to current hardware interrupt occurred through
+ * this pipe value.
+ */
+struct mtk_drm_crtc {
+ struct drm_crtc base;
+
+ unsigned int pipe;
+ struct drm_pending_vblank_event *event;
+ struct mtk_drm_gem_buf *flip_buffer;
+ struct mediatek_drm_crtc_ops *ops;
+ void *ctx;
+ bool pending_needs_vblank;
+
+ bool pending_ovl_config;
+ bool pending_ovl_enabled;
+ unsigned int pending_ovl_addr;
+ unsigned int pending_ovl_width;
+ unsigned int pending_ovl_height;
+ unsigned int pending_ovl_pitch;
+ unsigned int pending_ovl_format;
+
+};
+
+#define to_mtk_crtc(x) container_of(x, struct mtk_drm_crtc, base)
+
+struct mtk_drm_crtc *mtk_drm_crtc_create(
+ struct drm_device *drm_dev, int pipe,
+ struct mediatek_drm_crtc_ops *ops,
+ void *ctx);
+void mtk_drm_crtc_irq(struct mtk_drm_crtc *mtk_crtc);
+
+void mtk_crtc_finish_page_flip(struct mtk_drm_crtc *mtk_crtc);
+int mtk_drm_crtc_enable_vblank(struct drm_device *drm, int pipe);
+void mtk_drm_crtc_disable_vblank(struct drm_device *drm, int pipe);
+
+#endif
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_crtc_main.c b/drivers/gpu/drm/mediatek/mediatek_drm_crtc_main.c
new file mode 100644
index 0000000..4d16620
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_crtc_main.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Authors:
+ * YT Shen <yt.shen@mediatek.com>
+ * CK Hu <ck.hu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/component.h>
+#include <linux/pm_runtime.h>
+#include "mediatek_drm_drv.h"
+#include "mediatek_drm_crtc.h"
+#include "mediatek_drm_gem.h"
+#include "mediatek_drm_ddp_comp.h"
+
+
+struct crtc_main_context {
+ struct device *dev;
+ struct drm_device *drm_dev;
+ struct mtk_drm_crtc *crtc;
+ int pipe;
+
+ struct device *ddp_dev;
+ struct clk *ovl0_disp_clk;
+ struct clk *rdma0_disp_clk;
+ struct clk *color0_disp_clk;
+ struct clk *aal_disp_clk;
+ struct clk *ufoe_disp_clk;
+ struct clk *od_disp_clk;
+
+ void __iomem *ovl0_regs;
+ void __iomem *rdma0_regs;
+ void __iomem *color0_regs;
+ void __iomem *aal_regs;
+ void __iomem *ufoe_regs;
+ void __iomem *od_regs;
+
+ bool pending_ovl_config;
+ bool pending_ovl_enable;
+ unsigned int pending_ovl_addr;
+ unsigned int pending_ovl_width;
+ unsigned int pending_ovl_height;
+ unsigned int pending_ovl_pitch;
+ unsigned int pending_ovl_format;
+};
+
+
+static int crtc_main_ctx_initialize(struct crtc_main_context *ctx,
+ struct drm_device *drm_dev)
+{
+ struct mtk_drm_private *priv;
+
+ priv = drm_dev->dev_private;
+ ctx->drm_dev = drm_dev;
+ ctx->pipe = priv->pipe++;
+
+ return 0;
+}
+
+static void crtc_main_ctx_remove(struct crtc_main_context *ctx)
+{
+}
+
+static void crtc_main_power_on(struct crtc_main_context *ctx)
+{
+ int ret;
+
+ ret = clk_prepare_enable(ctx->ovl0_disp_clk);
+ if (ret != 0)
+ DRM_ERROR("clk_prepare_enable(ctx->ovl0_disp_clk) error!\n");
+
+ ret = clk_prepare_enable(ctx->rdma0_disp_clk);
+ if (ret != 0)
+ DRM_ERROR("clk_prepare_enable(ctx->rdma0_disp_clk) error!\n");
+
+ ret = clk_prepare_enable(ctx->color0_disp_clk);
+ if (ret != 0)
+ DRM_ERROR("clk_prepare_enable(ctx->color0_disp_clk) error!\n");
+
+ ret = clk_prepare_enable(ctx->aal_disp_clk);
+ if (ret != 0)
+ DRM_ERROR("clk_prepare_enable(ctx->aal_disp_clk) error!\n");
+
+ ret = clk_prepare_enable(ctx->ufoe_disp_clk);
+ if (ret != 0)
+ DRM_ERROR("clk_prepare_enable(ctx->ufoe_disp_clk) error!\n");
+
+ ret = clk_prepare_enable(ctx->od_disp_clk);
+ if (ret != 0)
+ DRM_ERROR("clk_prepare_enable(ctx->od_disp_clk) error!\n");
+}
+
+static void crtc_main_power_off(struct crtc_main_context *ctx)
+{
+ clk_disable_unprepare(ctx->ovl0_disp_clk);
+
+ clk_disable_unprepare(ctx->rdma0_disp_clk);
+
+ clk_disable_unprepare(ctx->color0_disp_clk);
+
+ clk_disable_unprepare(ctx->aal_disp_clk);
+
+ clk_disable_unprepare(ctx->ufoe_disp_clk);
+
+ clk_disable_unprepare(ctx->od_disp_clk);
+}
+
+static void crtc_main_dpms(struct mtk_drm_crtc *crtc, int mode)
+{
+ /* DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); */
+
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ crtc_main_power_on(crtc->ctx);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ crtc_main_power_off(crtc->ctx);
+ break;
+ default:
+ DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+ break;
+ }
+}
+
+static int crtc_main_enable_vblank(struct mtk_drm_crtc *crtc)
+{
+ struct crtc_main_context *ctx = (struct crtc_main_context *)crtc->ctx;
+
+ mediatek_od_enable_vblank(ctx->od_regs);
+
+ return 0;
+}
+
+static void crtc_main_disable_vblank(struct mtk_drm_crtc *crtc)
+{
+ struct crtc_main_context *ctx = (struct crtc_main_context *)crtc->ctx;
+
+ mediatek_od_disable_vblank(ctx->od_regs);
+}
+
+static void crtc_main_ovl_layer_config(struct mtk_drm_crtc *crtc,
+ bool enable, unsigned int addr)
+{
+ struct crtc_main_context *ctx = (struct crtc_main_context *)crtc->ctx;
+ unsigned int pitch = 0;
+
+ if (crtc->base.primary->fb && crtc->base.primary->fb->pitches[0])
+ pitch = crtc->base.primary->fb->pitches[0];
+
+ ctx->pending_ovl_enable = enable;
+ if (enable) {
+ ctx->pending_ovl_addr = addr;
+ ctx->pending_ovl_width = crtc->base.mode.hdisplay;
+ ctx->pending_ovl_height = crtc->base.mode.vdisplay;
+ ctx->pending_ovl_pitch = pitch;
+ ctx->pending_ovl_format = crtc->base.primary->fb->pixel_format;
+ }
+ ctx->pending_ovl_config = true;
+}
+
+static struct mediatek_drm_crtc_ops crtc_main_crtc_ops = {
+ .dpms = crtc_main_dpms,
+ .enable_vblank = crtc_main_enable_vblank,
+ .disable_vblank = crtc_main_disable_vblank,
+ .ovl_layer_config = crtc_main_ovl_layer_config,
+};
+
+static void crtc_main_irq(struct crtc_main_context *ctx)
+{
+ struct drm_device *dev = ctx->drm_dev;
+ struct mtk_drm_crtc *mtk_crtc = ctx->crtc;
+ unsigned long flags;
+
+ if (ctx->pending_ovl_config) {
+ ctx->pending_ovl_config = false;
+ mediatek_ovl_layer_config(ctx->ovl0_regs,
+ ctx->pending_ovl_enable,
+ ctx->pending_ovl_addr,
+ ctx->pending_ovl_width,
+ ctx->pending_ovl_height,
+ ctx->pending_ovl_pitch,
+ ctx->pending_ovl_format);
+ }
+
+ drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+ spin_lock_irqsave(&dev->event_lock, flags);
+ if (mtk_crtc->pending_needs_vblank) {
+ mtk_crtc_finish_page_flip(mtk_crtc);
+ mtk_crtc->pending_needs_vblank = false;
+ }
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+irqreturn_t crtc_main_irq_handler(int irq, void *dev_id)
+{
+ struct crtc_main_context *ctx = (struct crtc_main_context *)dev_id;
+
+ mediatek_od_clear_vblank(ctx->od_regs);
+
+ if (ctx->pipe < 0 || !ctx->drm_dev)
+ goto out;
+
+ crtc_main_irq(ctx);
+out:
+ return IRQ_HANDLED;
+}
+
+static int crtc_main_bind(struct device *dev, struct device *master, void *data)
+{
+ struct crtc_main_context *ctx = dev_get_drvdata(dev);
+ struct drm_device *drm_dev = data;
+ int ret;
+
+ ret = crtc_main_ctx_initialize(ctx, drm_dev);
+ if (ret) {
+ DRM_ERROR("crtc_main_ctx_initialize failed.\n");
+ return ret;
+ }
+
+ ctx->crtc = mtk_drm_crtc_create(drm_dev, ctx->pipe,
+ &crtc_main_crtc_ops, ctx);
+
+ if (IS_ERR(ctx->crtc)) {
+ crtc_main_ctx_remove(ctx);
+ return PTR_ERR(ctx->crtc);
+ }
+
+ DRM_INFO("mediatek_ddp_clock_on\n");
+ mediatek_ddp_clock_on(ctx->ddp_dev);
+
+ DRM_INFO("mediatek_ddp_main_path_setup\n");
+ mediatek_ddp_main_path_setup(ctx->ddp_dev);
+
+ DRM_INFO("main_disp_path_power_on\n");
+ main_disp_path_power_on(ctx->ovl0_regs, ctx->rdma0_regs,
+ ctx->color0_regs, ctx->ufoe_regs, ctx->od_regs);
+
+ return 0;
+
+}
+
+static void crtc_main_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct crtc_main_context *ctx = dev_get_drvdata(dev);
+
+ crtc_main_ctx_remove(ctx);
+}
+
+static const struct component_ops crtc_main_component_ops = {
+ .bind = crtc_main_bind,
+ .unbind = crtc_main_unbind,
+};
+
+static int crtc_main_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct crtc_main_context *ctx;
+ struct device_node *node;
+ struct platform_device *ddp_pdev;
+ struct resource *regs;
+ int irq;
+ int ret;
+
+ if (!dev->of_node)
+ return -ENODEV;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ node = of_parse_phandle(dev->of_node, "ddp", 0);
+ if (!node) {
+ dev_err(dev, "crtc_main_probe: Get ddp node fail.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ddp_pdev = of_find_device_by_node(node);
+ if (WARN_ON(!ddp_pdev)) {
+ dev_err(dev, "crtc_main_probe: Find ddp device fail.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ ctx->ddp_dev = &ddp_pdev->dev;
+
+ ctx->ovl0_disp_clk = devm_clk_get(dev, "ovl0_disp");
+ if (IS_ERR(ctx->ovl0_disp_clk)) {
+ dev_err(dev, "crtc_main_probe: Get ovl0_disp_clk fail.\n");
+ ret = PTR_ERR(ctx->ovl0_disp_clk);
+ goto err;
+ }
+
+ ctx->rdma0_disp_clk = devm_clk_get(dev, "rdma0_disp");
+ if (IS_ERR(ctx->rdma0_disp_clk)) {
+ dev_err(dev, "crtc_main_probe: Get rdma0_disp_clk.\n");
+ ret = PTR_ERR(ctx->rdma0_disp_clk);
+ goto err;
+ }
+
+ ctx->color0_disp_clk = devm_clk_get(dev, "color0_disp");
+ if (IS_ERR(ctx->color0_disp_clk)) {
+ dev_err(dev, "crtc_main_probe: Get color0_disp_clk fail.\n");
+ ret = PTR_ERR(ctx->color0_disp_clk);
+ goto err;
+ }
+
+ ctx->aal_disp_clk = devm_clk_get(dev, "aal_disp");
+ if (IS_ERR(ctx->aal_disp_clk)) {
+ dev_err(dev, "crtc_main_probe: Get aal_disp_clk fail.\n");
+ ret = PTR_ERR(ctx->aal_disp_clk);
+ goto err;
+ }
+
+ ctx->ufoe_disp_clk = devm_clk_get(dev, "ufoe_disp");
+ if (IS_ERR(ctx->ufoe_disp_clk)) {
+ dev_err(dev, "crtc_main_probe: Get ufoe_disp_clk fail.\n");
+ ret = PTR_ERR(ctx->ufoe_disp_clk);
+ goto err;
+ }
+
+ ctx->od_disp_clk = devm_clk_get(dev, "od_disp");
+ if (IS_ERR(ctx->od_disp_clk)) {
+ dev_err(dev, "crtc_main_probe: Get od_disp_clk fail.\n");
+ ret = PTR_ERR(ctx->od_disp_clk);
+ goto err;
+ }
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ctx->ovl0_regs = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(ctx->ovl0_regs))
+ return PTR_ERR(ctx->ovl0_regs);
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ ctx->rdma0_regs = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(ctx->rdma0_regs))
+ return PTR_ERR(ctx->rdma0_regs);
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ ctx->color0_regs = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(ctx->color0_regs))
+ return PTR_ERR(ctx->color0_regs);
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ ctx->aal_regs = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(ctx->aal_regs))
+ return PTR_ERR(ctx->aal_regs);
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+ ctx->ufoe_regs = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(ctx->ufoe_regs))
+ return PTR_ERR(ctx->ufoe_regs);
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 5);
+ ctx->od_regs = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(ctx->od_regs))
+ return PTR_ERR(ctx->od_regs);
+
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_request_irq(dev, irq, crtc_main_irq_handler,
+ IRQF_TRIGGER_NONE, dev_name(dev), ctx);
+ if (ret < 0) {
+ dev_err(dev, "devm_request_irq %d fail %d\n", irq, ret);
+ ret = -ENXIO;
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, ctx);
+
+ ret = component_add(&pdev->dev, &crtc_main_component_ops);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ if (node)
+ of_node_put(node);
+
+ return ret;
+}
+
+static int crtc_main_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &crtc_main_component_ops);
+
+ return 0;
+}
+
+static const struct of_device_id crtc_main_driver_dt_match[] = {
+ { .compatible = "mediatek,mt8173-crtc-main" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, crtc_main_driver_dt_match);
+
+struct platform_driver mediatek_crtc_main_driver = {
+ .probe = crtc_main_probe,
+ .remove = crtc_main_remove,
+ .driver = {
+ .name = "mediatek-crtc-main",
+ .owner = THIS_MODULE,
+ .of_match_table = crtc_main_driver_dt_match,
+ },
+};
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_ddp.c b/drivers/gpu/drm/mediatek/mediatek_drm_ddp.c
new file mode 100644
index 0000000..bb6959b
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_ddp.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+#include <linux/component.h>
+
+#include "mediatek_drm_crtc.h"
+#include "mediatek_drm_ddp.h"
+
+
+#define DISP_REG_CONFIG_DISP_OVL0_MOUT_EN 0x040
+#define DISP_REG_CONFIG_DISP_OVL1_MOUT_EN 0x044
+#define DISP_REG_CONFIG_DISP_OD_MOUT_EN 0x048
+#define DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN 0x04C
+#define DISP_REG_CONFIG_DISP_UFOE_MOUT_EN 0x050
+#define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN 0x084
+#define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN 0x088
+#define DISP_REG_CONFIG_DPI_SEL_IN 0x0AC
+#define DISP_REG_CONFIG_DISP_PATH1_SOUT_SEL_IN 0x0C8
+#define DISP_REG_CONFIG_MMSYS_CG_CON0 0x100
+
+#define DISP_REG_CONFIG_MUTEX_EN(n) (0x20 + 0x20 * n)
+#define DISP_REG_CONFIG_MUTEX_MOD(n) (0x2C + 0x20 * n)
+#define DISP_REG_CONFIG_MUTEX_SOF(n) (0x30 + 0x20 * n)
+
+
+enum {
+ MUTEX_MOD_OVL0 = 11,
+ MUTEX_MOD_RDMA0 = 13,
+ MUTEX_MOD_COLOR0 = 18,
+ MUTEX_MOD_AAL = 20,
+ MUTEX_MOD_UFOE = 22,
+ MUTEX_MOD_PWM0 = 23,
+ MUTEX_MOD_OD = 25,
+};
+
+enum {
+ MUTEX_SOF_DSI0 = 1,
+};
+
+enum {
+ OVL0_MOUT_EN_COLOR0 = 0x1,
+};
+
+enum {
+ OD_MOUT_EN_RDMA0 = 0x1,
+};
+
+enum {
+ UFOE_MOUT_EN_DSI0 = 0x1,
+};
+
+enum {
+ COLOR0_SEL_IN_OVL0 = 0x1,
+};
+
+struct ddp_context {
+ struct device *dev;
+ struct drm_device *drm_dev;
+ struct mediatek_drm_crtc *crtc;
+ int pipe;
+
+ struct clk *mutex_disp_clk;
+
+ void __iomem *config_regs;
+ void __iomem *mutex_regs;
+
+ bool pending_ovl_config;
+ bool pending_ovl_enable;
+ unsigned int pending_ovl_addr;
+ unsigned int pending_ovl_width;
+ unsigned int pending_ovl_height;
+ unsigned int pending_ovl_pitch;
+ unsigned int pending_ovl_format;
+};
+
+
+static void disp_config_main_path_connection(void __iomem *disp_base)
+{
+ writel(OVL0_MOUT_EN_COLOR0,
+ disp_base + DISP_REG_CONFIG_DISP_OVL0_MOUT_EN);
+ writel(OD_MOUT_EN_RDMA0, disp_base + DISP_REG_CONFIG_DISP_OD_MOUT_EN);
+ writel(UFOE_MOUT_EN_DSI0,
+ disp_base + DISP_REG_CONFIG_DISP_UFOE_MOUT_EN);
+ writel(COLOR0_SEL_IN_OVL0,
+ disp_base + DISP_REG_CONFIG_DISP_COLOR0_SEL_IN);
+}
+
+static void disp_config_main_path_mutex(void __iomem *mutex_base)
+{
+ unsigned int id = 0;
+
+ writel((1 << MUTEX_MOD_OVL0 | 1 << MUTEX_MOD_RDMA0 |
+ 1 << MUTEX_MOD_COLOR0 | 1 << MUTEX_MOD_AAL |
+ 1 << MUTEX_MOD_UFOE | 1 << MUTEX_MOD_PWM0 |
+ 1 << MUTEX_MOD_OD),
+ mutex_base + DISP_REG_CONFIG_MUTEX_MOD(id));
+
+ writel(MUTEX_SOF_DSI0, mutex_base + DISP_REG_CONFIG_MUTEX_SOF(id));
+ writel(1, mutex_base + DISP_REG_CONFIG_MUTEX_EN(id));
+}
+
+void mediatek_ddp_main_path_setup(struct device *dev)
+{
+ struct ddp_context *ddp = dev_get_drvdata(dev);
+
+ disp_config_main_path_connection(ddp->config_regs);
+ disp_config_main_path_mutex(ddp->mutex_regs);
+}
+
+void mediatek_ddp_clock_on(struct device *dev)
+{
+ struct ddp_context *ddp = dev_get_drvdata(dev);
+ int ret;
+
+ /* disp_mtcmos */
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0)
+ DRM_ERROR("failed to get_sync(%d)\n", ret);
+
+ ret = clk_prepare_enable(ddp->mutex_disp_clk);
+ if (ret != 0)
+ DRM_ERROR("clk_prepare_enable(mutex_disp_clk) error!\n");
+}
+
+static int ddp_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ddp_context *ddp;
+ struct resource *regs;
+ int ret;
+
+ if (!dev->of_node)
+ return -ENODEV;
+
+ ddp = devm_kzalloc(dev, sizeof(*ddp), GFP_KERNEL);
+ if (!ddp)
+ return -ENOMEM;
+
+ ddp->mutex_disp_clk = devm_clk_get(dev, "mutex_disp");
+ if (IS_ERR(ddp->mutex_disp_clk)) {
+ dev_err(dev, "ddp_probe: Get mutex_disp_clk fail.\n");
+ ret = PTR_ERR(ddp->mutex_disp_clk);
+ goto err;
+ }
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ddp->config_regs = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(ddp->config_regs))
+ return PTR_ERR(ddp->config_regs);
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ ddp->mutex_regs = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(ddp->mutex_regs))
+ return PTR_ERR(ddp->mutex_regs);
+
+ platform_set_drvdata(pdev, ddp);
+
+ pm_runtime_enable(dev);
+
+ return 0;
+
+err:
+
+ return ret;
+}
+
+static int ddp_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id ddp_driver_dt_match[] = {
+ { .compatible = "mediatek,mt8173-ddp" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ddp_driver_dt_match);
+
+struct platform_driver mediatek_ddp_driver = {
+ .probe = ddp_probe,
+ .remove = ddp_remove,
+ .driver = {
+ .name = "mediatek-ddp",
+ .owner = THIS_MODULE,
+ .of_match_table = ddp_driver_dt_match,
+ },
+};
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_ddp.h b/drivers/gpu/drm/mediatek/mediatek_drm_ddp.h
new file mode 100644
index 0000000..07dd637
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_ddp.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MEDIATEK_DRM_DDP_H_
+#define _MEDIATEK_DRM_DDP_H_
+
+void mediatek_ddp_main_path_setup(struct device *dev);
+
+void mediatek_ddp_clock_on(struct device *dev);
+
+
+#endif
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.c
new file mode 100644
index 0000000..dd7ac83
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Authors:
+ * YT Shen <yt.shen@mediatek.com>
+ * CK Hu <ck.hu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <linux/clk.h>
+
+
+#define DISP_REG_OVL_INTEN 0x0004
+#define DISP_REG_OVL_INTSTA 0x0008
+#define DISP_REG_OVL_EN 0x000C
+#define DISP_REG_OVL_RST 0x0014
+#define DISP_REG_OVL_ROI_SIZE 0x0020
+#define DISP_REG_OVL_ROI_BGCLR 0x0028
+#define DISP_REG_OVL_SRC_CON 0x002C
+#define DISP_REG_OVL_L0_CON 0x0030
+#define DISP_REG_OVL_L0_SRCKEY 0x0034
+#define DISP_REG_OVL_L0_SRC_SIZE 0x0038
+#define DISP_REG_OVL_L0_OFFSET 0x003C
+#define DISP_REG_OVL_L0_PITCH 0x0044
+#define DISP_REG_OVL_L1_CON 0x0050
+#define DISP_REG_OVL_L1_SRCKEY 0x0054
+#define DISP_REG_OVL_L1_SRC_SIZE 0x0058
+#define DISP_REG_OVL_L1_OFFSET 0x005C
+#define DISP_REG_OVL_L1_PITCH 0x0064
+#define DISP_REG_OVL_RDMA0_CTRL 0x00C0
+#define DISP_REG_OVL_RDMA0_MEM_GMC_SETTING 0x00C8
+#define DISP_REG_OVL_RDMA1_CTRL 0x00E0
+#define DISP_REG_OVL_RDMA1_MEM_GMC_SETTING 0x00E8
+#define DISP_REG_OVL_RDMA1_FIFO_CTRL 0x00F0
+#define DISP_REG_OVL_L0_ADDR 0x0f40
+#define DISP_REG_OVL_L1_ADDR 0x0f60
+
+#define DISP_REG_RDMA_INT_ENABLE 0x0000
+#define DISP_REG_RDMA_INT_STATUS 0x0004
+#define DISP_REG_RDMA_GLOBAL_CON 0x0010
+#define DISP_REG_RDMA_SIZE_CON_0 0x0014
+#define DISP_REG_RDMA_SIZE_CON_1 0x0018
+#define DISP_REG_RDMA_FIFO_CON 0x0040
+
+#define DISP_OD_EN 0x000
+#define DISP_OD_INTEN 0x008
+#define DISP_OD_INTS 0x00C
+#define DISP_OD_CFG 0x020
+#define DISP_OD_SIZE 0x030
+
+#define DISP_REG_UFO_START 0x000
+
+#define DISP_COLOR_CFG_MAIN 0x400
+#define DISP_COLOR_START 0xC00
+
+enum DISPLAY_PATH {
+ PRIMARY_PATH = 0,
+ EXTERNAL_PATH = 1,
+};
+
+enum RDMA_MODE {
+ RDMA_MODE_DIRECT_LINK = 0,
+ RDMA_MODE_MEMORY = 1,
+};
+
+enum RDMA_OUTPUT_FORMAT {
+ RDMA_OUTPUT_FORMAT_ARGB = 0,
+ RDMA_OUTPUT_FORMAT_YUV444 = 1,
+};
+
+#define OVL_COLOR_BASE 30
+enum OVL_INPUT_FORMAT {
+ OVL_INFMT_RGB565 = 0,
+ OVL_INFMT_RGB888 = 1,
+ OVL_INFMT_RGBA8888 = 2,
+ OVL_INFMT_ARGB8888 = 3,
+ OVL_INFMT_UYVY = 4,
+ OVL_INFMT_YUYV = 5,
+ OVL_INFMT_UNKNOWN = 16,
+
+ OVL_INFMT_BGR565 = OVL_INFMT_RGB565 + OVL_COLOR_BASE,
+ OVL_INFMT_BGR888 = OVL_INFMT_RGB888 + OVL_COLOR_BASE,
+ OVL_INFMT_BGRA8888 = OVL_INFMT_RGBA8888 + OVL_COLOR_BASE,
+ OVL_INFMT_ABGR8888 = OVL_INFMT_ARGB8888 + OVL_COLOR_BASE,
+};
+
+enum {
+ OD_RELAY_MODE = 0x1,
+};
+
+enum {
+ UFO_BYPASS = 0x4,
+};
+
+enum {
+ COLOR_BYPASS_ALL = (1UL<<7),
+ COLOR_SEQ_SEL = (1UL<<13),
+};
+
+enum {
+ OVL_LAYER_SRC_DRAM = 0,
+};
+
+
+static void mediatek_ovl_start(void __iomem *ovl_base)
+{
+ writel(0x01, ovl_base + DISP_REG_OVL_EN);
+}
+
+static void mediatek_ovl_roi(void __iomem *ovl_base,
+ unsigned int w, unsigned int h, unsigned int bg_color)
+{
+ writel(h << 16 | w, ovl_base + DISP_REG_OVL_ROI_SIZE);
+ writel(bg_color, ovl_base + DISP_REG_OVL_ROI_BGCLR);
+}
+
+void mediatek_ovl_layer_switch(void __iomem *ovl_base,
+ unsigned layer, bool en)
+{
+ u32 reg;
+
+ reg = readl(ovl_base + DISP_REG_OVL_SRC_CON);
+ if (en)
+ reg |= (1U<<layer);
+ else
+ reg &= ~(1U<<layer);
+
+ writel(reg, ovl_base + DISP_REG_OVL_SRC_CON);
+ writel(0x1, ovl_base + DISP_REG_OVL_RST);
+ writel(0x0, ovl_base + DISP_REG_OVL_RST);
+}
+
+static unsigned int ovl_fmt_convert(unsigned int fmt)
+{
+ switch (fmt) {
+ case DRM_FORMAT_RGB888:
+ return OVL_INFMT_RGB888;
+ case DRM_FORMAT_RGB565:
+ return OVL_INFMT_RGB565;
+ case DRM_FORMAT_ARGB8888:
+ return OVL_INFMT_ARGB8888;
+ case DRM_FORMAT_RGBA8888:
+ return OVL_INFMT_RGBA8888;
+ case DRM_FORMAT_BGR888:
+ return OVL_INFMT_BGR888;
+ case DRM_FORMAT_BGR565:
+ return OVL_INFMT_BGR565;
+ case DRM_FORMAT_ABGR8888:
+ return OVL_INFMT_ABGR8888;
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_BGRA8888:
+ return OVL_INFMT_BGRA8888;
+ case DRM_FORMAT_YUYV:
+ return OVL_INFMT_YUYV;
+ case DRM_FORMAT_UYVY:
+ return OVL_INFMT_UYVY;
+ default:
+ return OVL_INFMT_UNKNOWN;
+ }
+}
+
+void mediatek_ovl_layer_config(void __iomem *ovl_base, bool enabled,
+ unsigned int addr, unsigned int width, unsigned int height,
+ unsigned int pitch, unsigned int format)
+{
+ unsigned int reg;
+ unsigned int dst_x = 0;
+ unsigned int dst_y = 0;
+ bool color_key_en = 1;
+ unsigned int color_key = 0xFF000000;
+ bool alpha_en = 0;
+ unsigned char alpha = 0x0;
+ unsigned int src_con, new_set;
+
+ unsigned int rgb_swap, bpp;
+ unsigned int fmt = ovl_fmt_convert(format);
+
+ if (fmt == OVL_INFMT_BGR888 || fmt == OVL_INFMT_BGR565 ||
+ fmt == OVL_INFMT_ABGR8888 || fmt == OVL_INFMT_BGRA8888) {
+ fmt -= OVL_COLOR_BASE;
+ rgb_swap = 1;
+ } else {
+ rgb_swap = 0;
+ }
+
+ switch (fmt) {
+ case OVL_INFMT_ARGB8888:
+ case OVL_INFMT_RGBA8888:
+ bpp = 4;
+ break;
+ case OVL_INFMT_RGB888:
+ bpp = 3;
+ break;
+ case OVL_INFMT_RGB565:
+ case OVL_INFMT_YUYV:
+ case OVL_INFMT_UYVY:
+ bpp = 2;
+ break;
+ default:
+ bpp = 1;
+ }
+
+ if (pitch == 0)
+ pitch = width * bpp;
+
+ src_con = readl(ovl_base + DISP_REG_OVL_SRC_CON);
+ if (enabled == true)
+ new_set = src_con | 0x1;
+ else
+ new_set = src_con & ~(0x1);
+
+ writel(0x1, ovl_base + DISP_REG_OVL_RST);
+ writel(0x0, ovl_base + DISP_REG_OVL_RST);
+
+ writel(new_set, ovl_base + DISP_REG_OVL_SRC_CON);
+
+ writel(0x00000001, ovl_base + DISP_REG_OVL_RDMA0_CTRL);
+ writel(0x40402020, ovl_base + DISP_REG_OVL_RDMA0_MEM_GMC_SETTING);
+
+ reg = color_key_en << 30 | OVL_LAYER_SRC_DRAM << 28 |
+ rgb_swap << 25 | fmt << 12 | alpha_en << 8 | alpha;
+ writel(reg, ovl_base + DISP_REG_OVL_L0_CON);
+ writel(color_key, ovl_base + DISP_REG_OVL_L0_SRCKEY);
+ writel(height << 16 | width, ovl_base + DISP_REG_OVL_L0_SRC_SIZE);
+ writel(dst_y << 16 | dst_x, ovl_base + DISP_REG_OVL_L0_OFFSET);
+ writel(addr, ovl_base + DISP_REG_OVL_L0_ADDR);
+ writel(pitch & 0xFFFF, ovl_base + DISP_REG_OVL_L0_PITCH);
+}
+
+static void mediatek_rdma_start(void __iomem *rdma_base)
+{
+ unsigned int reg;
+
+ writel(0x4, rdma_base + DISP_REG_RDMA_INT_ENABLE);
+ reg = readl(rdma_base + DISP_REG_RDMA_GLOBAL_CON);
+ reg |= 1;
+ writel(reg, rdma_base + DISP_REG_RDMA_GLOBAL_CON);
+}
+
+static void mediatek_rdma_config_direct_link(void __iomem *rdma_base,
+ unsigned width, unsigned height)
+{
+ unsigned int reg;
+ enum RDMA_MODE mode = RDMA_MODE_DIRECT_LINK;
+ enum RDMA_OUTPUT_FORMAT output_format = RDMA_OUTPUT_FORMAT_ARGB;
+
+ reg = readl(rdma_base + DISP_REG_RDMA_GLOBAL_CON);
+ if (mode == RDMA_MODE_DIRECT_LINK)
+ reg &= ~(0x2U);
+ writel(reg, rdma_base + DISP_REG_RDMA_GLOBAL_CON);
+
+ reg = readl(rdma_base + DISP_REG_RDMA_SIZE_CON_0);
+ if (output_format == RDMA_OUTPUT_FORMAT_ARGB)
+ reg &= ~(0x20000000U);
+ else
+ reg |= 0x20000000U;
+ writel(reg, rdma_base + DISP_REG_RDMA_SIZE_CON_0);
+
+ reg = readl(rdma_base + DISP_REG_RDMA_SIZE_CON_0);
+ reg = (reg & ~(0xFFFU)) | (width & 0xFFFU);
+ writel(reg, rdma_base + DISP_REG_RDMA_SIZE_CON_0);
+
+ reg = readl(rdma_base + DISP_REG_RDMA_SIZE_CON_1);
+ reg = (reg & ~(0xFFFFFU)) | (height & 0xFFFFFU);
+ writel(reg, rdma_base + DISP_REG_RDMA_SIZE_CON_1);
+
+ writel(0x80F00008, rdma_base + DISP_REG_RDMA_FIFO_CON);
+}
+
+void mediatek_od_enable_vblank(void __iomem *disp_base)
+{
+ writel(0x1, disp_base + DISP_OD_INTEN);
+}
+
+void mediatek_od_disable_vblank(void __iomem *disp_base)
+{
+ writel(0x0, disp_base + DISP_OD_INTEN);
+}
+
+void mediatek_od_clear_vblank(void __iomem *disp_base)
+{
+ writel(0x0, disp_base + DISP_OD_INTS);
+}
+
+static void mediatek_od_start(void __iomem *od_base, unsigned int w,
+ unsigned int h)
+{
+ writel(w << 16 | h, od_base + DISP_OD_SIZE);
+ writel(OD_RELAY_MODE, od_base + DISP_OD_CFG);
+ writel(1, od_base + DISP_OD_EN);
+}
+
+static void mediatek_ufoe_start(void __iomem *ufoe_base)
+{
+ writel(UFO_BYPASS, ufoe_base + DISP_REG_UFO_START);
+}
+
+static void mediatek_color_start(void __iomem *color_base)
+{
+ writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL,
+ color_base + DISP_COLOR_CFG_MAIN);
+ writel(0x1, color_base + DISP_COLOR_START);
+}
+
+void main_disp_path_power_on(void __iomem *ovl_base,
+ void __iomem *rdma_base,
+ void __iomem *color_base,
+ void __iomem *ufoe_base,
+ void __iomem *od_base)
+{
+ struct device_node *node;
+ unsigned int width, height;
+ int err;
+
+ node = of_find_compatible_node(NULL, NULL, "mediatek,mt8173-dsi");
+
+ err = of_property_read_u32(node, "mediatek,width", &width);
+ if (err < 0)
+ return;
+
+ err = of_property_read_u32(node, "mediatek,height", &height);
+ if (err < 0)
+ return;
+
+ width = ((width + 3)>>2)<<2;
+
+ mediatek_ovl_start(ovl_base);
+ mediatek_rdma_start(rdma_base);
+
+ mediatek_ovl_roi(ovl_base, width, height, 0x00000000);
+ mediatek_ovl_layer_switch(ovl_base, 0, 1);
+ mediatek_rdma_config_direct_link(rdma_base, width, height);
+ mediatek_od_start(od_base, width, height);
+ mediatek_ufoe_start(ufoe_base);
+ mediatek_color_start(color_base);
+}
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.h b/drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.h
new file mode 100644
index 0000000..d3ed3e1
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MEDIATEK_DRM_DDP_COMP_H_
+#define _MEDIATEK_DRM_DDP_COMP_H_
+
+
+void mediatek_od_enable_vblank(void __iomem *drm_disp_base);
+void mediatek_od_disable_vblank(void __iomem *drm_disp_base);
+void mediatek_od_clear_vblank(void __iomem *drm_disp_base);
+void mediatek_ovl_layer_config(void __iomem *ovl_base, bool enabled,
+ unsigned int addr, unsigned int width, unsigned int height,
+ unsigned int pitch, unsigned int format);
+
+void main_disp_path_power_on(void __iomem *ovl_base,
+ void __iomem *rdma_base, void __iomem *color_base,
+ void __iomem *ufoe_base, void __iomem *od_base);
+
+void mediatek_ovl_layer_switch(void __iomem *ovl_base,
+ unsigned layer, bool en);
+
+#endif
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_drv.c b/drivers/gpu/drm/mediatek/mediatek_drm_drv.c
new file mode 100644
index 0000000..dfd816f
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_drv.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: YT SHEN <yt.shen@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <linux/of_platform.h>
+#include <linux/component.h>
+#include <linux/mtk-smi.h>
+#include <linux/pm_runtime.h>
+#include <linux/dma-iommu.h>
+
+#include "mediatek_drm_drv.h"
+#include "mediatek_drm_crtc.h"
+#include "mediatek_drm_fb.h"
+#include "mediatek_drm_gem.h"
+
+#include "drm/mediatek_drm.h"
+
+#define DRIVER_NAME "mediatek"
+#define DRIVER_DESC "Mediatek SoC DRM"
+#define DRIVER_DATE "20150513"
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+
+static struct drm_mode_config_funcs mediatek_drm_mode_config_funcs = {
+ .fb_create = mtk_drm_mode_fb_create,
+ .output_poll_changed = mtk_drm_mode_output_poll_changed,
+};
+
+static int mtk_drm_kms_init(struct drm_device *dev)
+{
+ struct device_node *node;
+ struct platform_device *pdev;
+ int err;
+
+ drm_mode_config_init(dev);
+
+ dev->mode_config.min_width = 640;
+ dev->mode_config.min_height = 480;
+
+ /*
+ * set max width and height as default value(4096x4096).
+ * this value would be used to check framebuffer size limitation
+ * at drm_mode_addfb().
+ */
+ dev->mode_config.max_width = 4096;
+ dev->mode_config.max_height = 4096;
+ dev->mode_config.funcs = &mediatek_drm_mode_config_funcs;
+
+ err = component_bind_all(dev->dev, dev);
+ if (err)
+ goto err_crtc;
+
+ /*
+ * We don't use the drm_irq_install() helpers provided by the DRM
+ * core, so we need to set this manually in order to allow the
+ * DRM_IOCTL_WAIT_VBLANK to operate correctly.
+ */
+ dev->irq_enabled = true;
+ err = drm_vblank_init(dev, MAX_CRTC);
+ if (err < 0)
+ goto err_crtc;
+
+ drm_kms_helper_poll_init(dev);
+
+ node = of_parse_phandle(dev->dev->of_node, "iommus", 0);
+ if (!node)
+ return 0;
+
+ pdev = of_find_device_by_node(node);
+ if (WARN_ON(!pdev)) {
+ of_node_put(node);
+ return -EINVAL;
+ }
+ err = iommu_dma_attach_device(dev->dev,
+ arch_get_dma_domain(&pdev->dev));
+ if (err)
+ DRM_ERROR("iommu_dma_attach_device fail %d\n", err);
+
+ node = of_parse_phandle(dev->dev->of_node, "larb", 0);
+ if (!node)
+ return 0;
+
+ pdev = of_find_device_by_node(node);
+ if (WARN_ON(!pdev)) {
+ of_node_put(node);
+ return -EINVAL;
+ }
+
+ err = mtk_smi_larb_get(&pdev->dev);
+ if (err)
+ DRM_ERROR("mtk_smi_larb_get fail %d\n", err);
+
+ node = of_parse_phandle(dev->dev->of_node, "larb", 1);
+ if (!node)
+ return 0;
+
+ pdev = of_find_device_by_node(node);
+ if (WARN_ON(!pdev)) {
+ of_node_put(node);
+ return -EINVAL;
+ }
+
+ err = mtk_smi_larb_get(&pdev->dev);
+ if (err)
+ DRM_ERROR("mtk_smi_larb_get fail %d\n", err);
+
+ mtk_fbdev_create(dev);
+
+ return 0;
+err_crtc:
+ drm_mode_config_cleanup(dev);
+
+ return err;
+}
+
+static int mtk_drm_load(struct drm_device *dev, unsigned long flags)
+{
+ struct mtk_drm_private *priv;
+
+ priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev->dev_private = priv;
+ platform_set_drvdata(dev->platformdev, dev);
+
+ return mtk_drm_kms_init(dev);
+}
+
+static void mtk_drm_kms_deinit(struct drm_device *dev)
+{
+ drm_kms_helper_poll_fini(dev);
+
+ mtk_fbdev_destroy(dev);
+
+ drm_vblank_cleanup(dev);
+ drm_mode_config_cleanup(dev);
+
+ pm_runtime_disable(dev->dev);
+}
+
+static int mtk_drm_unload(struct drm_device *dev)
+{
+ mtk_drm_kms_deinit(dev);
+ dev->dev_private = NULL;
+
+ return 0;
+}
+
+static int mtk_drm_open(struct drm_device *drm, struct drm_file *filp)
+{
+ return 0;
+}
+
+static void mediatek_drm_preclose(struct drm_device *drm, struct drm_file *file)
+{
+}
+
+static void mediatek_drm_lastclose(struct drm_device *drm)
+{
+}
+
+static const struct vm_operations_struct mediatek_drm_gem_vm_ops = {
+ .open = drm_gem_vm_open,
+ .close = drm_gem_vm_close,
+};
+
+static const struct drm_ioctl_desc mtk_ioctls[] = {
+ DRM_IOCTL_DEF_DRV(MTK_GEM_CREATE, mediatek_gem_create_ioctl,
+ DRM_UNLOCKED | DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(MTK_GEM_MAP_OFFSET,
+ mediatek_gem_map_offset_ioctl,
+ DRM_UNLOCKED | DRM_AUTH),
+};
+
+static const struct file_operations mediatek_drm_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+ .mmap = mtk_drm_gem_mmap,
+ .poll = drm_poll,
+ .read = drm_read,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
+};
+
+static struct drm_driver mediatek_drm_driver = {
+ .driver_features = DRIVER_MODESET | DRIVER_GEM,
+ .load = mtk_drm_load,
+ .unload = mtk_drm_unload,
+ .open = mtk_drm_open,
+ .preclose = mediatek_drm_preclose,
+ .lastclose = mediatek_drm_lastclose,
+ .set_busid = drm_platform_set_busid,
+
+ .get_vblank_counter = drm_vblank_count,
+ .enable_vblank = mtk_drm_crtc_enable_vblank,
+ .disable_vblank = mtk_drm_crtc_disable_vblank,
+
+ .gem_free_object = mtk_drm_gem_free_object,
+ .gem_vm_ops = &mediatek_drm_gem_vm_ops,
+ .dumb_create = mtk_drm_gem_dumb_create,
+ .dumb_map_offset = mtk_drm_gem_dumb_map_offset,
+ .dumb_destroy = drm_gem_dumb_destroy,
+
+ .num_ioctls = 0,
+ .fops = &mediatek_drm_fops,
+
+ .set_busid = drm_platform_set_busid,
+
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+static int mtk_drm_add_components(struct device *master, struct master *m)
+{
+ struct device_node *np = master->of_node;
+ unsigned i;
+ int ret;
+
+ for (i = 0; ; i++) {
+ struct device_node *node;
+
+ node = of_parse_phandle(np, "connectors", i);
+ if (!node)
+ break;
+
+ ret = component_master_add_child(m, compare_of, node);
+ of_node_put(node);
+ if (ret) {
+ dev_err(master, "component_master_add_child %s fail.\n",
+ node->full_name);
+ return ret;
+ }
+ }
+
+ for (i = 0; ; i++) {
+ struct device_node *node;
+
+ node = of_parse_phandle(np, "crtcs", i);
+ if (!node)
+ break;
+
+ ret = component_master_add_child(m, compare_of, node);
+ of_node_put(node);
+ if (ret) {
+ dev_err(master, "component_master_add_child %s fail.\n",
+ node->full_name);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int mtk_drm_bind(struct device *dev)
+{
+ return drm_platform_init(&mediatek_drm_driver, to_platform_device(dev));
+}
+
+static void mtk_drm_unbind(struct device *dev)
+{
+ drm_put_dev(platform_get_drvdata(to_platform_device(dev)));
+}
+
+static const struct component_master_ops mtk_drm_ops = {
+ .add_components = mtk_drm_add_components,
+ .bind = mtk_drm_bind,
+ .unbind = mtk_drm_unbind,
+};
+
+static int mtk_drm_probe(struct platform_device *pdev)
+{
+ component_master_add(&pdev->dev, &mtk_drm_ops);
+
+ return 0;
+}
+
+static int mtk_drm_remove(struct platform_device *pdev)
+{
+ drm_put_dev(platform_get_drvdata(pdev));
+
+ return 0;
+}
+
+static const struct of_device_id mediatek_drm_of_ids[] = {
+ { .compatible = "mediatek,mt8173-drm", },
+ { }
+};
+
+static struct platform_driver mediatek_drm_platform_driver = {
+ .probe = mtk_drm_probe,
+ .remove = mtk_drm_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mediatek-drm",
+ .of_match_table = mediatek_drm_of_ids,
+ /*.pm = &mtk_pm_ops, */
+ },
+ /* .id_table = mtk_drm_platform_ids, */
+};
+
+static int mediatek_drm_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&mediatek_ddp_driver);
+ if (err < 0) {
+ DRM_DEBUG_DRIVER("register ddp driver fail.\n");
+ return err;
+ }
+
+ err = platform_driver_register(&mtk_dsi_driver);
+ if (err < 0) {
+ DRM_DEBUG_DRIVER("register dsi driver fail.\n");
+ return err;
+ }
+
+ err = platform_driver_register(&mediatek_crtc_main_driver);
+ if (err < 0) {
+ DRM_DEBUG_DRIVER("register crtc_main driver fail.\n");
+ return err;
+ }
+
+ err = platform_driver_register(&mediatek_drm_platform_driver);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static void mediatek_drm_exit(void)
+{
+ platform_driver_unregister(&mediatek_drm_platform_driver);
+ platform_driver_unregister(&mtk_dsi_driver);
+}
+
+late_initcall(mediatek_drm_init);
+module_exit(mediatek_drm_exit);
+
+MODULE_AUTHOR("YT SHEN <yt.shen@mediatek.com>");
+MODULE_DESCRIPTION("Mediatek SoC DRM driver");
+MODULE_LICENSE("GPL");
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_drv.h b/drivers/gpu/drm/mediatek/mediatek_drm_drv.h
new file mode 100644
index 0000000..10ee4c4
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_drv.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MEDIATEK_DRM_DRV_H_
+#define _MEDIATEK_DRM_DRV_H_
+
+#define MAX_CRTC 2
+#define MAX_PLANE 4
+
+extern struct platform_driver mediatek_ddp_driver;
+extern struct platform_driver mtk_dsi_driver;
+extern struct platform_driver mediatek_crtc_main_driver;
+
+struct mtk_drm_private {
+ struct drm_fb_helper *fb_helper;
+
+ /*
+ * created crtc object would be contained at this array and
+ * this array is used to be aware of which crtc did it request vblank.
+ */
+ struct drm_crtc *crtc[MAX_CRTC];
+ unsigned int pipe;
+};
+
+
+#endif
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_dsi.c b/drivers/gpu/drm/mediatek/mediatek_drm_dsi.c
new file mode 100644
index 0000000..199ff9d
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_dsi.c
@@ -0,0 +1,1333 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_crtc_helper.h>
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_graph.h>
+#include <linux/component.h>
+
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <video/mipi_display.h>
+#include <video/videomode.h>
+
+#include "mediatek_drm_drv.h"
+#include "mediatek_drm_crtc.h"
+
+#include "mediatek_drm_ddp.h"
+
+#include "mediatek_drm_gem.h"
+#include "mediatek_drm_dsi.h"
+
+
+#define DSI_VIDEO_FIFO_DEPTH (1920 / 4)
+#define DSI_HOST_FIFO_DEPTH 64
+
+
+#define DSI_START 0x00
+
+#define DSI_CON_CTRL 0x10
+ #define DSI_RESET (1)
+
+#define DSI_MODE_CTRL 0x14
+ #define MODE 2
+ #define CMD_MODE 0
+ #define SYNC_PULSE_MODE 1
+ #define SYNC_EVENT_MODE 2
+ #define BURST_MODE 3
+ #define FRM_MODE (1<<16)
+ #define MIX_MODE (1<<17)
+
+#define DSI_TXRX_CTRL 0x18
+ #define VC_NUM (2<<0)
+ #define LANE_NUM (0xf<<2)
+ #define DIS_EOT (1<<6)
+ #define NULL_EN (1<<7)
+ #define TE_FREERUN (1<<8)
+ #define EXT_TE_EN (1<<9)
+ #define EXT_TE_EDGE (1<<10)
+ #define MAX_RTN_SIZE (0xf<<12)
+ #define HSTX_CKLP_EN (1<<16)
+
+#define DSI_PSCTRL 0x1c
+ #define DSI_PS_WC 0x3fff
+ #define DSI_PS_SEL (2<<16)
+ #define PACKED_PS_16BIT_RGB565 (0<<16)
+ #define LOOSELY_PS_18BIT_RGB666 (1<<16)
+ #define PACKED_PS_18BIT_RGB666 (2<<16)
+ #define PACKED_PS_24BIT_RGB888 (3<<16)
+
+#define DSI_VSA_NL 0x20
+#define DSI_VBP_NL 0x24
+#define DSI_VFP_NL 0x28
+
+#define DSI_VACT_NL 0x2C
+
+#define DSI_HSA_WC 0x50
+#define DSI_HBP_WC 0x54
+#define DSI_HFP_WC 0x58
+
+#define DSI_HSTX_CKL_WC 0x64
+
+#define DSI_PHY_LCCON 0x104
+ #define LC_HS_TX_EN (1)
+ #define LC_ULPM_EN (1<<1)
+ #define LC_WAKEUP_EN (1<<2)
+
+#define DSI_PHY_LD0CON 0x108
+ #define LD0_HS_TX_EN (1)
+ #define LD0_ULPM_EN (1<<1)
+ #define LD0_WAKEUP_EN (1<<2)
+
+#define DSI_PHY_TIMECON0 0x0110
+ #define LPX (0xff<<0)
+ #define HS_PRPR (0xff<<8)
+ #define HS_ZERO (0xff<<16)
+ #define HS_TRAIL (0xff<<24)
+
+#define DSI_PHY_TIMECON1 0x0114
+ #define TA_GO (0xff<<0)
+ #define TA_SURE (0xff<<8)
+ #define TA_GET (0xff<<16)
+ #define DA_HS_EXIT (0xff<<24)
+
+#define DSI_PHY_TIMECON2 0x0118
+ #define CONT_DET (0xff<<0)
+ #define CLK_ZERO (0xff<<16)
+ #define CLK_TRAIL (0xff<<24)
+
+#define DSI_PHY_TIMECON3 0x011c
+ #define CLK_HS_PRPR (0xff<<0)
+ #define CLK_HS_POST (0xff<<8)
+ #define CLK_HS_EXIT (0xff<<16)
+
+#define MIPITX_DSI0_CON 0x00
+ #define RG_DSI0_LDOCORE_EN (1)
+ #define RG_DSI0_CKG_LDOOUT_EN (1<<1)
+ #define RG_DSI0_BCLK_SEL (3<<2)
+ #define RG_DSI0_LD_IDX_SEL (7<<4)
+ #define RG_DSI0_PHYCLK_SEL (2<<8)
+ #define RG_DSI0_DSICLK_FREQ_SEL (1<<10)
+ #define RG_DSI0_LPTX_CLMP_EN (1<<11)
+
+#define MIPITX_DSI0_CLOCK_LANE 0x04
+ #define RG_DSI0_LNTC_LDOOUT_EN (1)
+ #define RG_DSI0_LNTC_CKLANE_EN (1<<1)
+ #define RG_DSI0_LNTC_LPTX_IPLUS1 (1<<2)
+ #define RG_DSI0_LNTC_LPTX_IPLUS2 (1<<3)
+ #define RG_DSI0_LNTC_LPTX_IMINUS (1<<4)
+ #define RG_DSI0_LNTC_LPCD_IPLUS (1<<5)
+ #define RG_DSI0_LNTC_LPCD_IMLUS (1<<6)
+ #define RG_DSI0_LNTC_RT_CODE (0xf<<8)
+
+#define MIPITX_DSI0_DATA_LANE0 0x08
+ #define RG_DSI0_LNT0_LDOOUT_EN (1)
+ #define RG_DSI0_LNT0_CKLANE_EN (1<<1)
+ #define RG_DSI0_LNT0_LPTX_IPLUS1 (1<<2)
+ #define RG_DSI0_LNT0_LPTX_IPLUS2 (1<<3)
+ #define RG_DSI0_LNT0_LPTX_IMINUS (1<<4)
+ #define RG_DSI0_LNT0_LPCD_IPLUS (1<<5)
+ #define RG_DSI0_LNT0_LPCD_IMINUS (1<<6)
+ #define RG_DSI0_LNT0_RT_CODE (0xf<<8)
+
+#define MIPITX_DSI0_DATA_LANE1 0x0c
+ #define RG_DSI0_LNT1_LDOOUT_EN (1)
+ #define RG_DSI0_LNT1_CKLANE_EN (1<<1)
+ #define RG_DSI0_LNT1_LPTX_IPLUS1 (1<<2)
+ #define RG_DSI0_LNT1_LPTX_IPLUS2 (1<<3)
+ #define RG_DSI0_LNT1_LPTX_IMINUS (1<<4)
+ #define RG_DSI0_LNT1_LPCD_IPLUS (1<<5)
+ #define RG_DSI0_LNT1_LPCD_IMINUS (1<<6)
+ #define RG_DSI0_LNT1_RT_CODE (0xf<<8)
+
+#define MIPITX_DSI0_DATA_LANE2 0x10
+ #define RG_DSI0_LNT2_LDOOUT_EN (1)
+ #define RG_DSI0_LNT2_CKLANE_EN (1<<1)
+ #define RG_DSI0_LNT2_LPTX_IPLUS1 (1<<2)
+ #define RG_DSI0_LNT2_LPTX_IPLUS2 (1<<3)
+ #define RG_DSI0_LNT2_LPTX_IMINUS (1<<4)
+ #define RG_DSI0_LNT2_LPCD_IPLUS (1<<5)
+ #define RG_DSI0_LNT2_LPCD_IMINUS (1<<6)
+ #define RG_DSI0_LNT2_RT_CODE (0xf<<8)
+
+#define MIPITX_DSI0_DATA_LANE3 0x14
+ #define RG_DSI0_LNT3_LDOOUT_EN (1)
+ #define RG_DSI0_LNT3_CKLANE_EN (1<<1)
+ #define RG_DSI0_LNT3_LPTX_IPLUS1 (1<<2)
+ #define RG_DSI0_LNT3_LPTX_IPLUS2 (1<<3)
+ #define RG_DSI0_LNT3_LPTX_IMINUS (1<<4)
+ #define RG_DSI0_LNT3_LPCD_IPLUS (1<<5)
+ #define RG_DSI0_LNT3_LPCD_IMINUS (1<<6)
+ #define RG_DSI0_LNT3_RT_CODE (0xf<<8)
+
+#define MIPITX_DSI_TOP_CON 0x40
+ #define RG_DSI_LNT_INTR_EN (1)
+ #define RG_DSI_LNT_HS_BIAS_EN (1<<1)
+ #define RG_DSI_LNT_IMP_CAL_EN (1<<2)
+ #define RG_DSI_LNT_TESTMODE_EN (1<<3)
+ #define RG_DSI_LNT_IMP_CAL_CODE (0xf<<4)
+ #define RG_DSI_LNT_AIO_SEL (7<<8)
+ #define RG_DSI_PAD_TIE_LOW_EN (1<<11)
+ #define RG_DSI_DEBUG_INPUT_EN (1<<12)
+ #define RG_DSI_PRESERVE (7<<13)
+
+#define MIPITX_DSI_BG_CON 0x44
+ #define RG_DSI_BG_CORE_EN 1
+ #define RG_DSI_BG_CKEN (1<<1)
+ #define RG_DSI_BG_DIV (0x3<<2)
+ #define RG_DSI_BG_FAST_CHARGE (1<<4)
+ #define RG_DSI_V12_SEL (7<<5)
+ #define RG_DSI_V10_SEL (7<<8)
+ #define RG_DSI_V072_SEL (7<<11)
+ #define RG_DSI_V04_SEL (7<<14)
+ #define RG_DSI_V032_SEL (7<<17)
+ #define RG_DSI_V02_SEL (7<<20)
+ #define rsv_23 (1<<)
+ #define RG_DSI_BG_R1_TRIM (0xf<<24)
+ #define RG_DSI_BG_R2_TRIM (0xf<<28)
+
+#define MIPITX_DSI_PLL_CON0 0x50
+ #define RG_DSI0_MPPLL_PLL_EN (1<<0)
+ #define RG_DSI0_MPPLL_PREDIV (3<<1)
+ #define RG_DSI0_MPPLL_TXDIV0 (3<<3)
+ #define RG_DSI0_MPPLL_TXDIV1 (3<<5)
+ #define RG_DSI0_MPPLL_POSDIV (7<<7)
+ #define RG_DSI0_MPPLL_MONVC_EN (1<<10)
+ #define RG_DSI0_MPPLL_MONREF_EN (1<<11)
+ #define RG_DSI0_MPPLL_VOD_EN (1<<12)
+
+#define MIPITX_DSI_PLL_CON1 0x54
+ #define RG_DSI0_MPPLL_SDM_FRA_EN (1)
+ #define RG_DSI0_MPPLL_SDM_SSC_PH_INIT (1<<1)
+ #define RG_DSI0_MPPLL_SDM_SSC_EN (1<<2)
+ #define RG_DSI0_MPPLL_SDM_SSC_PRD (0xffff<<16)
+
+#define MIPITX_DSI_PLL_CON2 0x58
+
+#define MIPITX_DSI_PLL_PWR 0x68
+ #define RG_DSI_MPPLL_SDM_PWR_ON (1<<0)
+ #define RG_DSI_MPPLL_SDM_ISO_EN (1<<1)
+ #define RG_DSI_MPPLL_SDM_PWR_ACK (1<<8)
+
+#define MIPITX_DSI_SW_CTRL 0x80
+ #define SW_CTRL_EN (1<<0)
+
+#define MIPITX_DSI_SW_CTRL_CON0 0x84
+ #define SW_LNTC_LPTX_PRE_OE (1<<0)
+ #define SW_LNTC_LPTX_OE (1<<1)
+ #define SW_LNTC_LPTX_P (1<<2)
+ #define SW_LNTC_LPTX_N (1<<3)
+ #define SW_LNTC_HSTX_PRE_OE (1<<4)
+ #define SW_LNTC_HSTX_OE (1<<5)
+ #define SW_LNTC_HSTX_ZEROCLK (1<<6)
+ #define SW_LNT0_LPTX_PRE_OE (1<<7)
+ #define SW_LNT0_LPTX_OE (1<<8)
+ #define SW_LNT0_LPTX_P (1<<9)
+ #define SW_LNT0_LPTX_N (1<<10)
+ #define SW_LNT0_HSTX_PRE_OE (1<<11)
+ #define SW_LNT0_HSTX_OE (1<<12)
+ #define SW_LNT0_LPRX_EN (1<<13)
+ #define SW_LNT1_LPTX_PRE_OE (1<<14)
+ #define SW_LNT1_LPTX_OE (1<<15)
+ #define SW_LNT1_LPTX_P (1<<16)
+ #define SW_LNT1_LPTX_N (1<<17)
+ #define SW_LNT1_HSTX_PRE_OE (1<<18)
+ #define SW_LNT1_HSTX_OE (1<<19)
+ #define SW_LNT2_LPTX_PRE_OE (1<<20)
+ #define SW_LNT2_LPTX_OE (1<<21)
+ #define SW_LNT2_LPTX_P (1<<22)
+ #define SW_LNT2_LPTX_N (1<<23)
+ #define SW_LNT2_HSTX_PRE_OE (1<<24)
+ #define SW_LNT2_HSTX_OE (1<<25)
+
+#define NS_TO_CYCLE(n, c) ((n) / c + (((n) % c) ? 1 : 0))
+
+
+static inline unsigned long mtk_dsi_readl(struct mtk_dsi *dsi,
+ unsigned long reg)
+{
+ return readl(dsi->dsi_reg_base + (reg << 2));
+}
+
+static inline void mtk_dsi_writel(struct mtk_dsi *dsi, unsigned long value,
+ unsigned long reg)
+{
+ writel(value, dsi->dsi_reg_base + (reg << 2));
+}
+
+static int mtk_dsi_of_read_u32(const struct device_node *np,
+ const char *propname, u32 *out_value)
+{
+ int ret = of_property_read_u32(np, propname, out_value);
+
+ if (ret < 0)
+ DRM_ERROR("%s: failed to get '%s' property\n", np->full_name,
+ propname);
+
+ return ret;
+}
+
+static void dsi_phy_clk_switch_off(struct mtk_dsi *dsi)
+{
+ u32 tmp_reg;
+
+ tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_SW_CTRL_CON0);
+
+ tmp_reg = tmp_reg | (SW_LNTC_LPTX_PRE_OE | SW_LNTC_LPTX_OE |
+ SW_LNTC_HSTX_PRE_OE | SW_LNTC_HSTX_OE |
+ SW_LNT0_LPTX_PRE_OE | SW_LNT0_LPTX_OE |
+ SW_LNT0_HSTX_PRE_OE | SW_LNT0_HSTX_OE |
+ SW_LNT1_LPTX_PRE_OE | SW_LNT1_LPTX_OE |
+ SW_LNT1_HSTX_PRE_OE | SW_LNT1_HSTX_OE |
+ SW_LNT2_LPTX_PRE_OE | SW_LNT2_LPTX_OE |
+ SW_LNT2_HSTX_PRE_OE | SW_LNT2_HSTX_OE);
+ writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI_SW_CTRL_CON0);
+
+
+
+ tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_SW_CTRL);
+ tmp_reg = (tmp_reg | SW_CTRL_EN);
+ writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI_SW_CTRL);
+
+
+ tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+ tmp_reg = (tmp_reg & (~RG_DSI0_MPPLL_PLL_EN));
+ writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+
+
+ udelay(100);
+
+ tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_TOP_CON);
+ tmp_reg = (tmp_reg & (~(RG_DSI_LNT_HS_BIAS_EN |
+ RG_DSI_LNT_IMP_CAL_EN |
+ RG_DSI_LNT_TESTMODE_EN)));
+ writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI_TOP_CON);
+
+ tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_CLOCK_LANE);
+ tmp_reg = tmp_reg & (~RG_DSI0_LNTC_LDOOUT_EN);
+ writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_CLOCK_LANE);
+
+ tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE0);
+ tmp_reg = tmp_reg & (~RG_DSI0_LNT0_LDOOUT_EN);
+ writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE0);
+
+ tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE1);
+ tmp_reg = tmp_reg & (~RG_DSI0_LNT1_LDOOUT_EN);
+ writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE1);
+
+ tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE2);
+ tmp_reg = tmp_reg & (~RG_DSI0_LNT2_LDOOUT_EN);
+ writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE2);
+
+ tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE3);
+ tmp_reg = tmp_reg & (~RG_DSI0_LNT3_LDOOUT_EN);
+ writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE3);
+
+
+ udelay(100);
+
+ tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_CON);
+ tmp_reg = tmp_reg & (~(RG_DSI0_CKG_LDOOUT_EN |
+ RG_DSI0_LDOCORE_EN));
+ writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_CON);
+
+ tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_BG_CON);
+ tmp_reg = tmp_reg & (~(RG_DSI_BG_CKEN | RG_DSI_BG_CORE_EN));
+ writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI_BG_CON);
+
+
+ udelay(100);
+
+ tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+ tmp_reg = (tmp_reg & (~RG_DSI0_MPPLL_PLL_EN));
+ writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+}
+
+static void dsi_phy_clk_setting(struct mtk_dsi *dsi)
+{
+ unsigned int data_Rate = dsi->pll_clk_rate * 2;
+ unsigned int txdiv = 0;
+ unsigned int txdiv0 = 0;
+ unsigned int txdiv1 = 0;
+ unsigned int pcw = 0;
+ u32 reg;
+ u32 temp;
+
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_BG_CON);
+ reg = (reg & (~RG_DSI_V032_SEL)) | (4<<17);
+ reg = (reg & (~RG_DSI_V04_SEL)) | (4<<14);
+ reg = (reg & (~RG_DSI_V072_SEL)) | (4<<11);
+ reg = (reg & (~RG_DSI_V10_SEL)) | (4<<8);
+ reg = (reg & (~RG_DSI_V12_SEL)) | (4<<5);
+ reg = (reg & (~RG_DSI_BG_CKEN)) | (1<<1);
+ reg = (reg & (~RG_DSI_BG_CORE_EN)) | (1);
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_BG_CON);
+
+ udelay(1000);
+
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_TOP_CON);
+ reg = (reg & (~RG_DSI_LNT_IMP_CAL_CODE)) | (8<<4);
+ reg = (reg & (~RG_DSI_LNT_HS_BIAS_EN)) | (1<<1);
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_TOP_CON);
+
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_CON);
+ reg = (reg & (~RG_DSI0_CKG_LDOOUT_EN)) | (1<<1);
+ reg = (reg & (~RG_DSI0_LDOCORE_EN)) | (1);
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_CON);
+
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_PWR);
+ reg = (reg & (~RG_DSI_MPPLL_SDM_PWR_ON)) | (1<<0);
+ reg = (reg & (~RG_DSI_MPPLL_SDM_ISO_EN));
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_PWR);
+
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+ reg = (reg & (~RG_DSI0_MPPLL_PLL_EN));
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+
+ udelay(1000);
+
+ if (data_Rate > 1250) {
+ txdiv = 1;
+ txdiv0 = 0;
+ txdiv1 = 0;
+ } else if (data_Rate >= 500) {
+ txdiv = 1;
+ txdiv0 = 0;
+ txdiv1 = 0;
+ } else if (data_Rate >= 250) {
+ txdiv = 2;
+ txdiv0 = 1;
+ txdiv1 = 0;
+ } else if (data_Rate >= 125) {
+ txdiv = 4;
+ txdiv0 = 2;
+ txdiv1 = 0;
+ } else if (data_Rate > 62) {
+ txdiv = 8;
+ txdiv0 = 2;
+ txdiv1 = 1;
+ } else if (data_Rate >= 50) {
+ txdiv = 16;
+ txdiv0 = 2;
+ txdiv1 = 2;
+ } else {
+ }
+
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+
+ switch (txdiv) {
+ case 1:
+ reg = (reg & (~RG_DSI0_MPPLL_TXDIV0)) | (0<<3);
+ reg = (reg & (~RG_DSI0_MPPLL_TXDIV1)) | (0<<5);
+
+ break;
+ case 2:
+ reg = (reg & (~RG_DSI0_MPPLL_TXDIV0)) | (1<<3);
+ reg = (reg & (~RG_DSI0_MPPLL_TXDIV1)) | (0<<5);
+ break;
+ case 4:
+ reg = (reg & (~RG_DSI0_MPPLL_TXDIV0)) | (2<<3);
+ reg = (reg & (~RG_DSI0_MPPLL_TXDIV1)) | (0<<5);
+ break;
+ case 8:
+ reg = (reg & (~RG_DSI0_MPPLL_TXDIV0)) | (2<<3);
+ reg = (reg & (~RG_DSI0_MPPLL_TXDIV1)) | (1<<5);
+ break;
+ case 16:
+ reg = (reg & (~RG_DSI0_MPPLL_TXDIV0)) | (2<<3);
+ reg = (reg & (~RG_DSI0_MPPLL_TXDIV1)) | (2<<5);
+ break;
+
+ default:
+ break;
+ }
+ reg = (reg & (~RG_DSI0_MPPLL_PREDIV));
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+
+ pcw = data_Rate * txdiv / 13;
+ temp = data_Rate * txdiv % 13;
+ reg = ((pcw & 0x7f)<<24) + (((256 * temp / 13) & 0xff)<<16)
+ + (((256 * (256 * temp % 13)/13) & 0xff)<<8)
+ + ((256 * (256 * (256 * temp % 13) % 13) / 13) & 0xff);
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON2);
+
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON1);
+ reg = (reg & (~RG_DSI0_MPPLL_SDM_FRA_EN)) | (1<<0);
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON1);
+
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_CLOCK_LANE);
+ reg = (reg & (~RG_DSI0_LNTC_LDOOUT_EN)) | (1<<0);
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_CLOCK_LANE);
+
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE0);
+ reg = (reg & (~RG_DSI0_LNT0_LDOOUT_EN)) | (1<<0);
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE0);
+
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE1);
+ reg = (reg & (~RG_DSI0_LNT1_LDOOUT_EN)) | (1<<0);
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE1);
+
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE2);
+ reg = (reg & (~RG_DSI0_LNT2_LDOOUT_EN)) | (1<<0);
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE2);
+
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE3);
+ reg = (reg & (~RG_DSI0_LNT3_LDOOUT_EN)) | (1<<0);
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE3);
+
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+ reg = (reg & (~RG_DSI0_MPPLL_PLL_EN)) | (1<<0);
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+
+ udelay(1000);
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON1);
+ reg = (reg & (~RG_DSI0_MPPLL_SDM_SSC_EN));
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON1);
+
+ reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_TOP_CON);
+ reg = (reg & (~RG_DSI_PAD_TIE_LOW_EN));
+ writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_TOP_CON);
+}
+
+static void dsi_phy_timconfig(struct mtk_dsi *dsi)
+{
+ u32 timcon0 = 0;
+ u32 timcon1 = 0;
+ u32 timcon2 = 0;
+ u32 timcon3 = 0;
+ unsigned int lane_no = dsi->lanes;
+ unsigned int cycle_time;
+ unsigned int ui;
+ unsigned int hs_trail_m, hs_trail_n;
+
+ ui = 1000/(250 * 2) + 0x01;
+ cycle_time = 8000/(250 * 2) + 0x01;
+
+ hs_trail_m = lane_no;
+ hs_trail_n = NS_TO_CYCLE(((lane_no * 4 * ui) + 60), cycle_time);
+
+ timcon0 = (timcon0 & (~HS_TRAIL)) | (8<<24);
+ timcon0 = (timcon0 & (~HS_PRPR)) | 0x6<<8;
+
+ if ((timcon0 & HS_PRPR) == 0)
+ timcon0 = (timcon0 & (~HS_PRPR)) | 1<<8;
+
+ timcon0 = (timcon0 & (~HS_ZERO)) | 0xA<<16;
+ timcon0 = (timcon0 & (~LPX)) | 5;
+
+ if ((timcon0 & LPX) == 0)
+ timcon0 = (timcon0 & (~LPX)) | 1;
+
+ timcon1 = (timcon1 & (~TA_GET)) | (5 * (timcon0 & LPX)<<16);
+ timcon1 = (timcon1 & (~TA_SURE)) | ((3 * (timcon0 & LPX) / 2) << 8);
+ timcon1 = (timcon1 & (~TA_GO)) | (4 * (timcon0 & LPX));
+ timcon1 = (timcon1 & (~DA_HS_EXIT)) | (7<<24);
+ timcon2 = (timcon2 & (~CLK_TRAIL)) | ((NS_TO_CYCLE(0x64, cycle_time) +
+ 0x0a)<<24);
+
+ if (((timcon2 & CLK_TRAIL)>>24) < 2)
+ timcon2 = (timcon2 & (~CLK_TRAIL)) | (2<<24);
+
+ timcon2 = (timcon2 & (~CONT_DET));
+ timcon3 = (timcon3 & (~CLK_HS_PRPR)) | NS_TO_CYCLE(0x40, cycle_time);
+ if ((timcon3 & CLK_HS_PRPR) == 0)
+ timcon3 = (timcon3 & (~CLK_HS_PRPR)) | 1;
+
+ timcon2 = (timcon2 & (~CLK_ZERO)) |
+ (NS_TO_CYCLE(0x190 - (timcon3 & CLK_HS_PRPR) * cycle_time,
+ cycle_time)<<16);
+
+ timcon3 = (timcon3 & (~CLK_HS_EXIT)) | ((2 * (timcon0 & LPX))<<16);
+ timcon3 = (timcon3 & (~CLK_HS_POST)) | (NS_TO_CYCLE((80 + 52 * ui),
+ cycle_time)<<8);
+
+ writel(timcon0, dsi->dsi_reg_base + DSI_PHY_TIMECON0);
+ writel(timcon1, dsi->dsi_reg_base + DSI_PHY_TIMECON1);
+ writel(timcon2, dsi->dsi_reg_base + DSI_PHY_TIMECON2);
+ writel(timcon3, dsi->dsi_reg_base + DSI_PHY_TIMECON3);
+}
+
+static void mtk_dsi_reset(struct mtk_dsi *dsi)
+{
+ writel(3, dsi->dsi_reg_base + DSI_CON_CTRL);
+ writel(2, dsi->dsi_reg_base + DSI_CON_CTRL);
+}
+
+static int mtk_dsi_poweron(struct mtk_dsi *dsi)
+{
+ int ret;
+ struct drm_device *dev = dsi->drm_dev;
+
+ dsi_phy_clk_setting(dsi);
+
+ ret = clk_prepare_enable(dsi->dsi0_engine_clk_cg);
+ if (ret < 0) {
+ dev_err(dev->dev, "can't enable dsi0_engine_clk_cg %d\n", ret);
+ goto err_dsi0_engine_clk_cg;
+ }
+
+ ret = clk_prepare_enable(dsi->dsi0_digital_clk_cg);
+ if (ret < 0) {
+ dev_err(dev->dev, "can't enable dsi0_digital_clk_cg %d\n", ret);
+ goto err_dsi0_digital_clk_cg;
+ }
+
+ mtk_dsi_reset((dsi));
+ dsi_phy_timconfig(dsi);
+
+ return 0;
+
+err_dsi0_digital_clk_cg:
+ clk_disable_unprepare(dsi->dsi0_engine_clk_cg);
+
+err_dsi0_engine_clk_cg:
+
+ return ret;
+}
+
+static void dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi)
+{
+ u32 tmp_reg1;
+
+ tmp_reg1 = readl(dsi->dsi_reg_base + DSI_PHY_LCCON);
+ tmp_reg1 = tmp_reg1 & (~LC_HS_TX_EN);
+ writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LCCON);
+ udelay(100);
+ tmp_reg1 = tmp_reg1 & (~LC_ULPM_EN);
+ writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LCCON);
+ udelay(100);
+}
+
+static void dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi)
+{
+ u32 tmp_reg1;
+
+ tmp_reg1 = readl(dsi->dsi_reg_base + DSI_PHY_LCCON);
+ tmp_reg1 = tmp_reg1 & (~LC_ULPM_EN);
+ writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LCCON);
+ udelay(100);
+ tmp_reg1 = tmp_reg1 | LC_WAKEUP_EN;
+ writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LCCON);
+ udelay(100);
+ tmp_reg1 = tmp_reg1 & (~LC_WAKEUP_EN);
+ writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LCCON);
+ udelay(100);
+}
+
+static void dsi_lane0_ulp_mode(struct mtk_dsi *dsi, bool enter)
+{
+ u32 tmp_reg1;
+
+ tmp_reg1 = readl(dsi->dsi_reg_base + DSI_PHY_LD0CON);
+
+ if (enter) {
+ tmp_reg1 = tmp_reg1 & (~LD0_HS_TX_EN);
+ writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LD0CON);
+ udelay(100);
+ tmp_reg1 = tmp_reg1 & (~LD0_ULPM_EN);
+ writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LD0CON);
+ udelay(100);
+ } else {
+ tmp_reg1 = tmp_reg1 & (~LD0_ULPM_EN);
+ writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LD0CON);
+ udelay(100);
+ tmp_reg1 = tmp_reg1 | LD0_WAKEUP_EN;
+ writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LD0CON);
+ udelay(100);
+ tmp_reg1 = tmp_reg1 & (~LD0_WAKEUP_EN);
+ writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LD0CON);
+ udelay(100);
+ }
+}
+
+static bool dsi_clk_hs_state(struct mtk_dsi *dsi)
+{
+ u32 tmp_reg1;
+
+ tmp_reg1 = readl(dsi->dsi_reg_base + DSI_PHY_LCCON);
+
+ return ((tmp_reg1 & LC_HS_TX_EN) == 1) ? true : false;
+}
+
+static void dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter)
+{
+ u32 tmp_reg1;
+
+ tmp_reg1 = readl(dsi->dsi_reg_base + DSI_PHY_LCCON);
+
+ if (enter && !dsi_clk_hs_state(dsi)) {
+ tmp_reg1 = tmp_reg1 | LC_HS_TX_EN;
+ writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LCCON);
+ } else if (!enter && dsi_clk_hs_state(dsi)) {
+ tmp_reg1 = tmp_reg1 & (~LC_HS_TX_EN);
+ writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LCCON);
+ }
+}
+
+static void dsi_set_mode(struct mtk_dsi *dsi)
+{
+ u32 tmp_reg1;
+
+ tmp_reg1 = 0;
+
+ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
+ tmp_reg1 = SYNC_PULSE_MODE;
+
+ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+ tmp_reg1 = BURST_MODE;
+
+ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+ tmp_reg1 = SYNC_PULSE_MODE;
+ }
+
+ writel(tmp_reg1, dsi->dsi_reg_base + DSI_MODE_CTRL);
+}
+
+static void dsi_ps_control_vact(struct mtk_dsi *dsi)
+{
+ struct videomode *vm = &dsi->vm;
+ u32 dsiTmpBufBpp, ps_wc;
+ u32 tmp_reg;
+ u32 tmp_hstx_cklp_wc;
+
+ tmp_reg = 0;
+
+ if (dsi->format == MIPI_DSI_FMT_RGB565)
+ dsiTmpBufBpp = 2;
+ else
+ dsiTmpBufBpp = 3;
+
+ ps_wc = vm->vactive * dsiTmpBufBpp;
+
+ tmp_reg = ps_wc;
+
+ switch (dsi->format) {
+ case MIPI_DSI_FMT_RGB888:
+ tmp_reg |= PACKED_PS_24BIT_RGB888;
+ break;
+ case MIPI_DSI_FMT_RGB666:
+ tmp_reg |= PACKED_PS_18BIT_RGB666;
+ break;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ tmp_reg |= LOOSELY_PS_18BIT_RGB666;
+ break;
+ case MIPI_DSI_FMT_RGB565:
+ tmp_reg |= PACKED_PS_16BIT_RGB565;
+ break;
+ }
+
+ tmp_hstx_cklp_wc = ps_wc;
+
+ writel(vm->vactive, dsi->dsi_reg_base + DSI_VACT_NL);
+ writel(tmp_reg, dsi->dsi_reg_base + DSI_PSCTRL);
+ writel(tmp_hstx_cklp_wc, dsi->dsi_reg_base + DSI_HSTX_CKL_WC);
+}
+
+static void dsi_rxtx_control(struct mtk_dsi *dsi)
+{
+ u32 tmp_reg = 0;
+
+ switch (dsi->lanes) {
+ case 1:
+ tmp_reg = 1<<2;
+ break;
+ case 2:
+ tmp_reg = 3<<2;
+ break;
+ case 3:
+ tmp_reg = 7<<2;
+ break;
+ case 4:
+ tmp_reg = 0xF<<2;
+ break;
+ default:
+ tmp_reg = 0xF<<2;
+ break;
+ }
+
+ writel(tmp_reg, dsi->dsi_reg_base + DSI_TXRX_CTRL);
+}
+
+void dsi_ps_control(struct mtk_dsi *dsi)
+{
+ unsigned int dsi_tmp_buf_bpp;
+ u32 tmp_reg1 = 0;
+
+ switch (dsi->format) {
+ case MIPI_DSI_FMT_RGB888:
+ tmp_reg1 = PACKED_PS_24BIT_RGB888;
+ dsi_tmp_buf_bpp = 3;
+ break;
+ case MIPI_DSI_FMT_RGB666:
+ tmp_reg1 = LOOSELY_PS_18BIT_RGB666;
+ dsi_tmp_buf_bpp = 3;
+ break;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ tmp_reg1 = PACKED_PS_18BIT_RGB666;
+ dsi_tmp_buf_bpp = 3;
+ break;
+ case MIPI_DSI_FMT_RGB565:
+ tmp_reg1 = PACKED_PS_16BIT_RGB565;
+ dsi_tmp_buf_bpp = 2;
+ break;
+ default:
+ tmp_reg1 = PACKED_PS_24BIT_RGB888;
+ dsi_tmp_buf_bpp = 3;
+ break;
+ }
+
+ tmp_reg1 = tmp_reg1 + ((dsi->vm.hactive * dsi_tmp_buf_bpp) & DSI_PS_WC);
+
+ writel(tmp_reg1, dsi->dsi_reg_base + DSI_PSCTRL);
+}
+
+static void dsi_config_vdo_timing(struct mtk_dsi *dsi)
+{
+ unsigned int horizontal_sync_active_byte;
+ unsigned int horizontal_backporch_byte;
+ unsigned int horizontal_frontporch_byte;
+ unsigned int dsi_tmp_buf_bpp;
+
+ struct videomode *vm = &dsi->vm;
+
+ if (dsi->format == MIPI_DSI_FMT_RGB565)
+ dsi_tmp_buf_bpp = 2;
+ else
+ dsi_tmp_buf_bpp = 3;
+
+ writel(vm->vsync_len, dsi->dsi_reg_base + DSI_VSA_NL);
+ writel(vm->vback_porch, dsi->dsi_reg_base + DSI_VBP_NL);
+ writel(vm->vfront_porch, dsi->dsi_reg_base + DSI_VFP_NL);
+ writel(vm->vactive, dsi->dsi_reg_base + DSI_VACT_NL);
+
+ horizontal_sync_active_byte = (vm->hsync_len * dsi_tmp_buf_bpp - 10);
+
+ if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+ horizontal_backporch_byte =
+ (vm->hback_porch * dsi_tmp_buf_bpp - 10);
+ else
+ horizontal_backporch_byte = ((vm->hback_porch + vm->hsync_len) *
+ dsi_tmp_buf_bpp - 10);
+
+ horizontal_frontporch_byte = (vm->vfront_porch * dsi_tmp_buf_bpp - 12);
+
+ writel(vm->hsync_len, dsi->dsi_reg_base + DSI_HSA_WC);
+ writel(vm->hback_porch, dsi->dsi_reg_base + DSI_HBP_WC);
+ writel(vm->hfront_porch, dsi->dsi_reg_base + DSI_HFP_WC);
+
+ dsi_ps_control(dsi);
+}
+
+static void mtk_dsi_start(struct mtk_dsi *dsi)
+{
+ writel(0, dsi->dsi_reg_base + DSI_START);
+ writel(1, dsi->dsi_reg_base + DSI_START);
+}
+
+static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
+{
+ clk_disable_unprepare(dsi->dsi0_engine_clk_cg);
+ clk_disable_unprepare(dsi->dsi0_digital_clk_cg);
+
+ usleep_range(10000, 20000);
+
+ dsi_phy_clk_switch_off(dsi);
+}
+
+static int mtk_output_dsi_enable(struct mtk_dsi *dsi)
+{
+ int ret;
+
+ if (dsi->enabled == true)
+ return 0;
+
+ ret = mtk_dsi_poweron(dsi);
+ if (ret < 0)
+ return ret;
+
+ dsi_rxtx_control(dsi);
+
+ dsi_clk_ulp_mode_leave(dsi);
+ dsi_lane0_ulp_mode(dsi, 0);
+ dsi_clk_hs_mode(dsi, 0);
+ dsi_set_mode(dsi);
+
+ dsi_ps_control_vact(dsi);
+ dsi_config_vdo_timing(dsi);
+
+ dsi_set_mode(dsi);
+ dsi_clk_hs_mode(dsi, 1);
+
+ mtk_dsi_start(dsi);
+
+ dsi->enabled = true;
+
+ return 0;
+}
+
+static int mtk_output_dsi_disable(struct mtk_dsi *dsi)
+{
+ if (dsi->enabled == false)
+ return 0;
+
+ dsi_lane0_ulp_mode(dsi, 1);
+ dsi_clk_ulp_mode_enter(dsi);
+ mtk_dsi_poweroff(dsi);
+ dsi_phy_clk_switch_off(dsi);
+
+ dsi->enabled = false;
+
+ return 0;
+}
+
+static void mtk_dsi_encoder_destroy(struct drm_encoder *encoder)
+{
+ drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs mtk_dsi_encoder_funcs = {
+ .destroy = mtk_dsi_encoder_destroy,
+};
+
+static void mtk_dsi_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+ struct mtk_dsi *dsi = encoder_to_dsi(encoder);
+ struct drm_panel *panel = dsi->panel;
+
+ mtk_dsi_info("%s dpms mode = %d !\n", __func__, mode);
+
+ if (mode != DRM_MODE_DPMS_ON) {
+ drm_panel_disable(panel);
+ mtk_output_dsi_disable(dsi);
+ } else {
+ mtk_output_dsi_enable(dsi);
+ drm_panel_enable(panel);
+ }
+}
+
+static bool mtk_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void mtk_dsi_encoder_prepare(struct drm_encoder *encoder)
+{
+ /* drm framework doesn't check NULL. */
+}
+
+static void mtk_dsi_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode, struct drm_display_mode *adjusted)
+{
+}
+
+static void mtk_dsi_encoder_commit(struct drm_encoder *encoder)
+{
+ /* DRM_MODE_DPMS_ON? */
+}
+
+static enum drm_connector_status mtk_dsi_connector_detect(
+ struct drm_connector *connector, bool force)
+{
+ enum drm_connector_status status = connector_status_unknown;
+
+ status = connector_status_connected; /* FIXME? */
+
+ return status;
+}
+
+static void mtk_dsi_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
+static const struct drm_display_mode default_modes[] = {
+ /* 1368x768@60Hz */
+ { DRM_MODE("1368x768", DRM_MODE_TYPE_DRIVER, 72070,
+ 1368, 1368 + 58, 1368 + 58 + 58, 1368 + 58 + 58 + 58, 0,
+ 768, 768 + 4, 768 + 4 + 4, 768 + 4 + 4 + 4, 0, 0) },
+};
+
+static int mtk_dsi_connector_get_modes(struct drm_connector *connector)
+{
+ const struct drm_display_mode *ptr = &default_modes[0];
+ struct drm_display_mode *mode;
+ int count = 0;
+
+ mode = drm_mode_duplicate(connector->dev, ptr);
+ if (mode) {
+ drm_mode_probed_add(connector, mode);
+ count++;
+ }
+
+ connector->display_info.width_mm = mode->hdisplay;
+ connector->display_info.height_mm = mode->vdisplay;
+
+ return 1;
+}
+
+static struct drm_encoder *
+mtk_dsi_connector_best_encoder(struct drm_connector *connector)
+{
+ struct mtk_dsi *dsi = connector_to_dsi(connector);
+
+ return &dsi->encoder;
+}
+
+static const struct drm_encoder_helper_funcs mtk_dsi_encoder_helper_funcs = {
+ .dpms = mtk_dsi_encoder_dpms,
+ .mode_fixup = mtk_dsi_encoder_mode_fixup,
+ .prepare = mtk_dsi_encoder_prepare,
+ .mode_set = mtk_dsi_encoder_mode_set,
+ .commit = mtk_dsi_encoder_commit,
+};
+
+static const struct drm_connector_funcs mtk_dsi_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .detect = mtk_dsi_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = mtk_dsi_connector_destroy,
+};
+
+static const struct drm_connector_helper_funcs
+ mtk_dsi_connector_helper_funcs = {
+ .get_modes = mtk_dsi_connector_get_modes,
+ .best_encoder = mtk_dsi_connector_best_encoder,
+};
+
+struct bridge_init {
+ struct i2c_client *mipirx_client;
+ struct i2c_client *dptx_client;
+ struct device_node *node_mipirx;
+ struct device_node *node_dptx;
+};
+
+static int mtk_drm_attach_lcm_bridge(struct drm_bridge *bridge,
+ struct drm_encoder *encoder)
+{
+ int ret;
+
+ encoder->bridge = bridge;
+ bridge->encoder = encoder;
+ ret = drm_bridge_attach(encoder->dev, bridge);
+ if (ret) {
+ DRM_ERROR("Failed to attach bridge to drm\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mtk_dsi_create_conn_enc(struct mtk_dsi *dsi)
+{
+ int ret;
+
+ ret = drm_encoder_init(dsi->drm_dev, &dsi->encoder,
+ &mtk_dsi_encoder_funcs, DRM_MODE_ENCODER_DSI);
+
+ if (ret)
+ goto errcode;
+
+ drm_encoder_helper_add(&dsi->encoder, &mtk_dsi_encoder_helper_funcs);
+
+ dsi->encoder.possible_crtcs = 1;
+
+ /* Pre-empt DP connector creation if there's a bridge */
+ ret = mtk_drm_attach_lcm_bridge(dsi->bridge, &dsi->encoder);
+ if (!ret)
+ return 0;
+
+ ret = drm_connector_init(dsi->drm_dev, &dsi->conn,
+ &mtk_dsi_connector_funcs, DRM_MODE_CONNECTOR_DSI);
+ if (ret)
+ goto errcode;
+
+ drm_connector_helper_add(&dsi->conn, &mtk_dsi_connector_helper_funcs);
+
+ ret = drm_connector_register(&dsi->conn);
+ if (ret)
+ goto errcode;
+
+ dsi->conn.dpms = DRM_MODE_DPMS_OFF;
+ dsi->conn.encoder = &dsi->encoder;
+
+ drm_mode_connector_attach_encoder(&dsi->conn, &dsi->encoder);
+
+ if (dsi->panel)
+ ret = drm_panel_attach(dsi->panel, &dsi->conn);
+
+ return 0;
+
+errcode:
+ drm_encoder_cleanup(&dsi->encoder);
+ drm_connector_unregister(&dsi->conn);
+ drm_connector_cleanup(&dsi->conn);
+
+ return ret;
+}
+
+static void mtk_dsi_destroy_conn_enc(struct mtk_dsi *dsi)
+{
+ drm_encoder_cleanup(&dsi->encoder);
+ drm_connector_unregister(&dsi->conn);
+ drm_connector_cleanup(&dsi->conn);
+}
+
+static int mtk_dsi_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ int ret;
+ struct mtk_dsi *dsi = NULL;
+
+ dsi = platform_get_drvdata(to_platform_device(dev));
+ if (!dsi) {
+ ret = -EFAULT;
+ goto errcode;
+ }
+
+ dsi->drm_dev = data;
+
+ ret = mtk_dsi_create_conn_enc(dsi);
+ if (ret) {
+ DRM_ERROR("Encoder create failed with %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+
+errcode:
+ return ret;
+
+}
+
+static void mtk_dsi_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct mtk_dsi *dsi = NULL;
+
+ dsi = platform_get_drvdata(to_platform_device(dev));
+ mtk_dsi_destroy_conn_enc(dsi);
+
+ dsi->drm_dev = NULL;
+}
+
+static const struct component_ops mtk_dsi_component_ops = {
+ .bind = mtk_dsi_bind,
+ .unbind = mtk_dsi_unbind,
+};
+
+static int mtk_dsi_host_attach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *device)
+{
+ struct mtk_dsi *dsi = host_to_mtk(host);
+
+ dsi->mode_flags = device->mode_flags;
+ dsi->format = device->format;
+ dsi->lanes = device->lanes;
+
+ dsi->panel = of_drm_find_panel(device->dev.of_node);
+ if (dsi->panel) {
+ if (dsi->conn.dev)
+ drm_helper_hpd_irq_event(dsi->conn.dev);
+ }
+
+ return 0;
+}
+
+static int mtk_dsi_host_detach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *device)
+{
+ struct mtk_dsi *dsi = host_to_mtk(host);
+
+ if (dsi->panel && &device->dev == dsi->panel->dev) {
+ if (dsi->conn.dev)
+ drm_helper_hpd_irq_event(dsi->conn.dev);
+
+ dsi->panel = NULL;
+ }
+
+ return 0;
+}
+
+static const struct mipi_dsi_host_ops mtk_dsi_host_ops = {
+ .attach = mtk_dsi_host_attach,
+ .detach = mtk_dsi_host_detach,
+};
+
+static int mtk_dsi_probe(struct platform_device *pdev)
+{
+ struct mtk_dsi *dsi = NULL;
+ struct device *dev = &pdev->dev;
+ struct device_node *panel_node, *bridge_node, *endpoint;
+ struct resource *regs;
+ int err;
+ int ret;
+
+ dsi = kzalloc(sizeof(struct mtk_dsi), GFP_KERNEL);
+
+ dsi->mode_flags = MIPI_DSI_MODE_VIDEO;
+ dsi->format = MIPI_DSI_FMT_RGB888;
+ dsi->lanes = 4;
+
+ dsi->vm.pixelclock = 76000;
+ dsi->vm.hactive = 1368;
+ dsi->vm.hback_porch = 100;
+ dsi->vm.hfront_porch = 106;
+ dsi->vm.hsync_len = 26;
+ dsi->vm.vactive = 768;
+ dsi->vm.vback_porch = 10;
+ dsi->vm.vfront_porch = 10;
+ dsi->vm.vsync_len = 12;
+
+ err = mtk_dsi_of_read_u32(dev->of_node, "mediatek,width",
+ &dsi->vm.hactive);
+ if (err < 0)
+ return err;
+
+ err = mtk_dsi_of_read_u32(dev->of_node, "mediatek,height",
+ &dsi->vm.vactive);
+ if (err < 0)
+ return err;
+
+ err = mtk_dsi_of_read_u32(dev->of_node, "mediatek,mipi-tx-burst-freq",
+ &dsi->pll_clk_rate);
+
+ if (err < 0)
+ return err;
+
+ endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (endpoint) {
+ bridge_node = of_graph_get_remote_port_parent(endpoint);
+ if (!bridge_node)
+ return -EPROBE_DEFER;
+
+ dsi->bridge = of_drm_find_bridge(bridge_node);
+ of_node_put(bridge_node);
+ if (!dsi->bridge)
+ return -EPROBE_DEFER;
+ }
+
+ dsi->dsi0_engine_clk_cg = devm_clk_get(dev, "dsi0_engine_disp_ck");
+ if (IS_ERR(dsi->dsi0_engine_clk_cg)) {
+ dev_err(dev, "cannot get dsi0_engine_clk_cg\n");
+ return PTR_ERR(dsi->dsi0_engine_clk_cg);
+ }
+
+ dsi->dsi0_digital_clk_cg = devm_clk_get(dev, "dsi0_digital_disp_ck");
+ if (IS_ERR(dsi->dsi0_digital_clk_cg)) {
+ dev_err(dev, "cannot get dsi0_digital_disp_ck\n");
+ return PTR_ERR(dsi->dsi0_digital_clk_cg);
+ }
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dsi->dsi_reg_base = devm_ioremap_resource(dev, regs);
+
+ if (IS_ERR(dsi->dsi_reg_base)) {
+ dev_err(dev, "cannot get dsi->dsi_reg_base\n");
+ return PTR_ERR(dsi->dsi_reg_base);
+ }
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ dsi->dsi_tx_reg_base = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(dsi->dsi_tx_reg_base)) {
+ dev_err(dev, "cannot get dsi->dsi_tx_reg_base\n");
+ return PTR_ERR(dsi->dsi_tx_reg_base);
+ }
+
+ dsi->disp_supplies = devm_regulator_get(&pdev->dev, "disp-bdg");
+ if (IS_ERR(dsi->disp_supplies)) {
+ dev_err(dev, "cannot get dsi->disp_supplies\n");
+ return PTR_ERR(dsi->disp_supplies);
+ }
+
+ ret = regulator_set_voltage(dsi->disp_supplies, 1800000, 1800000);
+ if (ret != 0) {
+ dev_err(dev, "lcm failed to set lcm_vgp voltage: %d\n", ret);
+ return PTR_ERR(dsi->disp_supplies);
+ }
+
+ ret = regulator_enable(dsi->disp_supplies);
+ if (ret != 0) {
+ dev_err(dev, "Failed to enable lcm_vgp: %d\n", ret);
+ return PTR_ERR(dsi->disp_supplies);
+ }
+
+ panel_node = of_parse_phandle(dev->of_node, "mediatek,panel", 0);
+ if (panel_node) {
+ dsi->panel = of_drm_find_panel(panel_node);
+ of_node_put(panel_node);
+ if (!dsi->panel)
+ return -EPROBE_DEFER;
+ } else
+ return -EPROBE_DEFER;
+
+ platform_set_drvdata(pdev, dsi);
+
+ ret = component_add(&pdev->dev, &mtk_dsi_component_ops);
+ if (ret)
+ goto err_del_component;
+
+ return 0;
+
+err_del_component:
+ component_del(&pdev->dev, &mtk_dsi_component_ops);
+ return -EPROBE_DEFER;
+
+}
+
+static int mtk_dsi_remove(struct platform_device *pdev)
+{
+ struct mtk_dsi *dsi = platform_get_drvdata(pdev);
+
+ mtk_output_dsi_disable(dsi);
+ component_del(&pdev->dev, &mtk_dsi_component_ops);
+
+ return 0;
+}
+
+static const struct of_device_id mtk_dsi_of_match[] = {
+ { .compatible = "mediatek,mt8173-dsi" },
+ { },
+};
+
+struct platform_driver mtk_dsi_driver = {
+ .probe = mtk_dsi_probe,
+ .remove = mtk_dsi_remove,
+ .driver = {
+ .name = "mtk-dsi",
+ .of_match_table = mtk_dsi_of_match,
+ .owner = THIS_MODULE,
+ },
+};
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_dsi.h b/drivers/gpu/drm/mediatek/mediatek_drm_dsi.h
new file mode 100644
index 0000000..7b7b93b
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_dsi.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MEDIATEK_DRM_DSI_H_
+#define _MEDIATEK_DRM_DSI_H_
+
+
+struct mtk_dsi {
+ struct drm_device *drm_dev;
+ struct drm_encoder encoder;
+ struct drm_connector conn;
+ struct drm_panel *panel;
+ struct drm_bridge *bridge;
+ struct mipi_dsi_host host;
+ struct regulator *disp_supplies;
+
+ void __iomem *dsi_reg_base;
+ void __iomem *dsi_tx_reg_base;
+
+ struct clk *dsi_disp_clk_cg;
+ struct clk *dsi_dsi_clk_cg;
+ struct clk *dsi_div2_clk_cg;
+
+ struct clk *dsi0_engine_clk_cg;
+ struct clk *dsi0_digital_clk_cg;
+
+ u32 pll_clk_rate;
+
+ unsigned long mode_flags;
+ enum mipi_dsi_pixel_format format;
+ unsigned int lanes;
+ struct videomode vm;
+ bool enabled;
+};
+
+
+static inline struct mtk_dsi *host_to_mtk(struct mipi_dsi_host *host)
+{
+ return container_of(host, struct mtk_dsi, host);
+}
+
+static inline struct mtk_dsi *encoder_to_dsi(struct drm_encoder *e)
+{
+ return container_of(e, struct mtk_dsi, encoder);
+}
+
+#define connector_to_dsi(c) container_of(c, struct mtk_dsi, conn)
+
+
+#define mtk_dsi_err(fmt, ...) \
+ pr_err("[mediatek drm dsi] ERROR!!! fun:%s, line:%d " \
+ fmt, __func__, __LINE__, ##__VA_ARGS__)
+#define mtk_dsi_info(fmt, ...) \
+ pr_info("[mediatek drm dsi] INFO fun:%s, line:%d " \
+ fmt, __func__, __LINE__, ##__VA_ARGS__)
+#define mtk_dsi_output(fmt, ...) \
+ pr_info(fmt, ##__VA_ARGS__)
+
+#endif
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_fb.c b/drivers/gpu/drm/mediatek/mediatek_drm_fb.c
new file mode 100644
index 0000000..fbaba95
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_fb.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+
+#include "mediatek_drm_drv.h"
+#include "mediatek_drm_fb.h"
+#include "mediatek_drm_gem.h"
+
+
+static int mtk_drm_fb_create_handle(struct drm_framebuffer *fb,
+ struct drm_file *file_priv,
+ unsigned int *handle)
+{
+ struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
+
+ return drm_gem_handle_create(file_priv, mtk_fb->gem_obj[0], handle);
+}
+
+static void mtk_drm_fb_destroy(struct drm_framebuffer *fb)
+{
+ unsigned int i;
+ struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
+ struct drm_gem_object *gem;
+ int nr = drm_format_num_planes(fb->pixel_format);
+
+ drm_framebuffer_cleanup(fb);
+
+ for (i = 0; i < nr; i++) {
+ gem = mtk_fb->gem_obj[i];
+ drm_gem_object_unreference_unlocked(gem);
+ }
+}
+
+static struct drm_framebuffer_funcs mediatek_drm_fb_funcs = {
+ .create_handle = mtk_drm_fb_create_handle,
+ .destroy = mtk_drm_fb_destroy,
+};
+
+static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev,
+ struct drm_mode_fb_cmd2 *mode,
+ struct drm_gem_object **obj)
+{
+ struct mtk_drm_fb *mtk_fb;
+ unsigned int i;
+ int ret;
+
+ mtk_fb = devm_kzalloc(dev->dev, sizeof(*mtk_fb), GFP_KERNEL);
+ if (!mtk_fb)
+ return ERR_PTR(-ENOMEM);
+
+ drm_helper_mode_fill_fb_struct(&mtk_fb->base, mode);
+
+ for (i = 0; i < drm_format_num_planes(mode->pixel_format); i++)
+ mtk_fb->gem_obj[i] = obj[i];
+
+ ret = drm_framebuffer_init(dev, &mtk_fb->base, &mediatek_drm_fb_funcs);
+ if (ret) {
+ DRM_ERROR("failed to initialize framebuffer\n");
+ return ERR_PTR(ret);
+ }
+
+ return mtk_fb;
+}
+
+static int mtk_drm_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct drm_fb_helper *helper = info->par;
+ struct device *dev = ((struct drm_device *)helper->dev)->dev;
+ struct mtk_drm_fb *mtk_fb = to_mtk_fb(helper->fb);
+ struct mtk_drm_gem_buf *buffer =
+ to_mtk_gem_obj(mtk_fb->gem_obj[0])->buffer;
+ int ret;
+
+ vma->vm_flags |= VM_MIXEDMAP;
+
+ if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, &buffer->dma_attrs)) {
+ ret = dma_mmap_attrs(dev, vma, buffer->pages,
+ buffer->mva_addr, buffer->size, &buffer->dma_attrs);
+ } else {
+ ret = dma_mmap_attrs(dev, vma, buffer->kvaddr,
+ buffer->mva_addr, buffer->size, &buffer->dma_attrs);
+ }
+
+ if (ret) {
+ DRM_ERROR("failed to fb_mmap %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct fb_ops mediatek_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_fillrect = sys_fillrect,
+ .fb_copyarea = sys_copyarea,
+ .fb_imageblit = sys_imageblit,
+ .fb_check_var = drm_fb_helper_check_var,
+ .fb_set_par = drm_fb_helper_set_par,
+ .fb_blank = drm_fb_helper_blank,
+ .fb_pan_display = drm_fb_helper_pan_display,
+ .fb_setcmap = drm_fb_helper_setcmap,
+ .fb_mmap = mtk_drm_fb_mmap,
+};
+
+static int mtk_fbdev_probe(struct drm_fb_helper *helper,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct drm_device *dev = helper->dev;
+ struct drm_mode_fb_cmd2 mode = { 0 };
+ struct mtk_drm_fb *mtk_fb;
+ struct mtk_drm_gem_buf *buffer;
+ struct mtk_drm_gem_obj *mtk_gem;
+ struct drm_gem_object *gem;
+ struct fb_info *info;
+ struct drm_framebuffer *fb;
+ unsigned long offset;
+ size_t size;
+ int err;
+
+ mode.width = sizes->surface_width;
+ mode.height = sizes->surface_height;
+ mode.pitches[0] = sizes->surface_width * ((sizes->surface_bpp + 7) / 8);
+ mode.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+ sizes->surface_depth);
+
+ mode.height = mode.height;/* << 1; for fb use? */
+ size = mode.pitches[0] * mode.height;
+ dev_info(dev->dev, "mtk_fbdev_probe %dx%d bpp %d pitch %d size %zu\n",
+ mode.width, mode.height, sizes->surface_bpp, mode.pitches[0],
+ size);
+
+ mtk_gem = mtk_drm_gem_create(dev, 3, size);
+ if (IS_ERR(mtk_gem)) {
+ err = PTR_ERR(mtk_gem);
+ goto fini;
+ }
+
+ gem = &mtk_gem->base;
+ buffer = mtk_gem->buffer;
+
+ mtk_fb = mtk_drm_framebuffer_init(dev, &mode, &gem);
+ if (IS_ERR(mtk_fb)) {
+ dev_err(dev->dev, "failed to allocate DRM framebuffer\n");
+ err = PTR_ERR(mtk_fb);
+ goto free;
+ }
+ fb = &mtk_fb->base;
+
+ info = framebuffer_alloc(0, dev->dev);
+ if (!info) {
+ dev_err(dev->dev, "failed to allocate framebuffer info\n");
+ err = PTR_ERR(info);
+ goto release;
+ }
+
+ helper->fb = fb;
+ helper->fbdev = info;
+
+ info->par = helper;
+ info->flags = FBINFO_FLAG_DEFAULT;
+ info->fbops = &mediatek_fb_ops;
+
+ err = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (err < 0) {
+ dev_err(dev->dev, "failed to allocate color map: %d\n", err);
+ goto destroy;
+ }
+
+ drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+ drm_fb_helper_fill_var(info, helper, fb->width, fb->height);
+
+ offset = info->var.xoffset * (fb->bits_per_pixel + 7) / 8;
+ offset += info->var.yoffset * fb->pitches[0];
+
+ strcpy(info->fix.id, "mtk");
+ /* dev->mode_config.fb_base = (resource_size_t)bo->paddr; */
+ info->var.yres = info->var.yres_virtual;/* >> 1; for fb use? */
+ info->fix.smem_start = buffer->mva_addr + offset;
+ info->fix.smem_len = size;
+ info->screen_base = buffer->kvaddr + offset;
+ info->screen_size = size;
+
+ return 0;
+
+destroy:
+ drm_framebuffer_unregister_private(fb);
+ mtk_drm_fb_destroy(fb);
+release:
+ framebuffer_release(info);
+free:
+ mtk_drm_gem_free_object(&mtk_gem->base);
+fini:
+ dev_err(dev->dev, "mtk_fbdev_probe fail\n");
+ return err;
+}
+
+static struct drm_fb_helper_funcs mediatek_drm_fb_helper_funcs = {
+ .fb_probe = mtk_fbdev_probe,
+};
+
+int mtk_fbdev_create(struct drm_device *dev)
+{
+ struct mtk_drm_private *priv =
+ (struct mtk_drm_private *)dev->dev_private;
+ struct drm_fb_helper *fbdev;
+ int ret;
+
+ fbdev = devm_kzalloc(dev->dev, sizeof(*fbdev), GFP_KERNEL);
+ if (!fbdev)
+ return -ENOMEM;
+
+ drm_fb_helper_prepare(dev, fbdev, &mediatek_drm_fb_helper_funcs);
+
+ ret = drm_fb_helper_init(dev, fbdev, dev->mode_config.num_crtc,
+ dev->mode_config.num_connector);
+ if (ret) {
+ dev_err(dev->dev, "failed to initialize DRM FB helper\n");
+ goto fini;
+ }
+
+ ret = drm_fb_helper_single_add_all_connectors(fbdev);
+ if (ret) {
+ dev_err(dev->dev, "failed to add connectors\n");
+ goto fini;
+ }
+
+ drm_helper_disable_unused_functions(dev);
+
+ ret = drm_fb_helper_initial_config(fbdev, FBDEV_BPP);
+ if (ret) {
+ dev_err(dev->dev, "failed to set initial configuration\n");
+ goto fini;
+ }
+ priv->fb_helper = fbdev;
+
+ return 0;
+
+fini:
+ drm_fb_helper_fini(fbdev);
+
+ return ret;
+}
+
+void mtk_fbdev_destroy(struct drm_device *dev)
+{
+ struct mtk_drm_private *priv =
+ (struct mtk_drm_private *)dev->dev_private;
+ struct drm_fb_helper *fbdev = priv->fb_helper;
+ struct fb_info *info = priv->fb_helper->fbdev;
+
+ if (info) {
+ int err;
+
+ err = unregister_framebuffer(info);
+ if (err < 0)
+ DRM_DEBUG_KMS("failed to unregister framebuffer\n");
+
+ if (info->cmap.len)
+ fb_dealloc_cmap(&info->cmap);
+
+ framebuffer_release(info);
+ }
+
+ if (fbdev->fb) {
+ drm_framebuffer_unregister_private(fbdev->fb);
+ mtk_drm_fb_destroy(fbdev->fb);
+ }
+
+ drm_fb_helper_fini(fbdev);
+ kfree(fbdev);
+}
+
+void mtk_drm_mode_output_poll_changed(struct drm_device *dev)
+{
+ struct mtk_drm_private *priv =
+ (struct mtk_drm_private *)dev->dev_private;
+
+ if (priv->fb_helper)
+ drm_fb_helper_hotplug_event(priv->fb_helper);
+}
+
+struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
+ struct drm_file *file,
+ struct drm_mode_fb_cmd2 *cmd)
+{
+ unsigned int hsub, vsub, i;
+ struct mtk_drm_fb *mtk_fb;
+ struct drm_gem_object *gem[MAX_FB_OBJ];
+ int err;
+
+ hsub = drm_format_horz_chroma_subsampling(cmd->pixel_format);
+ vsub = drm_format_vert_chroma_subsampling(cmd->pixel_format);
+ for (i = 0; i < drm_format_num_planes(cmd->pixel_format); i++) {
+ unsigned int width = cmd->width / (i ? hsub : 1);
+ unsigned int height = cmd->height / (i ? vsub : 1);
+ unsigned int size, bpp;
+
+ gem[i] = drm_gem_object_lookup(dev, file, cmd->handles[i]);
+ if (!gem[i]) {
+ err = -ENOENT;
+ goto unreference;
+ }
+
+ bpp = drm_format_plane_cpp(cmd->pixel_format, i);
+ size = (height - 1) * cmd->pitches[i] + width * bpp;
+ size += cmd->offsets[i];
+
+ if (gem[i]->size < size) {
+ err = -EINVAL;
+ goto unreference;
+ }
+ }
+
+ mtk_fb = mtk_drm_framebuffer_init(dev, cmd, gem);
+
+ return &mtk_fb->base;
+
+unreference:
+ while (i--)
+ drm_gem_object_unreference_unlocked(gem[i]);
+
+ return ERR_PTR(err);
+}
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_fb.h b/drivers/gpu/drm/mediatek/mediatek_drm_fb.h
new file mode 100644
index 0000000..ee8b6a6
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_fb.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MEDIATEK_DRM_FB_H_
+#define _MEDIATEK_DRM_FB_H_
+
+#define MAX_FB_OBJ 4
+#define FBDEV_BPP 16
+
+/*
+ * mtk specific framebuffer structure.
+ *
+ * @fb: drm framebuffer object.
+ * @mtk_gem_obj: array of mtk specific gem object containing a gem object.
+ */
+struct mtk_drm_fb {
+ struct drm_framebuffer base;
+ struct drm_gem_object *gem_obj[MAX_FB_OBJ]; /* FIXME? mtk_gem_obj? */
+};
+
+#define to_mtk_fb(x) container_of(x, struct mtk_drm_fb, base)
+
+void mtk_drm_mode_output_poll_changed(struct drm_device *dev);
+struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
+ struct drm_file *file,
+ struct drm_mode_fb_cmd2 *cmd);
+
+int mtk_fbdev_create(struct drm_device *dev);
+void mtk_fbdev_destroy(struct drm_device *dev);
+
+#endif
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_gem.c b/drivers/gpu/drm/mediatek/mediatek_drm_gem.c
new file mode 100644
index 0000000..3df3f4f
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_gem.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_gem.h>
+
+#include "mediatek_drm_gem.h"
+#include "drm/mediatek_drm.h"
+
+
+struct mtk_drm_gem_obj *mtk_drm_gem_init(struct drm_device *dev,
+ unsigned long size)
+{
+ struct mtk_drm_gem_obj *mtk_gem_obj;
+ struct drm_gem_object *obj;
+ int ret;
+
+ mtk_gem_obj = kzalloc(sizeof(*mtk_gem_obj), GFP_KERNEL);
+ if (!mtk_gem_obj)
+ return NULL;
+
+ mtk_gem_obj->size = size;
+ obj = &mtk_gem_obj->base;
+
+ ret = drm_gem_object_init(dev, obj, size);
+ if (ret < 0) {
+ DRM_ERROR("failed to initialize gem object\n");
+ kfree(mtk_gem_obj);
+ return NULL;
+ }
+
+ DRM_DEBUG_KMS("created file object = 0x%p\n", obj->filp);
+
+ return mtk_gem_obj;
+}
+
+struct mtk_drm_gem_obj *mtk_drm_gem_create(struct drm_device *dev,
+ unsigned int flags, unsigned long size)
+{
+ struct mtk_drm_gem_obj *mtk_gem;
+ struct mtk_drm_gem_buf *mtk_buf;
+ int ret;
+
+ if (!size) {
+ DRM_ERROR("invalid size.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ mtk_gem = kzalloc(sizeof(*mtk_gem), GFP_KERNEL);
+ if (!mtk_gem) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ mtk_buf = kzalloc(sizeof(*mtk_buf), GFP_KERNEL);
+ if (!mtk_buf) {
+ ret = -ENOMEM;
+ goto err_buf;
+ }
+ mtk_gem->buffer = mtk_buf;
+
+ if (flags == 0) {
+ size = round_up(size, PAGE_SIZE);
+ mtk_buf->kvaddr = kzalloc(size, GFP_KERNEL);
+ if (!mtk_buf->kvaddr) {
+ ret = -ENOMEM;
+ goto err_size;
+ }
+
+ mtk_buf->paddr = virt_to_phys(mtk_buf->kvaddr);
+ mtk_buf->size = size;
+ mtk_buf->mva_addr = mtk_buf->paddr;
+ } else {
+ struct page **pages;
+ int npages, size_pages;
+ int offset, index;
+
+ size = PAGE_ALIGN(size);
+ npages = size >> PAGE_SHIFT;
+ size_pages = npages * sizeof(*pages);
+ pages = kmalloc(size_pages, GFP_KERNEL);
+ if (!pages) {
+ ret = -ENOMEM;
+ goto err_size;
+ }
+ mtk_buf->pages = pages;
+
+ init_dma_attrs(&mtk_buf->dma_attrs);
+
+ mtk_buf->kvaddr = dma_alloc_attrs(dev->dev, size,
+ (dma_addr_t *)&mtk_buf->mva_addr, GFP_KERNEL,
+ &mtk_buf->dma_attrs);
+ if (!mtk_buf->kvaddr) {
+ ret = -ENOMEM;
+ goto err_mem;
+ }
+
+ mtk_buf->paddr = 0;
+ mtk_buf->size = size;
+
+ for (offset = 0, index = 0;
+ offset < size; offset += PAGE_SIZE, index++)
+ mtk_buf->pages[index] =
+ vmalloc_to_page(mtk_buf->kvaddr + offset);
+
+ mtk_buf->sgt = drm_prime_pages_to_sg(mtk_buf->pages, npages);
+ }
+ mtk_gem->flags = flags;
+
+ DRM_INFO("kvaddr = %p mva_addr = %X\n",
+ mtk_buf->kvaddr, mtk_buf->mva_addr);
+ ret = drm_gem_object_init(dev, &mtk_gem->base, size);
+ if (ret)
+ goto err_mem;
+
+ return mtk_gem;
+
+err_mem:
+ if (mtk_buf->paddr)
+ kfree(mtk_buf->kvaddr);
+ else
+ dma_free_attrs(dev->dev, size, mtk_buf->kvaddr,
+ mtk_buf->mva_addr, &mtk_buf->dma_attrs);
+
+ kfree(mtk_buf->pages);
+
+err_size:
+ kfree(mtk_buf);
+err_buf:
+ kfree(mtk_gem);
+err:
+ return ERR_PTR(ret);
+}
+
+void mtk_drm_gem_free_object(struct drm_gem_object *gem)
+{
+ struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(gem);
+
+ DRM_DEBUG_KMS("handle count = %d\n", gem->handle_count);
+
+ drm_gem_free_mmap_offset(gem);
+
+ /* release file pointer to gem object. */
+ drm_gem_object_release(gem);
+
+ if (mtk_gem->flags == 0)
+ kfree(mtk_gem->buffer->kvaddr);
+ else
+ dma_free_attrs(gem->dev->dev, mtk_gem->buffer->size,
+ mtk_gem->buffer->kvaddr, mtk_gem->buffer->mva_addr,
+ &mtk_gem->buffer->dma_attrs);
+
+ kfree(mtk_gem->buffer->pages);
+ kfree(mtk_gem->buffer);
+ kfree(mtk_gem);
+}
+
+int mtk_drm_gem_dumb_create(struct drm_file *file_priv,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
+
+{
+ struct mtk_drm_gem_obj *mtk_gem;
+ unsigned int min_pitch = args->width * ((args->bpp + 7) / 8);
+ int ret;
+
+ args->pitch = min_pitch;
+ args->size = args->pitch * args->height;
+
+ mtk_gem = mtk_drm_gem_create(dev, 3, args->size);
+ if (IS_ERR(mtk_gem))
+ return PTR_ERR(mtk_gem);
+
+ /*
+ * allocate a id of idr table where the obj is registered
+ * and handle has the id what user can see.
+ */
+ ret = drm_gem_handle_create(file_priv, &mtk_gem->base, &args->handle);
+ if (ret)
+ return ret;
+
+ /* drop reference from allocate - handle holds it now. */
+ drm_gem_object_unreference_unlocked(&mtk_gem->base);
+
+ return 0;
+}
+
+int mtk_drm_gem_dumb_map_offset(struct drm_file *file_priv,
+ struct drm_device *dev, uint32_t handle,
+ uint64_t *offset)
+{
+ struct drm_gem_object *obj;
+ int ret = 0;
+
+ mutex_lock(&dev->struct_mutex);
+
+ /*
+ * get offset of memory allocated for drm framebuffer.
+ * - this callback would be called by user application
+ * with DRM_IOCTL_MODE_MAP_DUMB command.
+ */
+
+ obj = drm_gem_object_lookup(dev, file_priv, handle);
+ if (!obj) {
+ DRM_ERROR("failed to lookup gem object.\n");
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ ret = drm_gem_create_mmap_offset(obj);
+ if (ret)
+ goto out;
+
+ *offset = drm_vma_node_offset_addr(&obj->vma_node);
+ DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset);
+
+out:
+ drm_gem_object_unreference(obj);
+unlock:
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+}
+
+int mtk_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct mtk_drm_gem_obj *mtk_gem;
+ struct drm_gem_object *gem;
+ int ret;
+
+ /* set vm_area_struct. */
+ ret = drm_gem_mmap(filp, vma);
+ if (ret) {
+ DRM_ERROR("failed to mmap.\n");
+ return ret;
+ }
+
+ gem = vma->vm_private_data;
+ mtk_gem = to_mtk_gem_obj(gem);
+
+ if (mtk_gem->flags == 0) {
+ /*
+ * get page frame number to physical memory to be mapped
+ * to user space.
+ */
+ ret = remap_pfn_range(vma, vma->vm_start,
+ mtk_gem->buffer->paddr >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot);
+ } else {
+ struct drm_file *file_priv = filp->private_data;
+ struct drm_device *dev = file_priv->minor->dev;
+ struct mtk_drm_gem_buf *buffer = mtk_gem->buffer;
+
+ vma->vm_flags |= VM_MIXEDMAP;
+
+ ret = dma_mmap_attrs(dev->dev, vma, buffer->kvaddr,
+ buffer->mva_addr, buffer->size, &buffer->dma_attrs);
+ if (ret) {
+ DRM_ERROR("failed to remap dma %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (ret)
+ drm_gem_vm_close(vma);
+
+ return ret;
+}
+
+int mediatek_gem_map_offset_ioctl(struct drm_device *drm, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_mtk_gem_map_off *args = data;
+
+ return mtk_drm_gem_dumb_map_offset(file_priv, drm, args->handle,
+ &args->offset);
+}
+
+int mediatek_gem_create_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct mtk_drm_gem_obj *mtk_gem;
+ struct drm_mtk_gem_create *args = data;
+ int ret;
+
+ mtk_gem = mtk_drm_gem_create(dev, 3, args->size);
+
+ if (IS_ERR(mtk_gem))
+ return PTR_ERR(mtk_gem);
+
+ /*
+ * allocate a id of idr table where the obj is registered
+ * and handle has the id what user can see.
+ */
+ ret = drm_gem_handle_create(file_priv, &mtk_gem->base, &args->handle);
+ if (ret)
+ return ret;
+
+ /* drop reference from allocate - handle holds it now. */
+ drm_gem_object_unreference_unlocked(&mtk_gem->base);
+
+ return 0;
+}
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_gem.h b/drivers/gpu/drm/mediatek/mediatek_drm_gem.h
new file mode 100644
index 0000000..1529481
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_gem.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MEDIATEK_DRM_GEM_H_
+#define _MEDIATEK_DRM_GEM_H_
+
+#include <drm/drm_gem.h>
+
+struct drm_gem_object;
+
+/*
+ * mtk drm gem buffer structure.
+ *
+ * @kvaddr: kernel virtual address to allocated memory region.
+ * @dma_addr: bus address(accessed by dma) to allocated memory region.
+ * - this address could be physical address without IOMMU and
+ * device address with IOMMU.
+ * @sgt: sg table to transfer page data.
+ * @pages: contain all pages to allocated memory region.
+ * @size: size of allocated memory region.
+ */
+struct mtk_drm_gem_buf {
+ void __iomem *kvaddr;
+ dma_addr_t dma_addr;
+ struct dma_attrs dma_attrs;
+ struct sg_table *sgt;
+ struct page **pages;
+ unsigned long size;
+ unsigned int mva_addr;
+ unsigned int paddr;
+};
+
+/*
+ * mtk drm buffer structure.
+ *
+ * @base: a gem object.
+ * - a new handle to this gem object would be created
+ * by drm_gem_handle_create().
+ * @buffer: a pointer to mtk_drm_gem_buffer object.
+ * - contain the information to memory region allocated
+ * by user request or at framebuffer creation.
+ * continuous memory region allocated by user request
+ * or at framebuffer creation.
+ * @size: total memory size to physically non-continuous memory region.
+ * @flags: indicate memory type to allocated buffer and cache attruibute.
+ *
+ * P.S. this object would be transferred to user as kms_bo.handle so
+ * user can access the buffer through kms_bo.handle.
+ */
+struct mtk_drm_gem_obj {
+ struct drm_gem_object base;
+ struct mtk_drm_gem_buf *buffer;
+ unsigned long size;
+ unsigned int flags;
+};
+
+#define to_mtk_gem_obj(x) container_of(x, struct mtk_drm_gem_obj, base)
+
+struct mtk_drm_gem_obj *mtk_drm_gem_init(struct drm_device *dev,
+ unsigned long size);
+void mtk_drm_gem_free_object(struct drm_gem_object *gem);
+struct mtk_drm_gem_obj *mtk_drm_gem_create(struct drm_device *dev,
+ unsigned int flags, unsigned long size);
+int mtk_drm_gem_dumb_create(struct drm_file *file_priv,
+ struct drm_device *dev, struct drm_mode_create_dumb *args);
+int mtk_drm_gem_dumb_map_offset(struct drm_file *file_priv,
+ struct drm_device *dev, uint32_t handle, uint64_t *offset);
+int mtk_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/*
+ * request gem object creation and buffer allocation as the size
+ * that it is calculated with framebuffer information such as width,
+ * height and bpp.
+ */
+int mediatek_gem_create_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+
+/* get buffer offset to map to user space. */
+int mediatek_gem_map_offset_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+
+
+#endif
+
diff --git a/include/uapi/drm/mediatek_drm.h b/include/uapi/drm/mediatek_drm.h
new file mode 100644
index 0000000..19ea357
--- /dev/null
+++ b/include/uapi/drm/mediatek_drm.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#ifndef _UAPI_MEDIATEK_DRM_H
+#define _UAPI_MEDIATEK_DRM_H
+
+#include <drm/drm.h>
+
+/**
+ * User-desired buffer creation information structure.
+ *
+ * @size: user-desired memory allocation size.
+ * - this size value would be page-aligned internally.
+ * @flags: user request for setting memory type or cache attributes.
+ * @handle: returned a handle to created gem object.
+ * - this handle will be set by gem module of kernel side.
+ */
+struct drm_mtk_gem_create {
+ uint64_t size;
+ uint32_t flags;
+ uint32_t handle;
+};
+
+/**
+ * A structure for getting buffer offset.
+ *
+ * @handle: a pointer to gem object created.
+ * @pad: just padding to be 64-bit aligned.
+ * @offset: relatived offset value of the memory region allocated.
+ * - this value should be set by user.
+ */
+struct drm_mtk_gem_map_off {
+ uint32_t handle;
+ uint32_t pad;
+ uint64_t offset;
+};
+
+#define DRM_MTK_GEM_CREATE 0x00
+#define DRM_MTK_GEM_MAP_OFFSET 0x01
+
+#define DRM_IOCTL_MTK_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_MTK_GEM_CREATE, struct drm_mtk_gem_create)
+
+#define DRM_IOCTL_MTK_GEM_MAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_MTK_GEM_MAP_OFFSET, struct drm_mtk_gem_map_off)
+
+
+#endif /* _UAPI_MEDIATEK_DRM_H */
--
1.8.1.1.dirty
^ permalink raw reply related
* [RFC][PATCH 1/2] dt-bindings: drm/mediatek: Add Mediatek DRM dts binding
From: CK Hu @ 2015-05-13 15:23 UTC (permalink / raw)
To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
David Airlie, Matthias Brugger
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
Ashwin Chaugule, Catalin Marinas, Will Deacon, Grant Likely,
Graeme Gregory, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-api-u79uwXL29TY76Z2rM5mHXA,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w, Sascha Hauer, Cawa Cheng,
YT Shen, Jitao Shi, CK Hu
In-Reply-To: <1431530626-31493-1-git-send-email-ck.hu-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
This patch includes
1. Mediatek DRM Device binding
2. Mediatek DSI Device binding
3. Mediatek CRTC Main Device binding
4. Mediatek DDP Device binding
Signed-off-by: CK Hu <ck.hu-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
.../bindings/drm/mediatek/mediatek,crtc-main.txt | 38 ++++++++++++++++++++++
.../bindings/drm/mediatek/mediatek,ddp.txt | 22 +++++++++++++
.../bindings/drm/mediatek/mediatek,drm.txt | 27 +++++++++++++++
.../bindings/drm/mediatek/mediatek,dsi.txt | 20 ++++++++++++
4 files changed, 107 insertions(+)
create mode 100644 Documentation/devicetree/bindings/drm/mediatek/mediatek,crtc-main.txt
create mode 100644 Documentation/devicetree/bindings/drm/mediatek/mediatek,ddp.txt
create mode 100644 Documentation/devicetree/bindings/drm/mediatek/mediatek,drm.txt
create mode 100644 Documentation/devicetree/bindings/drm/mediatek/mediatek,dsi.txt
diff --git a/Documentation/devicetree/bindings/drm/mediatek/mediatek,crtc-main.txt b/Documentation/devicetree/bindings/drm/mediatek/mediatek,crtc-main.txt
new file mode 100644
index 0000000..5c6c420
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/mediatek/mediatek,crtc-main.txt
@@ -0,0 +1,38 @@
+Mediatek CRTC Main Device
+================================
+
+The Mediatek CRTC Main device is a crtc device of DRM system.
+
+Required properties:
+- compatible: "mediatek,<chip>-crtc-main"
+- interrupts: The interrupt signal from the CRTC Main block.
+- reg: Physical base address and length of the controller's registers
+- clocks: device clocks
+ See Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
+- ddp: phandle of ddp device which control display data path.
+
+Example:
+
+crtc_main: crtc@1400c000 {
+ compatible = "mediatek,mt8173-crtc-main";
+ interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_LOW>;
+ reg = <0 0x1400c000 0 0x1000>, /* OVL0 */
+ <0 0x1400e000 0 0x1000>, /* RDMA0 */
+ <0 0x14013000 0 0x1000>, /* COLOR0 */
+ <0 0x14015000 0 0x1000>, /* AAL */
+ <0 0x1401a000 0 0x1000>, /* UFOE */
+ <0 0x14023000 0 0x1000>; /* OD */
+ clocks = <&mmsys MM_DISP_OVL0>,
+ <&mmsys MM_DISP_RDMA0>,
+ <&mmsys MM_DISP_COLOR0>,
+ <&mmsys MM_DISP_AAL>,
+ <&mmsys MM_DISP_UFOE>,
+ <&mmsys MM_DISP_OD>;
+ clock-names = "ovl0_disp",
+ "rdma0_disp",
+ "color0_disp",
+ "aal_disp",
+ "ufoe_disp",
+ "od_disp";
+ ddp = <&ddp>;
+};
\ No newline at end of file
diff --git a/Documentation/devicetree/bindings/drm/mediatek/mediatek,ddp.txt b/Documentation/devicetree/bindings/drm/mediatek/mediatek,ddp.txt
new file mode 100644
index 0000000..77cf630
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/mediatek/mediatek,ddp.txt
@@ -0,0 +1,22 @@
+Mediatek DDP Device
+================================
+
+The Mediatek DDP device control the display data path.
+
+Required properties:
+- compatible: "mediatek,<chip>-ddp"
+- reg: Physical base address and length of the controller's registers
+- power-domains: a phandle to DDP power domain node.
+- clocks: device clocks
+ See Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
+
+Example:
+
+ddp: ddp@14000000 {
+ compatible = "mediatek,mt8173-ddp";
+ reg = <0 0x14000000 0 0x100>, /* CONFIG */
+ <0 0x14020000 0 0x1000>; /* MUTEX */
+ power-domains = <&scpsys MT8173_POWER_DOMAIN_DIS>;
+ clocks = <&mmsys MM_MUTEX_32K>;
+ clock-names = "mutex_disp";
+};
\ No newline at end of file
diff --git a/Documentation/devicetree/bindings/drm/mediatek/mediatek,drm.txt b/Documentation/devicetree/bindings/drm/mediatek/mediatek,drm.txt
new file mode 100644
index 0000000..c4a5702
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/mediatek/mediatek,drm.txt
@@ -0,0 +1,27 @@
+Mediatek DRM Device
+================================
+
+The Mediatek DRM device is a device needed to list all
+display component nodes that comprise the display subsystem.
+And it list the memory-related interface.
+
+Required properties:
+- compatible: "mediatek,<chip>-drm"
+- larb: Should contain a list of phandles pointing to larb device.
+ larb definitions as defined in
+ Documentation/devicetree/bindings/soc/mediatek/mediatek,smi-larb.txt
+- iommus: required a iommu node
+- connectors: Should contain a list of phandles pointing to connector device.
+ connector device should be one component of this master.
+- crtcs: Should contain a list of phandles pointing to crtc device.
+ crtc device should be one component of this master.
+
+Example:
+
+drm0: drm {
+ compatible = "mediatek,mt8173-drm";
+ larb = <&larb0>;
+ iommus = <&iommu M4U_PORT_DISP_OVL0>;
+ connectors = <&dsi>;
+ crtcs = <&crtc_main>;
+};
\ No newline at end of file
diff --git a/Documentation/devicetree/bindings/drm/mediatek/mediatek,dsi.txt b/Documentation/devicetree/bindings/drm/mediatek/mediatek,dsi.txt
new file mode 100644
index 0000000..16e3eb3
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/mediatek/mediatek,dsi.txt
@@ -0,0 +1,20 @@
+Mediatek DSI Device
+================================
+
+The Mediatek DSI device is a connector device of DRM system.
+
+Required properties:
+- compatible: "mediatek,<chip>-dsi"
+- reg: Physical base address and length of the controller's registers
+- clocks: device clocks
+ See Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
+
+Example:
+
+dsi: dsi@10215000 {
+ compatible = "mediatek,mt8173-dsi";
+ reg = <0 0x1401B000 0 0x1000>, /* DSI0 */
+ <0 0x10215000 0 0x1000>; /* MIPITX */
+ clocks = <&mmsys MM_DSI0_ENGINE>, <&mmsys MM_DSI0_DIGITAL>;
+ clock-names = "dsi0_engine_disp_ck", "dsi0_digital_disp_ck";
+};
\ No newline at end of file
--
1.8.1.1.dirty
^ permalink raw reply related
* [RFC][PATCH 0/2] MT8173 DRM support
From: CK Hu @ 2015-05-13 15:23 UTC (permalink / raw)
To: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
David Airlie, Matthias Brugger
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
Ashwin Chaugule, Catalin Marinas, Will Deacon, Grant Likely,
Graeme Gregory, dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
linux-api-u79uwXL29TY76Z2rM5mHXA,
srv_heupstream-NuS5LvNUpcJWk0Htik3J/w, Sascha Hauer, Cawa Cheng,
YT Shen, Jitao Shi
MT8173 DRM include one master drm device and three sub device: dsi device,
crtc main device, and ddp device.
Master drm device control the drm sub device and memory management.
dsi device is a drm connector/encoder device which control MIPI/DSI hw block.
crtc main is a drm crtc device which control hw components in the display data
path.
ddp is a device which control display data path.
Display data path of crtc main is:
[OVL0] -> [COLOR0] -> [AAL] -> [OD] -> [UFOE] -> [RDMA0]
This patch depends on the other patches:
1. MT8173 IOMMU support
http://lists.infradead.org/pipermail/linux-mediatek/2015-March/000058.html
2. add IOMMU dma_ops
cherry picked from git://linux-arm.org/linux-rm iommu/dma
commit d76a1911b02185bdc5f8b5525f9228cf266725c5
CK Hu (2):
dt-bindings: drm/mediatek: Add Mediatek DRM dts binding
drm/mediatek: Add DRM Driver for Mediatek SoC MT8173.
.../bindings/drm/mediatek/mediatek,crtc-main.txt | 38 +
.../bindings/drm/mediatek/mediatek,ddp.txt | 22 +
.../bindings/drm/mediatek/mediatek,drm.txt | 27 +
.../bindings/drm/mediatek/mediatek,dsi.txt | 20 +
drivers/gpu/drm/Kconfig | 2 +
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/mediatek/Kconfig | 28 +
drivers/gpu/drm/mediatek/Makefile | 13 +
drivers/gpu/drm/mediatek/mediatek_drm_crtc.c | 246 ++++
drivers/gpu/drm/mediatek/mediatek_drm_crtc.h | 80 ++
drivers/gpu/drm/mediatek/mediatek_drm_crtc_main.c | 420 ++++++
drivers/gpu/drm/mediatek/mediatek_drm_ddp.c | 202 +++
drivers/gpu/drm/mediatek/mediatek_drm_ddp.h | 23 +
drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.c | 346 +++++
drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.h | 33 +
drivers/gpu/drm/mediatek/mediatek_drm_drv.c | 369 ++++++
drivers/gpu/drm/mediatek/mediatek_drm_drv.h | 37 +
drivers/gpu/drm/mediatek/mediatek_drm_dsi.c | 1333 ++++++++++++++++++++
drivers/gpu/drm/mediatek/mediatek_drm_dsi.h | 71 ++
drivers/gpu/drm/mediatek/mediatek_drm_fb.c | 339 +++++
drivers/gpu/drm/mediatek/mediatek_drm_fb.h | 43 +
drivers/gpu/drm/mediatek/mediatek_drm_gem.c | 315 +++++
drivers/gpu/drm/mediatek/mediatek_drm_gem.h | 94 ++
include/uapi/drm/mediatek_drm.h | 59 +
24 files changed, 4161 insertions(+)
create mode 100644 Documentation/devicetree/bindings/drm/mediatek/mediatek,crtc-main.txt
create mode 100644 Documentation/devicetree/bindings/drm/mediatek/mediatek,ddp.txt
create mode 100644 Documentation/devicetree/bindings/drm/mediatek/mediatek,drm.txt
create mode 100644 Documentation/devicetree/bindings/drm/mediatek/mediatek,dsi.txt
create mode 100644 drivers/gpu/drm/mediatek/Kconfig
create mode 100644 drivers/gpu/drm/mediatek/Makefile
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_crtc.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_crtc.h
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_crtc_main.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_ddp.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_ddp.h
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.h
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_drv.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_drv.h
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_dsi.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_dsi.h
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_fb.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_fb.h
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_gem.c
create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_gem.h
create mode 100644 include/uapi/drm/mediatek_drm.h
--
1.8.1.1.dirty
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v8 14/16] ARM: dts: Introduce STM32F429 MCU
From: Daniel Thompson @ 2015-05-13 15:20 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Mark Rutland, linux-doc@vger.kernel.org, Linus Walleij,
Will Deacon, Stefan Agner, Nikolay Borisov, Peter Meerwald,
linux-api@vger.kernel.org, Lee Jones, Mauro Carvalho Chehab,
Kees Cook, Linux-Arch, Russell King, Jonathan Corbet, Jiri Slaby,
Daniel Lezcano, Chanwoo Choi, Andy Shevchenko, Antti Palosaari,
Geert Uytterhoeven, linux-serial@vger.kernel.org
In-Reply-To: <3125409.QXbEmPolyh@wuerfel>
On 13/05/15 14:27, Arnd Bergmann wrote:
> On Wednesday 13 May 2015 13:58:05 Daniel Thompson wrote:
>> On 13/05/15 12:45, Maxime Coquelin wrote:
>>> 2015-05-12 23:21 GMT+02:00 Arnd Bergmann <arnd@arndb.de>:
>>>> On Saturday 09 May 2015 09:53:56 Maxime Coquelin wrote:
>>>>> +#include <dt-bindings/mfd/stm32f4-rcc.h>
>>>>> +
>>>>>
>>>>
>>>> Can you find a way to avoid this dependency?
>>>>
>>>> Maybe you can change the bindings so that the numbers you pass as
>>>> arguments to the reset and clock specifiers reflect the numbers that
>>>> the hardware use?
>>>
>>> If I understand correctly, you prefer the way I did in v7 [0]?
>
> Yes, that looks better. I would probably not list all the possible
> values in the binding though, when the intention is to use the
> hardware specific values, and being able to reuse the binding
> and driver for variations of the same chip.
Indeed. It was that long list that originally provoked me to comment in
the first place.
>>> Note that doing that won't break the DT binary compatibility, as the
>>> raw reset values, or the ones from defines are the same.
>>>
>>> Daniel, could you share an example of the bindings you would use for the clocks?
>>
>> For the most cases, where there is a clock gate just before the
>> peripheral it looks pretty much like the reset driver and I use the bit
>> offset of the clock gating bit as the index.
>
> Is this bit always the same index as the one for the reset driver?
For the all reset bits:
clock idx = reset idx + 256
The opposite is not true; the clock bits are a superset of the reset
bits (the reset bits act on cells but some cells have >1 clock).
>> However there are a couple of clocks without gating just before the
>> clock reaches the peripheral:
>>
>> 1. A hard coded /8. I think this will have to be given a synthetic
>> number.
>
> If this is just a divider, why not use a separate DT node for that,
> like this:
>
> clock {
> compatible = "fixed-factor-clock";
> clocks = <&parentclk>;
> #clock-cells = <0>;
> clock-div = <8>;
> clock-mult = <1>;
> };
>
> No need to assign a number for this.
I'd wondered about doing that.
It will certainly work but it seemed a bit odd to me to have one (really
tiny) part of the RCC cell included seperately in the platform
description whilst all the complicated bits end up aggregated into the
RCC cell.
Is there much prior art that uses this type of trick to avoid having
magic numbers into the bindings?
>> 2. Ungated dividers. For these I am using the bit offset of the LSB of
>> the mux field.
>
> Do these ones also come with resets?
No. They mostly run to the core and its intimate peripherals (i.e. only
reset line comes from WDT).
>> So I think there is only one value that is completely unrelated to the
>> hardware and will use a magic constant instead.
>>
>> I had planned to macros similar to the STM32F4_AxB_RESET() family of
>> macros in both clk driver and DT in order to reuse the bit layouts from
>> dt-bindings/mfd/stm32f4-rcc.h .
>>
>> Normal case would have looked like this:
>>
>> timer3: timer@40000000 {
>> compatible = "st,stm32-timer";
>> reg = <0x40000000 0x400>;
>> interrupts = <28>;
>> resets = <&rcc STM32F4_APB1_RESET(TIM3)>;
>> clocks = <&rcc STM32F4_APB1_CLK(TIM3)>;
>> status = "disabled";
>> };
>>
>> Without the macros it looks like this:
>>
>> timer3: timer@40000000 {
>> compatible = "st,stm32-timer";
>> reg = <0x40000000 0x400>;
>> interrupts = <28>;
>> resets = <&rcc 257>;
>> clocks = <&rcc 513>;
>> status = "disabled";
>> };
>>
>> However we could perhaps be more literate even if we don't use the macros?
>>
>> timer3: timer@40000000 {
>> compatible = "st,stm32-timer";
>> reg = <0x40000000 0x400>;
>> interrupts = <28>;
>> resets = <&rcc ((0x20*8) + 1)>;
>> clocks = <&rcc ((0x40*8) + 1)>;
>> status = "disabled";
>> };
>
> How about #address-cells = <2>, so you can do
>
> resets = <&rcc 8 1>;
> clocks = <&rcc 8 1>;
>
> with the first cell being an index for the block and the second cell the
> bit number within that block.
That would suit me very well (although is the 0x20/0x40 not the 8 that
we would need in the middle column).
Maxime: Does that suit reset driver?
Daniel.
^ permalink raw reply
* Re: [PATCH RFC] vfs: add a O_NOMTIME flag
From: Austin S Hemmelgarn @ 2015-05-13 15:16 UTC (permalink / raw)
To: Dave Chinner
Cc: J. Bruce Fields, John Stoffel, Kevin Easton, Theodore Ts'o,
Sage Weil, Trond Myklebust, Zach Brown, Alexander Viro,
Linux FS-devel Mailing List, Linux Kernel Mailing List,
Linux API Mailing List
In-Reply-To: <20150512215145.GA4316@dastard>
[-- Attachment #1: Type: text/plain, Size: 5070 bytes --]
On 2015-05-12 17:51, Dave Chinner wrote:
> On Tue, May 12, 2015 at 10:53:29AM -0400, Austin S Hemmelgarn wrote:
>> On 2015-05-12 10:36, J. Bruce Fields wrote:
>>> On Tue, May 12, 2015 at 09:54:27AM -0400, John Stoffel wrote:
>>>>>>>>> "Austin" == Austin S Hemmelgarn <ahferroin7@gmail.com> writes:
>>>>
>>>> Austin> On 2015-05-12 01:08, Kevin Easton wrote:
>>>>>> On Mon, May 11, 2015 at 07:10:21PM -0400, Theodore Ts'o wrote:
>>>>>>> On Mon, May 11, 2015 at 09:24:09AM -0700, Sage Weil wrote:
>>>>>>>>> Let me re-ask the question that I asked last week (and was apparently
>>>>>>>>> ignored). Why not trying to use the lazytime feature instead of
>>>>>>>>> pointing a head straight at the application's --- and system
>>>>>>>>> administrators' --- heads?
>>>>>>>>
>>>>>>>> Sorry Ted, I thought I responded already.
>>>>>>>>
>>>>>>>> The goal is to avoid inode writeout entirely when we can, and
>>>>>>>> as I understand it lazytime will still force writeout before the inode
>>>>>>>> is dropped from the cache. In systems like Ceph in particular, the
>>>>>>>> IOs can be spread across lots of files, so simply deferring writeout
>>>>>>>> doesn't always help.
>>>>>>>
>>>>>>> Sure, but it would reduce the writeout by orders of magnitude. I can
>>>>>>> understand if you want to reduce it further, but it might be good
>>>>>>> enough for your purposes.
>>>>>>>
>>>>>>> I considered doing the equivalent of O_NOMTIME for our purposes at
>>>>>>> $WORK, and our use case is actually not that different from Ceph's
>>>>>>> (i.e., using a local disk file system to support a cluster file
>>>>>>> system), and lazytime was (a) something I figured was something I
>>>>>>> could upstream in good conscience, and (b) was more than good enough
>>>>>>> for us.
>>>>>>
>>>>>> A safer alternative might be a chattr file attribute that if set, the
>>>>>> mtime is not updated on writes, and stat() on the file always shows the
>>>>>> mtime as "right now". At least that way, the file won't accidentally
>>>>>> get left out of backups that rely on the mtime.
>>>>>>
>>>>>> (If the file attribute is unset, you immediately update the mtime then
>>>>>> too, and from then on the file is back to normal).
>>>>>>
>>>>
>>>> Austin> I like this even better than the flag suggestion, it provides
>>>> Austin> better control, means that you don't need to update
>>>> Austin> applications to get the benefits, and prevents backup software
>>>> Austin> from breaking (although backups would be bigger).
>>>>
>>>> Me too, it fails in a safer mode, where you do more work on backups
>>>> than strictly needed. I'm still against this as a mount option
>>>> though, way way way too many bullets in the foot gun. And as someone
>>>> else said, once you mount with O_NOMTIME, then unmount, then mount
>>>> again without O_NOMTIME, you've lost information. Not good.
>>>
>>> That was me. Zach also pointed out to me that'd mean figuring out where
>>> to store that information on-disk for every filesystem you care about.
>>> I like the idea of something persistent, but maybe it's more trouble
>>> than it's worth--I honestly don't know.
>>>
>> But if we do it as a flag controlled by the API used by chattr, it
>> becomes the responsibility of the filesystems to deal with where to
>> store the information, assuming they choose to support it;
>> personally, I would be really surprised if XFS and BTRFS didn't add
>> support for this relatively soon after the API getting merged
>> upstream, and ext4 would likely follow soon afterwards.
>
> It's an on-disk format change, which means that there are all sorts
> of compatibility issues to take into account, as well as all the
> work needed to teach the filesystem userspace tools about the new
> flag. e.g. xfs_repair, xfs_db, xfsdump/restore, xfs_io, test code in
> xfstests, etc.
>
> Keep in mind that the moment we make something persistent, the
> amount of work to implement and verify the new functionality
> filesystem to implement it goes up by an order of magnitude *for
> each filesystem*. IOWs, support of new features that require
> persistence don't just magically appear overnight...
>
I'm not saying that it will, and any sane way of safely implementing
this will _almost_ certainly need some kind of work done on the
filesystems themselves. My only point was that it would be simpler on
the VFS side of things than most of the other proposals so far.
Also, BTRFS at least won't (theoretically) need a format change for
this, as it could just be added to the property interface. As for the
other filesystems, it would probably be possible to re-purpose one of
the other bits for this, s (secure delete) and u (undeletion) are both
not honored by any filesystem in the kernel, and also not honored by any
other UNIX filesystem implementation that I know of; s would probably be
the better of the 2 to use for this, as it's currently assigned purpose
is functionally impossible to implement properly on modern hardware.
[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 2967 bytes --]
^ permalink raw reply
* Re: [PATCH 0/3] Allow user to request memory to be locked on page fault
From: Eric B Munson @ 2015-05-13 15:00 UTC (permalink / raw)
To: Michal Hocko
Cc: Andrew Morton, Shuah Khan, linux-alpha, linux-kernel, linux-mips,
linux-parisc, linuxppc-dev, sparclinux, linux-xtensa, linux-mm,
linux-arch, linux-api
In-Reply-To: <20150511180631.GA1227@akamai.com>
[-- Attachment #1: Type: text/plain, Size: 2108 bytes --]
On Mon, 11 May 2015, Eric B Munson wrote:
> On Fri, 08 May 2015, Andrew Morton wrote:
>
> > On Fri, 8 May 2015 15:33:43 -0400 Eric B Munson <emunson@akamai.com> wrote:
> >
> > > mlock() allows a user to control page out of program memory, but this
> > > comes at the cost of faulting in the entire mapping when it is
> > > allocated. For large mappings where the entire area is not necessary
> > > this is not ideal.
> > >
> > > This series introduces new flags for mmap() and mlockall() that allow a
> > > user to specify that the covered are should not be paged out, but only
> > > after the memory has been used the first time.
> >
> > Please tell us much much more about the value of these changes: the use
> > cases, the behavioural improvements and performance results which the
> > patchset brings to those use cases, etc.
> >
>
> To illustrate the proposed use case I wrote a quick program that mmaps
> a 5GB file which is filled with random data and accesses 150,000 pages
> from that mapping. Setup and processing were timed separately to
> illustrate the differences between the three tested approaches. the
> setup portion is simply the call to mmap, the processing is the
> accessing of the various locations in that mapping. The following
> values are in milliseconds and are the averages of 20 runs each with a
> call to echo 3 > /proc/sys/vm/drop_caches between each run.
>
> The first mapping was made with MAP_PRIVATE | MAP_LOCKED as a baseline:
> Startup average: 9476.506
> Processing average: 3.573
>
> The second mapping was simply MAP_PRIVATE but each page was passed to
> mlock() before being read:
> Startup average: 0.051
> Processing average: 721.859
>
> The final mapping was MAP_PRIVATE | MAP_LOCKONFAULT:
> Startup average: 0.084
> Processing average: 42.125
>
Michal's suggestion of changing protections and locking in a signal
handler was better than the locking as needed, but still significantly
more work required than the LOCKONFAULT case.
Startup average: 0.047
Processing average: 86.431
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH 1/2] mmap.2: clarify MAP_LOCKED semantic
From: Eric B Munson @ 2015-05-13 14:48 UTC (permalink / raw)
To: Michal Hocko
Cc: Michael Kerrisk, Andrew Morton, Linus Torvalds, David Rientjes,
LKML, Linux API, linux-mm-Bw31MaZKKs3YtjvyW6yDsg, Michal Hocko
In-Reply-To: <20150513144506.GD1227-JqFfY2XvxFXQT0dZR+AlfA@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 1829 bytes --]
On Wed, 13 May 2015, Eric B Munson wrote:
> On Wed, 13 May 2015, Michal Hocko wrote:
>
> > From: Michal Hocko <mhocko-AlSwsSmVLrQ@public.gmane.org>
> >
> > MAP_LOCKED had a subtly different semantic from mmap(2)+mlock(2) since
> > it has been introduced.
> > mlock(2) fails if the memory range cannot get populated to guarantee
> > that no future major faults will happen on the range. mmap(MAP_LOCKED) on
> > the other hand silently succeeds even if the range was populated only
> > partially.
> >
> > Fixing this subtle difference in the kernel is rather awkward because
> > the memory population happens after mm locks have been dropped and so
> > the cleanup before returning failure (munlock) could operate on something
> > else than the originally mapped area.
> >
> > E.g. speculative userspace page fault handler catching SEGV and doing
> > mmap(fault_addr, MAP_FIXED|MAP_LOCKED) might discard portion of a racing
> > mmap and lead to lost data. Although it is not clear whether such a
> > usage would be valid, mmap page doesn't explicitly describe requirements
> > for threaded applications so we cannot exclude this possibility.
> >
> > This patch makes the semantic of MAP_LOCKED explicit and suggest using
> > mmap + mlock as the only way to guarantee no later major page faults.
> >
> > Signed-off-by: Michal Hocko <mhocko-AlSwsSmVLrQ@public.gmane.org>
>
> Does the problem still happend when MAP_POPULATE | MAP_LOCKED is used
> (AFAICT MAP_POPULATE will cause the mmap to fail if all the pages cannot
> be made present).
>
> Either way this is a good catch.
>
> Acked-by: Eric B Munson <emunson-JqFfY2XvxFXQT0dZR+AlfA@public.gmane.org>
>
Sorry for the noise, this should have been a
Reviewed-by: Eric B Munson <emunson-JqFfY2XvxFXQT0dZR+AlfA@public.gmane.org>
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH 1/5] misc: Beaglebone capemanager
From: Geert Uytterhoeven @ 2015-05-13 14:47 UTC (permalink / raw)
To: Pantelis Antoniou
Cc: Greg Kroah-Hartman, Matt Porter, Koen Kooi, Robert Nelson,
Rob Herring, Grant Likely, Jonathan Corbet, Srinivas Kandagatla,
Guenter Roeck, Geert Uytterhoeven, Benoît Cousso,
linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-doc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Pantelis Antoniou
In-Reply-To: <1431503985-31853-2-git-send-email-pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
On Wed, May 13, 2015 at 9:59 AM, Pantelis Antoniou
<pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org> wrote:
> diff --git a/drivers/misc/bone_capemgr.c b/drivers/misc/bone_capemgr.c
> new file mode 100644
> index 0000000..423719c
> --- /dev/null
> +++ b/drivers/misc/bone_capemgr.c
> +static int capemgr_load_slot(struct bone_cape_slot *slot)
> +{
[...]
> + of_fdt_unflatten_tree((void *)slot->fw->data, &slot->overlay);
After "[PATCH] of/fdt: Make fdt blob input parameters of unflatten functions
const", you can remove the cast.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 2/2] mmap2: clarify MAP_POPULATE
From: Eric B Munson @ 2015-05-13 14:47 UTC (permalink / raw)
To: Michal Hocko
Cc: Michael Kerrisk, Andrew Morton, Linus Torvalds, David Rientjes,
LKML, Linux API, linux-mm-Bw31MaZKKs3YtjvyW6yDsg, Michal Hocko
In-Reply-To: <1431527892-2996-3-git-send-email-miso-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 614 bytes --]
On Wed, 13 May 2015, Michal Hocko wrote:
> From: Michal Hocko <mhocko-AlSwsSmVLrQ@public.gmane.org>
>
> David Rientjes has noticed that MAP_POPULATE wording might promise much
> more than the kernel actually provides and intend to provide. The
> primary usage of the flag is to pre-fault the range. There is no
> guarantee that no major faults will happen later on. The pages might
> have been reclaimed by the time the process tries to access them.
>
> Signed-off-by: Michal Hocko <mhocko-AlSwsSmVLrQ@public.gmane.org>
Reviewed-by: Eric B Munson <emunson-JqFfY2XvxFXQT0dZR+AlfA@public.gmane.org>
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH 1/2] mmap.2: clarify MAP_LOCKED semantic
From: Eric B Munson @ 2015-05-13 14:45 UTC (permalink / raw)
To: Michal Hocko
Cc: Michael Kerrisk, Andrew Morton, Linus Torvalds, David Rientjes,
LKML, Linux API, linux-mm, Michal Hocko
In-Reply-To: <1431527892-2996-2-git-send-email-miso@dhcp22.suse.cz>
[-- Attachment #1: Type: text/plain, Size: 1515 bytes --]
On Wed, 13 May 2015, Michal Hocko wrote:
> From: Michal Hocko <mhocko@suse.cz>
>
> MAP_LOCKED had a subtly different semantic from mmap(2)+mlock(2) since
> it has been introduced.
> mlock(2) fails if the memory range cannot get populated to guarantee
> that no future major faults will happen on the range. mmap(MAP_LOCKED) on
> the other hand silently succeeds even if the range was populated only
> partially.
>
> Fixing this subtle difference in the kernel is rather awkward because
> the memory population happens after mm locks have been dropped and so
> the cleanup before returning failure (munlock) could operate on something
> else than the originally mapped area.
>
> E.g. speculative userspace page fault handler catching SEGV and doing
> mmap(fault_addr, MAP_FIXED|MAP_LOCKED) might discard portion of a racing
> mmap and lead to lost data. Although it is not clear whether such a
> usage would be valid, mmap page doesn't explicitly describe requirements
> for threaded applications so we cannot exclude this possibility.
>
> This patch makes the semantic of MAP_LOCKED explicit and suggest using
> mmap + mlock as the only way to guarantee no later major page faults.
>
> Signed-off-by: Michal Hocko <mhocko@suse.cz>
Does the problem still happend when MAP_POPULATE | MAP_LOCKED is used
(AFAICT MAP_POPULATE will cause the mmap to fail if all the pages cannot
be made present).
Either way this is a good catch.
Acked-by: Eric B Munson <emunson@akamai.com>
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [RFC PATCH v5] Documentation/arch: Add Documentation/arch-TODO
From: Geert Uytterhoeven @ 2015-05-13 14:42 UTC (permalink / raw)
To: Michele Curti
Cc: Ingo Molnar, Andrew Morton, Jonathan Corbet, Peter Zijlstra,
Josh Triplett, Andy Lutomirski, Ingo Molnar, H. Peter Anvin,
Thomas Gleixner, Linus Torvalds, linux-api@vger.kernel.org,
linux-kernel@vger.kernel.org, the arch/x86 maintainers,
Linux-Arch, Borislav Petkov
In-Reply-To: <20150513140945.GA8376@dellaz>
On Wed, May 13, 2015 at 4:09 PM, Michele Curti <michele.curti@gmail.com> wrote:
> Tried to transpose rows with columns, to avoid architecture name duplication
> and to get only one table while keeping 80 char width, but result seems less
> readable :p
>
>
> m
> i u
> b c o n
> l h r m p p i
> a e o n e p o c x
> a a a c x m b 1 n n a w s s o t
> l r v k c a i m m e l m 0 i r r e s c p t r e
> p a a m r f c r f g a 3 6 t a i 3 o i i r 3 o a i e x n
> h r r 6 3 i 6 i r o 6 2 8 a z p 0 s s s p 9 r s r l u 3 8 s
> a c m 4 2 n x s v n 4 r k g e s 0 2 c c c 0 e h c e m 2 6 a
> -------------------------------------------------------------------------------
> lockdep T K K K K K T T T K T T T K K K T T T T K K K K K K K K K K
> stackprotector T T K K T T T T T T T T T T T K T T T T T T T K T T T T K T
> jump-labels T T K K T T T T T T T T T T T K T T T T K K T T K T T T K T
> seccomp-filter T T K K T T T T T T T T T T T K T T T T T K T T T T T T K T
I thought about that, too, as there are more (not fully implemented) features
than architectures. But I expect more merge conflicts with the transposed
version.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* [PATCH 2/2] mmap2: clarify MAP_POPULATE
From: Michal Hocko @ 2015-05-13 14:38 UTC (permalink / raw)
To: Michael Kerrisk
Cc: Andrew Morton, Linus Torvalds, David Rientjes, LKML, Linux API,
linux-mm, Michal Hocko
In-Reply-To: <1431527892-2996-1-git-send-email-miso@dhcp22.suse.cz>
From: Michal Hocko <mhocko@suse.cz>
David Rientjes has noticed that MAP_POPULATE wording might promise much
more than the kernel actually provides and intend to provide. The
primary usage of the flag is to pre-fault the range. There is no
guarantee that no major faults will happen later on. The pages might
have been reclaimed by the time the process tries to access them.
Signed-off-by: Michal Hocko <mhocko@suse.cz>
---
man2/mmap.2 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/man2/mmap.2 b/man2/mmap.2
index 1486be2e96b3..dcf306f2f730 100644
--- a/man2/mmap.2
+++ b/man2/mmap.2
@@ -284,7 +284,7 @@ private writable mappings.
.BR MAP_POPULATE " (since Linux 2.5.46)"
Populate (prefault) page tables for a mapping.
For a file mapping, this causes read-ahead on the file.
-Later accesses to the mapping will not be blocked by page faults.
+This will help to reduce blocking on page faults later.
.BR MAP_POPULATE
is supported for private mappings only since Linux 2.6.23.
.TP
--
2.1.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH 1/2] mmap.2: clarify MAP_LOCKED semantic
From: Michal Hocko @ 2015-05-13 14:38 UTC (permalink / raw)
To: Michael Kerrisk
Cc: Andrew Morton, Linus Torvalds, David Rientjes, LKML, Linux API,
linux-mm-Bw31MaZKKs3YtjvyW6yDsg, Michal Hocko
In-Reply-To: <1431527892-2996-1-git-send-email-miso-2MMpYkNvuYDjFM9bn6wA6Q@public.gmane.org>
From: Michal Hocko <mhocko-AlSwsSmVLrQ@public.gmane.org>
MAP_LOCKED had a subtly different semantic from mmap(2)+mlock(2) since
it has been introduced.
mlock(2) fails if the memory range cannot get populated to guarantee
that no future major faults will happen on the range. mmap(MAP_LOCKED) on
the other hand silently succeeds even if the range was populated only
partially.
Fixing this subtle difference in the kernel is rather awkward because
the memory population happens after mm locks have been dropped and so
the cleanup before returning failure (munlock) could operate on something
else than the originally mapped area.
E.g. speculative userspace page fault handler catching SEGV and doing
mmap(fault_addr, MAP_FIXED|MAP_LOCKED) might discard portion of a racing
mmap and lead to lost data. Although it is not clear whether such a
usage would be valid, mmap page doesn't explicitly describe requirements
for threaded applications so we cannot exclude this possibility.
This patch makes the semantic of MAP_LOCKED explicit and suggest using
mmap + mlock as the only way to guarantee no later major page faults.
Signed-off-by: Michal Hocko <mhocko-AlSwsSmVLrQ@public.gmane.org>
---
man2/mmap.2 | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/man2/mmap.2 b/man2/mmap.2
index 54d68cf87e9e..1486be2e96b3 100644
--- a/man2/mmap.2
+++ b/man2/mmap.2
@@ -235,8 +235,19 @@ See the Linux kernel source file
for further information.
.TP
.BR MAP_LOCKED " (since Linux 2.5.37)"
-Lock the pages of the mapped region into memory in the manner of
+Mark the mmaped region to be locked in the same way as
.BR mlock (2).
+This implementation will try to populate (prefault) the whole range but
+the mmap call doesn't fail with
+.B ENOMEM
+if this fails. Therefore major faults might happen later on. So the semantic
+is not as strong as
+.BR mlock (2).
+.BR mmap (2)
++
+.BR mlock (2)
+should be used when major faults are not acceptable after the initialization
+of the mapping.
This flag is ignored in older kernels.
.\" If set, the mapped pages will not be swapped out.
.TP
--
2.1.4
^ permalink raw reply related
* [PATCH 0/2] man-pages: clarify MAP_LOCKED semantic
From: Michal Hocko @ 2015-05-13 14:38 UTC (permalink / raw)
To: Michael Kerrisk
Cc: Andrew Morton, Linus Torvalds, David Rientjes, LKML, Linux API,
linux-mm
Hi,
during the previous discussion http://marc.info/?l=linux-mm&m=143022313618001&w=2
it was made clear that making mmap(MAP_LOCKED) semantic really have
mlock() semantic is too dangerous. Even though we can try to reduce the
failure space the mmap man page should make it really clear about the
subtle distinctions between the two. This is what that first patch does.
The second patch is a small clarification for MAP_POPULATE based on
David Rientjes feedback.
^ permalink raw reply
* Re: [PATCH 0/3] Allow user to request memory to be locked on page fault
From: Eric B Munson @ 2015-05-13 14:14 UTC (permalink / raw)
To: Michal Hocko
Cc: Andrew Morton, Shuah Khan, linux-alpha, linux-kernel, linux-mips,
linux-parisc, linuxppc-dev, sparclinux, linux-xtensa, linux-mm,
linux-arch, linux-api
In-Reply-To: <20150513135805.GA17708@dhcp22.suse.cz>
[-- Attachment #1: Type: text/plain, Size: 2818 bytes --]
On Wed, 13 May 2015, Michal Hocko wrote:
> On Fri 08-05-15 16:06:10, Eric B Munson wrote:
> > On Fri, 08 May 2015, Andrew Morton wrote:
> >
> > > On Fri, 8 May 2015 15:33:43 -0400 Eric B Munson <emunson@akamai.com> wrote:
> > >
> > > > mlock() allows a user to control page out of program memory, but this
> > > > comes at the cost of faulting in the entire mapping when it is
> > > > allocated. For large mappings where the entire area is not necessary
> > > > this is not ideal.
> > > >
> > > > This series introduces new flags for mmap() and mlockall() that allow a
> > > > user to specify that the covered are should not be paged out, but only
> > > > after the memory has been used the first time.
> > >
> > > Please tell us much much more about the value of these changes: the use
> > > cases, the behavioural improvements and performance results which the
> > > patchset brings to those use cases, etc.
> > >
> >
> > The primary use case is for mmaping large files read only. The process
> > knows that some of the data is necessary, but it is unlikely that the
> > entire file will be needed. The developer only wants to pay the cost to
> > read the data in once. Unfortunately developer must choose between
> > allowing the kernel to page in the memory as needed and guaranteeing
> > that the data will only be read from disk once. The first option runs
> > the risk of having the memory reclaimed if the system is under memory
> > pressure, the second forces the memory usage and startup delay when
> > faulting in the entire file.
>
> Is there any reason you cannot do this from the userspace? Start by
> mmap(PROT_NONE) and do mmap(MAP_FIXED|MAP_LOCKED|MAP_READ|other_flags_you_need)
> from the SIGSEGV handler?
> You can generate a lot of vmas that way but you can mitigate that to a
> certain level by mapping larger than PAGE_SIZE chunks in the fault
> handler. Would that work in your usecase?
This might work for the use cases I have laid out (I am not sure about
the anonymous mmap one, but I will try it). I am concerned about how
much memory management policy these suggestions push into userspace.
I am also concerned about the number of system calls required to do the
same thing. This will require a new call to mmap() for every new page
accessed in the file (or for every file_size/map_size in the multiple
page chunk). The simple case of calling mlock() on the every time the
file was accessed was significantly slower than the LOCKONFAULT flag.
Your suggestion will be better in that it avoids the extra mlock call
for pages already locked, but there still significantly more system
calls. I will add this to the program I have been using to measure
executuion times and see how it compares to the other options.
Eric
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [RFC PATCH v5] Documentation/arch: Add Documentation/arch-TODO
From: Michele Curti @ 2015-05-13 14:09 UTC (permalink / raw)
To: Ingo Molnar
Cc: Andrew Morton, Jonathan Corbet, Peter Zijlstra, Josh Triplett,
Andy Lutomirski, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Linus Torvalds, linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, x86-DgEjT+Ai2ygdnm+yROfE0A,
linux-arch-u79uwXL29TY76Z2rM5mHXA, Borislav Petkov
In-Reply-To: <20150513094756.GD11030-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Wed, May 13, 2015 at 11:47:56AM +0200, Ingo Molnar wrote:
>
> (fixed the subject.)
>
> So this is the final version for now:
>
> - add a fourth table
>
> - fix errors in earlier tables, in particular I missed some PowerPC
> Kconfigs
>
> - introduce the '..' denotion (in the final table) to show features
> that cannot be supported by an architecture due to hardware
> dependencies:
>
> gcov-profile-all:---------------.
> THP:--------. |
> irq-time-acct:-. | |
> | | |
> ----------------------------------------
> alpha | TODO | TODO | TODO |
> arc | TODO | .. | TODO |
> arm | ok | ok | ok |
> arm64 | TODO | ok | ok |
> avr32 | TODO | .. | TODO |
> blackfin | TODO | .. | TODO |
> c6x | TODO | .. | TODO |
>
> so in the 'THP' column, if an architecture could in theory support
> THP, it's listed as 'TODO', if it cannot, it's listed as '..'.
>
> Please let me know about errors in these tables, and I can also add
> more features/facilities as well if I missed any.
>
> Thanks,
>
Tried to transpose rows with columns, to avoid architecture name duplication
and to get only one table while keeping 80 char width, but result seems less
readable :p
m
i u
b c o n
l h r m p p i
a e o n e p o c x
a a a c x m b 1 n n a w s s o t
l r v k c a i m m e l m 0 i r r e s c p t r e
p a a m r f c r f g a 3 6 t a i 3 o i i r 3 o a i e x n
h r r 6 3 i 6 i r o 6 2 8 a z p 0 s s s p 9 r s r l u 3 8 s
a c m 4 2 n x s v n 4 r k g e s 0 2 c c c 0 e h c e m 2 6 a
-------------------------------------------------------------------------------
lockdep T K K K K K T T T K T T T K K K T T T T K K K K K K K K K K
stackprotector T T K K T T T T T T T T T T T K T T T T T T T K T T T T K T
jump-labels T T K K T T T T T T T T T T T K T T T T K K T T K T T T K T
seccomp-filter T T K K T T T T T T T T T T T K T T T T T K T T T T T T K T
context-tracking T T K K T T T T T T T T T T T K T T T T K T T T K K T T K T
kgdb T K K K T K T T T K T T T T K K K K T T K T T K K K T T K T
modern-timekeeping K K T K K T K T K K K T T K K K K K K K K K K K K K K K K K
clockevents K K K K K K K K T K T T K K K K K K K T K K K K K K K K K K
ELF-ASLR T T K K T T T T T T T T T T T K T T T T K K T T T T T T K T
arch-tick-broadcast T T K K T T T T T T T T T T T K T T T T K T T T T T T T T T
kprobes T K K T K T T T T T K T T T T K T T T T K K T K K K T T K T
optprobes T T K T T T T T T T T T T T T T T T T T T T T T T K T T K T
kprobes-on-ftrace T T T T T T T T T T T T T T T T T T T T T T T T T T T T K T
uprobes T T K T T T T T T T T T T T T T T T T T K K T T T T T T K T
kretprobes T K K T T T T T T T K T T T T K T T T T K K T K K K T T K T
user-ret-profiler T T T T T T T T T T T T T T T T T T T T T T T T T K T T K T
ioremap_prot() T K T T T T T T T T T T T T T T T T T T K T T K T K T T K T
tracehook T K K K T K K T K K K T T K T K K K K T K K T K K K T T K T
generic-idle-thread K K K K T K T T T K K T T K T K T T T K K K T K K T T T K K
dma_*map*_attrs() K T K K T T T T T K K T T T K K T T K T K K T K K K T K K T
dma-contiguous T T K K T T T T T T T T T T T K T T T T T T T T T T T T K T
kprobes-event T T K T T T T T T K T T T T T T T T T T K K T K T K T T K T
dma-api-debug T T K K T T K T T T K T T T K K T T T T K K T K K K T T K T
perf-regs T T K K T T T T T T T T T T T T T T T T T T T T T T T T K T
perf-stackdump T T K K T T T T T T T T T T T T T T T T T T T T T T T T K T
cmpxchg-local T T T T T T T T T T T T T T T T T T T T T K T T T T T T K T
virt-cpuacct K T K K T T T T T T K T T T T K T T T K K K T T K K T T K T
irq-time-acct T T K T T T T T T T T T T T T K T T T T T T T T T T T T K K
THP T - K K - - - - - - T - - - - K - - - T K K - - K T - - K -
gcov-profile-all T T K K T T T T T T T T T T K T T T T T K K T K T T T T K T
Legend:
K = ok
T = TODO
- = cannot
Michele
^ permalink raw reply
* Re: [PATCH 0/3] Allow user to request memory to be locked on page fault
From: Michal Hocko @ 2015-05-13 13:58 UTC (permalink / raw)
To: Eric B Munson
Cc: Andrew Morton, Shuah Khan, linux-alpha, linux-kernel, linux-mips,
linux-parisc, linuxppc-dev, sparclinux, linux-xtensa, linux-mm,
linux-arch, linux-api
In-Reply-To: <20150508200610.GB29933@akamai.com>
On Fri 08-05-15 16:06:10, Eric B Munson wrote:
> On Fri, 08 May 2015, Andrew Morton wrote:
>
> > On Fri, 8 May 2015 15:33:43 -0400 Eric B Munson <emunson@akamai.com> wrote:
> >
> > > mlock() allows a user to control page out of program memory, but this
> > > comes at the cost of faulting in the entire mapping when it is
> > > allocated. For large mappings where the entire area is not necessary
> > > this is not ideal.
> > >
> > > This series introduces new flags for mmap() and mlockall() that allow a
> > > user to specify that the covered are should not be paged out, but only
> > > after the memory has been used the first time.
> >
> > Please tell us much much more about the value of these changes: the use
> > cases, the behavioural improvements and performance results which the
> > patchset brings to those use cases, etc.
> >
>
> The primary use case is for mmaping large files read only. The process
> knows that some of the data is necessary, but it is unlikely that the
> entire file will be needed. The developer only wants to pay the cost to
> read the data in once. Unfortunately developer must choose between
> allowing the kernel to page in the memory as needed and guaranteeing
> that the data will only be read from disk once. The first option runs
> the risk of having the memory reclaimed if the system is under memory
> pressure, the second forces the memory usage and startup delay when
> faulting in the entire file.
Is there any reason you cannot do this from the userspace? Start by
mmap(PROT_NONE) and do mmap(MAP_FIXED|MAP_LOCKED|MAP_READ|other_flags_you_need)
from the SIGSEGV handler?
You can generate a lot of vmas that way but you can mitigate that to a
certain level by mapping larger than PAGE_SIZE chunks in the fault
handler. Would that work in your usecase?
--
Michal Hocko
SUSE Labs
^ permalink raw reply
* [RFC PATCH v6] Documentation/arch: Add Documentation/arch-features.txt
From: Ingo Molnar @ 2015-05-13 13:48 UTC (permalink / raw)
To: Borislav Petkov
Cc: Andrew Morton, Jonathan Corbet, Peter Zijlstra, Josh Triplett,
Andy Lutomirski, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Linus Torvalds, linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, x86-DgEjT+Ai2ygdnm+yROfE0A,
linux-arch-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150513131835.GJ1517-fF5Pk5pvG8Y@public.gmane.org>
* Borislav Petkov <bp-Gina5bIWoIWzQB+pC5nmwQ@public.gmane.org> wrote:
> On Wed, May 13, 2015 at 11:47:56AM +0200, Ingo Molnar wrote:
> > - introduce the '..' denotion (in the final table) to show features
> > that cannot be supported by an architecture due to hardware
> > dependencies:
> >
> > gcov-profile-all:---------------.
> > THP:--------. |
> > irq-time-acct:-. | |
> > | | |
> > ----------------------------------------
> > alpha | TODO | TODO | TODO |
> > arc | TODO | .. | TODO |
> > arm | ok | ok | ok |
> > arm64 | TODO | ok | ok |
> > avr32 | TODO | .. | TODO |
> > blackfin | TODO | .. | TODO |
> > c6x | TODO | .. | TODO |
> >
> > so in the 'THP' column, if an architecture could in theory support
> > THP, it's listed as 'TODO', if it cannot, it's listed as '..'.
>
> Shouldn't exactly that explanation be in the text file itself too?
Yeah, indeed, added it.
> Also, how about s/TODO//g for less clutter:
No, I'd like there to be a very visible 'TODO' item for missing
features.
The 'clutter' shows how badly our generic kernel features are
propagating :-/ We hope to reduce this clutter in the future.
Updated patch attached - I've added a few more features to the last
table, and restructured the explanations, now every feature
description also lists the Kconfig variable that it's tracking, e.g.:
irq time acct: HAVE_IRQ_TIME_ACCOUNTING
THP: HAVE_ARCH_TRANSPARENT_HUGEPAGE && 64BIT
gcov profile all: ARCH_HAS_GCOV_PROFILE_ALL
rwsem optimized: Optimized asm/rwsem.h
queued spinlocks: ARCH_USE_QUEUED_SPINLOCKS
queued rwlocks: ARCH_USE_QUEUED_RWLOCKS
numa balancing: ARCH_SUPPORTS_NUMA_BALANCING && 64BIT && NUMA
Thanks,
Ingo
=========================================>
>From 93f6bd67b4348bf4bf27cbac8ffa9f1def4fa6aa Mon Sep 17 00:00:00 2001
From: Ingo Molnar <mingo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Date: Wed, 13 May 2015 10:30:11 +0200
Subject: [PATCH] Documentation/arch: Add Documentation/arch-features.txt
Add a support matrix for various generic kernel features that need
architecture support.
Signed-off-by: Ingo Molnar <mingo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
Documentation/arch-features.txt | 222 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 222 insertions(+)
diff --git a/Documentation/arch-features.txt b/Documentation/arch-features.txt
new file mode 100644
index 000000000000..4f6430bc552b
--- /dev/null
+++ b/Documentation/arch-features.txt
@@ -0,0 +1,222 @@
+
+For generic kernel features that need architecture support, this is
+the feature support matrix, for all upstream Linux architectures.
+
+Meaning of entries in the tables:
+
+ ' ok ': feature supported by the architecture
+ 'TODO': feature not yet supported by the architecture
+ ' .. ': feature cannot be supported by the hardware
+
+
+
+ lockdep: LOCKDEP_SUPPORT
+ stackprotector: HAVE_CC_STACKPROTECTOR
+ jump labels: HAVE_ARCH_JUMP_LABEL
+ seccomp filter: HAVE_ARCH_SECCOMP_FILTER
+ context tracking: HAVE_CONTEXT_TRACKING
+ kgdb: HAVE_ARCH_KGDB
+ modern timekeeping: !ARCH_USES_GETTIMEOFFSET
+ clockevents: GENERIC_CLOCKEVENTS
+ ELF ASLR: ARCH_HAS_ELF_RANDOMIZE
+
+ lockdep:---------------------------------------------------------.
+ stackprotector:--------------------------------------------------. |
+ jump labels:-------------------------------------------. | |
+ seccomp filter:------------------------------------. | | |
+ context tracking:-----------------------------. | | | |
+ kgdb:----------------------. | | | | |
+ modern timekeeping:---------------. | | | | | |
+ clockevents:--------. | | | | | | |
+ ELF ASLR:-. | | | | | | | |
+ | | | | | | | | |
+----------------------------------------------------------------------------------
+ alpha | TODO | ok | ok | TODO | TODO | TODO | TODO | TODO | TODO |
+ arc | TODO | ok | ok | ok | TODO | TODO | TODO | TODO | ok |
+ arm | ok | ok | TODO | ok | ok | ok | ok | ok | ok |
+ arm64 | ok | ok | ok | ok | ok | ok | ok | ok | ok |
+ avr32 | TODO | ok | ok | TODO | TODO | TODO | TODO | TODO | ok |
+ blackfin | TODO | ok | TODO | ok | TODO | TODO | TODO | TODO | ok |
+ c6x | TODO | ok | ok | TODO | TODO | TODO | TODO | TODO | TODO |
+ cris | TODO | ok | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ frv | TODO | TODO | ok | TODO | TODO | TODO | TODO | TODO | TODO |
+ hexagon | TODO | ok | ok | ok | TODO | TODO | TODO | TODO | ok |
+ ia64 | TODO | TODO | ok | TODO | TODO | TODO | TODO | TODO | TODO |
+ m32r | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ m68k | TODO | ok | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ metag | TODO | ok | ok | TODO | TODO | TODO | TODO | TODO | ok |
+ microblaze | TODO | ok | ok | ok | TODO | TODO | TODO | TODO | ok |
+ mips | ok | ok | ok | ok | ok | ok | ok | ok | ok |
+ mn10300 | TODO | ok | ok | ok | TODO | TODO | TODO | TODO | TODO |
+ nios2 | TODO | ok | ok | ok | TODO | TODO | TODO | TODO | TODO |
+ openrisc | TODO | ok | ok | TODO | TODO | TODO | TODO | TODO | TODO |
+ parisc | TODO | TODO | ok | TODO | TODO | TODO | TODO | TODO | TODO |
+ powerpc | ok | ok | ok | ok | ok | TODO | ok | TODO | ok |
+ s390 | ok | ok | ok | TODO | TODO | ok | ok | TODO | ok |
+ score | TODO | ok | ok | TODO | TODO | TODO | TODO | TODO | ok |
+ sh | TODO | ok | ok | ok | TODO | TODO | TODO | ok | ok |
+ sparc | TODO | ok | ok | ok | ok | TODO | ok | TODO | ok |
+ tile | TODO | ok | ok | ok | ok | TODO | TODO | TODO | ok |
+ um | TODO | ok | ok | TODO | TODO | TODO | TODO | TODO | ok |
+ unicore32 | TODO | ok | ok | TODO | TODO | TODO | TODO | TODO | ok |
+ x86 | ok | ok | ok | ok | ok | ok | ok | ok | ok |
+ xtensa | TODO | ok | ok | TODO | TODO | TODO | TODO | TODO | ok |
+----------------------------------------------------------------------------------
+
+
+arch tick broadcast: ARCH_HAS_TICK_BROADCAST
+ kprobes: HAVE_KPROBES
+ optprobes: HAVE_OPTPROBES
+ kprobes on ftrace: HAVE_KPROBES_ON_FTRACE
+ uprobes: ARCH_SUPPORTS_UPROBES
+ kretprobes: HAVE_KRETPROBES
+ user ret profiler: HAVE_USER_RETURN_NOTIFIER
+ ioremap_prot(): HAVE_IOREMAP_PROT
+ tracehook: HAVE_ARCH_TRACEHOOK
+
+arch tick broadcast:---------------------------------------------------------.
+ kprobes:--------------------------------------------------. |
+ optprobes:-------------------------------------------. | |
+ kprobes on ftrace:------------------------------------. | | |
+ uprobes:-----------------------------. | | | |
+ kretprobes:----------------------. | | | | |
+ user ret profiler:---------------. | | | | | |
+ ioremap_prot():--------. | | | | | | |
+ tracehook:-. | | | | | | | |
+ | | | | | | | | |
+----------------------------------------------------------------------------------
+ alpha | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ arc | ok | ok | TODO | ok | TODO | TODO | TODO | ok | TODO |
+ arm | ok | TODO | TODO | ok | ok | TODO | ok | ok | ok |
+ arm64 | ok | TODO | TODO | TODO | TODO | TODO | TODO | TODO | ok |
+ avr32 | TODO | TODO | TODO | TODO | TODO | TODO | TODO | ok | TODO |
+ blackfin | ok | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ c6x | ok | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ cris | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ frv | ok | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ hexagon | ok | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ ia64 | ok | TODO | TODO | ok | TODO | TODO | TODO | ok | TODO |
+ m32r | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ m68k | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ metag | ok | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ microblaze | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ mips | ok | TODO | TODO | ok | TODO | TODO | TODO | ok | ok |
+ mn10300 | ok | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ nios2 | ok | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ openrisc | ok | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ parisc | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ powerpc | ok | ok | TODO | ok | ok | TODO | TODO | ok | ok |
+ s390 | ok | TODO | TODO | ok | ok | TODO | TODO | ok | TODO |
+ score | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ sh | ok | ok | TODO | ok | TODO | TODO | TODO | ok | TODO |
+ sparc | ok | TODO | TODO | ok | TODO | TODO | TODO | ok | TODO |
+ tile | ok | ok | ok | ok | TODO | TODO | ok | ok | TODO |
+ um | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ unicore32 | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ x86 | ok | ok | ok | ok | ok | ok | ok | ok | TODO |
+ xtensa | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+----------------------------------------------------------------------------------
+
+
+generic idle thread: GENERIC_SMP_IDLE_THREAD
+ dma_*map*_attrs(): HAVE_DMA_ATTRS
+ dma contiguous: HAVE_DMA_CONTIGUOUS
+ kprobes event: HAVE_REGS_AND_STACK_ACCESS_API
+ dma api debug: HAVE_DMA_API_DEBUG
+ perf regs: HAVE_PERF_REGS
+ perf stackdump: HAVE_PERF_USER_STACK_DUMP
+ cmpxchg local: HAVE_CMPXCHG_LOCAL
+ virt cpuacct: HAVE_VIRT_CPU_ACCOUNTING || 64BIT
+
+generic idle thread:---------------------------------------------------------.
+ dma_*map*_attrs():--------------------------------------------------. |
+ dma contiguous:-------------------------------------------. | |
+ kprobes event:------------------------------------. | | |
+ dma api debug:-----------------------------. | | | |
+ perf regs:----------------------. | | | | |
+ perf stackdump:---------------. | | | | | |
+ cmpxchg local:--------. | | | | | | |
+ virt cpuacct:-. | | | | | | | |
+ | | | | | | | | |
+----------------------------------------------------------------------------------
+ alpha | ok | TODO | TODO | TODO | TODO | TODO | TODO | ok | ok |
+ arc | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | ok |
+ arm | ok | TODO | ok | ok | ok | ok | ok | ok | ok |
+ arm64 | ok | TODO | ok | ok | ok | TODO | ok | ok | ok |
+ avr32 | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ blackfin | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | ok |
+ c6x | TODO | TODO | TODO | TODO | ok | TODO | TODO | TODO | TODO |
+ cris | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ frv | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ hexagon | TODO | TODO | TODO | TODO | TODO | ok | TODO | ok | ok |
+ ia64 | ok | TODO | TODO | TODO | ok | TODO | TODO | ok | ok |
+ m32r | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ m68k | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ metag | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | ok |
+ microblaze | TODO | TODO | TODO | TODO | ok | TODO | TODO | ok | TODO |
+ mips | ok | TODO | TODO | TODO | ok | TODO | ok | ok | ok |
+ mn10300 | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ nios2 | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ openrisc | TODO | TODO | TODO | TODO | TODO | TODO | TODO | ok | TODO |
+ parisc | ok | TODO | TODO | TODO | TODO | TODO | TODO | TODO | ok |
+ powerpc | ok | TODO | TODO | TODO | ok | ok | TODO | ok | ok |
+ s390 | ok | ok | TODO | TODO | ok | ok | TODO | ok | ok |
+ score | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ sh | TODO | TODO | TODO | TODO | ok | ok | TODO | ok | ok |
+ sparc | ok | TODO | TODO | TODO | ok | TODO | TODO | ok | ok |
+ tile | ok | TODO | TODO | TODO | ok | ok | TODO | ok | TODO |
+ um | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ unicore32 | TODO | TODO | TODO | TODO | TODO | TODO | TODO | ok | TODO |
+ x86 | ok | ok | ok | ok | ok | ok | ok | ok | ok |
+ xtensa | TODO | TODO | TODO | TODO | TODO | TODO | TODO | TODO | ok |
+----------------------------------------------------------------------------------
+
+
+ irq time acct: HAVE_IRQ_TIME_ACCOUNTING
+ THP: HAVE_ARCH_TRANSPARENT_HUGEPAGE && 64BIT
+ gcov profile all: ARCH_HAS_GCOV_PROFILE_ALL
+ rwsem optimized: Optimized asm/rwsem.h
+ queued spinlocks: ARCH_USE_QUEUED_SPINLOCKS
+ queued rwlocks: ARCH_USE_QUEUED_RWLOCKS
+ numa balancing: ARCH_SUPPORTS_NUMA_BALANCING && 64BIT && NUMA
+
+ irq time acct:-------------------------------------------.
+ THP:------------------------------------. |
+ gcov profile all:-----------------------------. | |
+ rwsem optimized:----------------------. | | |
+ queued spinlocks:---------------. | | | |
+ queued rwlocks:--------. | | | | |
+ numa balancing:-. | | | | | |
+ | | | | | | |
+--------------------------------------------------------------------
+ alpha | TODO | TODO | TODO | ok | TODO | TODO | TODO |
+ arc | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ arm | .. | TODO | TODO | TODO | ok | ok | ok |
+ arm64 | .. | TODO | TODO | TODO | ok | ok | TODO |
+ avr32 | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ blackfin | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ c6x | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ cris | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ frv | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ hexagon | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ ia64 | TODO | TODO | TODO | ok | TODO | TODO | TODO |
+ m32r | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ m68k | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ metag | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ microblaze | .. | TODO | TODO | TODO | ok | .. | TODO |
+ mips | TODO | TODO | TODO | TODO | TODO | ok | ok |
+ mn10300 | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ nios2 | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ openrisc | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ parisc | .. | TODO | TODO | TODO | TODO | TODO | TODO |
+ powerpc | ok | TODO | TODO | TODO | ok | ok | TODO |
+ s390 | .. | TODO | TODO | ok | ok | ok | TODO |
+ score | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ sh | .. | TODO | TODO | ok | ok | .. | TODO |
+ sparc | TODO | TODO | TODO | ok | TODO | ok | TODO |
+ tile | TODO | TODO | TODO | TODO | TODO | TODO | TODO |
+ um | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ unicore32 | .. | TODO | TODO | TODO | TODO | .. | TODO |
+ x86 | ok | ok | ok | ok | ok | ok | ok |
+ xtensa | .. | TODO | TODO | ok | TODO | .. | ok |
+--------------------------------------------------------------------
^ permalink raw reply related
* Re: [PATCH v8 14/16] ARM: dts: Introduce STM32F429 MCU
From: Arnd Bergmann @ 2015-05-13 13:27 UTC (permalink / raw)
To: Daniel Thompson
Cc: Maxime Coquelin, Uwe Kleine-König, Andreas Färber,
Geert Uytterhoeven, Rob Herring, Philipp Zabel, Linus Walleij,
Stefan Agner, Peter Meerwald, Paul Bolle, Peter Hurley,
Andy Shevchenko, Chanwoo Choi, Russell King, Daniel Lezcano,
Joe Perches, Vladimir Zapolskiy, Lee Jones, Jonathan Corbet,
Pawel Moll, Mark Rutland
In-Reply-To: <55534A5D.6050904@linaro.org>
On Wednesday 13 May 2015 13:58:05 Daniel Thompson wrote:
> On 13/05/15 12:45, Maxime Coquelin wrote:
> > 2015-05-12 23:21 GMT+02:00 Arnd Bergmann <arnd@arndb.de>:
> >> On Saturday 09 May 2015 09:53:56 Maxime Coquelin wrote:
> >>> +#include <dt-bindings/mfd/stm32f4-rcc.h>
> >>> +
> >>>
> >>
> >> Can you find a way to avoid this dependency?
> >>
> >> Maybe you can change the bindings so that the numbers you pass as
> >> arguments to the reset and clock specifiers reflect the numbers that
> >> the hardware use?
> >
> > If I understand correctly, you prefer the way I did in v7 [0]?
Yes, that looks better. I would probably not list all the possible
values in the binding though, when the intention is to use the
hardware specific values, and being able to reuse the binding
and driver for variations of the same chip.
> > Note that doing that won't break the DT binary compatibility, as the
> > raw reset values, or the ones from defines are the same.
> >
> > Daniel, could you share an example of the bindings you would use for the clocks?
>
> For the most cases, where there is a clock gate just before the
> peripheral it looks pretty much like the reset driver and I use the bit
> offset of the clock gating bit as the index.
Is this bit always the same index as the one for the reset driver?
> However there are a couple of clocks without gating just before the
> clock reaches the peripheral:
>
> 1. A hard coded /8. I think this will have to be given a synthetic
> number.
If this is just a divider, why not use a separate DT node for that,
like this:
clock {
compatible = "fixed-factor-clock";
clocks = <&parentclk>;
#clock-cells = <0>;
clock-div = <8>;
clock-mult = <1>;
};
No need to assign a number for this.
> 2. Ungated dividers. For these I am using the bit offset of the LSB of
> the mux field.
Do these ones also come with resets?
> So I think there is only one value that is completely unrelated to the
> hardware and will use a magic constant instead.
>
> I had planned to macros similar to the STM32F4_AxB_RESET() family of
> macros in both clk driver and DT in order to reuse the bit layouts from
> dt-bindings/mfd/stm32f4-rcc.h .
>
> Normal case would have looked like this:
>
> timer3: timer@40000000 {
> compatible = "st,stm32-timer";
> reg = <0x40000000 0x400>;
> interrupts = <28>;
> resets = <&rcc STM32F4_APB1_RESET(TIM3)>;
> clocks = <&rcc STM32F4_APB1_CLK(TIM3)>;
> status = "disabled";
> };
>
> Without the macros it looks like this:
>
> timer3: timer@40000000 {
> compatible = "st,stm32-timer";
> reg = <0x40000000 0x400>;
> interrupts = <28>;
> resets = <&rcc 257>;
> clocks = <&rcc 513>;
> status = "disabled";
> };
>
> However we could perhaps be more literate even if we don't use the macros?
>
> timer3: timer@40000000 {
> compatible = "st,stm32-timer";
> reg = <0x40000000 0x400>;
> interrupts = <28>;
> resets = <&rcc ((0x20*8) + 1)>;
> clocks = <&rcc ((0x40*8) + 1)>;
> status = "disabled";
> };
How about #address-cells = <2>, so you can do
resets = <&rcc 8 1>;
clocks = <&rcc 8 1>;
with the first cell being an index for the block and the second cell the
bit number within that block.
Arnd
^ permalink raw reply
* Re: [RFC PATCH v5] Documentation/arch: Add Documentation/arch-TODO
From: Borislav Petkov @ 2015-05-13 13:18 UTC (permalink / raw)
To: Ingo Molnar
Cc: Andrew Morton, Jonathan Corbet, Peter Zijlstra, Josh Triplett,
Andy Lutomirski, Ingo Molnar, H. Peter Anvin, Thomas Gleixner,
Linus Torvalds, linux-api, linux-kernel, x86, linux-arch
In-Reply-To: <20150513094756.GD11030@gmail.com>
On Wed, May 13, 2015 at 11:47:56AM +0200, Ingo Molnar wrote:
> - introduce the '..' denotion (in the final table) to show features
> that cannot be supported by an architecture due to hardware
> dependencies:
>
> gcov-profile-all:---------------.
> THP:--------. |
> irq-time-acct:-. | |
> | | |
> ----------------------------------------
> alpha | TODO | TODO | TODO |
> arc | TODO | .. | TODO |
> arm | ok | ok | ok |
> arm64 | TODO | ok | ok |
> avr32 | TODO | .. | TODO |
> blackfin | TODO | .. | TODO |
> c6x | TODO | .. | TODO |
>
> so in the 'THP' column, if an architecture could in theory support
> THP, it's listed as 'TODO', if it cannot, it's listed as '..'.
Shouldn't exactly that explanation be in the text file itself too?
Also, how about s/TODO//g for less clutter:
+----------------------------------------------------------------------------------
+ alpha | | | | | | | ok | ok | |
+ arc | ok | | | | | ok | ok | ok | |
+ arm | ok | ok | ok | ok | ok | ok | | ok | ok |
...
--
Regards/Gruss,
Boris.
ECO tip #101: Trim your mails when you reply.
--
^ permalink raw reply
* Re: [PATCH v8 14/16] ARM: dts: Introduce STM32F429 MCU
From: Daniel Thompson @ 2015-05-13 12:58 UTC (permalink / raw)
To: Maxime Coquelin, Arnd Bergmann
Cc: Uwe Kleine-König, Andreas Färber, Geert Uytterhoeven,
Rob Herring, Philipp Zabel, Linus Walleij, Stefan Agner,
Peter Meerwald, Paul Bolle, Peter Hurley, Andy Shevchenko,
Chanwoo Choi, Russell King, Daniel Lezcano, Joe Perches,
Vladimir Zapolskiy, Lee Jones, Jonathan Corbet, Pawel Moll,
Mark Rutland, Ian Campbell
In-Reply-To: <CALszF6CS8Q9DWX+ERtu=k=Bzr1-25N3oZQyWyxDZBF3an4nFKQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On 13/05/15 12:45, Maxime Coquelin wrote:
> 2015-05-12 23:21 GMT+02:00 Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>:
>> On Saturday 09 May 2015 09:53:56 Maxime Coquelin wrote:
>>> +#include <dt-bindings/mfd/stm32f4-rcc.h>
>>> +
>>>
>>
>> Can you find a way to avoid this dependency?
>>
>> Maybe you can change the bindings so that the numbers you pass as
>> arguments to the reset and clock specifiers reflect the numbers that
>> the hardware use?
>
> If I understand correctly, you prefer the way I did in v7 [0]?
>
> I don't have a strong opinion on this. Either way is fine to me.
>
> I changed the bindings in the v8 after discussions with Daniel
> Thompson, who is implementing the clock driver part of the RCC IP.
>
> He proposed we used common defines, because each peripheral has a
> reset line and a clock gate.
> Both reset and clock are represented as a single bit, with only the
> base offset differing between clock and reset.
> You can have a look at chapter 6 of the reference manual [1] if you
> find some time.
>
> Having common defines between clocks and reset make sense to me, but I
> also understand your point of avoiding dependencies.
>
> Maybe I can revert back to v7 bindings for now, and then we can
> reconsider using common defines when Daniel will send the clock
> patches.
> Note that doing that won't break the DT binary compatibility, as the
> raw reset values, or the ones from defines are the same.
>
> Daniel, could you share an example of the bindings you would use for the clocks?
For the most cases, where there is a clock gate just before the
peripheral it looks pretty much like the reset driver and I use the bit
offset of the clock gating bit as the index.
However there are a couple of clocks without gating just before the
clock reaches the peripheral:
1. A hard coded /8. I think this will have to be given a synthetic
number.
2. Ungated dividers. For these I am using the bit offset of the LSB of
the mux field.
So I think there is only one value that is completely unrelated to the
hardware and will use a magic constant instead.
I had planned to macros similar to the STM32F4_AxB_RESET() family of
macros in both clk driver and DT in order to reuse the bit layouts from
dt-bindings/mfd/stm32f4-rcc.h .
Normal case would have looked like this:
timer3: timer@40000000 {
compatible = "st,stm32-timer";
reg = <0x40000000 0x400>;
interrupts = <28>;
resets = <&rcc STM32F4_APB1_RESET(TIM3)>;
clocks = <&rcc STM32F4_APB1_CLK(TIM3)>;
status = "disabled";
};
Without the macros it looks like this:
timer3: timer@40000000 {
compatible = "st,stm32-timer";
reg = <0x40000000 0x400>;
interrupts = <28>;
resets = <&rcc 257>;
clocks = <&rcc 513>;
status = "disabled";
};
However we could perhaps be more literate even if we don't use the macros?
timer3: timer@40000000 {
compatible = "st,stm32-timer";
reg = <0x40000000 0x400>;
interrupts = <28>;
resets = <&rcc ((0x20*8) + 1)>;
clocks = <&rcc ((0x40*8) + 1)>;
status = "disabled";
};
Daniel.
> Kind regards,
> Maxime
>
>>
>> Arnd
>
> [0]: http://lkml.iu.edu/hypermail/linux/kernel/1504.3/04523.html
> [1]: http://www.st.com/web/en/resource/technical/document/reference_manual/DM00031020.pdf
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 4/5] doc: ABI: bone_capemgr sysfs API
From: Pantelis Antoniou @ 2015-05-13 12:42 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Matt Porter, Koen Kooi, Robert Nelson, Rob Herring, Grant Likely,
Jonathan Corbet, Srinivas Kandagatla, Guenter Roeck,
Geert Uytterhoeven, Benoît Cousso,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA, devicetree,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150513120854.GA1516-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
Hi Greg,
> On May 13, 2015, at 15:08 , Greg Kroah-Hartman <gregkh@linuxfoundation.org> wrote:
>
> On Wed, May 13, 2015 at 02:56:49PM +0300, Pantelis Antoniou wrote:
>> Hi Greg,
>>
>>> On May 13, 2015, at 14:52 , Greg Kroah-Hartman <gregkh@linuxfoundation.org> wrote:
>>>
>>> On Wed, May 13, 2015 at 10:59:44AM +0300, Pantelis Antoniou wrote:
>>>> Document the beaglebone's capemgr sysfs API
>>>>
>>>> Signed-off-by: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
>>>> ---
>>>> .../testing/sysfs-devices-platform-bone_capemgr | 63 ++++++++++++++++++++++
>>>> 1 file changed, 63 insertions(+)
>>>> create mode 100644 Documentation/ABI/testing/sysfs-devices-platform-bone_capemgr
>>>>
>>>> diff --git a/Documentation/ABI/testing/sysfs-devices-platform-bone_capemgr b/Documentation/ABI/testing/sysfs-devices-platform-bone_capemgr
>>>> new file mode 100644
>>>> index 0000000..e2df613
>>>> --- /dev/null
>>>> +++ b/Documentation/ABI/testing/sysfs-devices-platform-bone_capemgr
>>>> @@ -0,0 +1,63 @@
>>>> +What: /sys/devices/platform/bone_capemgr/slots
>>>> +Date: May 2015
>>>> +KernelVersion: 4.0
>>>
>>> I don't think that version is correct :)
>>>
>>
>> Bah, ++
>>
>>>> +Contact: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
>>>> +Description:
>>>> + READ:
>>>> + Describe the state of all the slots of the beaglebone capemgr.
>>>> + Each line of the output describes a slot:
>>>
>>> sysfs files are "one value per file", so a sysfs file that displays
>>> multiple lines like this is not allowed at all, sorry.
>>>
>>> Please either make it a debugfs file (if this is only for debugging, or
>>> split it out into individual files, one per slot (hint, one per slot is
>>> probably best.)
>>>
>>
>> Well, it’s a status file. And it’s been used as is for a couple of years
>> so it was worth a shot for backward compatibility.
>
> There is not "backwards compatiblity" for when you do things wrong in
> the first place, you can't claim that here, sorry.
>
> And don't "try" to introduce things you know is wrong, that just makes
> maintainers _very_ suspicious of everything else you are doing here…
>
OK
>>>> + The slot format is as following:
>>>> + <slot-id>: [P-][F-][O-][l-][L-][D-] \
>>>> + <overlay-id> <board-name>,<version>,
>>>> + <manufacturer>,<part-number>
>>>> +
>>>> + Where the flags are:
>>>> + P: Slot has been probed
>>>> + F: Slot has failed probing (i.e. no EEPROM detected)
>>>> + O: Slot has been overridden by the user
>>>> + l: Slot is current loading
>>>> + L: Slot has completed loading and is ready
>>>> + D: Slot has been disabled
>>>> +
>>>> + Example:
>>>> + 0: P---L- -1 BeagleBone RS232 CAPE,00A1,Beagleboardtoys,BB-BONE-SERL-03
>>>> + 1: PF---- -1
>>>> + 2: PF---- -1
>>>> + 3: PF---- -1
>>>> +
>>>> + WRITE:
>>>> + Writing a string of the form <part-number>[:version] issues a request to
>>>> + load a firmware blob containing an overlay. The name of the firmware blob
>>>> + is <part-number>-[version|00A0].dtbo. This act is defined as a slot override.
>>>> +
>>>> + Writing a negative slot id removes the slot if it was an overridden one, or
>>>> + unloads a slot that was probed.
>>>> +
>>>> +What: /sys/devices/platform/bone_capemgr/baseboard/<eeprom-field>
>>>> +Date: May 2015
>>>> +KernelVersion: 4.0
>>>> +Contact: Pantelis Antoniou <pantelis.antoniou-OWPKS81ov/FWk0Htik3J/w@public.gmane.org>
>>>> +Description: Contains the probed base board EEPROM field; one of:
>>>> + board-name - board-name as stored in cape EEPROM
>>>> + dc-supplied - whether the cape draws or supplies DC
>>>> + eeprom-format-revision - EEPROM format rev, only 00A0 supported
>>>> + header - header; should be 'aa 55 33 ee'
>>>
>>> If it's always this value, why have the file?
>>>
>>
>> These are the contents of the EEPROM. If the format of the EEPROM changes then the
>> header information will change.
>
> Then don't say "should be", because what happens in the future if it is
> not.
>
OK
>>>> + manufacturer - manufacturer string
>>>> + part-number - part-number of the cape
>>>> + serial-number - serial number of the cape
>>>> + version - version of the cape, i.e. 00A0
>>>> + number-of-pins - displayed but ignored
>>>> + pin-usage - displayed but ignored
>>>> + sys-5v - displayed but ignored
>>>> + vdd-3v3exp - displayed but ignored
>>>> + vdd-5v - displayed but ignored
>>>
>>> Are these all individual different files?
>>>
>>
>> Yes
>
> Then write out the individual files please as different entries.
>
> Also, the "displayed but ignored" doesn't make sense, please fix that
> up.
>
OK
> greg k-h
Regards
— Pantelis
^ permalink raw reply
* Re: [PATCH RFC] vfs: add a O_NOMTIME flag
From: Jan Kara @ 2015-05-13 12:32 UTC (permalink / raw)
To: Sage Weil
Cc: Theodore Ts'o, Trond Myklebust, Dave Chinner, Zach Brown,
Alexander Viro, Linux FS-devel Mailing List,
Linux Kernel Mailing List, Linux API Mailing List
In-Reply-To: <alpine.DEB.2.00.1505110920520.28239-vIokxiIdD2AQNTJnQDzGJqxOck334EZe@public.gmane.org>
On Mon 11-05-15 09:24:09, Sage Weil wrote:
> On Mon, 11 May 2015, Theodore Ts'o wrote:
> > On Sun, May 10, 2015 at 07:13:24PM -0400, Trond Myklebust wrote:
> > > That makes it completely non-generic though. By putting this in the
> > > VFS, you are giving applications a loaded gun that is pointed straight
> > > at the application user's head.
> >
> > Let me re-ask the question that I asked last week (and was apparently
> > ignored). Why not trying to use the lazytime feature instead of
> > pointing a head straight at the application's --- and system
> > administrators' --- heads?
>
> Sorry Ted, I thought I responded already.
>
> The goal is to avoid inode writeout entirely when we can, and
> as I understand it lazytime will still force writeout before the inode
> is dropped from the cache. In systems like Ceph in particular, the
> IOs can be spread across lots of files, so simply deferring writeout
> doesn't always help.
Can we get some numbers on this? Before we go on and implement new mount
options, persistent inode flags, open flags, or whatever other crap
(neither of which looks particularly appealing to me) I'd like to know how
big is the performance difference between lazytime + fdatasync and not
updating mtime at all for Ceph...
Honza
--
Jan Kara <jack-AlSwsSmVLrQ@public.gmane.org>
SUSE Labs, CR
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox