new file mode 100644
@@ -0,0 +1,72 @@
+Device-Tree bindings for DesignWare DSI Host Controller v1.20a driver
+
+A DSI Host Controller resides in the middle of display controller and external
+HDMI converter or panel.
+
+Required properties:
+- compatible: value should be "hisilicon,hi6220-dsi".
+- reg: physical base address and length of dsi controller's registers.
+- clocks: contains APB clock phandle + clock-specifier pair.
+- clock-names: should be "pclk".
+- ports: contains DSI controller input and output sub port.
+ The input port connects to ADE output port with the reg value "0".
+ The output port with the reg value "1", it could connect to panel or
+ any other bridge endpoints.
+ See Documentation/devicetree/bindings/graph.txt for more device graph info.
+
+A example of HiKey board hi6220 SoC and board specific DT entry:
+Example:
+
+SoC specific:
+ dsi: dsi@f4107800 {
+ compatible = "hisilicon,hi6220-dsi";
+ reg = <0x0 0xf4107800 0x0 0x100>;
+ clocks = <&media_ctrl HI6220_DSI_PCLK>;
+ clock-names = "pclk";
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* 0 for input port */
+ port@0 {
+ reg = <0>;
+ dsi_in: endpoint {
+ remote-endpoint = <&ade_out>;
+ };
+ };
+ };
+ };
+
+
+Board specific:
+ &dsi {
+ status = "ok";
+
+ ports {
+ /* 1 for output port */
+ port@1 {
+ reg = <1>;
+
+ dsi_out0: endpoint@0 {
+ remote-endpoint = <&adv7533_in>;
+ };
+ };
+ };
+ };
+
+ &i2c2 {
+ ...
+
+ adv7533: adv7533@39 {
+ ...
+
+ port {
+ adv7533_in: endpoint {
+ remote-endpoint = <&dsi_out0>;
+ };
+ };
+ };
+ };
+
@@ -5,15 +5,31 @@ data from memory, do composition, do post image processing, generate RGB
timing stream and transfer to DSI.
Required properties:
-- compatible: value should be one of the following
- "hisilicon,hi6220-ade".
-- reg: physical base address and length of the controller's registers.
-- reg-names: name of physical base.
-- interrupt: the interrupt number.
-- clocks: the clocks needed.
-- clock-names: the name of the clocks.
-- ade_core_clk_rate: ADE core clock rate.
-- media_noc_clk_rate: media noc module clock rate.
+- compatible: value should be "hisilicon,hi6220-ade".
+- reg: physical base address and length of the ADE controller's registers.
+- hisilicon,noc-syscon: ADE NOC QoS syscon.
+- resets: The ADE reset controller node.
+- interrupt: the ldi vblank interrupt number used.
+- clocks: a list of phandle + clock-specifier pairs, one for each entry
+ in clock-names.
+- clock-names: should contain:
+ "clk_ade_core" for the ADE core clock.
+ "clk_codec_jpeg" for the media NOC QoS clock, which use the same clock with
+ jpeg codec.
+ "clk_ade_pix" for the ADE pixel clok.
+- assigned-clocks: Should contain "clk_ade_core" and "clk_codec_jpeg" clocks'
+ phandle + clock-specifier pairs.
+- assigned-clock-rates: clock rates, one for each entry in assigned-clocks.
+ The rate of "clk_ade_core" could be "360000000" or "180000000";
+ The rate of "clk_codec_jpeg" could be or less than "1440000000".
+ These rate values could be configured according to performance and power
+ consumption.
+- port: the output port. This contains one endpoint subnode, with its
+ remote-endpoint set to the phandle of the connected DSI input endpoint.
+ See Documentation/devicetree/bindings/graph.txt for more device graph info.
+
+Optional properties:
+- dma-coherent: Present if dma operations are coherent.
A example of HiKey board hi6220 SoC specific DT entry:
@@ -21,22 +37,28 @@ Example:
ade: ade@f4100000 {
compatible = "hisilicon,hi6220-ade";
- reg = <0x0 0xf4100000 0x0 0x7800>,
- <0x0 0xf4410000 0x0 0x1000>;
- reg-names = "ade_base",
- "media_base";
- interrupts = <0 115 4>;
+ reg = <0x0 0xf4100000 0x0 0x7800>;
+ reg-names = "ade_base";
+ hisilicon,noc-syscon = <&medianoc_ade>;
+ resets = <&media_ctrl MEDIA_ADE>;
+ interrupts = <0 115 4>; /* ldi interrupt */
clocks = <&media_ctrl HI6220_ADE_CORE>,
<&media_ctrl HI6220_CODEC_JPEG>,
- <&media_ctrl HI6220_ADE_PIX_SRC>,
- <&media_ctrl HI6220_PLL_SYS>,
- <&media_ctrl HI6220_PLL_SYS_MEDIA>;
+ <&media_ctrl HI6220_ADE_PIX_SRC>;
+ /*clock name*/
clock-names = "clk_ade_core",
- "aclk_codec_jpeg_src",
- "clk_ade_pix",
- "clk_syspll_src",
- "clk_medpll_src";
- ade_core_clk_rate = <360000000>;
- media_noc_clk_rate = <288000000>;
+ "clk_codec_jpeg",
+ "clk_ade_pix";
+
+ assigned-clocks = <&media_ctrl HI6220_ADE_CORE>,
+ <&media_ctrl HI6220_CODEC_JPEG>;
+ assigned-clock-rates = <360000000>, <288000000>;
+ dma-coherent;
+
+ port {
+ ade_out: endpoint {
+ remote-endpoint = <&dsi_in>;
+ };
+ };
};
deleted file mode 100644
@@ -1,66 +0,0 @@
-Hisilicon DRM master device
-
-The Hisilicon DRM master device is a virtual device needed to list all
-the other display relevant nodes that comprise the display subsystem.
-
-
-Required properties:
-- compatible: Should be "hisilicon,<chip>-dss"
-- #address-cells: should be set to 2.
-- #size-cells: should be set to 2.
-- range: to allow probing of subdevices.
-
-Optional properties:
-- dma-coherent: Present if dma operations are coherent.
-
-Required sub nodes:
-All the device nodes of display subsystem of SoC should be the sub nodes.
-Such as display controller node, DSI node and so on.
-
-A example of HiKey board hi6220 SoC specific DT entry:
-Example:
-
- display-subsystem {
- compatible = "hisilicon,hi6220-dss";
- #address-cells = <2>;
- #size-cells = <2>;
- ranges;
- dma-coherent;
-
- ade: ade@f4100000 {
- compatible = "hisilicon,hi6220-ade";
- reg = <0x0 0xf4100000 0x0 0x7800>,
- <0x0 0xf4410000 0x0 0x1000>;
- reg-names = "ade_base",
- "media_base";
- interrupts = <0 115 4>; /* ldi interrupt */
-
- clocks = <&media_ctrl HI6220_ADE_CORE>,
- <&media_ctrl HI6220_CODEC_JPEG>,
- <&media_ctrl HI6220_ADE_PIX_SRC>,
- <&media_ctrl HI6220_PLL_SYS>,
- <&media_ctrl HI6220_PLL_SYS_MEDIA>;
- /*clock name*/
- clock-names = "clk_ade_core",
- "aclk_codec_jpeg_src",
- "clk_ade_pix",
- "clk_syspll_src",
- "clk_medpll_src";
- ade_core_clk_rate = <360000000>;
- media_noc_clk_rate = <288000000>;
- };
-
- dsi: dsi@0xf4107800 {
- compatible = "hisilicon,hi6220-dsi";
- reg = <0x0 0xf4107800 0x0 0x100>;
- clocks = <&media_ctrl HI6220_DSI_PCLK>;
- clock-names = "pclk_dsi";
-
- port {
- dsi_out: endpoint {
- remote-endpoint = <&adv_in>;
- };
- };
-
- };
- };
deleted file mode 100644
@@ -1,53 +0,0 @@
-Device-Tree bindings for hisilicon DSI controller driver
-
-A DSI controller resides in the middle of display controller and external
-HDMI converter.
-
-Required properties:
-- compatible: value should be one of the following
- "hisilicon,hi6220-dsi".
-- reg: physical base address and length of the controller's registers.
-- clocks: the clocks needed.
-- clock-names: the name of the clocks.
-- port: DSI controller output port. This contains one endpoint subnode, with its
- remote-endpoint set to the phandle of the connected external HDMI endpoint.
- See Documentation/devicetree/bindings/graph.txt for device graph info.
-
-A example of HiKey board hi6220 SoC and board specific DT entry:
-Example:
-
-SoC specific:
- dsi: dsi@0xf4107800 {
- compatible = "hisilicon,hi6220-dsi";
- reg = <0x0 0xf4107800 0x0 0x100>;
- clocks = <&media_ctrl HI6220_DSI_PCLK>;
- clock-names = "pclk_dsi";
-
- port {
- dsi_out: endpoint {
- remote-endpoint = <&adv_in>;
- };
- };
-
- };
-
-Board specific:
- i2c2: i2c@f7102000 {
- status = "ok";
-
- adv7533: adv7533@39 {
- compatible = "adi,adv7533";
- reg = <0x39>;
- interrupt-parent = <&gpio1>;
- interrupts = <1 2>;
- pd-gpio = <&gpio0 4 0>;
- adi,dsi-lanes = <4>;
-
- port {
- adv_in: endpoint {
- remote-endpoint = <&dsi_out>;
- };
- };
- };
- };
-
@@ -3705,6 +3705,16 @@ S: Maintained
F: drivers/gpu/drm/gma500
F: include/drm/gma500*
+DRM DRIVERS FOR HISILICON
+M: Xinliang Liu <z.liuxinliang@hisilicon.com>
+R: Xinwei Kong <kong.kongxinwei@hisilicon.com>
+R: Chen Feng <puck.chen@hisilicon.com>
+L: dri-devel@lists.freedesktop.org
+T: git git://github.com/xin3liang/linux.git
+S: Maintained
+F: drivers/gpu/drm/hisilicon/
+F: Documentation/devicetree/bindings/display/hisilicon/
+
DRM DRIVERS FOR NVIDIA TEGRA
M: Thierry Reding <thierry.reding@gmail.com>
M: Terje Bergström <tbergstrom@nvidia.com>
@@ -107,15 +107,15 @@
interrupts = <1 2>;
pd-gpio = <&gpio0 4 0>;
adi,dsi-lanes = <4>;
+ adi,disable-timing-generator;
port {
- adv_in: endpoint {
- remote-endpoint = <&dsi_out>;
+ adv7533_in: endpoint {
+ remote-endpoint = <&dsi_out0>;
};
};
};
};
-
uart1: uart@f7111000 {
status = "ok";
};
@@ -336,3 +336,55 @@
};
};
};
+
+&ade {
+ status = "ok";
+};
+
+&dsi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mux-gpio = <&gpio0 1 0>;
+ status = "ok";
+
+ ports {
+ /* 1 for output port */
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ dsi_out0: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&adv7533_in>;
+ };
+
+ dsi_out1: endpoint@1 {
+ reg = <1>;
+ remote-endpoint = <&panel0_in>;
+ };
+ };
+ };
+
+ /* For panel reg's value should >= 1 */
+ panel@1 {
+ compatible = "innolux,n070icn-pb1";
+ reg = <1>;
+ power-on-delay= <50>;
+ reset-delay = <100>;
+ init-delay = <100>;
+ panel-width-mm = <58>;
+ panel-height-mm = <103>;
+ pwr-en-gpio = <&gpio2 1 0>;
+ bl-en-gpio = <&gpio2 3 0>;
+ pwm-gpio = <&gpio12 7 0>;
+
+ port {
+ panel0_in: endpoint {
+ remote-endpoint = <&dsi_out1>;
+ };
+ };
+ };
+};
+
+
@@ -255,6 +255,7 @@
compatible = "hisilicon,hi6220-mediactrl", "syscon";
reg = <0x0 0xf4410000 0x0 0x1000>;
#clock-cells = <1>;
+ #reset-cells = <1>;
};
pm_ctrl: pm_ctrl@f7032000 {
@@ -271,6 +272,11 @@
mboxes = <&mailbox 1 0 11>;
};
+ medianoc_ade: medianoc_ade@f4520000 {
+ compatible = "syscon";
+ reg = <0x0 0xf4520000 0x0 0x4000>;
+ };
+
uart0: uart@f8015000 { /* console */
compatible = "arm,pl011", "arm,primecell";
reg = <0x0 0xf8015000 0x0 0x1000>;
@@ -705,7 +711,7 @@
pinctrl-0 = <&spi0_pmx_func &spi0_cfg_func>;
num-cs = <1>;
cs-gpios = <&gpio6 2 0>;
- status = "ok";
+ status = "disabled";
};
i2c0: i2c@f7100000 {
@@ -925,46 +931,51 @@
};
};
- display-subsystem {
- compatible = "hisilicon,hi6220-dss";
- #address-cells = <2>;
- #size-cells = <2>;
- ranges;
-
- ade: ade@f4100000 {
- compatible = "hisilicon,hi6220-ade";
- reg = <0x0 0xf4100000 0x0 0x7800>,
- <0x0 0xf4410000 0x0 0x1000>,
- <0x0 0xf4520000 0x0 0x1000>;
- reg-names = "ade_base",
- "media_base",
- "media_noc_base";
- interrupts = <0 115 4>; /* ldi interrupt */
-
- clocks = <&media_ctrl HI6220_ADE_CORE>,
- <&media_ctrl HI6220_CODEC_JPEG>,
- <&media_ctrl HI6220_ADE_PIX_SRC>,
- <&media_ctrl HI6220_PLL_SYS>,
- <&media_ctrl HI6220_PLL_SYS_MEDIA>;
- /*clock name*/
- clock-names = "clk_ade_core",
- "aclk_codec_jpeg_src",
- "clk_ade_pix",
- "clk_syspll_src",
- "clk_medpll_src";
- ade_core_clk_rate = <360000000>;
- media_noc_clk_rate = <288000000>;
+ ade: ade@f4100000 {
+ compatible = "hisilicon,hi6220-ade";
+ reg = <0x0 0xf4100000 0x0 0x7800>;
+ reg-names = "ade_base";
+ hisilicon,noc-syscon = <&medianoc_ade>;
+ resets = <&media_ctrl MEDIA_ADE>;
+ interrupts = <0 115 4>; /* ldi interrupt */
+
+ clocks = <&media_ctrl HI6220_ADE_CORE>,
+ <&media_ctrl HI6220_CODEC_JPEG>,
+ <&media_ctrl HI6220_ADE_PIX_SRC>;
+ /*clock name*/
+ clock-names = "clk_ade_core",
+ "clk_codec_jpeg",
+ "clk_ade_pix";
+
+ assigned-clocks = <&media_ctrl HI6220_ADE_CORE>,
+ <&media_ctrl HI6220_CODEC_JPEG>;
+ assigned-clock-rates = <360000000>, <288000000>;
+ dma-coherent;
+ status = "disabled";
+
+ port {
+ ade_out: endpoint {
+ remote-endpoint = <&dsi_in>;
+ };
};
+ };
+
+ dsi: dsi@f4107800 {
+ compatible = "hisilicon,hi6220-dsi";
+ reg = <0x0 0xf4107800 0x0 0x100>;
+ clocks = <&media_ctrl HI6220_DSI_PCLK>;
+ clock-names = "pclk";
+ status = "disabled";
- dsi: dsi@0xf4107800 {
- compatible = "hisilicon,hi6220-dsi";
- reg = <0x0 0xf4107800 0x0 0x100>;
- clocks = <&media_ctrl HI6220_DSI_PCLK>;
- clock-names = "pclk_dsi";
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
- port {
- dsi_out: endpoint {
- remote-endpoint = <&adv_in>;
+ /* 0 for input port */
+ port@0 {
+ reg = <0>;
+ dsi_in: endpoint {
+ remote-endpoint = <&ade_out>;
};
};
};
@@ -75,4 +75,4 @@ obj-y += i2c/
obj-y += panel/
obj-y += bridge/
obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
-obj-$(CONFIG_DRM_HISI) += hisilicon/
+obj-y += hisilicon/
@@ -1,13 +1,3 @@
-config DRM_HISI
- tristate "DRM Support for Hisilicon SoCs Platform"
- depends on DRM
- select DRM_KMS_HELPER
- select DRM_GEM_CMA_HELPER
- select DRM_KMS_CMA_HELPER
- select DRM_MIPI_DSI
- help
- Choose this option if you have a hisilicon chipsets(hi6220).
- If M is selected the module will be called hisi-drm.
#
# hisilicon drm device configuration.
# Please keep this list sorted alphabetically
@@ -4,6 +4,7 @@ config DRM_HISI_KIRIN
select DRM_KMS_HELPER
select DRM_GEM_CMA_HELPER
select DRM_KMS_CMA_HELPER
+ select HISI_KIRIN_DW_DSI
help
Choose this option if you have a hisilicon Kirin chipsets(hi6220).
If M is selected the module will be called kirin-drm.
@@ -1,10 +1,12 @@
/*
- * Hisilicon hi6220 SoC dsi driver
+ * DesignWare MIPI DSI Host Controller v1.02 driver
+ *
+ * Copyright (c) 2016 Linaro Limited.
+ * Copyright (c) 2014-2016 Hisilicon Limited.
*
- * Copyright (c) 2014-2015 Hisilicon Limited.
* Author:
- * Xinliang Liu <xinliang.liu@linaro.org>
* Xinliang Liu <z.liuxinliang@hisilicon.com>
+ * Xinliang Liu <xinliang.liu@linaro.org>
* Xinwei Kong <kong.kongxinwei@hisilicon.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -16,27 +18,39 @@
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/of_graph.h>
+#include <linux/iopoll.h>
+#include <video/mipi_display.h>
+#include <linux/gpio/consumer.h>
+#include <drm/drm_of.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_encoder_slave.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_panel.h>
#include "dw_dsi_reg.h"
-#define MAX_TX_ESC_CLK (10)
-#define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
-#define DEFAULT_MIPI_CLK_RATE 19200000
-#define DEFAULT_MIPI_CLK_PERIOD_PS (1000000000 / (DEFAULT_MIPI_CLK_RATE / 1000))
-#define R(x) ((u32)((((u64)(x) * (u64)1000 * (u64)mode->clock) / \
- phy->lane_byte_clk_kHz)))
+#define MAX_TX_ESC_CLK 10
+#define ROUND(x, y) ((x) / (y) + \
+ ((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
+#define PHY_REF_CLK_RATE 19200000
+#define PHY_REF_CLK_PERIOD_PS (1000000000 / (PHY_REF_CLK_RATE / 1000))
#define encoder_to_dsi(encoder) \
- container_of(encoder, struct hisi_dsi, encoder)
+ container_of(encoder, struct dw_dsi, encoder)
#define host_to_dsi(host) \
- container_of(host, struct hisi_dsi, host)
+ container_of(host, struct dw_dsi, host)
+#define connector_to_dsi(connector) \
+ container_of(connector, struct dw_dsi, connector)
+
+enum dsi_output_client {
+ OUT_HDMI = 0,
+ OUT_PANEL,
+ OUT_MAX
+};
-struct mipi_phy_register {
+struct mipi_phy_params {
u32 clk_t_lpx;
u32 clk_t_hs_prepare;
u32 clk_t_hs_zero;
@@ -73,41 +87,53 @@ struct mipi_phy_register {
struct dsi_hw_ctx {
void __iomem *base;
- struct clk *dsi_cfg_clk;
+ struct clk *pclk;
+};
+
+struct dw_dsi_client {
+ u32 lanes;
+ u32 phy_clock; /* in kHz */
+ enum mipi_dsi_pixel_format format;
+ unsigned long mode_flags;
};
-struct hisi_dsi {
+struct dw_dsi {
struct drm_encoder encoder;
struct drm_bridge *bridge;
+ struct drm_panel *panel;
struct mipi_dsi_host host;
+ struct drm_connector connector; /* connector for panel */
struct drm_display_mode cur_mode;
struct dsi_hw_ctx *ctx;
- struct mipi_phy_register phy;
+ struct mipi_phy_params phy;
u32 lanes;
enum mipi_dsi_pixel_format format;
unsigned long mode_flags;
+ struct gpio_desc *gpio_mux;
+ struct dw_dsi_client client[OUT_MAX];
+ enum dsi_output_client cur_client;
bool enable;
};
struct dsi_data {
- struct hisi_dsi dsi;
+ struct dw_dsi dsi;
struct dsi_hw_ctx ctx;
};
-struct dsi_phy_seq_info {
+struct dsi_phy_range {
u32 min_range_kHz;
u32 max_range_kHz;
u32 pll_vco_750M;
u32 hstx_ckg_sel;
};
-static const struct dsi_phy_seq_info dphy_seq_info[] = {
- { 46000, 62000, 1, 7 },
- { 62000, 93000, 0, 7 },
- { 93000, 125000, 1, 6 },
- { 125000, 187000, 0, 6 },
- { 187000, 250000, 1, 5 },
+static const struct dsi_phy_range dphy_range_info[] = {
+ { 46875, 62500, 1, 7 },
+ { 62500, 93750, 0, 7 },
+ { 93750, 125000, 1, 6 },
+ { 125000, 187500, 0, 6 },
+ { 187500, 250000, 1, 5 },
{ 250000, 375000, 0, 5 },
{ 375000, 500000, 1, 4 },
{ 500000, 750000, 0, 4 },
@@ -115,11 +141,55 @@ static const struct dsi_phy_seq_info dphy_seq_info[] = {
{ 1000000, 1500000, 0, 0 }
};
-static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
- struct mipi_phy_register *phy)
+void dsi_set_output_client(struct drm_device *dev)
+{
+ enum dsi_output_client client;
+ struct drm_connector *connector;
+ struct drm_encoder *encoder;
+ struct dw_dsi *dsi;
+
+
+ mutex_lock(&dev->mode_config.mutex);
+
+ /* find dsi encoder */
+ drm_for_each_encoder(encoder, dev)
+ if (encoder->encoder_type == DRM_MODE_ENCODER_DSI)
+ break;
+ dsi = encoder_to_dsi(encoder);
+
+ /* find HDMI connector */
+ drm_for_each_connector(connector, dev)
+ if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)
+ break;
+
+ /*
+ * set the proper dsi output client
+ */
+ client = connector->status == connector_status_connected ?
+ OUT_HDMI : OUT_PANEL;
+ if (client != dsi->cur_client) {
+ /* associate bridge and dsi encoder */
+ if (client == OUT_HDMI)
+ encoder->bridge = dsi->bridge;
+ else
+ encoder->bridge = NULL;
+
+ gpiod_set_value_cansleep(dsi->gpio_mux, client);
+ dsi->cur_client = client;
+ /* let the userspace know panel connector status has changed */
+ drm_sysfs_hotplug_event(dev);
+ DRM_INFO("client change to %s\n", client == OUT_HDMI ?
+ "HDMI" : "panel");
+ }
+
+ mutex_unlock(&dev->mode_config.mutex);
+}
+EXPORT_SYMBOL(dsi_set_output_client);
+
+static u32 dsi_calc_phy_rate(u32 req_kHz, struct mipi_phy_params *phy)
{
- u32 ui = 0;
- u32 cfg_clk_ps = DEFAULT_MIPI_CLK_PERIOD_PS;
+ u32 ref_clk_ps = PHY_REF_CLK_PERIOD_PS;
+ u32 tmp_kHz = req_kHz;
u32 i = 0;
u32 q_pll = 1;
u32 m_pll = 0;
@@ -127,32 +197,33 @@ static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
u32 r_pll = 1;
u32 m_n = 0;
u32 m_n_int = 0;
- u64 f_kHz;
+ u32 f_kHz = 0;
u64 temp;
- u64 tmp_kHz = phy_freq_kHz;
+ /*
+ * Find a rate >= req_kHz.
+ */
do {
f_kHz = tmp_kHz;
- /* Find the PLL clock range from the table */
- for (i = 0; i < ARRAY_SIZE(dphy_seq_info); i++)
- if (f_kHz > dphy_seq_info[i].min_range_kHz &&
- f_kHz <= dphy_seq_info[i].max_range_kHz)
+ for (i = 0; i < ARRAY_SIZE(dphy_range_info); i++)
+ if (f_kHz >= dphy_range_info[i].min_range_kHz &&
+ f_kHz <= dphy_range_info[i].max_range_kHz)
break;
- if (i == ARRAY_SIZE(dphy_seq_info)) {
- DRM_ERROR("%lldkHz out of range\n", f_kHz);
- return;
+ if (i == ARRAY_SIZE(dphy_range_info)) {
+ DRM_ERROR("%dkHz out of range\n", f_kHz);
+ return 0;
}
- phy->pll_vco_750M = dphy_seq_info[i].pll_vco_750M;
- phy->hstx_ckg_sel = dphy_seq_info[i].hstx_ckg_sel;
+ phy->pll_vco_750M = dphy_range_info[i].pll_vco_750M;
+ phy->hstx_ckg_sel = dphy_range_info[i].hstx_ckg_sel;
if (phy->hstx_ckg_sel <= 7 &&
phy->hstx_ckg_sel >= 4)
q_pll = 0x10 >> (7 - phy->hstx_ckg_sel);
- temp = f_kHz * (u64)q_pll * (u64)cfg_clk_ps;
+ temp = f_kHz * (u64)q_pll * (u64)ref_clk_ps;
m_n_int = temp / (u64)1000000000;
m_n = (temp % (u64)1000000000) / (u64)100000000;
@@ -226,23 +297,39 @@ static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
}
f_kHz = (u64)1000000000 * (u64)m_pll /
- ((u64)cfg_clk_ps * (u64)n_pll * (u64)q_pll);
+ ((u64)ref_clk_ps * (u64)n_pll * (u64)q_pll);
- if (f_kHz >= phy_freq_kHz)
+ if (f_kHz >= req_kHz)
break;
tmp_kHz += 10;
- } while (1);
+ } while (true);
- ui = 1000000 / f_kHz;
+ return f_kHz;
+}
+
+static void dsi_get_phy_params(u32 phy_req_kHz,
+ struct mipi_phy_params *phy)
+{
+ u32 ref_clk_ps = PHY_REF_CLK_PERIOD_PS;
+ u32 phy_rate_kHz;
+ u32 ui;
+
+ memset(phy, 0, sizeof(*phy));
+
+ phy_rate_kHz = dsi_calc_phy_rate(phy_req_kHz, phy);
+ if (!phy_rate_kHz)
+ return;
+
+ ui = 1000000 / phy_rate_kHz;
phy->clk_t_lpx = ROUND(50, 8 * ui);
phy->clk_t_hs_prepare = ROUND(133, 16 * ui) - 1;
phy->clk_t_hs_zero = ROUND(262, 8 * ui);
phy->clk_t_hs_trial = 2 * (ROUND(60, 8 * ui) - 1);
- phy->clk_t_wakeup = ROUND(1000000, (cfg_clk_ps / 1000) - 1);
+ phy->clk_t_wakeup = ROUND(1000000, (ref_clk_ps / 1000) - 1);
if (phy->clk_t_wakeup > 0xff)
phy->clk_t_wakeup = 0xff;
phy->data_t_wakeup = phy->clk_t_wakeup;
@@ -262,17 +349,18 @@ static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
phy->data_to_clk_delay = ROUND(60 + 52 * ui, 8 * ui) +
phy->clkhs2lp_time;
- phy->lane_byte_clk_kHz = f_kHz / 8;
- phy->clk_division = phy->lane_byte_clk_kHz / MAX_TX_ESC_CLK;
- if (phy->lane_byte_clk_kHz % MAX_TX_ESC_CLK)
- phy->clk_division++;
+ phy->lane_byte_clk_kHz = phy_rate_kHz / 8;
+ phy->clk_division =
+ DIV_ROUND_UP(phy->lane_byte_clk_kHz, MAX_TX_ESC_CLK);
}
static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
{
u32 val;
- /* TODO: only support RGB888 now, to support more */
+ /*
+ * TODO: only support RGB888 now, to support more
+ */
switch (format) {
case MIPI_DSI_FMT_RGB888:
val = DSI_24BITS_1;
@@ -285,120 +373,146 @@ static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
return val;
}
-static void dsi_mipi_phy_clks(void __iomem *base,
- struct mipi_phy_register *phy,
+/*
+ * dsi phy reg write function
+ */
+static void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
+{
+ u32 reg_write = 0x10000 + reg;
+
+ /*
+ * latch reg first
+ */
+ writel(reg_write, base + PHY_TST_CTRL1);
+ writel(0x02, base + PHY_TST_CTRL0);
+ writel(0x00, base + PHY_TST_CTRL0);
+
+ /*
+ * then latch value
+ */
+ writel(val, base + PHY_TST_CTRL1);
+ writel(0x02, base + PHY_TST_CTRL0);
+ writel(0x00, base + PHY_TST_CTRL0);
+}
+
+static void dsi_set_phy_timer(void __iomem *base,
+ struct mipi_phy_params *phy,
u32 lanes)
{
- u32 delay_count;
- bool is_ready;
u32 val;
- u32 i;
- /* set lanes value */
+ /*
+ * Set lane value and phy stop wait time.
+ */
val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8);
writel(val, base + PHY_IF_CFG);
- /* set phy clk division */
+ /*
+ * Set phy clk division.
+ */
val = readl(base + CLKMGR_CFG) | phy->clk_division;
writel(val, base + CLKMGR_CFG);
- /* clean up phy set param */
+ /*
+ * Set lp and hs switching params.
+ */
+ dw_update_bits(base + PHY_TMR_CFG, 24, MASK(8), phy->hs2lp_time);
+ dw_update_bits(base + PHY_TMR_CFG, 16, MASK(8), phy->lp2hs_time);
+ dw_update_bits(base + PHY_TMR_LPCLK_CFG, 16, MASK(10),
+ phy->clkhs2lp_time);
+ dw_update_bits(base + PHY_TMR_LPCLK_CFG, 0, MASK(10),
+ phy->clklp2hs_time);
+ dw_update_bits(base + CLK_DATA_TMR_CFG, 8, MASK(8),
+ phy->data_to_clk_delay);
+ dw_update_bits(base + CLK_DATA_TMR_CFG, 0, MASK(8),
+ phy->clk_to_data_delay);
+}
+
+static void dsi_set_mipi_phy(void __iomem *base,
+ struct mipi_phy_params *phy,
+ u32 lanes)
+{
+ u32 delay_count;
+ u32 val;
+ u32 i;
+
+ /* phy timer setting */
+ dsi_set_phy_timer(base, phy, lanes);
+
+ /*
+ * Reset to clean up phy tst params.
+ */
writel(0, base + PHY_RSTZ);
writel(0, base + PHY_TST_CTRL0);
writel(1, base + PHY_TST_CTRL0);
writel(0, base + PHY_TST_CTRL0);
- /* clock lane Timing control - TLPX */
- dsi_phy_tst_set(base, 0x10010, phy->clk_t_lpx);
-
- /* clock lane Timing control - THS-PREPARE */
- dsi_phy_tst_set(base, 0x10011, phy->clk_t_hs_prepare);
-
- /* clock lane Timing control - THS-ZERO */
- dsi_phy_tst_set(base, 0x10012, phy->clk_t_hs_zero);
-
- /* clock lane Timing control - THS-TRAIL */
- dsi_phy_tst_set(base, 0x10013, phy->clk_t_hs_trial);
-
- /* clock lane Timing control - TWAKEUP */
- dsi_phy_tst_set(base, 0x10014, phy->clk_t_wakeup);
+ /*
+ * Clock lane timing control setting: TLPX, THS-PREPARE,
+ * THS-ZERO, THS-TRAIL, TWAKEUP.
+ */
+ dsi_phy_tst_set(base, CLK_TLPX, phy->clk_t_lpx);
+ dsi_phy_tst_set(base, CLK_THS_PREPARE, phy->clk_t_hs_prepare);
+ dsi_phy_tst_set(base, CLK_THS_ZERO, phy->clk_t_hs_zero);
+ dsi_phy_tst_set(base, CLK_THS_TRAIL, phy->clk_t_hs_trial);
+ dsi_phy_tst_set(base, CLK_TWAKEUP, phy->clk_t_wakeup);
- /* data lane */
+ /*
+ * Data lane timing control setting: TLPX, THS-PREPARE,
+ * THS-ZERO, THS-TRAIL, TTA-GO, TTA-GET, TWAKEUP.
+ */
for (i = 0; i < lanes; i++) {
- /* Timing control - TLPX*/
- dsi_phy_tst_set(base, 0x10020 + (i << 4), phy->data_t_lpx);
-
- /* Timing control - THS-PREPARE */
- dsi_phy_tst_set(base, 0x10021 + (i << 4),
+ dsi_phy_tst_set(base, DATA_TLPX(i), phy->data_t_lpx);
+ dsi_phy_tst_set(base, DATA_THS_PREPARE(i),
phy->data_t_hs_prepare);
-
- /* Timing control - THS-ZERO */
- dsi_phy_tst_set(base, 0x10022 + (i << 4), phy->data_t_hs_zero);
-
- /* Timing control - THS-TRAIL */
- dsi_phy_tst_set(base, 0x10023 + (i << 4), phy->data_t_hs_trial);
-
- /* Timing control - TTA-GO */
- dsi_phy_tst_set(base, 0x10024 + (i << 4), phy->data_t_ta_go);
-
- /* Timing control - TTA-GET */
- dsi_phy_tst_set(base, 0x10025 + (i << 4), phy->data_t_ta_get);
-
- /* Timing control - TWAKEUP */
- dsi_phy_tst_set(base, 0x10026 + (i << 4), phy->data_t_wakeup);
+ dsi_phy_tst_set(base, DATA_THS_ZERO(i), phy->data_t_hs_zero);
+ dsi_phy_tst_set(base, DATA_THS_TRAIL(i), phy->data_t_hs_trial);
+ dsi_phy_tst_set(base, DATA_TTA_GO(i), phy->data_t_ta_go);
+ dsi_phy_tst_set(base, DATA_TTA_GET(i), phy->data_t_ta_get);
+ dsi_phy_tst_set(base, DATA_TWAKEUP(i), phy->data_t_wakeup);
}
- /* physical configuration I */
- dsi_phy_tst_set(base, 0x10060, phy->hstx_ckg_sel);
-
- /* physical configuration pll II */
+ /*
+ * physical configuration: I, pll I, pll II, pll III,
+ * pll IV, pll V.
+ */
+ dsi_phy_tst_set(base, PHY_CFG_I, phy->hstx_ckg_sel);
val = (phy->pll_fbd_div5f << 5) + (phy->pll_fbd_div1f << 4) +
(phy->pll_fbd_2p << 1) + phy->pll_enbwt;
- dsi_phy_tst_set(base, 0x10063, val);
-
- /* physical configuration pll II */
- dsi_phy_tst_set(base, 0x10064, phy->pll_fbd_p);
-
- /* physical configuration pll III */
- dsi_phy_tst_set(base, 0x10065, phy->pll_fbd_s);
-
- /*physical configuration pll IV*/
+ dsi_phy_tst_set(base, PHY_CFG_PLL_I, val);
+ dsi_phy_tst_set(base, PHY_CFG_PLL_II, phy->pll_fbd_p);
+ dsi_phy_tst_set(base, PHY_CFG_PLL_III, phy->pll_fbd_s);
val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p;
- dsi_phy_tst_set(base, 0x10066, val);
+ dsi_phy_tst_set(base, PHY_CFG_PLL_IV, val);
+ val = (5 << 5) + (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) +
+ phy->pll_lpf_cs;
+ dsi_phy_tst_set(base, PHY_CFG_PLL_V, val);
- /*physical configuration pll V*/
- val = (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) +
- phy->pll_lpf_cs + BIT(5);
- dsi_phy_tst_set(base, 0x10067, val);
-
- writel(BIT(2), base + PHY_RSTZ);
+ writel(PHY_ENABLECLK, base + PHY_RSTZ);
udelay(1);
- writel(BIT(2) | BIT(0), base + PHY_RSTZ);
+ writel(PHY_ENABLECLK | PHY_UNSHUTDOWNZ, base + PHY_RSTZ);
udelay(1);
- writel(BIT(2) | BIT(1) | BIT(0), base + PHY_RSTZ);
+ writel(PHY_ENABLECLK | PHY_UNRSTZ | PHY_UNSHUTDOWNZ, base + PHY_RSTZ);
usleep_range(1000, 1500);
- /* wait for phy's clock ready */
- delay_count = 0;
- is_ready = false;
- while (1) {
+ /*
+ * wait for phy's clock ready
+ */
+ delay_count = 100;
+ while (delay_count--) {
val = readl(base + PHY_STATUS);
- if (((BIT(0) | BIT(2)) & val) || delay_count > 100) {
- is_ready = (delay_count < 100) ? true : false;
- delay_count = 0;
+ if ((BIT(0) | BIT(2)) & val)
break;
- }
udelay(1);
- ++delay_count;
}
- if (!is_ready)
+ if (!delay_count)
DRM_INFO("phylock and phystopstateclklane is not ready.\n");
}
static void dsi_set_mode_timing(void __iomem *base,
- struct mipi_phy_register *phy,
+ u32 lane_byte_clk_kHz,
struct drm_display_mode *mode,
enum mipi_dsi_pixel_format format)
{
@@ -409,12 +523,11 @@ static void dsi_set_mode_timing(void __iomem *base,
u32 pixel_clk_kHz;
int htot, vtot;
u32 val;
+ u64 tmp;
- /* DSI color coding setting */
val = dsi_get_dpi_color_coding(format);
writel(val, base + DPI_COLOR_CODING);
- /* DSI format and pol setting */
val = (mode->flags & DRM_MODE_FLAG_NHSYNC ? 1 : 0) << 2;
val |= (mode->flags & DRM_MODE_FLAG_NVSYNC ? 1 : 0) << 1;
writel(val, base + DPI_CFG_POL);
@@ -436,25 +549,14 @@ static void dsi_set_mode_timing(void __iomem *base,
vbp = mode->vtotal - mode->vsync_end;
vsw = mode->vsync_end - mode->vsync_start;
if (vsw > 15) {
- DRM_INFO("vsw exceeded 15\n");
- vtot -= vsw - 15;
+ DRM_DEBUG_DRIVER("vsw exceeded 15\n");
vsw = 15;
}
- hsa_time = (hsw * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
- hbp_time = (hbp * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
- hline_time = (((u64)htot * (u64)phy->lane_byte_clk_kHz)) /
- pixel_clk_kHz;
-
- if ((R(hline_time) / 1000) > htot) {
- DRM_INFO("--: hline_time=%d\n", hline_time);
- hline_time--;
- }
-
- if ((R(hline_time) / 1000) < htot) {
- DRM_INFO("++: hline_time=%d\n", hline_time);
- hline_time++;
- }
+ hsa_time = (hsw * lane_byte_clk_kHz) / pixel_clk_kHz;
+ hbp_time = (hbp * lane_byte_clk_kHz) / pixel_clk_kHz;
+ tmp = (u64)htot * (u64)lane_byte_clk_kHz;
+ hline_time = DIV_ROUND_UP(tmp, pixel_clk_kHz);
/* all specified in byte-lane clocks */
writel(hsa_time, base + VID_HSA_TIME);
@@ -466,11 +568,16 @@ static void dsi_set_mode_timing(void __iomem *base,
writel(vfp, base + VID_VFP_LINES);
writel(mode->vdisplay, base + VID_VACTIVE_LINES);
writel(mode->hdisplay, base + VID_PKT_SIZE);
+
+ DRM_DEBUG_DRIVER("htot=%d, hfp=%d, hbp=%d, hsw=%d\n",
+ htot, hfp, hbp, hsw);
+ DRM_DEBUG_DRIVER("vtol=%d, vfp=%d, vbp=%d, vsw=%d\n",
+ vtot, vfp, vbp, vsw);
+ DRM_DEBUG_DRIVER("hsa_time=%d, hbp_time=%d, hline_time=%d\n",
+ hsa_time, hbp_time, hline_time);
}
-static void dsi_set_video_mode_type(void __iomem *base,
- struct mipi_phy_register *phy,
- unsigned long flags)
+static void dsi_set_video_mode(void __iomem *base, unsigned long flags)
{
u32 val;
u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
@@ -480,152 +587,185 @@ static void dsi_set_video_mode_type(void __iomem *base,
u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO;
/*
- * choose video type
+ * choose video mode type
*/
if ((flags & mode_mask) == non_burst_sync_pulse)
val = DSI_NON_BURST_SYNC_PULSES;
else if ((flags & mode_mask) == non_burst_sync_event)
val = DSI_NON_BURST_SYNC_EVENTS;
else
- val = DSI_BURST_SYNC_PULSES_1;
+ val = DSI_BURST_SYNC_PULSES_1 | (0x3f << 8);
writel(val, base + VID_MODE_CFG);
- /* TODO: to support LCD panel need to set LP command transfer */
+ writel(PHY_TXREQUESTCLKHS, base + LPCLK_CTRL);
}
-static void dsi_mipi_init(struct hisi_dsi *dsi)
+static void dsi_set_command_mode(void __iomem *base)
+{
+ writel(CMD_MODE_ALL_LP, base + CMD_MODE_CFG);
+ writel(DSI_COMMAND_MODE, base + MODE_CFG);
+}
+
+static void dw_dsi_set_mode(struct dw_dsi *dsi, enum dsi_work_mode mode)
+{
+ struct dsi_hw_ctx *ctx = dsi->ctx;
+ void __iomem *base = ctx->base;
+
+ writel(RESET, base + PWR_UP);
+ writel(mode, base + MODE_CFG);
+ writel(POWERUP, base + PWR_UP);
+}
+static void dsi_mipi_init(struct dw_dsi *dsi)
{
struct dsi_hw_ctx *ctx = dsi->ctx;
- struct mipi_phy_register *phy = &dsi->phy;
+ struct mipi_phy_params *phy = &dsi->phy;
struct drm_display_mode *mode = &dsi->cur_mode;
void __iomem *base = ctx->base;
- u32 dphy_freq_kHz;
+ u32 id = dsi->cur_client;
+ u32 dphy_req_kHz;
+ int bpp;
- /* count phy params */
- dphy_freq_kHz = mode->clock * 24 / dsi->lanes;
- set_dsi_phy_rate_equal_or_faster(dphy_freq_kHz, phy);
+ /*
+ * count phy params
+ */
+ bpp = mipi_dsi_pixel_format_to_bpp(dsi->client[id].format);
+ if (bpp < 0)
+ return;
+ if (dsi->client[id].phy_clock)
+ dphy_req_kHz = dsi->client[id].phy_clock;
+ else
+ dphy_req_kHz = mode->clock * bpp / dsi->client[id].lanes;
+ dsi_get_phy_params(dphy_req_kHz, phy);
/* reset Core */
- writel(0, base + PWR_UP);
+ writel(RESET, base + PWR_UP);
- /* set phy clocks */
- dsi_mipi_phy_clks(base, phy, dsi->lanes);
+ /* set dsi phy params */
+ dsi_set_mipi_phy(base, phy, dsi->client[id].lanes);
- /* set dsi mode */
- dsi_set_mode_timing(base, phy, mode, dsi->format);
+ /* set dsi mode timing */
+ dsi_set_mode_timing(base, phy->lane_byte_clk_kHz, mode,
+ dsi->client[id].format);
- /* set video mode type and low power */
- dsi_set_video_mode_type(base, phy, dsi->mode_flags);
+ /* set dsi video mode */
+ dsi_set_video_mode(base, dsi->client[id].mode_flags);
- /* DSI and D-PHY Initialization */
- writel(DSI_VIDEO_MODE, base + MODE_CFG);
- writel(BIT(0), base + LPCLK_CTRL);
- writel(BIT(0), base + PWR_UP);
+ /* set command mode */
+ dsi_set_command_mode(base);
- DRM_INFO("lanes=%d, pixel_clk=%d kHz, bytes_freq=%d kHz\n",
- dsi->lanes, mode->clock, phy->lane_byte_clk_kHz);
+ /* dsi wake up */
+ writel(POWERUP, base + PWR_UP);
+
+ DRM_DEBUG_DRIVER("lanes=%d, pixel_clk=%d kHz, bytes_freq=%d kHz\n",
+ dsi->client[id].lanes, mode->clock,
+ phy->lane_byte_clk_kHz);
}
static void dsi_encoder_disable(struct drm_encoder *encoder)
{
- struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+ struct dw_dsi *dsi = encoder_to_dsi(encoder);
struct dsi_hw_ctx *ctx = dsi->ctx;
void __iomem *base = ctx->base;
- DRM_DEBUG_DRIVER("enter\n");
if (!dsi->enable)
return;
+ dw_dsi_set_mode(dsi, DSI_COMMAND_MODE);
+ /* turn off panel's backlight */
+ if (dsi->panel && drm_panel_disable(dsi->panel))
+ DRM_ERROR("failed to disaable panel\n");
+
+ /* turn off panel */
+ if (dsi->panel && drm_panel_unprepare(dsi->panel))
+ DRM_ERROR("failed to unprepare panel\n");
+
writel(0, base + PWR_UP);
writel(0, base + LPCLK_CTRL);
writel(0, base + PHY_RSTZ);
- clk_disable_unprepare(ctx->dsi_cfg_clk);
+ clk_disable_unprepare(ctx->pclk);
dsi->enable = false;
- DRM_DEBUG_DRIVER("exit success.\n");
}
static void dsi_encoder_enable(struct drm_encoder *encoder)
{
- struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+ struct dw_dsi *dsi = encoder_to_dsi(encoder);
struct dsi_hw_ctx *ctx = dsi->ctx;
int ret;
- DRM_DEBUG_DRIVER("enter.\n");
if (dsi->enable)
return;
- /* mipi dphy clock enable */
- ret = clk_prepare_enable(ctx->dsi_cfg_clk);
+ ret = clk_prepare_enable(ctx->pclk);
if (ret) {
- DRM_ERROR("fail to enable dsi_cfg_clk: %d\n", ret);
+ DRM_ERROR("fail to enable pclk: %d\n", ret);
return;
}
dsi_mipi_init(dsi);
+ /* turn on panel */
+ if (dsi->panel && drm_panel_prepare(dsi->panel))
+ DRM_ERROR("failed to prepare panel\n");
+
+ dw_dsi_set_mode(dsi, DSI_VIDEO_MODE);
+
+ /* turn on panel's back light */
+ if (dsi->panel && drm_panel_enable(dsi->panel))
+ DRM_ERROR("failed to enable panel\n");
+
dsi->enable = true;
- DRM_DEBUG_DRIVER("exit success.\n");
}
static void dsi_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adj_mode)
{
- struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+ struct dw_dsi *dsi = encoder_to_dsi(encoder);
- DRM_DEBUG_DRIVER("enter.\n");
drm_mode_copy(&dsi->cur_mode, adj_mode);
- DRM_DEBUG_DRIVER("exit success.\n");
}
static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state)
{
- struct drm_display_mode *mode = &crtc_state->mode;
-
- DRM_DEBUG_DRIVER("enter.\n");
- if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
- DRM_ERROR("not support INTERLACE mode\n");
- return MODE_NO_INTERLACE;
- }
-
- /* pixel clock support range is (1190494208/64, 1190494208)Hz */
- if (mode->clock < 18602 || mode->clock > 1190494) {
- DRM_ERROR("mode clock not support\n");
- return MODE_CLOCK_RANGE;
- }
-
- DRM_DEBUG_DRIVER("exit success.\n");
+ /* do nothing */
return 0;
}
-static const struct drm_encoder_helper_funcs hisi_encoder_helper_funcs = {
+static const struct drm_encoder_helper_funcs dw_encoder_helper_funcs = {
.atomic_check = dsi_encoder_atomic_check,
.mode_set = dsi_encoder_mode_set,
.enable = dsi_encoder_enable,
.disable = dsi_encoder_disable
};
-static const struct drm_encoder_funcs hisi_encoder_funcs = {
+static const struct drm_encoder_funcs dw_encoder_funcs = {
.destroy = drm_encoder_cleanup,
};
-static int hisi_drm_encoder_init(struct drm_device *dev,
- struct drm_encoder *encoder)
+static int dw_drm_encoder_init(struct device *dev,
+ struct drm_device *drm_dev,
+ struct drm_encoder *encoder)
{
int ret;
+ u32 crtc_mask = drm_of_find_possible_crtcs(drm_dev, dev->of_node);
+
+ if (!crtc_mask) {
+ DRM_ERROR("failed to find crtc mask\n");
+ return -EINVAL;
+ }
- encoder->possible_crtcs = 1;
- ret = drm_encoder_init(dev, encoder, &hisi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
+ encoder->possible_crtcs = crtc_mask;
+ ret = drm_encoder_init(drm_dev, encoder, &dw_encoder_funcs,
+ DRM_MODE_ENCODER_DSI);
if (ret) {
DRM_ERROR("failed to init dsi encoder\n");
return ret;
}
- drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs);
+ drm_encoder_helper_add(encoder, &dw_encoder_helper_funcs);
return 0;
}
@@ -633,16 +773,20 @@ static int hisi_drm_encoder_init(struct drm_device *dev,
static int dsi_host_attach(struct mipi_dsi_host *host,
struct mipi_dsi_device *mdsi)
{
- struct hisi_dsi *dsi = host_to_dsi(host);
+ struct dw_dsi *dsi = host_to_dsi(host);
+ u32 id = mdsi->channel >= 1 ? OUT_PANEL : OUT_HDMI;
if (mdsi->lanes < 1 || mdsi->lanes > 4) {
DRM_ERROR("dsi device params invalid\n");
return -EINVAL;
}
- dsi->lanes = mdsi->lanes;
- dsi->format = mdsi->format;
- dsi->mode_flags = mdsi->mode_flags;
+ dsi->client[id].lanes = mdsi->lanes;
+ dsi->client[id].format = mdsi->format;
+ dsi->client[id].mode_flags = mdsi->mode_flags;
+ dsi->client[id].phy_clock = mdsi->phy_clock;
+
+ DRM_INFO("host attach, client name=[%s], id=%d\n", mdsi->name, id);
return 0;
}
@@ -654,12 +798,117 @@ static int dsi_host_detach(struct mipi_dsi_host *host,
return 0;
}
-static struct mipi_dsi_host_ops dsi_host_ops = {
+static int dsi_gen_pkt_hdr_write(void __iomem *base, u32 val)
+{
+ u32 status;
+ int ret;
+
+ ret = readx_poll_timeout(readl, base + CMD_PKT_STATUS, status,
+ !(status & GEN_CMD_FULL), 1000,
+ CMD_PKT_STATUS_TIMEOUT_US);
+ if (ret < 0) {
+ DRM_ERROR("failed to get available command FIFO\n");
+ return ret;
+ }
+
+ writel(val, base + GEN_HDR);
+
+ ret = readx_poll_timeout(readl, base + CMD_PKT_STATUS, status,
+ status & (GEN_CMD_EMPTY | GEN_PLD_W_EMPTY),
+ 1000, CMD_PKT_STATUS_TIMEOUT_US);
+ if (ret < 0) {
+ DRM_ERROR("failed to write command FIFO\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dsi_dcs_short_write(void __iomem *base,
+ const struct mipi_dsi_msg *msg)
+{
+ const u16 *tx_buf = msg->tx_buf;
+ u32 val = GEN_HDATA(*tx_buf) | GEN_HTYPE(msg->type);
+
+ if (msg->tx_len > 2) {
+ DRM_ERROR("too long tx buf length %zu for short write\n",
+ msg->tx_len);
+ return -EINVAL;
+ }
+
+ return dsi_gen_pkt_hdr_write(base, val);
+}
+
+static int dsi_dcs_long_write(void __iomem *base,
+ const struct mipi_dsi_msg *msg)
+{
+ const u32 *tx_buf = msg->tx_buf;
+ int len = msg->tx_len, pld_data_bytes = sizeof(*tx_buf), ret;
+ u32 val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type);
+ u32 remainder = 0;
+ u32 status;
+
+ if (msg->tx_len < 3) {
+ DRM_ERROR("wrong tx buf length %zu for long write\n",
+ msg->tx_len);
+ return -EINVAL;
+ }
+
+ while (DIV_ROUND_UP(len, pld_data_bytes)) {
+ if (len < pld_data_bytes) {
+ memcpy(&remainder, tx_buf, len);
+ writel(remainder, base + GEN_PLD_DATA);
+ len = 0;
+ } else {
+ writel(*tx_buf, base + GEN_PLD_DATA);
+ tx_buf++;
+ len -= pld_data_bytes;
+ }
+
+ ret = readx_poll_timeout(readl, base + CMD_PKT_STATUS,
+ status, !(status & GEN_PLD_W_FULL), 1000,
+ CMD_PKT_STATUS_TIMEOUT_US);
+ if (ret < 0) {
+ DRM_ERROR("failed to get available write payload FIFO\n");
+ return ret;
+ }
+ }
+
+ return dsi_gen_pkt_hdr_write(base, val);
+}
+
+static ssize_t dsi_host_transfer(struct mipi_dsi_host *host,
+ const struct mipi_dsi_msg *msg)
+{
+ struct dw_dsi *dsi = host_to_dsi(host);
+ struct dsi_hw_ctx *ctx = dsi->ctx;
+ void __iomem *base = ctx->base;
+ int ret;
+
+ switch (msg->type) {
+ case MIPI_DSI_DCS_SHORT_WRITE:
+ case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+ case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
+ ret = dsi_dcs_short_write(base, msg);
+ break;
+ case MIPI_DSI_DCS_LONG_WRITE:
+ ret = dsi_dcs_long_write(base, msg);
+ break;
+ default:
+ DRM_ERROR("unsupported message type\n");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct mipi_dsi_host_ops dsi_host_ops = {
.attach = dsi_host_attach,
.detach = dsi_host_detach,
+ .transfer = dsi_host_transfer,
};
-static int dsi_host_init(struct device *dev, struct hisi_dsi *dsi)
+static int dsi_host_init(struct device *dev, struct dw_dsi *dsi)
{
struct mipi_dsi_host *host = &dsi->host;
int ret;
@@ -675,44 +924,132 @@ static int dsi_host_init(struct device *dev, struct hisi_dsi *dsi)
return 0;
}
-static int dsi_bridge_init(struct drm_device *dev, struct hisi_dsi *dsi)
+static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
{
struct drm_encoder *encoder = &dsi->encoder;
struct drm_bridge *bridge = dsi->bridge;
int ret;
/* associate the bridge to dsi encoder */
- encoder->bridge = bridge;
bridge->encoder = encoder;
ret = drm_bridge_attach(dev, bridge);
if (ret) {
- DRM_ERROR("failed to attach exteranl bridge\n");
+ DRM_ERROR("failed to attach external bridge\n");
return ret;
}
return 0;
}
-static int dsi_bind(struct device *dev, struct device *master, void *data)
+static int dsi_connector_get_modes(struct drm_connector *connector)
{
- struct dsi_data *ddata = dev_get_drvdata(dev);
- struct hisi_dsi *dsi = &ddata->dsi;
- struct drm_device *drm_dev = data;
+ struct dw_dsi *dsi = connector_to_dsi(connector);
+
+ return drm_panel_get_modes(dsi->panel);
+}
+
+static enum drm_mode_status
+dsi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ enum drm_mode_status mode_status = MODE_OK;
+
+ return mode_status;
+}
+
+static struct drm_encoder *
+dsi_connector_best_encoder(struct drm_connector *connector)
+{
+ struct dw_dsi *dsi = connector_to_dsi(connector);
+
+ return &dsi->encoder;
+}
+
+static struct drm_connector_helper_funcs dsi_connector_helper_funcs = {
+ .get_modes = dsi_connector_get_modes,
+ .mode_valid = dsi_connector_mode_valid,
+ .best_encoder = dsi_connector_best_encoder,
+};
+
+static enum drm_connector_status
+dsi_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct dw_dsi *dsi = connector_to_dsi(connector);
+ enum drm_connector_status status;
+
+ status = dsi->cur_client == OUT_PANEL ? connector_status_connected :
+ connector_status_disconnected;
+
+ return status;
+}
+
+static void dsi_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
+static struct drm_connector_funcs dsi_atomic_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = dsi_connector_detect,
+ .destroy = dsi_connector_destroy,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int dsi_connector_init(struct drm_device *dev, struct dw_dsi *dsi)
+{
+ struct drm_encoder *encoder = &dsi->encoder;
+ struct drm_connector *connector = &dsi->connector;
int ret;
- ret = hisi_drm_encoder_init(drm_dev, &dsi->encoder);
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+ drm_connector_helper_add(connector,
+ &dsi_connector_helper_funcs);
+
+ ret = drm_connector_init(dev, &dsi->connector,
+ &dsi_atomic_connector_funcs,
+ DRM_MODE_CONNECTOR_DSI);
if (ret)
return ret;
- ret = dsi_host_init(dev, dsi);
+ ret = drm_mode_connector_attach_encoder(connector, encoder);
if (ret)
return ret;
- ret = dsi_bridge_init(drm_dev, dsi);
+ ret = drm_panel_attach(dsi->panel, connector);
if (ret)
return ret;
+ DRM_INFO("connector init\n");
+ return 0;
+}
+static int dsi_bind(struct device *dev, struct device *master, void *data)
+{
+ struct dsi_data *ddata = dev_get_drvdata(dev);
+ struct dw_dsi *dsi = &ddata->dsi;
+ struct drm_device *drm_dev = data;
+ int ret;
+
+ ret = dw_drm_encoder_init(dev, drm_dev, &dsi->encoder);
+ if (ret)
+ return ret;
+
+ if (dsi->bridge) {
+ ret = dsi_bridge_init(drm_dev, dsi);
+ if (ret)
+ return ret;
+ }
+
+ if (dsi->panel) {
+ ret = dsi_connector_init(drm_dev, dsi);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
@@ -726,24 +1063,11 @@ static const struct component_ops dsi_ops = {
.unbind = dsi_unbind,
};
-static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
+static int dsi_parse_bridge_endpoint(struct dw_dsi *dsi,
+ struct device_node *endpoint)
{
- struct dsi_hw_ctx *ctx = dsi->ctx;
- struct device_node *np = pdev->dev.of_node;
- struct device_node *endpoint, *bridge_node;
+ struct device_node *bridge_node;
struct drm_bridge *bridge;
- struct resource *res;
-
- /*
- * Get the endpoint node. In our case, dsi has one output port
- * to which the external HDMI bridge is connected.
- */
- endpoint = of_graph_get_next_endpoint(np, NULL);
- if (!endpoint) {
- DRM_ERROR("no valid endpoint node\n");
- return -ENODEV;
- }
- of_node_put(endpoint);
bridge_node = of_graph_get_remote_port_parent(endpoint);
if (!bridge_node) {
@@ -759,10 +1083,92 @@ static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
}
dsi->bridge = bridge;
- ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
- if (IS_ERR(ctx->dsi_cfg_clk)) {
- DRM_ERROR("failed to get dsi plck clock\n");
- return PTR_ERR(ctx->dsi_cfg_clk);
+ return 0;
+}
+
+static int dsi_parse_panel_endpoint(struct dw_dsi *dsi,
+ struct device_node *endpoint)
+{
+ struct device_node *panel_node;
+ struct drm_panel *panel;
+
+ panel_node = of_graph_get_remote_port_parent(endpoint);
+ if (!panel_node) {
+ DRM_ERROR("no valid panel node\n");
+ return -ENODEV;
+ }
+ of_node_put(panel_node);
+
+ panel = of_drm_find_panel(panel_node);
+ if (!panel) {
+ DRM_DEBUG_DRIVER("skip this panel endpoint.\n");
+ return 0;
+ }
+ dsi->panel = panel;
+
+ return 0;
+}
+
+static int dsi_parse_endpoint(struct dw_dsi *dsi,
+ struct device_node *np,
+ enum dsi_output_client client)
+{
+ struct device_node *ep_node;
+ struct of_endpoint ep;
+ int ret = 0;
+
+ if (client == OUT_MAX)
+ return -EINVAL;
+
+ for_each_endpoint_of_node(np, ep_node) {
+ ret = of_graph_parse_endpoint(ep_node, &ep);
+ if (ret) {
+ of_node_put(ep_node);
+ return ret;
+ }
+
+ /* skip dsi input port, port == 0 is input port */
+ if (ep.port == 0)
+ continue;
+
+ /* parse bridge endpoint */
+ if (client == OUT_HDMI) {
+ if (ep.id == 0) {
+ ret = dsi_parse_bridge_endpoint(dsi, ep_node);
+ if (dsi->bridge)
+ break;
+ }
+ } else { /* parse panel endpoint */
+ if (ep.id > 0) {
+ ret = dsi_parse_panel_endpoint(dsi, ep_node);
+ if (dsi->panel)
+ break;
+ }
+ }
+
+ if (ret) {
+ of_node_put(ep_node);
+ return ret;
+ }
+ }
+
+ if (!dsi->bridge && !dsi->panel) {
+ DRM_ERROR("at least one bridge or panel node is required\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int dsi_parse_dt(struct platform_device *pdev, struct dw_dsi *dsi)
+{
+ struct dsi_hw_ctx *ctx = dsi->ctx;
+ struct resource *res;
+
+ ctx->pclk = devm_clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(ctx->pclk)) {
+ DRM_ERROR("failed to get pclk clock\n");
+ return PTR_ERR(ctx->pclk);
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -772,17 +1178,25 @@ static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
return PTR_ERR(ctx->base);
}
+ dsi->gpio_mux = devm_gpiod_get(&pdev->dev, "mux", GPIOD_OUT_HIGH);
+ if (IS_ERR(dsi->gpio_mux))
+ return PTR_ERR(dsi->gpio_mux);
+ /* set dsi default output to panel */
+ dsi->cur_client = OUT_PANEL;
+
return 0;
}
static int dsi_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
struct dsi_data *data;
- struct hisi_dsi *dsi;
+ struct dw_dsi *dsi;
struct dsi_hw_ctx *ctx;
int ret;
- data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data) {
DRM_ERROR("failed to allocate dsi data.\n");
return -ENOMEM;
@@ -791,13 +1205,35 @@ static int dsi_probe(struct platform_device *pdev)
ctx = &data->ctx;
dsi->ctx = ctx;
- ret = dsi_parse_dt(pdev, dsi);
+ /* parse HDMI bridge endpoint */
+ ret = dsi_parse_endpoint(dsi, np, OUT_HDMI);
+ if (ret)
+ return ret;
+
+ ret = dsi_host_init(dev, dsi);
if (ret)
return ret;
+ /* parse panel endpoint */
+ ret = dsi_parse_endpoint(dsi, np, OUT_PANEL);
+ if (ret)
+ goto err_host_unregister;
+
+ ret = dsi_parse_dt(pdev, dsi);
+ if (ret)
+ goto err_host_unregister;
+
platform_set_drvdata(pdev, data);
- return component_add(&pdev->dev, &dsi_ops);
+ ret = component_add(dev, &dsi_ops);
+ if (ret)
+ goto err_host_unregister;
+
+ return 0;
+
+err_host_unregister:
+ mipi_dsi_host_unregister(&dsi->host);
+ return ret;
}
static int dsi_remove(struct platform_device *pdev)
@@ -817,8 +1253,7 @@ static struct platform_driver dsi_driver = {
.probe = dsi_probe,
.remove = dsi_remove,
.driver = {
- .name = "hisi-dsi",
- .owner = THIS_MODULE,
+ .name = "dw-dsi",
.of_match_table = dsi_of_match,
},
};
@@ -828,5 +1263,5 @@ module_platform_driver(dsi_driver);
MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
-MODULE_DESCRIPTION("hisilicon hi6220 SoC dsi driver");
+MODULE_DESCRIPTION("DesignWare MIPI DSI Host Controller v1.02 driver");
MODULE_LICENSE("GPL v2");
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Copyright (c) 2016 Linaro Limited.
+ * Copyright (c) 2014-2016 Hisilicon Limited.
*
* 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
@@ -7,42 +8,106 @@
*
*/
-#ifndef __HISI_DSI_REG_H__
-#define __HISI_DSI_REG_H__
+#ifndef __DW_DSI_REG_H__
+#define __DW_DSI_REG_H__
+
+#define MASK(x) (BIT(x) - 1)
/*
* regs
*/
-#define PWR_UP (0x4) /* Core power-up */
-#define PHY_IF_CFG (0xA4) /* D-PHY interface configuration */
-#define CLKMGR_CFG (0x8) /* the internal clock dividers */
-#define PHY_RSTZ (0xA0) /* D-PHY reset control */
-#define PHY_TST_CTRL0 (0xB4) /* D-PHY test interface control 0 */
-#define PHY_TST_CTRL1 (0xB8) /* D-PHY test interface control 1 */
-#define DPI_VCID (0xC) /* DPI virtual channel id */
-#define DPI_COLOR_CODING (0x10) /* DPI color coding */
-#define DPI_CFG_POL (0x14) /* DPI polarity configuration */
-#define VID_HSA_TIME (0x48) /* Horizontal Sync Active time */
-#define VID_HBP_TIME (0x4C) /* Horizontal Back Porch time */
-#define VID_HLINE_TIME (0x50) /* Line time */
-#define VID_VSA_LINES (0x54) /* Vertical Sync Active period */
-#define VID_VBP_LINES (0x58) /* Vertical Back Porch period */
-#define VID_VFP_LINES (0x5C) /* Vertical Front Porch period */
-#define VID_VACTIVE_LINES (0x60) /* Vertical resolution */
-#define VID_PKT_SIZE (0x3C) /* Video packet size */
-#define VID_MODE_CFG (0x38) /* Video mode configuration */
-#define DPI_LP_CMD_TIM (0x18) /* Low-power command timing config */
-#define PHY_TMR_CFG (0x9C) /* Data lanes timing configuration */
-#define BTA_TO_CNT (0x8C) /* Response timeout definition */
-#define PHY_TMR_LPCLK_CFG (0x98) /* clock lane timing configuration */
-#define CLK_DATA_TMR_CFG (0xCC)
-#define LPCLK_CTRL (0x94) /* Low-power in clock lane */
-#define PCKHDL_CFG (0x2C) /* Packet handler configuration */
-#define EDPI_CMD_SIZE (0x64) /* Size for eDPI packets */
-#define MODE_CFG (0x34) /* Video or Command mode selection */
-#define PHY_STATUS (0xB0) /* D-PHY PPI status interface */
+#define PWR_UP 0x04 /* Core power-up */
+#define RESET 0
+#define POWERUP BIT(0)
+#define PHY_IF_CFG 0xA4 /* D-PHY interface configuration */
+#define CLKMGR_CFG 0x08 /* the internal clock dividers */
+#define PHY_RSTZ 0xA0 /* D-PHY reset control */
+#define PHY_ENABLECLK BIT(2)
+#define PHY_UNRSTZ BIT(1)
+#define PHY_UNSHUTDOWNZ BIT(0)
+#define PHY_TST_CTRL0 0xB4 /* D-PHY test interface control 0 */
+#define PHY_TST_CTRL1 0xB8 /* D-PHY test interface control 1 */
+#define CLK_TLPX 0x10
+#define CLK_THS_PREPARE 0x11
+#define CLK_THS_ZERO 0x12
+#define CLK_THS_TRAIL 0x13
+#define CLK_TWAKEUP 0x14
+#define DATA_TLPX(x) (0x20 + ((x) << 4))
+#define DATA_THS_PREPARE(x) (0x21 + ((x) << 4))
+#define DATA_THS_ZERO(x) (0x22 + ((x) << 4))
+#define DATA_THS_TRAIL(x) (0x23 + ((x) << 4))
+#define DATA_TTA_GO(x) (0x24 + ((x) << 4))
+#define DATA_TTA_GET(x) (0x25 + ((x) << 4))
+#define DATA_TWAKEUP(x) (0x26 + ((x) << 4))
+#define PHY_CFG_I 0x60
+#define PHY_CFG_PLL_I 0x63
+#define PHY_CFG_PLL_II 0x64
+#define PHY_CFG_PLL_III 0x65
+#define PHY_CFG_PLL_IV 0x66
+#define PHY_CFG_PLL_V 0x67
+#define DPI_COLOR_CODING 0x10 /* DPI color coding */
+#define DPI_CFG_POL 0x14 /* DPI polarity configuration */
+#define VID_HSA_TIME 0x48 /* Horizontal Sync Active time */
+#define VID_HBP_TIME 0x4C /* Horizontal Back Porch time */
+#define VID_HLINE_TIME 0x50 /* Line time */
+#define VID_VSA_LINES 0x54 /* Vertical Sync Active period */
+#define VID_VBP_LINES 0x58 /* Vertical Back Porch period */
+#define VID_VFP_LINES 0x5C /* Vertical Front Porch period */
+#define VID_VACTIVE_LINES 0x60 /* Vertical resolution */
+#define VID_PKT_SIZE 0x3C /* Video packet size */
+#define VID_MODE_CFG 0x38 /* Video mode configuration */
+#define GEN_HDR 0x6c
+#define GEN_HDATA(data) (((data) & 0xffff) << 8)
+#define GEN_HDATA_MASK (0xffff << 8)
+#define GEN_HTYPE(type) (((type) & 0xff) << 0)
+#define GEN_HTYPE_MASK 0xff
+#define GEN_PLD_DATA 0x70
+#define CMD_PKT_STATUS 0x74
+#define GEN_CMD_EMPTY BIT(0)
+#define GEN_CMD_FULL BIT(1)
+#define GEN_PLD_W_EMPTY BIT(2)
+#define GEN_PLD_W_FULL BIT(3)
+#define GEN_PLD_R_EMPTY BIT(4)
+#define GEN_PLD_R_FULL BIT(5)
+#define GEN_RD_CMD_BUSY BIT(6)
+#define CMD_MODE_CFG 0x68
+#define MAX_RD_PKT_SIZE_LP BIT(24)
+#define DCS_LW_TX_LP BIT(19)
+#define DCS_SR_0P_TX_LP BIT(18)
+#define DCS_SW_1P_TX_LP BIT(17)
+#define DCS_SW_0P_TX_LP BIT(16)
+#define GEN_LW_TX_LP BIT(14)
+#define GEN_SR_2P_TX_LP BIT(13)
+#define GEN_SR_1P_TX_LP BIT(12)
+#define GEN_SR_0P_TX_LP BIT(11)
+#define GEN_SW_2P_TX_LP BIT(10)
+#define GEN_SW_1P_TX_LP BIT(9)
+#define GEN_SW_0P_TX_LP BIT(8)
+#define EN_ACK_RQST BIT(1)
+#define EN_TEAR_FX BIT(0)
+#define CMD_MODE_ALL_LP (MAX_RD_PKT_SIZE_LP | \
+ DCS_LW_TX_LP | \
+ DCS_SR_0P_TX_LP | \
+ DCS_SW_1P_TX_LP | \
+ DCS_SW_0P_TX_LP | \
+ GEN_LW_TX_LP | \
+ GEN_SR_2P_TX_LP | \
+ GEN_SR_1P_TX_LP | \
+ GEN_SR_0P_TX_LP | \
+ GEN_SW_2P_TX_LP | \
+ GEN_SW_1P_TX_LP | \
+ GEN_SW_0P_TX_LP)
+#define PHY_TMR_CFG 0x9C /* Data lanes timing configuration */
+#define BTA_TO_CNT 0x8C /* Response timeout definition */
+#define PHY_TMR_LPCLK_CFG 0x98 /* clock lane timing configuration */
+#define CLK_DATA_TMR_CFG 0xCC
+#define LPCLK_CTRL 0x94 /* Low-power in clock lane */
+#define PHY_TXREQUESTCLKHS BIT(0)
+#define MODE_CFG 0x34 /* Video or Command mode selection */
+#define PHY_STATUS 0xB0 /* D-PHY PPI status interface */
-#define PHY_STOP_WAIT_TIME (0x30)
+#define PHY_STOP_WAIT_TIME 0x30
+#define CMD_PKT_STATUS_TIMEOUT_US 20000
/*
* regs relevant enum
@@ -64,26 +129,17 @@ enum dsi_work_mode {
};
/*
- * regs Write/Read functions
+ * Register Write/Read Helper functions
*/
-static inline void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
+static inline void dw_update_bits(void __iomem *addr, u32 bit_start,
+ u32 mask, u32 val)
{
- writel(reg, base + PHY_TST_CTRL1);
- /* reg addr written at first */
- wmb();
- writel(0x02, base + PHY_TST_CTRL0);
- /* cmd1 sent for write */
- wmb();
- writel(0x00, base + PHY_TST_CTRL0);
- /* cmd2 sent for write */
- wmb();
- writel(val, base + PHY_TST_CTRL1);
- /* Then write data */
- wmb();
- writel(0x02, base + PHY_TST_CTRL0);
- /* cmd2 sent for write */
- wmb();
- writel(0x00, base + PHY_TST_CTRL0);
+ u32 tmp, orig;
+
+ orig = readl(addr);
+ tmp = orig & ~(mask << bit_start);
+ tmp |= (val & mask) << bit_start;
+ writel(tmp, addr);
}
-#endif /* __HISI_DRM_DSI_H__ */
+#endif /* __DW_DRM_DSI_H__ */
deleted file mode 100644
@@ -1,16 +0,0 @@
-/*
- * Copyright (c) 2014-2015 Hisilicon Limited.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#ifndef __HISI_DRM_ADE_H__
-#define __HISI_DRM_ADE_H__
-
-int ade_enable_vblank(struct drm_device *dev, unsigned int pipe);
-void ade_disable_vblank(struct drm_device *dev, unsigned int pipe);
-
-#endif
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Copyright (c) 2016 Linaro Limited.
+ * Copyright (c) 2014-2016 Hisilicon Limited.
*
* 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
@@ -7,164 +8,119 @@
*
*/
-#ifndef __HISI_ADE_REG_H__
-#define __HISI_ADE_REG_H__
+#ifndef __KIRIN_ADE_REG_H__
+#define __KIRIN_ADE_REG_H__
/*
- * ADE Registers Offset
+ * ADE Registers
*/
-#define ADE_CTRL (0x4)
-#define ADE_CTRL1 (0x8C)
-#define ADE_ROT_SRC_CFG (0x10)
-#define ADE_DISP_SRC_CFG (0x18)
-#define ADE_WDMA2_SRC_CFG (0x1C)
-#define ADE_SEC_OVLY_SRC_CFG (0x20)
-#define ADE_WDMA3_SRC_CFG (0x24)
-#define ADE_OVLY1_TRANS_CFG (0x2C)
-#define ADE_EN (0x100)
-#define INTR_MASK_CPU_0 (0xC10)
-#define INTR_MASK_CPU_1 (0xC14)
-#define ADE_FRM_DISGARD_CTRL (0xA4)
+#define MASK(x) (BIT(x) - 1)
+
+#define ADE_CTRL 0x0004
+#define FRM_END_START_OFST 0
+#define FRM_END_START_MASK MASK(2)
+#define AUTO_CLK_GATE_EN_OFST 0
+#define AUTO_CLK_GATE_EN BIT(0)
+#define ADE_DISP_SRC_CFG 0x0018
+#define ADE_CTRL1 0x008C
+#define ADE_EN 0x0100
+#define ADE_DISABLE 0
+#define ADE_ENABLE 1
/* reset and reload regs */
-#define ADE_SOFT_RST_SEL0 (0x78)
-#define ADE_SOFT_RST_SEL1 (0x7C)
-#define ADE_RELOAD_DIS0 (0xAC)
-#define ADE_RELOAD_DIS1 (0xB0)
-#define ADE_CH_RDMA_BIT_OFST (0)
-#define ADE_CLIP_BIT_OFST (15)
-#define ADE_SCL_BIT_OFST (21)
-#define ADE_CTRAN_BIT_OFST (24)
-#define ADE_OVLY_BIT_OFST (37) /* 32+5 */
+#define ADE_SOFT_RST_SEL(x) (0x0078 + (x) * 0x4)
+#define ADE_RELOAD_DIS(x) (0x00AC + (x) * 0x4)
+#define RDMA_OFST 0
+#define CLIP_OFST 15
+#define SCL_OFST 21
+#define CTRAN_OFST 24
+#define OVLY_OFST 37 /* 32+5 */
/* channel regs */
-#define RD_CH_PE(x) (0x1000 + (x) * 0x80)
#define RD_CH_CTRL(x) (0x1004 + (x) * 0x80)
#define RD_CH_ADDR(x) (0x1008 + (x) * 0x80)
#define RD_CH_SIZE(x) (0x100C + (x) * 0x80)
#define RD_CH_STRIDE(x) (0x1010 + (x) * 0x80)
#define RD_CH_SPACE(x) (0x1014 + (x) * 0x80)
-#define RD_CH_PARTIAL_SIZE(x) (0x1018 + (x) * 0x80)
-#define RD_CH_PARTIAL_SPACE(x) (0x101C + (x) * 0x80)
#define RD_CH_EN(x) (0x1020 + (x) * 0x80)
-#define RD_CH_STATUS(x) (0x1024 + (x) * 0x80)
-#define RD_CH_DISP_CTRL (0x1404)
-#define RD_CH_DISP_ADDR (0x1408)
-#define RD_CH_DISP_SIZE (0x140C)
-#define RD_CH_DISP_STRIDE (0x1410)
-#define RD_CH_DISP_SPACE (0x1414)
-#define RD_CH_DISP_EN (0x142C)
-/* clip regs */
-#define ADE_CLIP_DISABLE(x) (0x6800 + (x) * 0x100)
-#define ADE_CLIP_SIZE0(x) (0x6804 + (x) * 0x100)
-#define ADE_CLIP_SIZE1(x) (0x6808 + (x) * 0x100)
-#define ADE_CLIP_SIZE2(x) (0x680C + (x) * 0x100)
-#define ADE_CLIP_CFG_OK(x) (0x6810 + (x) * 0x100)
-/* scale regs */
-#define ADE_SCL1_MUX_CFG (0xC)
-#define ADE_SCL2_SRC_CFG (0x14)
-#define ADE_SCL3_MUX_CFG (0x8)
-#define ADE_SCL_CTRL(x) (0x3000 + (x) * 0x800)
-#define ADE_SCL_HSP(x) (0x3004 + (x) * 0x800)
-#define ADE_SCL_UV_HSP(x) (0x3008 + (x) * 0x800)
-#define ADE_SCL_VSP(x) (0x300C + (x) * 0x800)
-#define ADE_SCL_UV_VSP(x) (0x3010 + (x) * 0x800)
-#define ADE_SCL_ORES(x) (0x3014 + (x) * 0x800)
-#define ADE_SCL_IRES(x) (0x3018 + (x) * 0x800)
-#define ADE_SCL_START(x) (0x301C + (x) * 0x800)
-#define ADE_SCL_ERR(x) (0x3020 + (x) * 0x800)
-#define ADE_SCL_PIX_OFST(x) (0x3024 + (x) * 0x800)
-#define ADE_SCL_UV_PIX_OFST(x) (0x3028 + (x) * 0x800)
-#define ADE_SCL_COEF_CLR(x) (0x3030 + (x) * 0x800)
-#define ADE_SCL_HCOEF(x, m, n) (0x3100 + (x) * 0x800 + \
- 12 * (m) + 4 * (n))
-#define ADE_SCL_VCOEF(x, i, j) (0x340C + (x) * 0x800 + \
- 12 * (i) + 4 * (j))
-/* ctran regs */
-#define ADE_CTRAN5_TRANS_CFG (0x40)
-#define ADE_CTRAN_DIS(x) (0x5004 + (x) * 0x100)
-#define ADE_CTRAN_MODE_CHOOSE(x) (0x5008 + (x) * 0x100)
-#define ADE_CTRAN_STAT(x) (0x500C + (x) * 0x100)
-#define ADE_CTRAN_CHDC0(x) (0x5010 + (x) * 0x100)
-#define ADE_CTRAN_CHDC1(x) (0x5014 + (x) * 0x100)
-#define ADE_CTRAN_CHDC2(x) (0x5018 + (x) * 0x100)
-#define ADE_CTRAN_CHDC3(x) (0x501C + (x) * 0x100)
-#define ADE_CTRAN_CHDC4(x) (0x5020 + (x) * 0x100)
-#define ADE_CTRAN_CHDC5(x) (0x5024 + (x) * 0x100)
-#define ADE_CTRAN_CSC0(x) (0x5028 + (x) * 0x100)
-#define ADE_CTRAN_CSC1(x) (0x502C + (x) * 0x100)
-#define ADE_CTRAN_CSC2(x) (0x5030 + (x) * 0x100)
-#define ADE_CTRAN_CSC3(x) (0x5034 + (x) * 0x100)
-#define ADE_CTRAN_CSC4(x) (0x5038 + (x) * 0x100)
-#define ADE_CTRAN_IMAGE_SIZE(x) (0x503C + (x) * 0x100)
-#define ADE_CTRAN_CFG_OK(x) (0x5040 + (x) * 0x100)
/* overlay regs */
-#define ADE_OVLY_ALPHA_ST (0x2000)
+#define ADE_OVLY1_TRANS_CFG 0x002C
+#define ADE_OVLY_CTL 0x0098
#define ADE_OVLY_CH_XY0(x) (0x2004 + (x) * 4)
#define ADE_OVLY_CH_XY1(x) (0x2024 + (x) * 4)
#define ADE_OVLY_CH_CTL(x) (0x204C + (x) * 4)
#define ADE_OVLY_OUTPUT_SIZE(x) (0x2070 + (x) * 8)
-#define ADE_OVLY_BASE_COLOR(x) (0x2074 + (x) * 8)
+#define OUTPUT_XSIZE_OFST 16
#define ADE_OVLYX_CTL(x) (0x209C + (x) * 4)
-#define ADE_OVLY_CTL (0x98)
-#define ADE_OVLY_CH_ALP_MODE_OFST (0)
-#define ADE_OVLY_CH_ALP_SEL_OFST (2)
-#define ADE_OVLY_CH_UNDER_ALP_SEL_OFST (4)
-#define ADE_OVLY_CH_EN_OFST (6)
-#define ADE_OVLY_CH_ALP_GBL_OFST (15)
-#define ADE_OVLY_CH_SEL_OFST (28)
+#define CH_OVLY_SEL_OFST(x) ((x) * 4)
+#define CH_OVLY_SEL_MASK MASK(2)
+#define CH_OVLY_SEL_VAL(x) ((x) + 1)
+#define CH_ALP_MODE_OFST 0
+#define CH_ALP_SEL_OFST 2
+#define CH_UNDER_ALP_SEL_OFST 4
+#define CH_EN_OFST 6
+#define CH_ALP_GBL_OFST 15
+#define CH_SEL_OFST 28
+/* ctran regs */
+#define ADE_CTRAN_DIS(x) (0x5004 + (x) * 0x100)
+#define CTRAN_BYPASS_ON 1
+#define CTRAN_BYPASS_OFF 0
+#define ADE_CTRAN_IMAGE_SIZE(x) (0x503C + (x) * 0x100)
+/* clip regs */
+#define ADE_CLIP_DISABLE(x) (0x6800 + (x) * 0x100)
+#define ADE_CLIP_SIZE0(x) (0x6804 + (x) * 0x100)
+#define ADE_CLIP_SIZE1(x) (0x6808 + (x) * 0x100)
/*
- * media regs
+ * LDI Registers
*/
-#define SC_MEDIA_RSTDIS (0x530)
-#define SC_MEDIA_RSTEN (0x52C)
-#define NOC_ADE0_QOSGENERATOR_MODE 0x010C
-#define NOC_ADE0_QOSGENERATOR_EXTCONTROL 0x0118
-#define NOC_ADE1_QOSGENERATOR_MODE 0x020C
-#define NOC_ADE1_QOSGENERATOR_EXTCONTROL 0x0218
+#define LDI_HRZ_CTRL0 0x7400
+#define HBP_OFST 20
+#define LDI_HRZ_CTRL1 0x7404
+#define LDI_VRT_CTRL0 0x7408
+#define VBP_OFST 20
+#define LDI_VRT_CTRL1 0x740C
+#define LDI_PLR_CTRL 0x7410
+#define FLAG_NVSYNC BIT(0)
+#define FLAG_NHSYNC BIT(1)
+#define FLAG_NPIXCLK BIT(2)
+#define FLAG_NDE BIT(3)
+#define LDI_DSP_SIZE 0x7414
+#define VSIZE_OFST 20
+#define LDI_INT_EN 0x741C
+#define FRAME_END_INT_EN_OFST 1
+#define LDI_CTRL 0x7420
+#define BPP_OFST 3
+#define DATA_GATE_EN BIT(2)
+#define LDI_EN BIT(0)
+#define LDI_MSK_INT 0x7428
+#define LDI_INT_CLR 0x742C
+#define LDI_WORK_MODE 0x7430
+#define LDI_HDMI_DSI_GT 0x7434
/*
- * regs relevant enum
+ * ADE media bus service regs
*/
-enum {
- LDI_TEST = 0,
- LDI_WORK
-};
-
-enum {
- LDI_ISR_FRAME_END_INT = 0x2,
- LDI_ISR_UNDER_FLOW_INT = 0x4
-};
-
-enum {
- ADE_ISR1_RES_SWITCH_CMPL = 0x80000000
-};
-
-enum {
- LDI_DISP_MODE_NOT_3D_FBF = 0,
- LDI_DISP_MODE_3D_FBF
-};
-
-enum {
- ADE_RGB = 0,
- ADE_BGR
-};
-
-enum {
- ADE_DISABLE = 0,
- ADE_ENABLE
-};
-
-enum {
- ADE_OUT_RGB_565 = 0,
- ADE_OUT_RGB_666,
- ADE_OUT_RGB_888
-};
+#define ADE0_QOSGENERATOR_MODE 0x010C
+#define QOSGENERATOR_MODE_MASK MASK(2)
+#define ADE0_QOSGENERATOR_EXTCONTROL 0x0118
+#define SOCKET_QOS_EN BIT(0)
+#define ADE1_QOSGENERATOR_MODE 0x020C
+#define ADE1_QOSGENERATOR_EXTCONTROL 0x0218
/*
- * ADE read as big-endian, so revert the
- * rgb order described in the SoC datasheet
+ * ADE regs relevant enums
*/
-enum ADE_FORMAT {
+enum frame_end_start {
+ /* regs take effect in every vsync */
+ REG_EFFECTIVE_IN_VSYNC = 0,
+ /* regs take effect in fist ade en and every frame end */
+ REG_EFFECTIVE_IN_ADEEN_FRMEND,
+ /* regs take effect in ade en immediately */
+ REG_EFFECTIVE_IN_ADEEN,
+ /* regs take effect in first vsync and every frame end */
+ REG_EFFECTIVE_IN_VSYNC_FRMEND
+};
+
+enum ade_fb_format {
ADE_RGB_565 = 0,
ADE_BGR_565,
ADE_XRGB_8888,
@@ -175,20 +131,7 @@ enum ADE_FORMAT {
ADE_BGRA_8888,
ADE_RGB_888,
ADE_BGR_888 = 9,
- ADE_FORMAT_NOT_SUPPORT = 800
-};
-
-/* ldi src cfg */
-enum {
- TOP_DISP_SRC_NONE = 0,
- TOP_DISP_SRC_OVLY2,
- TOP_DISP_SRC_DISP,
- TOP_DISP_SRC_ROT,
- TOP_DISP_SRC_SCL2
-};
-
-enum {
- ADE_ISR_DMA_ERROR = 0x2000000
+ ADE_FORMAT_UNSUPPORT = 800
};
enum ade_channel {
@@ -220,13 +163,13 @@ enum ade_overlay {
ADE_OVLY_NUM
};
-enum {
+enum ade_alpha_mode {
ADE_ALP_GLOBAL = 0,
ADE_ALP_PIXEL,
ADE_ALP_PIXEL_AND_GLB
};
-enum {
+enum ade_alpha_blending_mode {
ADE_ALP_MUL_COEFF_0 = 0, /* alpha */
ADE_ALP_MUL_COEFF_1, /* 1-alpha */
ADE_ALP_MUL_COEFF_2, /* 0 */
@@ -234,261 +177,54 @@ enum {
};
/*
- * ADE Register Union Struct
+ * LDI regs relevant enums
*/
-union U_ADE_CTRL1 {
-struct {
- unsigned int auto_clk_gate_en :1;
- unsigned int rot_buf_shr_out :1;
- unsigned int reserved_44 :30;
- } bits;
- unsigned int u32;
+enum dsi_pclk_en {
+ DSI_PCLK_ON = 0,
+ DSI_PCLK_OFF
};
-union U_ADE_SOFT_RST_SEL0 {
-struct {
- unsigned int ch1_rdma_srst_sel :1;
- unsigned int ch2_rdma_srst_sel :1;
- unsigned int ch3_rdma_srst_sel :1;
- unsigned int ch4_rdma_srst_sel :1;
- unsigned int ch5_rdma_srst_sel :1;
- unsigned int ch6_rdma_srst_sel :1;
- unsigned int disp_rdma_srst_sel :1;
- unsigned int cmdq1_rdma_srst_sel :1;
- unsigned int cmdq2_rdma_srst_sel :1;
- unsigned int reserved_29 :1;
- unsigned int ch1_wdma_srst_sel :1;
- unsigned int ch2_wdma_srst_sel :1;
- unsigned int ch3_wdma_srst_sel :1;
- unsigned int reserved_28 :1;
- unsigned int cmdq_wdma_srst_sel :1;
- unsigned int clip1_srst_sel :1;
- unsigned int clip2_srst_sel :1;
- unsigned int clip3_srst_sel :1;
- unsigned int clip4_srst_sel :1;
- unsigned int clip5_srst_sel :1;
- unsigned int clip6_srst_sel :1;
- unsigned int scl1_srst_sel :1;
- unsigned int scl2_srst_sel :1;
- unsigned int scl3_srst_sel :1;
- unsigned int ctran1_srst_sel :1;
- unsigned int ctran2_srst_sel :1;
- unsigned int ctran3_srst_sel :1;
- unsigned int ctran4_srst_sel :1;
- unsigned int ctran5_srst_sel :1;
- unsigned int ctran6_srst_sel :1;
- unsigned int rot_srst_sel :1;
- unsigned int reserved_27 :1;
- } bits;
- unsigned int u32;
+enum ldi_output_format {
+ LDI_OUT_RGB_565 = 0,
+ LDI_OUT_RGB_666,
+ LDI_OUT_RGB_888
};
-union U_ADE_CTRL {
-struct {
- unsigned int frm_end_start :2;
- unsigned int dfs_buf_cfg :1;
- unsigned int rot_buf_cfg :3;
- unsigned int rd_ch5_nv :1;
- unsigned int rd_ch6_nv :1;
- unsigned int dfs_buf_unflow_lev1 :13;
- unsigned int dfs_buf_unflow_lev2 :11;
- } bits;
- unsigned int u32;
+enum ldi_work_mode {
+ TEST_MODE = 0,
+ NORMAL_MODE
};
-/*
- * ADE Register Write/Read functions
- */
-static inline void set_TOP_CTL_clk_gate_en(u8 *base, u32 val)
-{
- union U_ADE_CTRL1 ade_ctrl1;
- u8 *reg_addr = base + ADE_CTRL1;
-
- ade_ctrl1.u32 = readl(reg_addr);
- ade_ctrl1.bits.auto_clk_gate_en = val;
- writel(ade_ctrl1.u32, reg_addr);
-}
-
-static inline void set_TOP_SOFT_RST_SEL0_disp_rdma(u8 *base, u32 val)
-{
- union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
- u8 *addr = base + ADE_SOFT_RST_SEL0;
-
- ade_soft_rst.u32 = readl(addr);
- ade_soft_rst.bits.disp_rdma_srst_sel = val;
- writel(ade_soft_rst.u32, addr);
-}
-
-static inline void set_TOP_SOFT_RST_SEL0_ctran5(u8 *base, u32 val)
-{
- union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
- u8 *addr = base + ADE_SOFT_RST_SEL0;
-
- ade_soft_rst.u32 = readl(addr);
- ade_soft_rst.bits.ctran5_srst_sel = val;
- writel(ade_soft_rst.u32, addr);
-}
-
-static inline void set_TOP_SOFT_RST_SEL0_ctran6(u8 *base, u32 val)
-{
- union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
- u8 *addr = base + ADE_SOFT_RST_SEL0;
-
- ade_soft_rst.u32 = readl(addr);
- ade_soft_rst.bits.ctran6_srst_sel = val;
- writel(ade_soft_rst.u32, addr);
-}
-
-static inline void set_TOP_CTL_frm_end_start(u8 *base, u32 val)
-{
- union U_ADE_CTRL ade_ctrl;
- u8 *reg_addr = base + ADE_CTRL;
-
- ade_ctrl.u32 = readl(reg_addr);
- ade_ctrl.bits.frm_end_start = val;
- writel(ade_ctrl.u32, reg_addr);
-}
-
-/*
- * LDI Registers Offset
- */
-#define LDI_HRZ_CTRL0 (0x7400)
-#define LDI_HRZ_CTRL1 (0x7404)
-#define LDI_VRT_CTRL0 (0x7408)
-#define LDI_VRT_CTRL1 (0x740C)
-#define LDI_PLR_CTRL (0x7410)
-#define LDI_DSP_SIZE (0x7414)
-#define LDI_INT_EN (0x741C)
-#define LDI_CTRL (0x7420)
-#define LDI_ORG_INT (0x7424)
-#define LDI_MSK_INT (0x7428)
-#define LDI_INT_CLR (0x742C)
-#define LDI_WORK_MODE (0x7430)
-#define LDI_DE_SPACE_LOW (0x7438)
-#define LDI_MCU_INTS (0x7450)
-#define LDI_MCU_INTE (0x7454)
-#define LDI_MCU_INTC (0x7458)
-#define LDI_HDMI_DSI_GT (0x7434)
-
-/*
- * LDI Timing Polarity defines
- */
-#define HISI_LDI_FLAG_NVSYNC BIT(0)
-#define HISI_LDI_FLAG_NHSYNC BIT(1)
-#define HISI_LDI_FLAG_NPIXCLK BIT(2)
-#define HISI_LDI_FLAG_NDE BIT(3)
+enum ldi_input_source {
+ DISP_SRC_NONE = 0,
+ DISP_SRC_OVLY2,
+ DISP_SRC_DISP,
+ DISP_SRC_ROT,
+ DISP_SRC_SCL2
+};
/*
- * LDI Register Union Struct
+ * ADE media bus service relevant enums
*/
-union U_LDI_CTRL {
-struct {
- unsigned int ldi_en :1;
- unsigned int disp_mode_buf :1;
- unsigned int date_gate_en :1;
- unsigned int bpp :2;
- unsigned int wait_vsync_en :1;
- unsigned int corlorbar_width :7;
- unsigned int bgr :1;
- unsigned int color_mode :1;
- unsigned int shutdown :1;
- unsigned int vactive_line :12;
- unsigned int ldi_en_self_clr :1;
- unsigned int reserved_573 :3;
- } bits;
- unsigned int u32;
-};
-
-union U_LDI_WORK_MODE {
-struct {
- unsigned int work_mode :1;
- unsigned int wback_en :1;
- unsigned int colorbar_en :1;
- unsigned int reserved_577 :29;
- } bits;
- unsigned int u32;
+enum qos_generator_mode {
+ FIXED_MODE = 0,
+ LIMITER_MODE,
+ BYPASS_MODE,
+ REGULATOR_MODE
};
/*
- * LDI Register Write/Read Helper functions
+ * Register Write/Read Helper functions
*/
-static inline void set_reg(u8 *addr, u32 val, u32 bw, u32 bs)
-{
- u32 mask = (1 << bw) - 1;
- u32 tmp = readl(addr);
-
- tmp &= ~(mask << bs);
- writel(tmp | ((val & mask) << bs), addr);
-}
-
-static inline void set_LDI_CTRL_ldi_en(u8 *base, u32 val)
-{
- union U_LDI_CTRL ldi_ctrl;
- u8 *addr = base + LDI_CTRL;
-
- ldi_ctrl.u32 = readl(addr);
- ldi_ctrl.bits.ldi_en = val;
- writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_CTRL_disp_mode(u8 *base, u32 val)
-{
- union U_LDI_CTRL ldi_ctrl;
- u8 *addr = base + LDI_CTRL;
-
- ldi_ctrl.u32 = readl(addr);
- ldi_ctrl.bits.disp_mode_buf = val;
- writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_CTRL_bpp(u8 *base, u32 val)
-{
- union U_LDI_CTRL ldi_ctrl;
- u8 *addr = base + LDI_CTRL;
-
- ldi_ctrl.u32 = readl(addr);
- ldi_ctrl.bits.bpp = val;
- writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_CTRL_corlorbar_width(u8 *base, u32 val)
-{
- union U_LDI_CTRL ldi_ctrl;
- u8 *addr = base + LDI_CTRL;
-
- ldi_ctrl.u32 = readl(addr);
- ldi_ctrl.bits.corlorbar_width = (val > 0) ? val - 1 : 0;
- writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_CTRL_bgr(u8 *base, u32 val)
-{
- union U_LDI_CTRL ldi_ctrl;
- u8 *addr = base + LDI_CTRL;
-
- ldi_ctrl.u32 = readl(addr);
- ldi_ctrl.bits.bgr = val;
- writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_WORK_MODE_work_mode(u8 *base, u32 val)
-{
- union U_LDI_WORK_MODE ldi_work_mode;
- u8 *addr = base + LDI_WORK_MODE;
-
- ldi_work_mode.u32 = readl(addr);
- ldi_work_mode.bits.work_mode = val;
- writel(ldi_work_mode.u32, addr);
-}
-
-static inline void set_LDI_WORK_MODE_colorbar_en(u8 *base, u32 val)
+static inline void ade_update_bits(void __iomem *addr, u32 bit_start,
+ u32 mask, u32 val)
{
- union U_LDI_WORK_MODE ldi_work_mode;
- u8 *addr = base + LDI_WORK_MODE;
+ u32 tmp, orig;
- ldi_work_mode.u32 = readl(addr);
- ldi_work_mode.bits.colorbar_en = val;
- writel(ldi_work_mode.u32, addr);
+ orig = readl(addr);
+ tmp = orig & ~(mask << bit_start);
+ tmp |= (val & mask) << bit_start;
+ writel(tmp, addr);
}
#endif
@@ -1,10 +1,12 @@
/*
* Hisilicon Hi6220 SoC ADE(Advanced Display Engine)'s crtc&plane driver
*
- * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Copyright (c) 2016 Linaro Limited.
+ * Copyright (c) 2014-2016 Hisilicon Limited.
+ *
* Author:
- * Xinliang Liu <xinliang.liu@linaro.org>
* Xinliang Liu <z.liuxinliang@hisilicon.com>
+ * Xinliang Liu <xinliang.liu@linaro.org>
* Xinwei Kong <kong.kongxinwei@hisilicon.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -15,8 +17,10 @@
#include <linux/bitops.h>
#include <linux/clk.h>
-#include <linux/component.h>
#include <video/display_timing.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
@@ -30,8 +34,9 @@
#include "kirin_drm_drv.h"
#include "kirin_ade_reg.h"
-#define FORCE_PIXEL_CLOCK_SAME_OR_HIGHER 0
-#define PRIMARY_CH (ADE_CH1)
+#define PRIMARY_CH ADE_CH1 /* primary plane */
+#define OUT_OVLY ADE_OVLY2 /* output overlay compositor */
+#define ADE_DEBUG 1
#define to_ade_crtc(crtc) \
container_of(crtc, struct ade_crtc, base)
@@ -41,24 +46,20 @@
struct ade_hw_ctx {
void __iomem *base;
- void __iomem *media_base;
- void __iomem *media_noc_base;
-
- int irq;
- u32 ade_core_rate;
- u32 media_noc_rate;
-
+ struct regmap *noc_regmap;
struct clk *ade_core_clk;
struct clk *media_noc_clk;
struct clk *ade_pix_clk;
+ struct reset_control *reset;
bool power_on;
+ int irq;
};
struct ade_crtc {
struct drm_crtc base;
struct ade_hw_ctx *ctx;
bool enable;
- u64 use_mask;
+ u32 out_format;
};
struct ade_plane {
@@ -76,7 +77,7 @@ struct ade_data {
/* ade-format info: */
struct ade_format {
u32 pixel_format;
- enum ADE_FORMAT ade_format;
+ enum ade_fb_format ade_format;
};
static const struct ade_format ade_formats[] = {
@@ -126,8 +127,31 @@ static u32 ade_get_format(u32 pixel_format)
return ade_formats[i].ade_format;
/* not found */
- DRM_ERROR("Not found pixel format!!fourcc_format= %d\n", pixel_format);
- return ADE_FORMAT_NOT_SUPPORT;
+ DRM_ERROR("Not found pixel format!!fourcc_format= %d\n",
+ pixel_format);
+ return ADE_FORMAT_UNSUPPORT;
+}
+
+static void ade_update_reload_bit(void __iomem *base, u32 bit_num, u32 val)
+{
+ u32 bit_ofst, reg_num;
+
+ bit_ofst = bit_num % 32;
+ reg_num = bit_num / 32;
+
+ ade_update_bits(base + ADE_RELOAD_DIS(reg_num), bit_ofst,
+ MASK(1), !!val);
+}
+
+static u32 ade_read_reload_bit(void __iomem *base, u32 bit_num)
+{
+ u32 tmp, bit_ofst, reg_num;
+
+ bit_ofst = bit_num % 32;
+ reg_num = bit_num / 32;
+
+ tmp = readl(base + ADE_RELOAD_DIS(reg_num));
+ return !!(BIT(bit_ofst) & tmp);
}
static void ade_init(struct ade_hw_ctx *ctx)
@@ -135,20 +159,40 @@ static void ade_init(struct ade_hw_ctx *ctx)
void __iomem *base = ctx->base;
/* enable clk gate */
- set_TOP_CTL_clk_gate_en(base, 1);
+ ade_update_bits(base + ADE_CTRL1, AUTO_CLK_GATE_EN_OFST,
+ AUTO_CLK_GATE_EN, ADE_ENABLE);
/* clear overlay */
writel(0, base + ADE_OVLY1_TRANS_CFG);
writel(0, base + ADE_OVLY_CTL);
- writel(0, base + ADE_OVLYX_CTL(ADE_OVLY2));
+ writel(0, base + ADE_OVLYX_CTL(OUT_OVLY));
/* clear reset and reload regs */
- writel(0, base + ADE_SOFT_RST_SEL0);
- writel(0, base + ADE_SOFT_RST_SEL1);
- writel(0xFFFFFFFF, base + ADE_RELOAD_DIS0);
- writel(0xFFFFFFFF, base + ADE_RELOAD_DIS1);
- /* for video set to 1, means that ade registers
- * became effective at frame end
+ writel(MASK(32), base + ADE_SOFT_RST_SEL(0));
+ writel(MASK(32), base + ADE_SOFT_RST_SEL(1));
+ writel(MASK(32), base + ADE_RELOAD_DIS(0));
+ writel(MASK(32), base + ADE_RELOAD_DIS(1));
+ /*
+ * for video mode, all the ade registers should
+ * become effective at frame end.
+ */
+ ade_update_bits(base + ADE_CTRL, FRM_END_START_OFST,
+ FRM_END_START_MASK, REG_EFFECTIVE_IN_ADEEN_FRMEND);
+}
+
+static void ade_set_pix_clk(struct ade_hw_ctx *ctx,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adj_mode)
+{
+ u32 clk_Hz = mode->clock * 1000;
+ int ret;
+
+ /*
+ * Success should be guaranteed in mode_valid call back,
+ * so failure shouldn't happen here
*/
- set_TOP_CTL_frm_end_start(base, 1);
+ ret = clk_set_rate(ctx->ade_pix_clk, clk_Hz);
+ if (ret)
+ DRM_ERROR("failed to set pixel clk %dHz (%d)\n", clk_Hz, ret);
+ adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
}
static void ade_ldi_set_mode(struct ade_crtc *acrtc,
@@ -157,16 +201,13 @@ static void ade_ldi_set_mode(struct ade_crtc *acrtc,
{
struct ade_hw_ctx *ctx = acrtc->ctx;
void __iomem *base = ctx->base;
- u32 out_w = mode->hdisplay;
- u32 out_h = mode->vdisplay;
+ u32 width = mode->hdisplay;
+ u32 height = mode->vdisplay;
u32 hfp, hbp, hsw, vfp, vbp, vsw;
u32 plr_flags;
- int ret;
- plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC)
- ? HISI_LDI_FLAG_NVSYNC : 0;
- plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC)
- ? HISI_LDI_FLAG_NHSYNC : 0;
+ plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC) ? FLAG_NVSYNC : 0;
+ plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC) ? FLAG_NHSYNC : 0;
hfp = mode->hsync_start - mode->hdisplay;
hbp = mode->htotal - mode->hsync_end;
hsw = mode->hsync_end - mode->hsync_start;
@@ -174,77 +215,55 @@ static void ade_ldi_set_mode(struct ade_crtc *acrtc,
vbp = mode->vtotal - mode->vsync_end;
vsw = mode->vsync_end - mode->vsync_start;
if (vsw > 15) {
- DRM_INFO("vsw exceeded 15\n");
+ DRM_DEBUG_DRIVER("vsw exceeded 15\n");
vsw = 15;
}
- writel((hbp << 20) | (hfp << 0), base + LDI_HRZ_CTRL0);
- /* p3-73 6220V100 pdf:
- * "The configured value is the actual width - 1"
- */
+ writel((hbp << HBP_OFST) | hfp, base + LDI_HRZ_CTRL0);
+ /* the configured value is actual value - 1 */
writel(hsw - 1, base + LDI_HRZ_CTRL1);
- writel((vbp << 20) | (vfp << 0), base + LDI_VRT_CTRL0);
- /* p3-74 6220V100 pdf:
- * "The configured value is the actual width - 1"
- */
+ writel((vbp << VBP_OFST) | vfp, base + LDI_VRT_CTRL0);
+ /* the configured value is actual value - 1 */
writel(vsw - 1, base + LDI_VRT_CTRL1);
-
- /* p3-75 6220V100 pdf:
- * "The configured value is the actual width - 1"
- */
- writel(((out_h - 1) << 20) | ((out_w - 1) << 0),
+ /* the configured value is actual value - 1 */
+ writel(((height - 1) << VSIZE_OFST) | (width - 1),
base + LDI_DSP_SIZE);
writel(plr_flags, base + LDI_PLR_CTRL);
- ret = clk_set_rate(ctx->ade_pix_clk, mode->clock * 1000);
- /* Success should be guaranteed in aotomic_check
- * failer shouldn't happen here
- */
- if (ret)
- DRM_ERROR("set ade_pixel_clk_rate fail\n");
- adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
+ /* set overlay compositor output size */
+ writel(((width - 1) << OUTPUT_XSIZE_OFST) | (height - 1),
+ base + ADE_OVLY_OUTPUT_SIZE(OUT_OVLY));
/* ctran6 setting */
- writel(1, base + ADE_CTRAN_DIS(ADE_CTRAN6));
- writel(out_w * out_h - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6));
- acrtc->use_mask |= BIT(ADE_CTRAN_BIT_OFST + ADE_CTRAN6);
- DRM_INFO("set mode: %dx%d\n", out_w, out_h);
+ writel(CTRAN_BYPASS_ON, base + ADE_CTRAN_DIS(ADE_CTRAN6));
+ /* the configured value is actual value - 1 */
+ writel(width * height - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6));
+ ade_update_reload_bit(base, CTRAN_OFST + ADE_CTRAN6, 0);
- /*
- * other parameters setting
- */
- writel(BIT(0), base + LDI_WORK_MODE);
- writel((0x3c << 6) | (ADE_OUT_RGB_888 << 3) | BIT(2) | BIT(0),
- base + LDI_CTRL);
- set_reg(base + LDI_DE_SPACE_LOW, 0x1, 1, 1);
+ ade_set_pix_clk(ctx, mode, adj_mode);
+
+ DRM_DEBUG_DRIVER("set mode: %dx%d\n", width, height);
}
static int ade_power_up(struct ade_hw_ctx *ctx)
{
- void __iomem *media_base = ctx->media_base;
int ret;
- ret = clk_set_rate(ctx->ade_core_clk, ctx->ade_core_rate);
- if (ret) {
- DRM_ERROR("clk_set_rate ade_core_rate error\n");
- return ret;
- }
- ret = clk_set_rate(ctx->media_noc_clk, ctx->media_noc_rate);
+ ret = clk_prepare_enable(ctx->media_noc_clk);
if (ret) {
- DRM_ERROR("media_noc_clk media_noc_rate error\n");
+ DRM_ERROR("failed to enable media_noc_clk (%d)\n", ret);
return ret;
}
- ret = clk_prepare_enable(ctx->media_noc_clk);
+
+ ret = reset_control_deassert(ctx->reset);
if (ret) {
- DRM_ERROR("fail to clk_prepare_enable media_noc_clk\n");
+ DRM_ERROR("failed to deassert reset\n");
return ret;
}
- writel(0x20, media_base + SC_MEDIA_RSTDIS);
-
ret = clk_prepare_enable(ctx->ade_core_clk);
if (ret) {
- DRM_ERROR("fail to clk_prepare_enable ade_core_clk\n");
+ DRM_ERROR("failed to enable ade_core_clk (%d)\n", ret);
return ret;
}
@@ -256,70 +275,63 @@ static int ade_power_up(struct ade_hw_ctx *ctx)
static void ade_power_down(struct ade_hw_ctx *ctx)
{
void __iomem *base = ctx->base;
- void __iomem *media_base = ctx->media_base;
- set_LDI_CTRL_ldi_en(base, ADE_DISABLE);
+ writel(ADE_DISABLE, base + LDI_CTRL);
/* dsi pixel off */
- set_reg(base + LDI_HDMI_DSI_GT, 0x1, 1, 0);
+ writel(DSI_PCLK_OFF, base + LDI_HDMI_DSI_GT);
clk_disable_unprepare(ctx->ade_core_clk);
- writel(0x20, media_base + SC_MEDIA_RSTEN);
+ reset_control_assert(ctx->reset);
clk_disable_unprepare(ctx->media_noc_clk);
ctx->power_on = false;
}
-static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
- unsigned int index)
+static void ade_set_medianoc_qos(struct ade_crtc *acrtc)
{
- unsigned int index_tmp = 0;
- struct drm_crtc *crtc;
+ struct ade_hw_ctx *ctx = acrtc->ctx;
+ struct regmap *map = ctx->noc_regmap;
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- if (index_tmp == index)
- return crtc;
+ regmap_update_bits(map, ADE0_QOSGENERATOR_MODE,
+ QOSGENERATOR_MODE_MASK, BYPASS_MODE);
+ regmap_update_bits(map, ADE0_QOSGENERATOR_EXTCONTROL,
+ SOCKET_QOS_EN, SOCKET_QOS_EN);
- index_tmp++;
- }
-
- WARN_ON(true);
- return NULL;
+ regmap_update_bits(map, ADE1_QOSGENERATOR_MODE,
+ QOSGENERATOR_MODE_MASK, BYPASS_MODE);
+ regmap_update_bits(map, ADE1_QOSGENERATOR_EXTCONTROL,
+ SOCKET_QOS_EN, SOCKET_QOS_EN);
}
-int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
+static int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
{
- struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, pipe);
- struct ade_crtc *acrtc = to_ade_crtc(crtc);
+ struct kirin_drm_private *priv = dev->dev_private;
+ struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]);
struct ade_hw_ctx *ctx = acrtc->ctx;
void __iomem *base = ctx->base;
- u32 intr_en;
- DRM_INFO("enable_vblank enter.\n");
if (!ctx->power_on)
(void)ade_power_up(ctx);
- intr_en = readl(base + LDI_INT_EN);
- intr_en |= LDI_ISR_FRAME_END_INT;
- writel(intr_en, base + LDI_INT_EN);
+ ade_update_bits(base + LDI_INT_EN, FRAME_END_INT_EN_OFST,
+ MASK(1), 1);
return 0;
}
-void ade_disable_vblank(struct drm_device *dev, unsigned int pipe)
+static void ade_disable_vblank(struct drm_device *dev, unsigned int pipe)
{
- struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, pipe);
- struct ade_crtc *acrtc = to_ade_crtc(crtc);
+ struct kirin_drm_private *priv = dev->dev_private;
+ struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]);
struct ade_hw_ctx *ctx = acrtc->ctx;
void __iomem *base = ctx->base;
- u32 intr_en;
- DRM_INFO("disable_vblank enter.\n");
if (!ctx->power_on) {
DRM_ERROR("power is down! vblank disable fail\n");
return;
}
- intr_en = readl(base + LDI_INT_EN);
- intr_en &= ~LDI_ISR_FRAME_END_INT;
- writel(intr_en, base + LDI_INT_EN);
+
+ ade_update_bits(base + LDI_INT_EN, FRAME_END_INT_EN_OFST,
+ MASK(1), 0);
}
static irqreturn_t ade_irq_handler(int irq, void *data)
@@ -327,94 +339,135 @@ static irqreturn_t ade_irq_handler(int irq, void *data)
struct ade_crtc *acrtc = data;
struct ade_hw_ctx *ctx = acrtc->ctx;
struct drm_crtc *crtc = &acrtc->base;
- struct drm_device *dev = crtc->dev;
void __iomem *base = ctx->base;
u32 status;
status = readl(base + LDI_MSK_INT);
- /* DRM_INFO("LDI IRQ: status=0x%X\n",status); */
+ DRM_DEBUG_VBL("LDI IRQ: status=0x%X\n", status);
/* vblank irq */
- if (status & LDI_ISR_FRAME_END_INT) {
- writel(LDI_ISR_FRAME_END_INT, base + LDI_INT_CLR);
- drm_handle_vblank(dev, drm_crtc_index(crtc));
+ if (status & BIT(FRAME_END_INT_EN_OFST)) {
+ ade_update_bits(base + LDI_INT_CLR, FRAME_END_INT_EN_OFST,
+ MASK(1), 1);
+ drm_crtc_handle_vblank(crtc);
}
return IRQ_HANDLED;
}
-/*
- * set modules' reset mode: by software or hardware
- * set modules' reload enable/disable
- */
-static void ade_set_reset_and_reload(struct ade_crtc *acrtc)
+static void ade_display_enable(struct ade_crtc *acrtc)
{
struct ade_hw_ctx *ctx = acrtc->ctx;
void __iomem *base = ctx->base;
- u32 mask0 = (u32)acrtc->use_mask;
- u32 mask1 = (u32)(acrtc->use_mask >> 32);
+ u32 out_fmt = acrtc->out_format;
- DRM_DEBUG_DRIVER("mask=0x%llX, mask0=0x%X, mask1=0x%X\n",
- acrtc->use_mask, mask0, mask1);
+ /* enable output overlay compositor */
+ writel(ADE_ENABLE, base + ADE_OVLYX_CTL(OUT_OVLY));
+ ade_update_reload_bit(base, OVLY_OFST + OUT_OVLY, 0);
- writel(mask0, base + ADE_SOFT_RST_SEL0);
- writel(mask1, base + ADE_SOFT_RST_SEL1);
- writel(~mask0, base + ADE_RELOAD_DIS0);
- writel(~mask1, base + ADE_RELOAD_DIS1);
+ /* display source setting */
+ writel(DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG);
+
+ /* enable ade */
+ writel(ADE_ENABLE, base + ADE_EN);
+ /* enable ldi */
+ writel(NORMAL_MODE, base + LDI_WORK_MODE);
+ writel((out_fmt << BPP_OFST) | DATA_GATE_EN | LDI_EN,
+ base + LDI_CTRL);
+ /* dsi pixel on */
+ writel(DSI_PCLK_ON, base + LDI_HDMI_DSI_GT);
}
-void ade_set_medianoc_qos(struct ade_crtc *acrtc)
+#if ADE_DEBUG
+static void ade_rdma_dump_regs(void __iomem *base, u32 ch)
{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->media_noc_base;
- void __iomem *reg;
+ u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
u32 val;
- reg = base + NOC_ADE0_QOSGENERATOR_MODE;
- val = (readl(reg) & 0xfffffffc) | 0x2;
- writel(val, reg);
+ reg_ctrl = RD_CH_CTRL(ch);
+ reg_addr = RD_CH_ADDR(ch);
+ reg_size = RD_CH_SIZE(ch);
+ reg_stride = RD_CH_STRIDE(ch);
+ reg_space = RD_CH_SPACE(ch);
+ reg_en = RD_CH_EN(ch);
- reg = base + NOC_ADE0_QOSGENERATOR_EXTCONTROL;
- val = readl(reg) | 0x1;
- writel(val, reg);
+ val = ade_read_reload_bit(base, RDMA_OFST + ch);
+ DRM_DEBUG_DRIVER("[rdma%d]: reload(%d)\n", ch + 1, val);
+ val = readl(base + reg_ctrl);
+ DRM_DEBUG_DRIVER("[rdma%d]: reg_ctrl(0x%08x)\n", ch + 1, val);
+ val = readl(base + reg_addr);
+ DRM_DEBUG_DRIVER("[rdma%d]: reg_addr(0x%08x)\n", ch + 1, val);
+ val = readl(base + reg_size);
+ DRM_DEBUG_DRIVER("[rdma%d]: reg_size(0x%08x)\n", ch + 1, val);
+ val = readl(base + reg_stride);
+ DRM_DEBUG_DRIVER("[rdma%d]: reg_stride(0x%08x)\n", ch + 1, val);
+ val = readl(base + reg_space);
+ DRM_DEBUG_DRIVER("[rdma%d]: reg_space(0x%08x)\n", ch + 1, val);
+ val = readl(base + reg_en);
+ DRM_DEBUG_DRIVER("[rdma%d]: reg_en(0x%08x)\n", ch + 1, val);
+}
- reg = base + NOC_ADE1_QOSGENERATOR_MODE;
- val = (readl(reg) & 0xfffffffc) | 0x2;
- writel(val, reg);
+static void ade_clip_dump_regs(void __iomem *base, u32 ch)
+{
+ u32 val;
- reg = base + NOC_ADE1_QOSGENERATOR_EXTCONTROL;
- val = readl(reg) | 0x1;
- writel(val, reg);
+ val = ade_read_reload_bit(base, CLIP_OFST + ch);
+ DRM_DEBUG_DRIVER("[clip%d]: reload(%d)\n", ch + 1, val);
+ val = readl(base + ADE_CLIP_DISABLE(ch));
+ DRM_DEBUG_DRIVER("[clip%d]: reg_clip_disable(0x%08x)\n", ch + 1, val);
+ val = readl(base + ADE_CLIP_SIZE0(ch));
+ DRM_DEBUG_DRIVER("[clip%d]: reg_clip_size0(0x%08x)\n", ch + 1, val);
+ val = readl(base + ADE_CLIP_SIZE1(ch));
+ DRM_DEBUG_DRIVER("[clip%d]: reg_clip_size1(0x%08x)\n", ch + 1, val);
}
-/*
- * commit to ldi to display
- */
-static void ade_display_commit(struct ade_crtc *acrtc)
+static void ade_compositor_routing_dump_regs(void __iomem *base, u32 ch)
{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
+ u8 ovly_ch = 0; /* TODO: Only primary plane now */
+ u32 val;
- /* TODO: set rotator after overlay */
+ val = readl(base + ADE_OVLY_CH_XY0(ovly_ch));
+ DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_xy0(0x%08x)\n", ovly_ch, val);
+ val = readl(base + ADE_OVLY_CH_XY1(ovly_ch));
+ DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_xy1(0x%08x)\n", ovly_ch, val);
+ val = readl(base + ADE_OVLY_CH_CTL(ovly_ch));
+ DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_ctl(0x%08x)\n", ovly_ch, val);
+}
- /* TODO: set scale after overlay */
+static void ade_dump_overlay_compositor_regs(void __iomem *base, u32 comp)
+{
+ u32 val;
- /* display source setting */
- writel(TOP_DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG);
+ val = ade_read_reload_bit(base, OVLY_OFST + comp);
+ DRM_DEBUG_DRIVER("[overlay%d]: reload(%d)\n", comp + 1, val);
+ writel(ADE_ENABLE, base + ADE_OVLYX_CTL(comp));
+ DRM_DEBUG_DRIVER("[overlay%d]: reg_ctl(0x%08x)\n", comp + 1, val);
+ val = readl(base + ADE_OVLY_CTL);
+ DRM_DEBUG_DRIVER("ovly_ctl(0x%08x)\n", val);
+}
- /* set reset mode:soft or hw, and reload modules */
- ade_set_reset_and_reload(acrtc);
+static void ade_dump_regs(void __iomem *base)
+{
+ u32 i;
- DRM_INFO("ADE GO\n");
- /* enable ade */
- wmb();
- writel(ADE_ENABLE, base + ADE_EN);
- /* enable ldi */
- wmb();
- set_LDI_CTRL_ldi_en(base, ADE_ENABLE);
- /* dsi pixel on */
- set_reg(base + LDI_HDMI_DSI_GT, 0x0, 1, 0);
+ /* dump channel regs */
+ for (i = 0; i < ADE_CH_NUM; i++) {
+ /* dump rdma regs */
+ ade_rdma_dump_regs(base, i);
+
+ /* dump clip regs */
+ ade_clip_dump_regs(base, i);
+
+ /* dump compositor routing regs */
+ ade_compositor_routing_dump_regs(base, i);
+ }
+
+ /* dump overlay compositor regs */
+ ade_dump_overlay_compositor_regs(base, OUT_OVLY);
}
+#else
+static void ade_dump_regs(void __iomem *base) { }
+#endif
static void ade_crtc_enable(struct drm_crtc *crtc)
{
@@ -422,23 +475,19 @@ static void ade_crtc_enable(struct drm_crtc *crtc)
struct ade_hw_ctx *ctx = acrtc->ctx;
int ret;
- DRM_DEBUG_DRIVER("enter.\n");
if (acrtc->enable)
return;
if (!ctx->power_on) {
ret = ade_power_up(ctx);
- if (ret) {
- DRM_ERROR("failed to initialize ade clk\n");
+ if (ret)
return;
- }
}
ade_set_medianoc_qos(acrtc);
- ade_display_commit(acrtc);
+ ade_display_enable(acrtc);
+ ade_dump_regs(ctx->base);
acrtc->enable = true;
-
- DRM_DEBUG_DRIVER("exit success.\n");
}
static void ade_crtc_disable(struct drm_crtc *crtc)
@@ -446,21 +495,16 @@ static void ade_crtc_disable(struct drm_crtc *crtc)
struct ade_crtc *acrtc = to_ade_crtc(crtc);
struct ade_hw_ctx *ctx = acrtc->ctx;
- DRM_DEBUG_DRIVER("enter.\n");
-
if (!acrtc->enable)
return;
ade_power_down(ctx);
- acrtc->use_mask = 0;
acrtc->enable = false;
- DRM_DEBUG_DRIVER("exit success.\n");
}
-int ade_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
+static int ade_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
{
- DRM_DEBUG_DRIVER("enter.\n");
- DRM_DEBUG_DRIVER("exit success.\n");
/* do nothing */
return 0;
}
@@ -472,11 +516,9 @@ static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
struct drm_display_mode *mode = &crtc->state->mode;
struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode;
- DRM_DEBUG_DRIVER("enter.\n");
if (!ctx->power_on)
(void)ade_power_up(ctx);
ade_ldi_set_mode(acrtc, mode, adj_mode);
- DRM_DEBUG_DRIVER("exit success.\n");
}
static void ade_crtc_atomic_begin(struct drm_crtc *crtc,
@@ -485,10 +527,8 @@ static void ade_crtc_atomic_begin(struct drm_crtc *crtc,
struct ade_crtc *acrtc = to_ade_crtc(crtc);
struct ade_hw_ctx *ctx = acrtc->ctx;
- DRM_DEBUG_DRIVER("enter.\n");
if (!ctx->power_on)
(void)ade_power_up(ctx);
- DRM_DEBUG_DRIVER("exit success.\n");
}
static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
@@ -499,16 +539,12 @@ static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
struct ade_hw_ctx *ctx = acrtc->ctx;
void __iomem *base = ctx->base;
- DRM_DEBUG_DRIVER("enter.\n");
- /* commit to display: LDI input setting */
+ /* only crtc is enabled regs take effect */
if (acrtc->enable) {
- /* set reset and reload */
- ade_set_reset_and_reload(acrtc);
- /* flush ade regitsters */
- wmb();
+ ade_dump_regs(base);
+ /* flush ade registers */
writel(ADE_ENABLE, base + ADE_EN);
}
- DRM_DEBUG_DRIVER("exit success.\n");
}
static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
@@ -533,35 +569,48 @@ static const struct drm_crtc_funcs ade_crtc_funcs = {
static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
struct drm_plane *plane)
{
+ struct kirin_drm_private *priv = dev->dev_private;
+ struct device_node *port;
int ret;
- ret = drm_crtc_init_with_planes(dev, crtc, plane,
- NULL, &ade_crtc_funcs);
+ /* set crtc port so that
+ * drm_of_find_possible_crtcs call works
+ */
+ port = of_get_child_by_name(dev->dev->of_node, "port");
+ if (!port) {
+ DRM_ERROR("no port node found in %s\n",
+ dev->dev->of_node->full_name);
+ return -EINVAL;
+ }
+ of_node_put(port);
+ crtc->port = port;
+
+ ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
+ &ade_crtc_funcs);
if (ret) {
DRM_ERROR("failed to init crtc.\n");
return ret;
}
drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs);
+ priv->crtc[drm_crtc_index(crtc)] = crtc;
return 0;
}
-static void ade_rdma_set(struct ade_crtc *acrtc, struct drm_framebuffer *fb,
+static void ade_rdma_set(void __iomem *base, struct drm_framebuffer *fb,
u32 ch, u32 y, u32 in_h, u32 fmt)
{
- u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0);
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
+ u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
u32 stride = fb->pitches[0];
u32 addr = (u32)obj->paddr + y * stride;
- DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x, \
- addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n",
- ch + 1, y, in_h, stride, (u32)obj->paddr,
- addr, fb->width, fb->height,
- fmt, drm_get_format_name(fb->pixel_format));
+ DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x\n",
+ ch + 1, y, in_h, stride, (u32)obj->paddr);
+ DRM_DEBUG_DRIVER("addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n",
+ addr, fb->width, fb->height, fmt,
+ drm_get_format_name(fb->pixel_format));
/* get reg offset */
reg_ctrl = RD_CH_CTRL(ch);
@@ -579,29 +628,23 @@ static void ade_rdma_set(struct ade_crtc *acrtc, struct drm_framebuffer *fb,
writel((in_h << 16) | stride, base + reg_size);
writel(stride, base + reg_stride);
writel(in_h * stride, base + reg_space);
- writel(1, base + reg_en);
-
- acrtc->use_mask |= BIT(ADE_CH_RDMA_BIT_OFST + ch);
+ writel(ADE_ENABLE, base + reg_en);
+ ade_update_reload_bit(base, RDMA_OFST + ch, 0);
}
-static void ade_rdma_disable(struct ade_crtc *acrtc, u32 ch)
+static void ade_rdma_disable(void __iomem *base, u32 ch)
{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
u32 reg_en;
/* get reg offset */
reg_en = RD_CH_EN(ch);
-
writel(0, base + reg_en);
- acrtc->use_mask &= ~BIT(ADE_CH_RDMA_BIT_OFST + ch);
+ ade_update_reload_bit(base, RDMA_OFST + ch, 1);
}
-static void ade_clip_set(struct ade_crtc *acrtc, u32 ch, u32 fb_w, u32 x,
+static void ade_clip_set(void __iomem *base, u32 ch, u32 fb_w, u32 x,
u32 in_w, u32 in_h)
{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
u32 disable_val;
u32 clip_left;
u32 clip_right;
@@ -625,17 +668,13 @@ static void ade_clip_set(struct ade_crtc *acrtc, u32 ch, u32 fb_w, u32 x,
writel(disable_val, base + ADE_CLIP_DISABLE(ch));
writel((fb_w - 1) << 16 | (in_h - 1), base + ADE_CLIP_SIZE0(ch));
writel(clip_left << 16 | clip_right, base + ADE_CLIP_SIZE1(ch));
-
- acrtc->use_mask |= BIT(ADE_CLIP_BIT_OFST + ch);
+ ade_update_reload_bit(base, CLIP_OFST + ch, 0);
}
-static void ade_clip_disable(struct ade_crtc *acrtc, u32 ch)
+static void ade_clip_disable(void __iomem *base, u32 ch)
{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
-
writel(1, base + ADE_CLIP_DISABLE(ch));
- acrtc->use_mask &= ~BIT(ADE_CLIP_BIT_OFST + ch);
+ ade_update_reload_bit(base, CLIP_OFST + ch, 1);
}
static bool has_Alpha_channel(int format)
@@ -673,13 +712,11 @@ static void ade_get_blending_params(u32 fmt, u8 glb_alpha, u8 *alp_mode,
*under_alp_sel = ADE_ALP_MUL_COEFF_2; /* 0 */
}
-static void ade_overlay_set(struct ade_crtc *acrtc, u8 ch, u32 x0, u32 y0,
- u32 in_w, u32 in_h, u32 fmt)
+static void ade_compositor_routing_set(void __iomem *base, u8 ch,
+ u32 x0, u32 y0,
+ u32 in_w, u32 in_h, u32 fmt)
{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
- u8 ovly_ch = 0;
- u8 x = ADE_OVLY2;
+ u8 ovly_ch = 0; /* TODO: This is the zpos, only one plane now */
u8 glb_alpha = 255;
u32 x1 = x0 + in_w - 1;
u32 y1 = y0 + in_h - 1;
@@ -691,56 +728,46 @@ static void ade_overlay_set(struct ade_crtc *acrtc, u8 ch, u32 x0, u32 y0,
ade_get_blending_params(fmt, glb_alpha, &alp_mode, &alp_sel,
&under_alp_sel);
- /* overlay routing setting */
+ /* overlay routing setting
+ */
writel(x0 << 16 | y0, base + ADE_OVLY_CH_XY0(ovly_ch));
writel(x1 << 16 | y1, base + ADE_OVLY_CH_XY1(ovly_ch));
- val = (ch + 1) << ADE_OVLY_CH_SEL_OFST | BIT(ADE_OVLY_CH_EN_OFST) |
- alp_sel << ADE_OVLY_CH_ALP_SEL_OFST |
- under_alp_sel << ADE_OVLY_CH_UNDER_ALP_SEL_OFST |
- glb_alpha << ADE_OVLY_CH_ALP_GBL_OFST |
- alp_mode << ADE_OVLY_CH_ALP_MODE_OFST;
- DRM_DEBUG_DRIVER("ch%d_ctl=0x%X\n", ovly_ch + 1, val);
+ val = (ch + 1) << CH_SEL_OFST | BIT(CH_EN_OFST) |
+ alp_sel << CH_ALP_SEL_OFST |
+ under_alp_sel << CH_UNDER_ALP_SEL_OFST |
+ glb_alpha << CH_ALP_GBL_OFST |
+ alp_mode << CH_ALP_MODE_OFST;
writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
- val = (x + 1) << (ovly_ch * 4) | readl(base + ADE_OVLY_CTL);
- DRM_DEBUG_DRIVER("ovly_ctl=0x%X\n", val);
- writel(val, base + ADE_OVLY_CTL);
-
- /* when primary is enable, indicate that it's ready to output. */
- if (ch == PRIMARY_CH) {
- val = (in_w - 1) << 16 | (in_h - 1);
- writel(val, base + ADE_OVLY_OUTPUT_SIZE(x));
- writel(1, base + ADE_OVLYX_CTL(x));
- acrtc->use_mask |= BIT(ADE_OVLY_BIT_OFST + x);
- }
+ /* connect this plane/channel to overlay2 compositor */
+ ade_update_bits(base + ADE_OVLY_CTL, CH_OVLY_SEL_OFST(ovly_ch),
+ CH_OVLY_SEL_MASK, CH_OVLY_SEL_VAL(OUT_OVLY));
}
-static void ade_overlay_disable(struct ade_crtc *acrtc, u32 ch)
+static void ade_compositor_routing_disable(void __iomem *base, u32 ch)
{
- struct ade_hw_ctx *ctx = acrtc->ctx;
- void __iomem *base = ctx->base;
- u8 ovly_ch = 0;
- u32 val;
-
- val = ~BIT(6) & readl(base + ADE_OVLY_CH_CTL(ovly_ch));
- DRM_DEBUG_DRIVER("ch%d_ctl=0x%X\n", ovly_ch + 1, val);
- writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
- val = ~(0x3 << (ovly_ch * 4)) & readl(base + ADE_OVLY_CTL);
-
- DRM_DEBUG_DRIVER("ovly_ctl=0x%X\n", val);
- writel(val, base + ADE_OVLY_CTL);
+ u8 ovly_ch = 0; /* TODO: Only primary plane now */
+
+ /* disable this plane/channel */
+ ade_update_bits(base + ADE_OVLY_CH_CTL(ovly_ch), CH_EN_OFST,
+ MASK(1), 0);
+ /* dis-connect this plane/channel of overlay2 compositor */
+ ade_update_bits(base + ADE_OVLY_CTL, CH_OVLY_SEL_OFST(ovly_ch),
+ CH_OVLY_SEL_MASK, 0);
}
/*
- * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->overlay
+ * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->compositor
*/
-static void ade_update_channel(struct ade_plane *aplane, struct ade_crtc *acrtc,
+static void ade_update_channel(struct ade_plane *aplane,
struct drm_framebuffer *fb, int crtc_x,
int crtc_y, unsigned int crtc_w,
unsigned int crtc_h, u32 src_x,
u32 src_y, u32 src_w, u32 src_h)
{
- u8 ch = aplane->ch;
+ struct ade_hw_ctx *ctx = aplane->ctx;
+ void __iomem *base = ctx->base;
u32 fmt = ade_get_format(fb->pixel_format);
+ u32 ch = aplane->ch;
u32 in_w;
u32 in_h;
@@ -751,60 +778,48 @@ static void ade_update_channel(struct ade_plane *aplane, struct ade_crtc *acrtc,
/* 1) DMA setting */
in_w = src_w;
in_h = src_h;
- ade_rdma_set(acrtc, fb, ch, src_y, in_h, fmt);
+ ade_rdma_set(base, fb, ch, src_y, in_h, fmt);
/* 2) clip setting */
- ade_clip_set(acrtc, ch, fb->width, src_x, in_w, in_h);
+ ade_clip_set(base, ch, fb->width, src_x, in_w, in_h);
/* 3) TODO: scale setting for overlay planes */
/* 4) TODO: ctran/csc setting for overlay planes */
- /* 5) overlay/compositor routing setting */
- ade_overlay_set(acrtc, ch, crtc_x, crtc_y, in_w, in_h, fmt);
-
- DRM_DEBUG_DRIVER("exit success.\n");
+ /* 5) compositor routing setting */
+ ade_compositor_routing_set(base, ch, crtc_x, crtc_y, in_w, in_h, fmt);
}
-static void ade_disable_channel(struct ade_plane *aplane,
- struct ade_crtc *acrtc)
+static void ade_disable_channel(struct ade_plane *aplane)
{
+ struct ade_hw_ctx *ctx = aplane->ctx;
+ void __iomem *base = ctx->base;
u32 ch = aplane->ch;
DRM_DEBUG_DRIVER("disable channel%d\n", ch + 1);
- /*
- * when primary is disable, power is down
- * so no need to disable this channel.
- */
- if (ch == PRIMARY_CH)
- return;
-
/* disable read DMA */
- ade_rdma_disable(acrtc, ch);
+ ade_rdma_disable(base, ch);
/* disable clip */
- ade_clip_disable(acrtc, ch);
+ ade_clip_disable(base, ch);
- /* disable overlay routing */
- ade_overlay_disable(acrtc, ch);
-
- DRM_DEBUG_DRIVER("exit success.\n");
+ /* disable compositor routing */
+ ade_compositor_routing_disable(base, ch);
}
static int ade_plane_prepare_fb(struct drm_plane *plane,
const struct drm_plane_state *new_state)
{
- DRM_DEBUG_DRIVER("enter.\n");
- DRM_DEBUG_DRIVER("exit success.\n");
+ /* do nothing */
return 0;
}
static void ade_plane_cleanup_fb(struct drm_plane *plane,
const struct drm_plane_state *old_state)
{
- DRM_DEBUG_DRIVER("enter.\n");
- DRM_DEBUG_DRIVER("exit success.\n");
+ /* do nothing */
}
static int ade_plane_atomic_check(struct drm_plane *plane,
@@ -821,10 +836,15 @@ static int ade_plane_atomic_check(struct drm_plane *plane,
int crtc_y = state->crtc_y;
u32 crtc_w = state->crtc_w;
u32 crtc_h = state->crtc_h;
+ u32 fmt;
if (!crtc || !fb)
return 0;
+ fmt = ade_get_format(fb->pixel_format);
+ if (fmt == ADE_FORMAT_UNSUPPORT)
+ return -EINVAL;
+
crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
@@ -853,14 +873,8 @@ static void ade_plane_atomic_update(struct drm_plane *plane,
{
struct drm_plane_state *state = plane->state;
struct ade_plane *aplane = to_ade_plane(plane);
- struct ade_crtc *acrtc;
-
- if (!state->crtc)
- return;
- acrtc = to_ade_crtc(state->crtc);
- ade_update_channel(aplane, acrtc, state->fb,
- state->crtc_x, state->crtc_y,
+ ade_update_channel(aplane, state->fb, state->crtc_x, state->crtc_y,
state->crtc_w, state->crtc_h,
state->src_x >> 16, state->src_y >> 16,
state->src_w >> 16, state->src_h >> 16);
@@ -870,12 +884,8 @@ static void ade_plane_atomic_disable(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
struct ade_plane *aplane = to_ade_plane(plane);
- struct ade_crtc *acrtc;
- if (!old_state->crtc)
- return;
- acrtc = to_ade_crtc(old_state->crtc);
- ade_disable_channel(aplane, acrtc);
+ ade_disable_channel(aplane);
}
static const struct drm_plane_helper_funcs ade_plane_helper_funcs = {
@@ -920,181 +930,128 @@ static int ade_plane_init(struct drm_device *dev, struct ade_plane *aplane,
return 0;
}
-static int ade_bind(struct device *dev, struct device *master, void *data)
-{
- struct ade_data *ade = dev_get_drvdata(dev);
- struct ade_hw_ctx *ctx = &ade->ctx;
- struct ade_crtc *acrtc = &ade->acrtc;
- struct drm_device *drm_dev = (struct drm_device *)data;
- struct ade_plane *aplane;
- enum drm_plane_type type;
- int ret;
- int i;
-
- /*
- * plane init
- * TODO: Now only support primary plane, overlay planes
- * need to do.
- */
- for (i = 0; i < ADE_CH_NUM; i++) {
- aplane = &ade->aplane[i];
- aplane->ch = i;
- aplane->ctx = ctx;
- type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY :
- DRM_PLANE_TYPE_OVERLAY;
-
- ret = ade_plane_init(drm_dev, aplane, type);
- if (ret)
- return ret;
- }
-
- /* crtc init */
- acrtc->ctx = ctx;
- ret = ade_crtc_init(drm_dev, &acrtc->base,
- &ade->aplane[PRIMARY_CH].base);
- if (ret)
- return ret;
-
- /* vblank irq init */
- ret = request_irq(ctx->irq, ade_irq_handler, DRIVER_IRQ_SHARED,
- drm_dev->driver->name, acrtc);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static void ade_unbind(struct device *dev, struct device *master, void *data)
-{
- /* do nothing */
-}
-
-static const struct component_ops ade_ops = {
- .bind = ade_bind,
- .unbind = ade_unbind,
-};
-
static int ade_dts_parse(struct platform_device *pdev, struct ade_hw_ctx *ctx)
{
struct resource *res;
- struct device *dev;
- struct device_node *np;
- int ret;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = pdev->dev.of_node;
- dev = &pdev->dev;
- np = dev->of_node;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ade_base");
- ctx->base = devm_ioremap_resource(&pdev->dev, res);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ctx->base = devm_ioremap_resource(dev, res);
if (IS_ERR(ctx->base)) {
DRM_ERROR("failed to remap ade io base\n");
return PTR_ERR(ctx->base);
}
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "media_base");
- ctx->media_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ctx->media_base)) {
- DRM_ERROR("failed to remap media io base\n");
- return PTR_ERR(ctx->media_base);
- }
+ ctx->reset = devm_reset_control_get(dev, NULL);
+ if (IS_ERR(ctx->reset))
+ return PTR_ERR(ctx->reset);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "media_noc_base");
- ctx->media_noc_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ctx->media_noc_base)) {
- DRM_ERROR("failed to remap media noc base\n");
- return PTR_ERR(ctx->media_noc_base);
+ ctx->noc_regmap =
+ syscon_regmap_lookup_by_phandle(np, "hisilicon,noc-syscon");
+ if (IS_ERR(ctx->noc_regmap)) {
+ DRM_ERROR("failed to get noc regmap\n");
+ return PTR_ERR(ctx->noc_regmap);
}
ctx->irq = platform_get_irq(pdev, 0);
if (ctx->irq < 0) {
- DRM_ERROR("failed to parse the irq\n");
+ DRM_ERROR("failed to get irq\n");
return -ENODEV;
}
- ctx->ade_core_clk = devm_clk_get(&pdev->dev, "clk_ade_core");
+ ctx->ade_core_clk = devm_clk_get(dev, "clk_ade_core");
if (!ctx->ade_core_clk) {
- DRM_ERROR("failed to parse the ADE_CORE\n");
+ DRM_ERROR("failed to parse clk ADE_CORE\n");
return -ENODEV;
}
- ctx->media_noc_clk = devm_clk_get(&pdev->dev,
- "aclk_codec_jpeg_src");
+
+ ctx->media_noc_clk = devm_clk_get(dev, "clk_codec_jpeg");
if (!ctx->media_noc_clk) {
- DRM_ERROR("failed to parse the CODEC_JPEG\n");
- return -ENODEV;
- }
- ctx->ade_pix_clk = devm_clk_get(&pdev->dev, "clk_ade_pix");
- if (!ctx->ade_pix_clk) {
- DRM_ERROR("failed to parse the ADE_PIX_SRC\n");
+ DRM_ERROR("failed to parse clk CODEC_JPEG\n");
return -ENODEV;
}
- ret = of_property_read_u32(np, "ade_core_clk_rate",
- &ctx->ade_core_rate);
- if (ret) {
- DRM_ERROR("failed to parse the ade_core_clk_rate\n");
+ ctx->ade_pix_clk = devm_clk_get(dev, "clk_ade_pix");
+ if (!ctx->ade_pix_clk) {
+ DRM_ERROR("failed to parse clk ADE_PIX\n");
return -ENODEV;
}
- ret = of_property_read_u32(np, "media_noc_clk_rate",
- &ctx->media_noc_rate);
- if (ret) {
- DRM_ERROR("failed to parse the media_noc_clk_rate\n");
- return -ENODEV;
- }
return 0;
}
-static int ade_probe(struct platform_device *pdev)
+static int ade_drm_init(struct drm_device *dev)
{
+ struct platform_device *pdev = dev->platformdev;
struct ade_data *ade;
+ struct ade_hw_ctx *ctx;
+ struct ade_crtc *acrtc;
+ struct ade_plane *aplane;
+ enum drm_plane_type type;
int ret;
+ int i;
- DRM_DEBUG_DRIVER("enter.\n");
-
- ade = devm_kzalloc(&pdev->dev, sizeof(*ade), GFP_KERNEL);
+ ade = devm_kzalloc(dev->dev, sizeof(*ade), GFP_KERNEL);
if (!ade) {
DRM_ERROR("failed to alloc ade_data\n");
return -ENOMEM;
}
+ platform_set_drvdata(pdev, ade);
- ret = ade_dts_parse(pdev, &ade->ctx);
- if (ret) {
- DRM_ERROR("failed to parse dts!!\n");
+ ctx = &ade->ctx;
+ acrtc = &ade->acrtc;
+ acrtc->ctx = ctx;
+ acrtc->out_format = LDI_OUT_RGB_888;
+
+ ret = ade_dts_parse(pdev, ctx);
+ if (ret)
return ret;
+
+ /*
+ * plane init
+ * TODO: Now only support primary plane, overlay planes
+ * need to do.
+ */
+ for (i = 0; i < ADE_CH_NUM; i++) {
+ aplane = &ade->aplane[i];
+ aplane->ch = i;
+ aplane->ctx = ctx;
+ type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY :
+ DRM_PLANE_TYPE_OVERLAY;
+
+ ret = ade_plane_init(dev, aplane, type);
+ if (ret)
+ return ret;
}
- platform_set_drvdata(pdev, ade);
+ /* crtc init */
+ ret = ade_crtc_init(dev, &acrtc->base, &ade->aplane[PRIMARY_CH].base);
+ if (ret)
+ return ret;
+
+ /* vblank irq init */
+ ret = devm_request_irq(dev->dev, ctx->irq, ade_irq_handler,
+ IRQF_SHARED, dev->driver->name, acrtc);
+ if (ret)
+ return ret;
+ dev->driver->get_vblank_counter = drm_vblank_no_hw_counter;
+ dev->driver->enable_vblank = ade_enable_vblank;
+ dev->driver->disable_vblank = ade_disable_vblank;
- return component_add(&pdev->dev, &ade_ops);
+ return 0;
}
-static int ade_remove(struct platform_device *pdev)
+static void ade_drm_cleanup(struct drm_device *dev)
{
- component_del(&pdev->dev, &ade_ops);
+ struct platform_device *pdev = dev->platformdev;
+ struct ade_data *ade = platform_get_drvdata(pdev);
+ struct drm_crtc *crtc = &ade->acrtc.base;
- return 0;
+ drm_crtc_cleanup(crtc);
}
-static const struct of_device_id ade_of_match[] = {
- { .compatible = "hisilicon,hi6220-ade" },
- { }
+const struct kirin_dc_ops ade_dc_ops = {
+ .init = ade_drm_init,
+ .cleanup = ade_drm_cleanup
};
-MODULE_DEVICE_TABLE(of, ade_of_match);
-
-static struct platform_driver ade_driver = {
- .probe = ade_probe,
- .remove = ade_remove,
- .driver = {
- .name = "hisi-ade",
- .owner = THIS_MODULE,
- .of_match_table = ade_of_match,
- },
-};
-
-module_platform_driver(ade_driver);
-
-MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
-MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
-MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
-MODULE_DESCRIPTION("Hisilicon DRM ADE(crtc/plane) Driver");
-MODULE_LICENSE("GPL v2");
@@ -1,10 +1,12 @@
/*
- * Hisilicon SoCs drm master driver
+ * Hisilicon Kirin SoCs drm master driver
+ *
+ * Copyright (c) 2016 Linaro Limited.
+ * Copyright (c) 2014-2016 Hisilicon Limited.
*
- * Copyright (c) 2014-2015 Hisilicon Limited.
* Author:
- * Xinliang Liu <xinliang.liu@linaro.org>
* Xinliang Liu <z.liuxinliang@hisilicon.com>
+ * Xinliang Liu <xinliang.liu@linaro.org>
* Xinwei Kong <kong.kongxinwei@hisilicon.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -15,6 +17,7 @@
#include <linux/of_platform.h>
#include <linux/component.h>
+#include <linux/of_graph.h>
#include <drm/drmP.h>
#include <drm/drm_gem_cma_helper.h>
@@ -22,14 +25,13 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
-#include "hisi_drm_ade.h"
#include "kirin_drm_drv.h"
-#define DRIVER_NAME "hisi-drm"
+static struct kirin_dc_ops *dc_ops;
-static int hisi_drm_unload(struct drm_device *dev)
+static int kirin_drm_kms_cleanup(struct drm_device *dev)
{
- struct hisi_drm_private *priv = dev->dev_private;
+ struct kirin_drm_private *priv = dev->dev_private;
#ifdef CONFIG_DRM_FBDEV_EMULATION
if (priv->fbdev) {
@@ -39,6 +41,7 @@ static int hisi_drm_unload(struct drm_device *dev)
#endif
drm_kms_helper_poll_fini(dev);
drm_vblank_cleanup(dev);
+ dc_ops->cleanup(dev);
drm_mode_config_cleanup(dev);
devm_kfree(dev->dev, priv);
dev->dev_private = NULL;
@@ -46,11 +49,15 @@ static int hisi_drm_unload(struct drm_device *dev)
return 0;
}
-#ifdef CONFIG_DRM_FBDEV_EMULATION
-static void hisi_fbdev_output_poll_changed(struct drm_device *dev)
+static void kirin_fbdev_output_poll_changed(struct drm_device *dev)
{
- struct hisi_drm_private *priv = dev->dev_private;
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+ struct kirin_drm_private *priv = dev->dev_private;
+#endif
+ dsi_set_output_client(dev);
+
+#ifdef CONFIG_DRM_FBDEV_EMULATION
if (priv->fbdev) {
drm_fbdev_cma_hotplug_event(priv->fbdev);
} else {
@@ -60,19 +67,17 @@ static void hisi_fbdev_output_poll_changed(struct drm_device *dev)
if (IS_ERR(priv->fbdev))
priv->fbdev = NULL;
}
-}
#endif
+}
-static const struct drm_mode_config_funcs hisi_drm_mode_config_funcs = {
+static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = {
.fb_create = drm_fb_cma_create,
-#ifdef CONFIG_DRM_FBDEV_EMULATION
- .output_poll_changed = hisi_fbdev_output_poll_changed,
-#endif
+ .output_poll_changed = kirin_fbdev_output_poll_changed,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
-static void hisi_drm_mode_config_init(struct drm_device *dev)
+static void kirin_drm_mode_config_init(struct drm_device *dev)
{
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
@@ -80,12 +85,12 @@ static void hisi_drm_mode_config_init(struct drm_device *dev)
dev->mode_config.max_width = 2048;
dev->mode_config.max_height = 2048;
- dev->mode_config.funcs = &hisi_drm_mode_config_funcs;
+ dev->mode_config.funcs = &kirin_drm_mode_config_funcs;
}
-static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
+static int kirin_drm_kms_init(struct drm_device *dev)
{
- struct hisi_drm_private *priv;
+ struct kirin_drm_private *priv;
int ret;
priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
@@ -97,13 +102,18 @@ static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
/* dev->mode_config initialization */
drm_mode_config_init(dev);
- hisi_drm_mode_config_init(dev);
+ kirin_drm_mode_config_init(dev);
+
+ /* display controller init */
+ ret = dc_ops->init(dev);
+ if (ret)
+ goto err_mode_config_cleanup;
/* bind and init sub drivers */
ret = component_bind_all(dev->dev, dev);
if (ret) {
DRM_ERROR("failed to bind all component.\n");
- goto err_mode_config_cleanup;
+ goto err_dc_cleanup;
}
/* vblank init */
@@ -128,6 +138,8 @@ static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
err_unbind_all:
component_unbind_all(dev->dev, dev);
+err_dc_cleanup:
+ dc_ops->cleanup(dev);
err_mode_config_cleanup:
drm_mode_config_cleanup(dev);
devm_kfree(dev->dev, priv);
@@ -136,7 +148,7 @@ err_mode_config_cleanup:
return ret;
}
-static const struct file_operations hisi_drm_fops = {
+static const struct file_operations kirin_drm_fops = {
.owner = THIS_MODULE,
.open = drm_open,
.release = drm_release,
@@ -150,44 +162,28 @@ static const struct file_operations hisi_drm_fops = {
.mmap = drm_gem_cma_mmap,
};
-static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
- struct drm_gem_object *obj,
- int flags)
+static int kirin_gem_cma_dumb_create(struct drm_file *file,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
{
- /* we want to be able to write in mmapped buffer */
- flags |= O_RDWR;
- return drm_gem_prime_export(dev, obj, flags);
-}
-
-static int hisi_gem_cma_dumb_create(struct drm_file *file,
- struct drm_device *dev,
- struct drm_mode_create_dumb *args)
-{
- int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
-
- /* mali gpu need pitch 8 bytes alignment for 32bpp */
- args->pitch = roundup(min_pitch, 8);
-
return drm_gem_cma_dumb_create_internal(file, dev, args);
}
-static struct drm_driver hisi_drm_driver = {
+static struct drm_driver kirin_drm_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
- .load = hisi_drm_load,
- .unload = hisi_drm_unload,
- .fops = &hisi_drm_fops,
+ .fops = &kirin_drm_fops,
.set_busid = drm_platform_set_busid,
.gem_free_object = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
- .dumb_create = hisi_gem_cma_dumb_create,
+ .dumb_create = kirin_gem_cma_dumb_create,
.dumb_map_offset = drm_gem_cma_dumb_map_offset,
.dumb_destroy = drm_gem_dumb_destroy,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
- .gem_prime_export = hisi_gem_prime_export,
+ .gem_prime_export = drm_gem_prime_export,
.gem_prime_import = drm_gem_prime_import,
.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
@@ -195,12 +191,8 @@ static struct drm_driver hisi_drm_driver = {
.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
.gem_prime_mmap = drm_gem_cma_prime_mmap,
- .get_vblank_counter = drm_vblank_count,
- .enable_vblank = ade_enable_vblank,
- .disable_vblank = ade_disable_vblank,
-
- .name = "hisi",
- .desc = "Hisilicon SoCs' DRM Driver",
+ .name = "kirin",
+ .desc = "Hisilicon Kirin SoCs' DRM Driver",
.date = "20150718",
.major = 1,
.minor = 0,
@@ -211,70 +203,167 @@ static int compare_of(struct device *dev, void *data)
return dev->of_node == data;
}
-static int hisi_drm_bind(struct device *dev)
+static int kirin_drm_connectors_register(struct drm_device *dev)
{
- dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
- return drm_platform_init(&hisi_drm_driver, to_platform_device(dev));
+ struct drm_connector *connector;
+ struct drm_connector *failed_connector;
+ int ret;
+
+ mutex_lock(&dev->mode_config.mutex);
+ drm_for_each_connector(connector, dev) {
+ ret = drm_connector_register(connector);
+ if (ret) {
+ failed_connector = connector;
+ goto err;
+ }
+ }
+ mutex_unlock(&dev->mode_config.mutex);
+
+ return 0;
+
+err:
+ drm_for_each_connector(connector, dev) {
+ if (failed_connector == connector)
+ break;
+ drm_connector_unregister(connector);
+ }
+ mutex_unlock(&dev->mode_config.mutex);
+
+ return ret;
}
-static void hisi_drm_unbind(struct device *dev)
+static int kirin_drm_bind(struct device *dev)
+{
+ struct drm_driver *driver = &kirin_drm_driver;
+ struct drm_device *drm_dev;
+ int ret;
+
+ drm_dev = drm_dev_alloc(driver, dev);
+ if (!drm_dev)
+ return -ENOMEM;
+
+ drm_dev->platformdev = to_platform_device(dev);
+
+ ret = kirin_drm_kms_init(drm_dev);
+ if (ret)
+ goto err_drm_dev_unref;
+
+ ret = drm_dev_register(drm_dev, 0);
+ if (ret)
+ goto err_kms_cleanup;
+
+ /* connectors should be registered after drm device register */
+ ret = kirin_drm_connectors_register(drm_dev);
+ if (ret)
+ goto err_drm_dev_unregister;
+
+ DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+ driver->name, driver->major, driver->minor, driver->patchlevel,
+ driver->date, drm_dev->primary->index);
+
+ return 0;
+
+err_drm_dev_unregister:
+ drm_dev_unregister(drm_dev);
+err_kms_cleanup:
+ kirin_drm_kms_cleanup(drm_dev);
+err_drm_dev_unref:
+ drm_dev_unref(drm_dev);
+
+ return ret;
+}
+
+static void kirin_drm_unbind(struct device *dev)
{
drm_put_dev(dev_get_drvdata(dev));
}
-static const struct component_master_ops hisi_drm_ops = {
- .bind = hisi_drm_bind,
- .unbind = hisi_drm_unbind,
+static const struct component_master_ops kirin_drm_ops = {
+ .bind = kirin_drm_bind,
+ .unbind = kirin_drm_unbind,
};
-static int hisi_drm_platform_probe(struct platform_device *pdev)
+static struct device_node *kirin_get_remote_node(struct device_node *np)
+{
+ struct device_node *endpoint, *remote;
+
+ /* get the first endpoint, in our case only one remote node
+ * is connected to display controller.
+ */
+ endpoint = of_graph_get_next_endpoint(np, NULL);
+ if (!endpoint) {
+ DRM_ERROR("no valid endpoint node\n");
+ return ERR_PTR(-ENODEV);
+ }
+ of_node_put(endpoint);
+
+ remote = of_graph_get_remote_port_parent(endpoint);
+ if (!remote) {
+ DRM_ERROR("no valid remote node\n");
+ return ERR_PTR(-ENODEV);
+ }
+ of_node_put(remote);
+
+ if (!of_device_is_available(remote)) {
+ DRM_ERROR("not available for remote node\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ return remote;
+}
+
+static int kirin_drm_platform_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *node = dev->of_node;
- struct device_node *child_np;
+ struct device_node *np = dev->of_node;
struct component_match *match = NULL;
+ struct device_node *remote;
- of_platform_populate(node, NULL, NULL, dev);
-
- child_np = of_get_next_available_child(node, NULL);
- while (child_np) {
- component_match_add(dev, &match, compare_of, child_np);
- of_node_put(child_np);
- child_np = of_get_next_available_child(node, child_np);
+ dc_ops = (struct kirin_dc_ops *)of_device_get_match_data(dev);
+ if (!dc_ops) {
+ DRM_ERROR("failed to get dt id data\n");
+ return -EINVAL;
}
- return component_master_add_with_match(dev, &hisi_drm_ops, match);
+ remote = kirin_get_remote_node(np);
+ if (IS_ERR(remote))
+ return PTR_ERR(remote);
+
+ component_match_add(dev, &match, compare_of, remote);
+
+ return component_master_add_with_match(dev, &kirin_drm_ops, match);
return 0;
}
-static int hisi_drm_platform_remove(struct platform_device *pdev)
+static int kirin_drm_platform_remove(struct platform_device *pdev)
{
- component_master_del(&pdev->dev, &hisi_drm_ops);
- of_platform_depopulate(&pdev->dev);
+ component_master_del(&pdev->dev, &kirin_drm_ops);
+ dc_ops = NULL;
return 0;
}
-static const struct of_device_id hisi_drm_dt_ids[] = {
- { .compatible = "hisilicon,hi6220-dss", },
+static const struct of_device_id kirin_drm_dt_ids[] = {
+ { .compatible = "hisilicon,hi6220-ade",
+ .data = &ade_dc_ops,
+ },
{ /* end node */ },
};
-MODULE_DEVICE_TABLE(of, hisi_drm_dt_ids);
+MODULE_DEVICE_TABLE(of, kirin_drm_dt_ids);
-static struct platform_driver hisi_drm_platform_driver = {
- .probe = hisi_drm_platform_probe,
- .remove = hisi_drm_platform_remove,
+static struct platform_driver kirin_drm_platform_driver = {
+ .probe = kirin_drm_platform_probe,
+ .remove = kirin_drm_platform_remove,
.driver = {
- .owner = THIS_MODULE,
- .name = DRIVER_NAME,
- .of_match_table = hisi_drm_dt_ids,
+ .name = "kirin-drm",
+ .of_match_table = kirin_drm_dt_ids,
},
};
-module_platform_driver(hisi_drm_platform_driver);
+module_platform_driver(kirin_drm_platform_driver);
MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
-MODULE_DESCRIPTION("hisilicon SoCs' DRM master driver");
+MODULE_DESCRIPTION("hisilicon Kirin SoCs' DRM master driver");
MODULE_LICENSE("GPL v2");
@@ -1,5 +1,6 @@
/*
- * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Copyright (c) 2016 Linaro Limited.
+ * Copyright (c) 2014-2016 Hisilicon Limited.
*
* 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
@@ -7,13 +8,25 @@
*
*/
-#ifndef __HISI_DRM_DRV_H__
-#define __HISI_DRM_DRV_H__
+#ifndef __KIRIN_DRM_DRV_H__
+#define __KIRIN_DRM_DRV_H__
-struct hisi_drm_private {
+#define MAX_CRTC 2
+
+/* display controller init/cleanup ops */
+struct kirin_dc_ops {
+ int (*init)(struct drm_device *dev);
+ void (*cleanup)(struct drm_device *dev);
+};
+
+struct kirin_drm_private {
+ struct drm_crtc *crtc[MAX_CRTC];
#ifdef CONFIG_DRM_FBDEV_EMULATION
struct drm_fbdev_cma *fbdev;
#endif
};
-#endif /* __HISI_DRM_DRV_H__ */
+extern const struct kirin_dc_ops ade_dc_ops;
+extern void dsi_set_output_client(struct drm_device *dev);
+
+#endif /* __KIRIN_DRM_DRV_H__ */
@@ -144,6 +144,31 @@ enum mipi_dsi_pixel_format {
#define DSI_DEV_NAME_SIZE 20
/**
+ * mipi_dsi_pixel_format_to_bpp - obtain the number of bits per pixel for any
+ * given pixel format defined by the MIPI DSI
+ * specification
+ * @fmt: MIPI DSI pixel format
+ *
+ * Returns: The number of bits per pixel of the given pixel format.
+ */
+static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
+{
+ switch (fmt) {
+ case MIPI_DSI_FMT_RGB888:
+ case MIPI_DSI_FMT_RGB666:
+ return 24;
+
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ return 18;
+
+ case MIPI_DSI_FMT_RGB565:
+ return 16;
+ }
+
+ return -EINVAL;
+}
+
+/**
* struct mipi_dsi_device - DSI peripheral device
* @host: DSI host for this peripheral
* @dev: driver model device node for this peripheral
@@ -152,6 +177,7 @@ enum mipi_dsi_pixel_format {
* @format: pixel format for video mode
* @lanes: number of active data lanes
* @mode_flags: DSI operation mode related flags
+ * @phy_clock: phy clock assigned to this peripheral in kHz
*/
struct mipi_dsi_device {
struct mipi_dsi_host *host;
@@ -163,6 +189,7 @@ struct mipi_dsi_device {
unsigned int lanes;
enum mipi_dsi_pixel_format format;
unsigned long mode_flags;
+ u32 phy_clock; /* in kHz */
};
static inline struct mipi_dsi_device *to_mipi_dsi_device(struct device *dev)
This patch syncs the now moved hisi driver with the upstream kirin driver backport from Guodong's rebase tree. This provides binding documentation as well as device-tree changes, which allow for features like HDMI hotplug support as well as DSI panel support. Credit for the hisilicon/kirin driver we're syncing with goes to Xinliang Liu <xinliang.liu@linaro.org> who authored most of the code. Signed-off-by: John Stultz <john.stultz@linaro.org> --- .../bindings/display/hisilicon/dw-dsi.txt | 72 ++ .../bindings/display/hisilicon/hisi-ade.txt | 68 +- .../bindings/display/hisilicon/hisi-drm.txt | 66 -- .../bindings/display/hisilicon/hisi-dsi.txt | 53 -- MAINTAINERS | 10 + arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts | 58 +- arch/arm64/boot/dts/hisilicon/hi6220.dtsi | 87 +- drivers/gpu/drm/Makefile | 2 +- drivers/gpu/drm/hisilicon/Kconfig | 10 - drivers/gpu/drm/hisilicon/kirin/Kconfig | 1 + drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 929 +++++++++++++++------ drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h | 158 ++-- drivers/gpu/drm/hisilicon/kirin/hisi_drm_ade.h | 16 - drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h | 512 +++--------- drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c | 803 +++++++++--------- drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c | 255 ++++-- drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h | 23 +- include/drm/drm_mipi_dsi.h | 27 + 18 files changed, 1743 insertions(+), 1407 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/hisilicon/dw-dsi.txt delete mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt delete mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt delete mode 100644 drivers/gpu/drm/hisilicon/kirin/hisi_drm_ade.h -- 1.9.1