diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm')
50 files changed, 1903 insertions, 561 deletions
diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig index 336ad4de9981..556f81f6b2c7 100644 --- a/drivers/gpu/drm/omapdrm/Kconfig +++ b/drivers/gpu/drm/omapdrm/Kconfig @@ -4,11 +4,6 @@ config DRM_OMAP depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM select OMAP2_DSS select DRM_KMS_HELPER - select DRM_KMS_FB_HELPER - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS default n help DRM display driver for OMAP2/3/4 based boards. diff --git a/drivers/gpu/drm/omapdrm/displays/Kconfig b/drivers/gpu/drm/omapdrm/displays/Kconfig index 2a618afe0f53..c226da145fb3 100644 --- a/drivers/gpu/drm/omapdrm/displays/Kconfig +++ b/drivers/gpu/drm/omapdrm/displays/Kconfig @@ -1,80 +1,80 @@ menu "OMAPDRM External Display Device Drivers" -config DISPLAY_ENCODER_OPA362 +config DRM_OMAP_ENCODER_OPA362 tristate "OPA362 external analog amplifier" help Driver for OPA362 external analog TV amplifier controlled through a GPIO. -config DISPLAY_ENCODER_TFP410 +config DRM_OMAP_ENCODER_TFP410 tristate "TFP410 DPI to DVI Encoder" help Driver for TFP410 DPI to DVI encoder. -config DISPLAY_ENCODER_TPD12S015 +config DRM_OMAP_ENCODER_TPD12S015 tristate "TPD12S015 HDMI ESD protection and level shifter" help Driver for TPD12S015, which offers HDMI ESD protection and level shifting. -config DISPLAY_CONNECTOR_DVI +config DRM_OMAP_CONNECTOR_DVI tristate "DVI Connector" depends on I2C help Driver for a generic DVI connector. -config DISPLAY_CONNECTOR_HDMI +config DRM_OMAP_CONNECTOR_HDMI tristate "HDMI Connector" help Driver for a generic HDMI connector. -config DISPLAY_CONNECTOR_ANALOG_TV +config DRM_OMAP_CONNECTOR_ANALOG_TV tristate "Analog TV Connector" help Driver for a generic analog TV connector. -config DISPLAY_PANEL_DPI +config DRM_OMAP_PANEL_DPI tristate "Generic DPI panel" help Driver for generic DPI panels. -config DISPLAY_PANEL_DSI_CM +config DRM_OMAP_PANEL_DSI_CM tristate "Generic DSI Command Mode Panel" depends on BACKLIGHT_CLASS_DEVICE help Driver for generic DSI command mode panels. -config DISPLAY_PANEL_SONY_ACX565AKM +config DRM_OMAP_PANEL_SONY_ACX565AKM tristate "ACX565AKM Panel" depends on SPI && BACKLIGHT_CLASS_DEVICE help This is the LCD panel used on Nokia N900 -config DISPLAY_PANEL_LGPHILIPS_LB035Q02 +config DRM_OMAP_PANEL_LGPHILIPS_LB035Q02 tristate "LG.Philips LB035Q02 LCD Panel" depends on SPI help LCD Panel used on the Gumstix Overo Palo35 -config DISPLAY_PANEL_SHARP_LS037V7DW01 +config DRM_OMAP_PANEL_SHARP_LS037V7DW01 tristate "Sharp LS037V7DW01 LCD Panel" depends on BACKLIGHT_CLASS_DEVICE help LCD Panel used in TI's SDP3430 and EVM boards -config DISPLAY_PANEL_TPO_TD028TTEC1 +config DRM_OMAP_PANEL_TPO_TD028TTEC1 tristate "TPO TD028TTEC1 LCD Panel" depends on SPI help LCD panel used in Openmoko. -config DISPLAY_PANEL_TPO_TD043MTEA1 +config DRM_OMAP_PANEL_TPO_TD043MTEA1 tristate "TPO TD043MTEA1 LCD Panel" depends on SPI help LCD Panel used in OMAP3 Pandora -config DISPLAY_PANEL_NEC_NL8048HL11 +config DRM_OMAP_PANEL_NEC_NL8048HL11 tristate "NEC NL8048HL11 Panel" depends on SPI depends on BACKLIGHT_CLASS_DEVICE diff --git a/drivers/gpu/drm/omapdrm/displays/Makefile b/drivers/gpu/drm/omapdrm/displays/Makefile index 9aa176bfbf2e..46baafb1a83e 100644 --- a/drivers/gpu/drm/omapdrm/displays/Makefile +++ b/drivers/gpu/drm/omapdrm/displays/Makefile @@ -1,14 +1,14 @@ -obj-$(CONFIG_DISPLAY_ENCODER_OPA362) += encoder-opa362.o -obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o -obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o -obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o -obj-$(CONFIG_DISPLAY_CONNECTOR_HDMI) += connector-hdmi.o -obj-$(CONFIG_DISPLAY_CONNECTOR_ANALOG_TV) += connector-analog-tv.o -obj-$(CONFIG_DISPLAY_PANEL_DPI) += panel-dpi.o -obj-$(CONFIG_DISPLAY_PANEL_DSI_CM) += panel-dsi-cm.o -obj-$(CONFIG_DISPLAY_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o -obj-$(CONFIG_DISPLAY_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o -obj-$(CONFIG_DISPLAY_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o -obj-$(CONFIG_DISPLAY_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o -obj-$(CONFIG_DISPLAY_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o -obj-$(CONFIG_DISPLAY_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o +obj-$(CONFIG_DRM_OMAP_ENCODER_OPA362) += encoder-opa362.o +obj-$(CONFIG_DRM_OMAP_ENCODER_TFP410) += encoder-tfp410.o +obj-$(CONFIG_DRM_OMAP_ENCODER_TPD12S015) += encoder-tpd12s015.o +obj-$(CONFIG_DRM_OMAP_CONNECTOR_DVI) += connector-dvi.o +obj-$(CONFIG_DRM_OMAP_CONNECTOR_HDMI) += connector-hdmi.o +obj-$(CONFIG_DRM_OMAP_CONNECTOR_ANALOG_TV) += connector-analog-tv.o +obj-$(CONFIG_DRM_OMAP_PANEL_DPI) += panel-dpi.o +obj-$(CONFIG_DRM_OMAP_PANEL_DSI_CM) += panel-dsi-cm.o +obj-$(CONFIG_DRM_OMAP_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o +obj-$(CONFIG_DRM_OMAP_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o +obj-$(CONFIG_DRM_OMAP_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o +obj-$(CONFIG_DRM_OMAP_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o +obj-$(CONFIG_DRM_OMAP_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o +obj-$(CONFIG_DRM_OMAP_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o diff --git a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c index 8511c648a15c..3485d1ecd655 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-analog-tv.c @@ -14,9 +14,10 @@ #include <linux/platform_device.h> #include <linux/of.h> -#include <video/omapdss.h> #include <video/omap-panel-data.h> +#include "../dss/omapdss.h" + struct panel_drv_data { struct omap_dss_device dssdev; struct omap_dss_device *in; @@ -25,7 +26,6 @@ struct panel_drv_data { struct omap_video_timings timings; - enum omap_dss_venc_type connector_type; bool invert_polarity; }; @@ -45,10 +45,6 @@ static const struct omap_video_timings tvc_pal_timings = { static const struct of_device_id tvc_of_match[]; -struct tvc_of_data { - enum omap_dss_venc_type connector_type; -}; - #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) static int tvc_connect(struct omap_dss_device *dssdev) @@ -99,7 +95,7 @@ static int tvc_enable(struct omap_dss_device *dssdev) in->ops.atv->set_timings(in, &ddata->timings); if (!ddata->dev->of_node) { - in->ops.atv->set_type(in, ddata->connector_type); + in->ops.atv->set_type(in, OMAP_DSS_VENC_TYPE_COMPOSITE); in->ops.atv->invert_vid_out_polarity(in, ddata->invert_polarity); @@ -207,7 +203,6 @@ static int tvc_probe_pdata(struct platform_device *pdev) ddata->in = in; - ddata->connector_type = pdata->connector_type; ddata->invert_polarity = pdata->invert_polarity; dssdev = &ddata->dssdev; diff --git a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c index 747f26a55e43..684b7aeda411 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-dvi.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-dvi.c @@ -15,10 +15,10 @@ #include <linux/slab.h> #include <drm/drm_edid.h> - -#include <video/omapdss.h> #include <video/omap-panel-data.h> +#include "../dss/omapdss.h" + static const struct omap_video_timings dvic_default_timings = { .x_res = 640, .y_res = 480, @@ -255,6 +255,7 @@ static int dvic_probe_of(struct platform_device *pdev) adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0); if (adapter_node) { adapter = of_get_i2c_adapter_by_node(adapter_node); + of_node_put(adapter_node); if (adapter == NULL) { dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n"); omap_dss_put_device(ddata->in); diff --git a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c index 667ca4a24ece..7bdf83af9797 100644 --- a/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c +++ b/drivers/gpu/drm/omapdrm/displays/connector-hdmi.c @@ -17,10 +17,10 @@ #include <linux/of_gpio.h> #include <drm/drm_edid.h> - -#include <video/omapdss.h> #include <video/omap-panel-data.h> +#include "../dss/omapdss.h" + static const struct omap_video_timings hdmic_default_timings = { .x_res = 640, .y_res = 480, diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c index 9594ff7a2b0c..fe4e7ec3bab0 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-opa362.c @@ -18,9 +18,8 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> -#include <linux/of_gpio.h> -#include <video/omapdss.h> +#include "../dss/omapdss.h" struct panel_drv_data { struct omap_dss_device dssdev; diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c index 671806ca7d6a..d768217cefe0 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tfp410.c @@ -15,8 +15,7 @@ #include <linux/slab.h> #include <linux/of_gpio.h> -#include <video/omapdss.h> -#include <video/omap-panel-data.h> +#include "../dss/omapdss.h" struct panel_drv_data { struct omap_dss_device dssdev; diff --git a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c index 916a89978387..46855c8f5cbf 100644 --- a/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c +++ b/drivers/gpu/drm/omapdrm/displays/encoder-tpd12s015.c @@ -16,8 +16,7 @@ #include <linux/platform_device.h> #include <linux/gpio/consumer.h> -#include <video/omapdss.h> -#include <video/omap-panel-data.h> +#include "../dss/omapdss.h" struct panel_drv_data { struct omap_dss_device dssdev; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dpi.c b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c index 7c2331be8d15..7f16f985ab22 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dpi.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dpi.c @@ -15,11 +15,13 @@ #include <linux/slab.h> #include <linux/of.h> #include <linux/of_gpio.h> +#include <linux/regulator/consumer.h> -#include <video/omapdss.h> #include <video/omap-panel-data.h> #include <video/of_display_timing.h> +#include "../dss/omapdss.h" + struct panel_drv_data { struct omap_dss_device dssdev; struct omap_dss_device *in; @@ -32,6 +34,7 @@ struct panel_drv_data { int backlight_gpio; struct gpio_desc *enable_gpio; + struct regulator *vcc_supply; }; #define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev) @@ -83,6 +86,12 @@ static int panel_dpi_enable(struct omap_dss_device *dssdev) if (r) return r; + r = regulator_enable(ddata->vcc_supply); + if (r) { + in->ops.dpi->disable(in); + return r; + } + gpiod_set_value_cansleep(ddata->enable_gpio, 1); if (gpio_is_valid(ddata->backlight_gpio)) @@ -105,6 +114,7 @@ static void panel_dpi_disable(struct omap_dss_device *dssdev) gpio_set_value_cansleep(ddata->backlight_gpio, 0); gpiod_set_value_cansleep(ddata->enable_gpio, 0); + regulator_disable(ddata->vcc_supply); in->ops.dpi->disable(in); @@ -213,6 +223,20 @@ static int panel_dpi_probe_of(struct platform_device *pdev) ddata->enable_gpio = gpio; + /* + * Many different panels are supported by this driver and there are + * probably very different needs for their reset pins in regards to + * timing and order relative to the enable gpio. So for now it's just + * ensured that the reset line isn't active. + */ + gpio = devm_gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + + ddata->vcc_supply = devm_regulator_get(&pdev->dev, "vcc"); + if (IS_ERR(ddata->vcc_supply)) + return PTR_ERR(ddata->vcc_supply); + ddata->backlight_gpio = -ENOENT; r = of_get_display_timing(node, "panel-timing", &timing); diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c index 2b118071b5a1..0eae8afaed90 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c @@ -25,10 +25,10 @@ #include <linux/of_device.h> #include <linux/of_gpio.h> -#include <video/omapdss.h> -#include <video/omap-panel-data.h> #include <video/mipi_display.h> +#include "../dss/omapdss.h" + /* DSI Virtual channel. Hardcoded for now. */ #define TCH 0 @@ -1284,8 +1284,7 @@ static int dsicm_probe(struct platform_device *pdev) return 0; err_sysfs_create: - if (bldev != NULL) - backlight_device_unregister(bldev); + backlight_device_unregister(bldev); err_bl: destroy_workqueue(ddata->workqueue); err_reg: diff --git a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c index ac680e1de603..6dfb96cea293 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-lgphilips-lb035q02.c @@ -17,8 +17,7 @@ #include <linux/gpio.h> #include <linux/gpio/consumer.h> -#include <video/omapdss.h> -#include <video/omap-panel-data.h> +#include "../dss/omapdss.h" static struct omap_video_timings lb035q02_timings = { .x_res = 320, @@ -51,9 +50,6 @@ struct panel_drv_data { struct omap_video_timings videomode; - /* used for non-DT boot, to be removed */ - int backlight_gpio; - struct gpio_desc *enable_gpio; }; @@ -171,9 +167,6 @@ static int lb035q02_enable(struct omap_dss_device *dssdev) if (ddata->enable_gpio) gpiod_set_value_cansleep(ddata->enable_gpio, 1); - if (gpio_is_valid(ddata->backlight_gpio)) - gpio_set_value_cansleep(ddata->backlight_gpio, 1); - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; return 0; @@ -190,9 +183,6 @@ static void lb035q02_disable(struct omap_dss_device *dssdev) if (ddata->enable_gpio) gpiod_set_value_cansleep(ddata->enable_gpio, 0); - if (gpio_is_valid(ddata->backlight_gpio)) - gpio_set_value_cansleep(ddata->backlight_gpio, 0); - in->ops.dpi->disable(in); dssdev->state = OMAP_DSS_DISPLAY_DISABLED; @@ -256,8 +246,6 @@ static int lb035q02_probe_of(struct spi_device *spi) ddata->enable_gpio = gpio; - ddata->backlight_gpio = -ENOENT; - in = omapdss_of_find_source_for_first_ep(node); if (IS_ERR(in)) { dev_err(&spi->dev, "failed to find video source\n"); @@ -290,13 +278,6 @@ static int lb035q02_panel_spi_probe(struct spi_device *spi) if (r) return r; - if (gpio_is_valid(ddata->backlight_gpio)) { - r = devm_gpio_request_one(&spi->dev, ddata->backlight_gpio, - GPIOF_OUT_INIT_LOW, "panel backlight"); - if (r) - goto err_gpio; - } - ddata->videomode = lb035q02_timings; dssdev = &ddata->dssdev; @@ -316,7 +297,6 @@ static int lb035q02_panel_spi_probe(struct spi_device *spi) return 0; err_reg: -err_gpio: omap_dss_put_device(ddata->in); return r; } diff --git a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c index 38d2920a95e6..fc4c238c9583 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-nec-nl8048hl11.c @@ -18,7 +18,7 @@ #include <linux/gpio/consumer.h> #include <linux/of_gpio.h> -#include <video/omapdss.h> +#include "../dss/omapdss.h" struct panel_drv_data { struct omap_dss_device dssdev; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c index 4363fffc87e3..3d3efc561ea9 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sharp-ls037v7dw01.c @@ -13,11 +13,11 @@ #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/regulator/consumer.h> -#include <video/omapdss.h> + +#include "../dss/omapdss.h" struct panel_drv_data { struct omap_dss_device dssdev; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c index deb416736aad..157c512205d1 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c @@ -33,9 +33,10 @@ #include <linux/of.h> #include <linux/of_gpio.h> -#include <video/omapdss.h> #include <video/omap-panel-data.h> +#include "../dss/omapdss.h" + #define MIPID_CMD_READ_DISP_ID 0x04 #define MIPID_CMD_READ_RED 0x06 #define MIPID_CMD_READ_GREEN 0x07 diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c index bd8d85041926..e859b3f893f7 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c @@ -28,7 +28,8 @@ #include <linux/delay.h> #include <linux/spi/spi.h> #include <linux/gpio.h> -#include <video/omapdss.h> + +#include "../dss/omapdss.h" struct panel_drv_data { struct omap_dss_device dssdev; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c index d93175b03a12..66c6bbe6472b 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td043mtea1.c @@ -19,7 +19,7 @@ #include <linux/slab.h> #include <linux/of_gpio.h> -#include <video/omapdss.h> +#include "../dss/omapdss.h" #define TPO_R02_MODE(x) ((x) & 7) #define TPO_R02_MODE_800x480 7 diff --git a/drivers/gpu/drm/omapdrm/dss/core.c b/drivers/gpu/drm/omapdrm/dss/core.c index 7e4e5bebabbe..6a3ebfcd7223 100644 --- a/drivers/gpu/drm/omapdrm/dss/core.c +++ b/drivers/gpu/drm/omapdrm/dss/core.c @@ -35,8 +35,7 @@ #include <linux/suspend.h> #include <linux/slab.h> -#include <video/omapdss.h> - +#include "omapdss.h" #include "dss.h" #include "dss_features.h" @@ -196,8 +195,6 @@ static int __init omap_dss_probe(struct platform_device *pdev) core.default_display_name = def_disp_name; else if (pdata->default_display_name) core.default_display_name = pdata->default_display_name; - else if (pdata->default_device) - core.default_display_name = pdata->default_device->name; return 0; diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c index f83608b69e68..535240fba671 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc.c @@ -41,8 +41,7 @@ #include <linux/of.h> #include <linux/component.h> -#include <video/omapdss.h> - +#include "omapdss.h" #include "dss.h" #include "dss_features.h" #include "dispc.h" @@ -113,9 +112,14 @@ struct dispc_features { * never both, we can just use this flag for now. */ bool reverse_ilace_field_order:1; + + bool has_gamma_table:1; + + bool has_gamma_i734_bug:1; }; #define DISPC_MAX_NR_FIFOS 5 +#define DISPC_MAX_CHANNEL_GAMMA 4 static struct { struct platform_device *pdev; @@ -135,6 +139,8 @@ static struct { bool ctx_valid; u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; + u32 *gamma_table[DISPC_MAX_CHANNEL_GAMMA]; + const struct dispc_features *feat; bool is_enabled; @@ -178,11 +184,19 @@ struct dispc_reg_field { u8 low; }; +struct dispc_gamma_desc { + u32 len; + u32 bits; + u16 reg; + bool has_index; +}; + static const struct { const char *name; u32 vsync_irq; u32 framedone_irq; u32 sync_lost_irq; + struct dispc_gamma_desc gamma; struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM]; } mgr_desc[] = { [OMAP_DSS_CHANNEL_LCD] = { @@ -190,6 +204,12 @@ static const struct { .vsync_irq = DISPC_IRQ_VSYNC, .framedone_irq = DISPC_IRQ_FRAMEDONE, .sync_lost_irq = DISPC_IRQ_SYNC_LOST, + .gamma = { + .len = 256, + .bits = 8, + .reg = DISPC_GAMMA_TABLE0, + .has_index = true, + }, .reg_desc = { [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 0, 0 }, [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL, 3, 3 }, @@ -207,6 +227,12 @@ static const struct { .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN, .framedone_irq = DISPC_IRQ_FRAMEDONETV, .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT, + .gamma = { + .len = 1024, + .bits = 10, + .reg = DISPC_GAMMA_TABLE2, + .has_index = false, + }, .reg_desc = { [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 }, [DISPC_MGR_FLD_STNTFT] = { }, @@ -224,6 +250,12 @@ static const struct { .vsync_irq = DISPC_IRQ_VSYNC2, .framedone_irq = DISPC_IRQ_FRAMEDONE2, .sync_lost_irq = DISPC_IRQ_SYNC_LOST2, + .gamma = { + .len = 256, + .bits = 8, + .reg = DISPC_GAMMA_TABLE1, + .has_index = true, + }, .reg_desc = { [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL2, 0, 0 }, [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL2, 3, 3 }, @@ -241,6 +273,12 @@ static const struct { .vsync_irq = DISPC_IRQ_VSYNC3, .framedone_irq = DISPC_IRQ_FRAMEDONE3, .sync_lost_irq = DISPC_IRQ_SYNC_LOST3, + .gamma = { + .len = 256, + .bits = 8, + .reg = DISPC_GAMMA_TABLE3, + .has_index = true, + }, .reg_desc = { [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL3, 0, 0 }, [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL3, 3, 3 }, @@ -1084,20 +1122,6 @@ static u32 dispc_ovl_get_burst_size(enum omap_plane plane) return unit * 8; } -void dispc_enable_gamma_table(bool enable) -{ - /* - * This is partially implemented to support only disabling of - * the gamma table. - */ - if (enable) { - DSSWARN("Gamma table enabling for TV not yet supported"); - return; - } - - REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); -} - static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) { if (channel == OMAP_DSS_CHANNEL_DIGIT) @@ -3299,30 +3323,21 @@ static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div, static unsigned long dispc_fclk_rate(void) { - struct dss_pll *pll; - unsigned long r = 0; + unsigned long r; + enum dss_clk_source src; + + src = dss_get_dispc_clk_source(); - switch (dss_get_dispc_clk_source()) { - case OMAP_DSS_CLK_SRC_FCK: + if (src == DSS_CLK_SRC_FCK) { r = dss_get_dispc_clk_rate(); - break; - case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: - pll = dss_pll_find("dsi0"); - if (!pll) - pll = dss_pll_find("video0"); + } else { + struct dss_pll *pll; + unsigned clkout_idx; - r = pll->cinfo.clkout[0]; - break; - case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: - pll = dss_pll_find("dsi1"); - if (!pll) - pll = dss_pll_find("video1"); + pll = dss_pll_find_by_src(src); + clkout_idx = dss_pll_get_clkout_idx_for_src(src); - r = pll->cinfo.clkout[0]; - break; - default: - BUG(); - return 0; + r = pll->cinfo.clkout[clkout_idx]; } return r; @@ -3330,43 +3345,31 @@ static unsigned long dispc_fclk_rate(void) static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) { - struct dss_pll *pll; int lcd; unsigned long r; - u32 l; - - if (dss_mgr_is_lcd(channel)) { - l = dispc_read_reg(DISPC_DIVISORo(channel)); + enum dss_clk_source src; - lcd = FLD_GET(l, 23, 16); + /* for TV, LCLK rate is the FCLK rate */ + if (!dss_mgr_is_lcd(channel)) + return dispc_fclk_rate(); - switch (dss_get_lcd_clk_source(channel)) { - case OMAP_DSS_CLK_SRC_FCK: - r = dss_get_dispc_clk_rate(); - break; - case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: - pll = dss_pll_find("dsi0"); - if (!pll) - pll = dss_pll_find("video0"); + src = dss_get_lcd_clk_source(channel); - r = pll->cinfo.clkout[0]; - break; - case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: - pll = dss_pll_find("dsi1"); - if (!pll) - pll = dss_pll_find("video1"); + if (src == DSS_CLK_SRC_FCK) { + r = dss_get_dispc_clk_rate(); + } else { + struct dss_pll *pll; + unsigned clkout_idx; - r = pll->cinfo.clkout[0]; - break; - default: - BUG(); - return 0; - } + pll = dss_pll_find_by_src(src); + clkout_idx = dss_pll_get_clkout_idx_for_src(src); - return r / lcd; - } else { - return dispc_fclk_rate(); + r = pll->cinfo.clkout[clkout_idx]; } + + lcd = REG_GET(DISPC_DIVISORo(channel), 23, 16); + + return r / lcd; } static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) @@ -3426,15 +3429,14 @@ static unsigned long dispc_plane_lclk_rate(enum omap_plane plane) static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) { int lcd, pcd; - enum omap_dss_clk_source lcd_clk_src; + enum dss_clk_source lcd_clk_src; seq_printf(s, "- %s -\n", mgr_desc[channel].name); lcd_clk_src = dss_get_lcd_clk_source(channel); - seq_printf(s, "%s clk source = %s (%s)\n", mgr_desc[channel].name, - dss_get_generic_clk_source_name(lcd_clk_src), - dss_feat_get_clk_source_name(lcd_clk_src)); + seq_printf(s, "%s clk source = %s\n", mgr_desc[channel].name, + dss_get_clk_source_name(lcd_clk_src)); dispc_mgr_get_lcd_divisor(channel, &lcd, &pcd); @@ -3448,16 +3450,15 @@ void dispc_dump_clocks(struct seq_file *s) { int lcd; u32 l; - enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); + enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); if (dispc_runtime_get()) return; seq_printf(s, "- DISPC -\n"); - seq_printf(s, "dispc fclk source = %s (%s)\n", - dss_get_generic_clk_source_name(dispc_clk_src), - dss_feat_get_clk_source_name(dispc_clk_src)); + seq_printf(s, "dispc fclk source = %s\n", + dss_get_clk_source_name(dispc_clk_src)); seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate()); @@ -3814,6 +3815,139 @@ void dispc_disable_sidle(void) REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */ } +u32 dispc_mgr_gamma_size(enum omap_channel channel) +{ + const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; + + if (!dispc.feat->has_gamma_table) + return 0; + + return gdesc->len; +} +EXPORT_SYMBOL(dispc_mgr_gamma_size); + +static void dispc_mgr_write_gamma_table(enum omap_channel channel) +{ + const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; + u32 *table = dispc.gamma_table[channel]; + unsigned int i; + + DSSDBG("%s: channel %d\n", __func__, channel); + + for (i = 0; i < gdesc->len; ++i) { + u32 v = table[i]; + + if (gdesc->has_index) + v |= i << 24; + else if (i == 0) + v |= 1 << 31; + + dispc_write_reg(gdesc->reg, v); + } +} + +static void dispc_restore_gamma_tables(void) +{ + DSSDBG("%s()\n", __func__); + + if (!dispc.feat->has_gamma_table) + return; + + dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD); + + dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_DIGIT); + + if (dss_has_feature(FEAT_MGR_LCD2)) + dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD2); + + if (dss_has_feature(FEAT_MGR_LCD3)) + dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD3); +} + +static const struct drm_color_lut dispc_mgr_gamma_default_lut[] = { + { .red = 0, .green = 0, .blue = 0, }, + { .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, }, +}; + +void dispc_mgr_set_gamma(enum omap_channel channel, + const struct drm_color_lut *lut, + unsigned int length) +{ + const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; + u32 *table = dispc.gamma_table[channel]; + uint i; + + DSSDBG("%s: channel %d, lut len %u, hw len %u\n", __func__, + channel, length, gdesc->len); + + if (!dispc.feat->has_gamma_table) + return; + + if (lut == NULL || length < 2) { + lut = dispc_mgr_gamma_default_lut; + length = ARRAY_SIZE(dispc_mgr_gamma_default_lut); + } + + for (i = 0; i < length - 1; ++i) { + uint first = i * (gdesc->len - 1) / (length - 1); + uint last = (i + 1) * (gdesc->len - 1) / (length - 1); + uint w = last - first; + u16 r, g, b; + uint j; + + if (w == 0) + continue; + + for (j = 0; j <= w; j++) { + r = (lut[i].red * (w - j) + lut[i+1].red * j) / w; + g = (lut[i].green * (w - j) + lut[i+1].green * j) / w; + b = (lut[i].blue * (w - j) + lut[i+1].blue * j) / w; + + r >>= 16 - gdesc->bits; + g >>= 16 - gdesc->bits; + b >>= 16 - gdesc->bits; + + table[first + j] = (r << (gdesc->bits * 2)) | + (g << gdesc->bits) | b; + } + } + + if (dispc.is_enabled) + dispc_mgr_write_gamma_table(channel); +} +EXPORT_SYMBOL(dispc_mgr_set_gamma); + +static int dispc_init_gamma_tables(void) +{ + int channel; + + if (!dispc.feat->has_gamma_table) + return 0; + + for (channel = 0; channel < ARRAY_SIZE(dispc.gamma_table); channel++) { + const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma; + u32 *gt; + + if (channel == OMAP_DSS_CHANNEL_LCD2 && + !dss_has_feature(FEAT_MGR_LCD2)) + continue; + + if (channel == OMAP_DSS_CHANNEL_LCD3 && + !dss_has_feature(FEAT_MGR_LCD3)) + continue; + + gt = devm_kmalloc_array(&dispc.pdev->dev, gdesc->len, + sizeof(u32), GFP_KERNEL); + if (!gt) + return -ENOMEM; + + dispc.gamma_table[channel] = gt; + + dispc_mgr_set_gamma(channel, NULL, 0); + } + return 0; +} + static void _omap_dispc_initial_config(void) { u32 l; @@ -3829,8 +3963,15 @@ static void _omap_dispc_initial_config(void) dispc.core_clk_rate = dispc_fclk_rate(); } - /* FUNCGATED */ - if (dss_has_feature(FEAT_FUNCGATED)) + /* Use gamma table mode, instead of palette mode */ + if (dispc.feat->has_gamma_table) + REG_FLD_MOD(DISPC_CONFIG, 1, 3, 3); + + /* For older DSS versions (FEAT_FUNCGATED) this enables + * func-clock auto-gating. For newer versions + * (dispc.feat->has_gamma_table) this enables tv-out gamma tables. + */ + if (dss_has_feature(FEAT_FUNCGATED) || dispc.feat->has_gamma_table) REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); dispc_setup_color_conv_coef(); @@ -3934,6 +4075,8 @@ static const struct dispc_features omap44xx_dispc_feats = { .has_writeback = true, .supports_double_pixel = true, .reverse_ilace_field_order = true, + .has_gamma_table = true, + .has_gamma_i734_bug = true, }; static const struct dispc_features omap54xx_dispc_feats = { @@ -3959,6 +4102,8 @@ static const struct dispc_features omap54xx_dispc_feats = { .has_writeback = true, .supports_double_pixel = true, .reverse_ilace_field_order = true, + .has_gamma_table = true, + .has_gamma_i734_bug = true, }; static int dispc_init_features(struct platform_device *pdev) @@ -4050,6 +4195,168 @@ void dispc_free_irq(void *dev_id) } EXPORT_SYMBOL(dispc_free_irq); +/* + * Workaround for errata i734 in DSS dispc + * - LCD1 Gamma Correction Is Not Working When GFX Pipe Is Disabled + * + * For gamma tables to work on LCD1 the GFX plane has to be used at + * least once after DSS HW has come out of reset. The workaround + * sets up a minimal LCD setup with GFX plane and waits for one + * vertical sync irq before disabling the setup and continuing with + * the context restore. The physical outputs are gated during the + * operation. This workaround requires that gamma table's LOADMODE + * is set to 0x2 in DISPC_CONTROL1 register. + * + * For details see: + * OMAP543x Multimedia Device Silicon Revision 2.0 Silicon Errata + * Literature Number: SWPZ037E + * Or some other relevant errata document for the DSS IP version. + */ + +static const struct dispc_errata_i734_data { + struct omap_video_timings timings; + struct omap_overlay_info ovli; + struct omap_overlay_manager_info mgri; + struct dss_lcd_mgr_config lcd_conf; +} i734 = { + .timings = { + .x_res = 8, .y_res = 1, + .pixelclock = 16000000, + .hsw = 8, .hfp = 4, .hbp = 4, + .vsw = 1, .vfp = 1, .vbp = 1, + .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, + .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, + .interlace = false, + .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, + .de_level = OMAPDSS_SIG_ACTIVE_HIGH, + .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, + .double_pixel = false, + }, + .ovli = { + .screen_width = 1, + .width = 1, .height = 1, + .color_mode = OMAP_DSS_COLOR_RGB24U, + .rotation = OMAP_DSS_ROT_0, + .rotation_type = OMAP_DSS_ROT_DMA, + .mirror = 0, + .pos_x = 0, .pos_y = 0, + .out_width = 0, .out_height = 0, + .global_alpha = 0xff, + .pre_mult_alpha = 0, + .zorder = 0, + }, + .mgri = { + .default_color = 0, + .trans_enabled = false, + .partial_alpha_enabled = false, + .cpr_enable = false, + }, + .lcd_conf = { + .io_pad_mode = DSS_IO_PAD_MODE_BYPASS, + .stallmode = false, + .fifohandcheck = false, + .clock_info = { + .lck_div = 1, + .pck_div = 2, + }, + .video_port_width = 24, + .lcden_sig_polarity = 0, + }, +}; + +static struct i734_buf { + size_t size; + dma_addr_t paddr; + void *vaddr; +} i734_buf; + +static int dispc_errata_i734_wa_init(void) +{ + if (!dispc.feat->has_gamma_i734_bug) + return 0; + + i734_buf.size = i734.ovli.width * i734.ovli.height * + color_mode_to_bpp(i734.ovli.color_mode) / 8; + + i734_buf.vaddr = dma_alloc_writecombine(&dispc.pdev->dev, i734_buf.size, + &i734_buf.paddr, GFP_KERNEL); + if (!i734_buf.vaddr) { + dev_err(&dispc.pdev->dev, "%s: dma_alloc_writecombine failed", + __func__); + return -ENOMEM; + } + + return 0; +} + +static void dispc_errata_i734_wa_fini(void) +{ + if (!dispc.feat->has_gamma_i734_bug) + return; + + dma_free_writecombine(&dispc.pdev->dev, i734_buf.size, i734_buf.vaddr, + i734_buf.paddr); +} + +static void dispc_errata_i734_wa(void) +{ + u32 framedone_irq = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_LCD); + struct omap_overlay_info ovli; + struct dss_lcd_mgr_config lcd_conf; + u32 gatestate; + unsigned int count; + + if (!dispc.feat->has_gamma_i734_bug) + return; + + gatestate = REG_GET(DISPC_CONFIG, 8, 4); + + ovli = i734.ovli; + ovli.paddr = i734_buf.paddr; + lcd_conf = i734.lcd_conf; + + /* Gate all LCD1 outputs */ + REG_FLD_MOD(DISPC_CONFIG, 0x1f, 8, 4); + + /* Setup and enable GFX plane */ + dispc_ovl_set_channel_out(OMAP_DSS_GFX, OMAP_DSS_CHANNEL_LCD); + dispc_ovl_setup(OMAP_DSS_GFX, &ovli, false, &i734.timings, false); + dispc_ovl_enable(OMAP_DSS_GFX, true); + + /* Set up and enable display manager for LCD1 */ + dispc_mgr_setup(OMAP_DSS_CHANNEL_LCD, &i734.mgri); + dispc_calc_clock_rates(dss_get_dispc_clk_rate(), + &lcd_conf.clock_info); + dispc_mgr_set_lcd_config(OMAP_DSS_CHANNEL_LCD, &lcd_conf); + dispc_mgr_set_timings(OMAP_DSS_CHANNEL_LCD, &i734.timings); + + dispc_clear_irqstatus(framedone_irq); + + /* Enable and shut the channel to produce just one frame */ + dispc_mgr_enable(OMAP_DSS_CHANNEL_LCD, true); + dispc_mgr_enable(OMAP_DSS_CHANNEL_LCD, false); + + /* Busy wait for framedone. We can't fiddle with irq handlers + * in PM resume. Typically the loop runs less than 5 times and + * waits less than a micro second. + */ + count = 0; + while (!(dispc_read_irqstatus() & framedone_irq)) { + if (count++ > 10000) { + dev_err(&dispc.pdev->dev, "%s: framedone timeout\n", + __func__); + break; + } + } + dispc_ovl_enable(OMAP_DSS_GFX, false); + + /* Clear all irq bits before continuing */ + dispc_clear_irqstatus(0xffffffff); + + /* Restore the original state to LCD1 output gates */ + REG_FLD_MOD(DISPC_CONFIG, gatestate, 8, 4); +} + /* DISPC HW IP initialisation */ static int dispc_bind(struct device *dev, struct device *master, void *data) { @@ -4067,6 +4374,10 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) if (r) return r; + r = dispc_errata_i734_wa_init(); + if (r) + return r; + dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); if (!dispc_mem) { DSSERR("can't get IORESOURCE_MEM DISPC\n"); @@ -4100,6 +4411,10 @@ static int dispc_bind(struct device *dev, struct device *master, void *data) } } + r = dispc_init_gamma_tables(); + if (r) + return r; + pm_runtime_enable(&pdev->dev); r = dispc_runtime_get(); @@ -4127,6 +4442,8 @@ static void dispc_unbind(struct device *dev, struct device *master, void *data) { pm_runtime_disable(dev); + + dispc_errata_i734_wa_fini(); } static const struct component_ops dispc_component_ops = { @@ -4169,7 +4486,11 @@ static int dispc_runtime_resume(struct device *dev) if (REG_GET(DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) { _omap_dispc_initial_config(); + dispc_errata_i734_wa(); + dispc_restore_context(); + + dispc_restore_gamma_tables(); } dispc.is_enabled = true; diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.h b/drivers/gpu/drm/omapdrm/dss/dispc.h index 483744223dd1..bc1d8126ee87 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc.h +++ b/drivers/gpu/drm/omapdrm/dss/dispc.h @@ -42,6 +42,11 @@ #define DISPC_MSTANDBY_CTRL 0x0858 #define DISPC_GLOBAL_MFLAG_ATTRIBUTE 0x085C +#define DISPC_GAMMA_TABLE0 0x0630 +#define DISPC_GAMMA_TABLE1 0x0634 +#define DISPC_GAMMA_TABLE2 0x0638 +#define DISPC_GAMMA_TABLE3 0x0850 + /* DISPC overlay registers */ #define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \ DISPC_BA0_OFFSET(n)) diff --git a/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c b/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c index 038c15b04215..34fad2376f8d 100644 --- a/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c +++ b/drivers/gpu/drm/omapdrm/dss/dispc_coefs.c @@ -18,8 +18,8 @@ */ #include <linux/kernel.h> -#include <video/omapdss.h> +#include "omapdss.h" #include "dispc.h" static const struct dispc_coef coef3_M8[8] = { diff --git a/drivers/gpu/drm/omapdrm/dss/display.c b/drivers/gpu/drm/omapdrm/dss/display.c index 9f3dd09b0a6c..8dcdd7cf9937 100644 --- a/drivers/gpu/drm/omapdrm/dss/display.c +++ b/drivers/gpu/drm/omapdrm/dss/display.c @@ -28,7 +28,7 @@ #include <linux/platform_device.h> #include <linux/of.h> -#include <video/omapdss.h> +#include "omapdss.h" #include "dss.h" #include "dss_features.h" diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c index 97ea60257884..b268295b76cf 100644 --- a/drivers/gpu/drm/omapdrm/dss/dpi.c +++ b/drivers/gpu/drm/omapdrm/dss/dpi.c @@ -34,17 +34,15 @@ #include <linux/clk.h> #include <linux/component.h> -#include <video/omapdss.h> - +#include "omapdss.h" #include "dss.h" #include "dss_features.h" -#define HSDIV_DISPC 0 - struct dpi_data { struct platform_device *pdev; struct regulator *vdds_dsi_reg; + enum dss_clk_source clk_src; struct dss_pll *pll; struct mutex lock; @@ -69,7 +67,7 @@ static struct dpi_data *dpi_get_data_from_pdev(struct platform_device *pdev) return dev_get_drvdata(&pdev->dev); } -static struct dss_pll *dpi_get_pll(enum omap_channel channel) +static enum dss_clk_source dpi_get_clk_src(enum omap_channel channel) { /* * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL @@ -83,64 +81,51 @@ static struct dss_pll *dpi_get_pll(enum omap_channel channel) case OMAPDSS_VER_OMAP3630: case OMAPDSS_VER_AM35xx: case OMAPDSS_VER_AM43xx: - return NULL; + return DSS_CLK_SRC_FCK; case OMAPDSS_VER_OMAP4430_ES1: case OMAPDSS_VER_OMAP4430_ES2: case OMAPDSS_VER_OMAP4: switch (channel) { case OMAP_DSS_CHANNEL_LCD: - return dss_pll_find("dsi0"); + return DSS_CLK_SRC_PLL1_1; case OMAP_DSS_CHANNEL_LCD2: - return dss_pll_find("dsi1"); + return DSS_CLK_SRC_PLL2_1; default: - return NULL; + return DSS_CLK_SRC_FCK; } case OMAPDSS_VER_OMAP5: switch (channel) { case OMAP_DSS_CHANNEL_LCD: - return dss_pll_find("dsi0"); + return DSS_CLK_SRC_PLL1_1; case OMAP_DSS_CHANNEL_LCD3: - return dss_pll_find("dsi1"); + return DSS_CLK_SRC_PLL2_1; + case OMAP_DSS_CHANNEL_LCD2: default: - return NULL; + return DSS_CLK_SRC_FCK; } case OMAPDSS_VER_DRA7xx: switch (channel) { case OMAP_DSS_CHANNEL_LCD: + return DSS_CLK_SRC_PLL1_1; case OMAP_DSS_CHANNEL_LCD2: - return dss_pll_find("video0"); + return DSS_CLK_SRC_PLL1_3; case OMAP_DSS_CHANNEL_LCD3: - return dss_pll_find("video1"); + return DSS_CLK_SRC_PLL2_1; default: - return NULL; + return DSS_CLK_SRC_FCK; } default: - return NULL; - } -} - -static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel) -{ - switch (channel) { - case OMAP_DSS_CHANNEL_LCD: - return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC; - case OMAP_DSS_CHANNEL_LCD2: - return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; - case OMAP_DSS_CHANNEL_LCD3: - return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; - default: - /* this shouldn't happen */ - WARN_ON(1); - return OMAP_DSS_CLK_SRC_FCK; + return DSS_CLK_SRC_FCK; } } struct dpi_clk_calc_ctx { struct dss_pll *pll; + unsigned clkout_idx; /* inputs */ @@ -148,7 +133,7 @@ struct dpi_clk_calc_ctx { /* outputs */ - struct dss_pll_clock_info dsi_cinfo; + struct dss_pll_clock_info pll_cinfo; unsigned long fck; struct dispc_clock_info dispc_cinfo; }; @@ -193,8 +178,8 @@ static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc, if (m_dispc > 1 && m_dispc % 2 != 0 && ctx->pck_min >= 100000000) return false; - ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc; - ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc; + ctx->pll_cinfo.mX[ctx->clkout_idx] = m_dispc; + ctx->pll_cinfo.clkout[ctx->clkout_idx] = dispc; return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max, dpi_calc_dispc_cb, ctx); @@ -207,12 +192,12 @@ static bool dpi_calc_pll_cb(int n, int m, unsigned long fint, { struct dpi_clk_calc_ctx *ctx = data; - ctx->dsi_cinfo.n = n; - ctx->dsi_cinfo.m = m; - ctx->dsi_cinfo.fint = fint; - ctx->dsi_cinfo.clkdco = clkdco; + ctx->pll_cinfo.n = n; + ctx->pll_cinfo.m = m; + ctx->pll_cinfo.fint = fint; + ctx->pll_cinfo.clkdco = clkdco; - return dss_pll_hsdiv_calc(ctx->pll, clkdco, + return dss_pll_hsdiv_calc_a(ctx->pll, clkdco, ctx->pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK), dpi_calc_hsdiv_cb, ctx); } @@ -227,25 +212,39 @@ static bool dpi_calc_dss_cb(unsigned long fck, void *data) dpi_calc_dispc_cb, ctx); } -static bool dpi_dsi_clk_calc(struct dpi_data *dpi, unsigned long pck, +static bool dpi_pll_clk_calc(struct dpi_data *dpi, unsigned long pck, struct dpi_clk_calc_ctx *ctx) { unsigned long clkin; - unsigned long pll_min, pll_max; memset(ctx, 0, sizeof(*ctx)); ctx->pll = dpi->pll; - ctx->pck_min = pck - 1000; - ctx->pck_max = pck + 1000; + ctx->clkout_idx = dss_pll_get_clkout_idx_for_src(dpi->clk_src); - pll_min = 0; - pll_max = 0; + clkin = clk_get_rate(dpi->pll->clkin); - clkin = clk_get_rate(ctx->pll->clkin); + if (dpi->pll->hw->type == DSS_PLL_TYPE_A) { + unsigned long pll_min, pll_max; - return dss_pll_calc(ctx->pll, clkin, - pll_min, pll_max, - dpi_calc_pll_cb, ctx); + ctx->pck_min = pck - 1000; + ctx->pck_max = pck + 1000; + + pll_min = 0; + pll_max = 0; + + return dss_pll_calc_a(ctx->pll, clkin, + pll_min, pll_max, + dpi_calc_pll_cb, ctx); + } else { /* DSS_PLL_TYPE_B */ + dss_pll_calc_b(dpi->pll, clkin, pck, &ctx->pll_cinfo); + + ctx->dispc_cinfo.lck_div = 1; + ctx->dispc_cinfo.pck_div = 1; + ctx->dispc_cinfo.lck = ctx->pll_cinfo.clkout[0]; + ctx->dispc_cinfo.pck = ctx->dispc_cinfo.lck; + + return true; + } } static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx) @@ -279,7 +278,7 @@ static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx) -static int dpi_set_dsi_clk(struct dpi_data *dpi, enum omap_channel channel, +static int dpi_set_pll_clk(struct dpi_data *dpi, enum omap_channel channel, unsigned long pck_req, unsigned long *fck, int *lck_div, int *pck_div) { @@ -287,20 +286,19 @@ static int dpi_set_dsi_clk(struct dpi_data *dpi, enum omap_channel channel, int r; bool ok; - ok = dpi_dsi_clk_calc(dpi, pck_req, &ctx); + ok = dpi_pll_clk_calc(dpi, pck_req, &ctx); if (!ok) return -EINVAL; - r = dss_pll_set_config(dpi->pll, &ctx.dsi_cinfo); + r = dss_pll_set_config(dpi->pll, &ctx.pll_cinfo); if (r) return r; - dss_select_lcd_clk_source(channel, - dpi_get_alt_clk_src(channel)); + dss_select_lcd_clk_source(channel, dpi->clk_src); dpi->mgr_config.clock_info = ctx.dispc_cinfo; - *fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC]; + *fck = ctx.pll_cinfo.clkout[ctx.clkout_idx]; *lck_div = ctx.dispc_cinfo.lck_div; *pck_div = ctx.dispc_cinfo.pck_div; @@ -342,7 +340,7 @@ static int dpi_set_mode(struct dpi_data *dpi) int r = 0; if (dpi->pll) - r = dpi_set_dsi_clk(dpi, channel, t->pixelclock, &fck, + r = dpi_set_pll_clk(dpi, channel, t->pixelclock, &fck, &lck_div, &pck_div); else r = dpi_set_dispc_clk(dpi, t->pixelclock, &fck, @@ -419,7 +417,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) if (dpi->pll) { r = dss_pll_enable(dpi->pll); if (r) - goto err_dsi_pll_init; + goto err_pll_init; } r = dpi_set_mode(dpi); @@ -442,7 +440,7 @@ err_mgr_enable: err_set_mode: if (dpi->pll) dss_pll_disable(dpi->pll); -err_dsi_pll_init: +err_pll_init: err_src_sel: dispc_runtime_put(); err_get_dispc: @@ -465,7 +463,7 @@ static void dpi_display_disable(struct omap_dss_device *dssdev) dss_mgr_disable(channel); if (dpi->pll) { - dss_select_lcd_clk_source(channel, OMAP_DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(channel, DSS_CLK_SRC_FCK); dss_pll_disable(dpi->pll); } @@ -524,11 +522,11 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, return -EINVAL; if (dpi->pll) { - ok = dpi_dsi_clk_calc(dpi, timings->pixelclock, &ctx); + ok = dpi_pll_clk_calc(dpi, timings->pixelclock, &ctx); if (!ok) return -EINVAL; - fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC]; + fck = ctx.pll_cinfo.clkout[ctx.clkout_idx]; } else { ok = dpi_dss_clk_calc(timings->pixelclock, &ctx); if (!ok) @@ -558,7 +556,7 @@ static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) mutex_unlock(&dpi->lock); } -static int dpi_verify_dsi_pll(struct dss_pll *pll) +static int dpi_verify_pll(struct dss_pll *pll) { int r; @@ -602,16 +600,14 @@ static void dpi_init_pll(struct dpi_data *dpi) if (dpi->pll) return; - pll = dpi_get_pll(dpi->output.dispc_channel); + dpi->clk_src = dpi_get_clk_src(dpi->output.dispc_channel); + + pll = dss_pll_find_by_src(dpi->clk_src); if (!pll) return; - /* On DRA7 we need to set a mux to use the PLL */ - if (omapdss_get_version() == OMAPDSS_VER_DRA7xx) - dss_ctrl_pll_set_control_mux(pll->id, dpi->output.dispc_channel); - - if (dpi_verify_dsi_pll(pll)) { - DSSWARN("DSI PLL not operational\n"); + if (dpi_verify_pll(pll)) { + DSSWARN("PLL not operational\n"); return; } diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c index 56c43f355ce3..e1be5e795cd8 100644 --- a/drivers/gpu/drm/omapdrm/dss/dsi.c +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c @@ -42,9 +42,9 @@ #include <linux/of_platform.h> #include <linux/component.h> -#include <video/omapdss.h> #include <video/mipi_display.h> +#include "omapdss.h" #include "dss.h" #include "dss_features.h" @@ -1261,7 +1261,7 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev) unsigned long r; struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); - if (dss_get_dsi_clk_source(dsi->module_id) == OMAP_DSS_CLK_SRC_FCK) { + if (dss_get_dsi_clk_source(dsi->module_id) == DSS_CLK_SRC_FCK) { /* DSI FCLK source is DSS_CLK_FCK */ r = clk_get_rate(dsi->dss_clk); } else { @@ -1474,7 +1474,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dss_pll_clock_info *cinfo = &dsi->pll.cinfo; - enum omap_dss_clk_source dispc_clk_src, dsi_clk_src; + enum dss_clk_source dispc_clk_src, dsi_clk_src; int dsi_module = dsi->module_id; struct dss_pll *pll = &dsi->pll; @@ -1494,28 +1494,27 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, cinfo->clkdco, cinfo->m); seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16lum_dispc %u\t(%s)\n", - dss_feat_get_clk_source_name(dsi_module == 0 ? - OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : - OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC), + dss_get_clk_source_name(dsi_module == 0 ? + DSS_CLK_SRC_PLL1_1 : + DSS_CLK_SRC_PLL2_1), cinfo->clkout[HSDIV_DISPC], cinfo->mX[HSDIV_DISPC], - dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ? + dispc_clk_src == DSS_CLK_SRC_FCK ? "off" : "on"); seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16lum_dsi %u\t(%s)\n", - dss_feat_get_clk_source_name(dsi_module == 0 ? - OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : - OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI), + dss_get_clk_source_name(dsi_module == 0 ? + DSS_CLK_SRC_PLL1_2 : + DSS_CLK_SRC_PLL2_2), cinfo->clkout[HSDIV_DSI], cinfo->mX[HSDIV_DSI], - dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ? + dsi_clk_src == DSS_CLK_SRC_FCK ? "off" : "on"); seq_printf(s, "- DSI%d -\n", dsi_module + 1); - seq_printf(s, "dsi fclk source = %s (%s)\n", - dss_get_generic_clk_source_name(dsi_clk_src), - dss_feat_get_clk_source_name(dsi_clk_src)); + seq_printf(s, "dsi fclk source = %s\n", + dss_get_clk_source_name(dsi_clk_src)); seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev)); @@ -4101,8 +4100,8 @@ static int dsi_display_init_dispc(struct platform_device *dsidev, int r; dss_select_lcd_clk_source(channel, dsi->module_id == 0 ? - OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : - OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC); + DSS_CLK_SRC_PLL1_1 : + DSS_CLK_SRC_PLL2_1); if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { r = dss_mgr_register_framedone_handler(channel, @@ -4149,7 +4148,7 @@ err1: dss_mgr_unregister_framedone_handler(channel, dsi_framedone_irq_callback, dsidev); err: - dss_select_lcd_clk_source(channel, OMAP_DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(channel, DSS_CLK_SRC_FCK); return r; } @@ -4162,7 +4161,7 @@ static void dsi_display_uninit_dispc(struct platform_device *dsidev, dss_mgr_unregister_framedone_handler(channel, dsi_framedone_irq_callback, dsidev); - dss_select_lcd_clk_source(channel, OMAP_DSS_CLK_SRC_FCK); + dss_select_lcd_clk_source(channel, DSS_CLK_SRC_FCK); } static int dsi_configure_dsi_clocks(struct platform_device *dsidev) @@ -4196,8 +4195,8 @@ static int dsi_display_init_dsi(struct platform_device *dsidev) goto err1; dss_select_dsi_clk_source(dsi->module_id, dsi->module_id == 0 ? - OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : - OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI); + DSS_CLK_SRC_PLL1_2 : + DSS_CLK_SRC_PLL2_2); DSSDBG("PLL OK\n"); @@ -4229,7 +4228,7 @@ static int dsi_display_init_dsi(struct platform_device *dsidev) err3: dsi_cio_uninit(dsidev); err2: - dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); + dss_select_dsi_clk_source(dsi->module_id, DSS_CLK_SRC_FCK); err1: dss_pll_disable(&dsi->pll); err0: @@ -4251,7 +4250,7 @@ static void dsi_display_uninit_dsi(struct platform_device *dsidev, dsi_vc_enable(dsidev, 2, 0); dsi_vc_enable(dsidev, 3, 0); - dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); + dss_select_dsi_clk_source(dsi->module_id, DSS_CLK_SRC_FCK); dsi_cio_uninit(dsidev); dsi_pll_uninit(dsidev, disconnect_lanes); } @@ -4452,7 +4451,7 @@ static bool dsi_cm_calc_pll_cb(int n, int m, unsigned long fint, ctx->dsi_cinfo.fint = fint; ctx->dsi_cinfo.clkdco = clkdco; - return dss_pll_hsdiv_calc(ctx->pll, clkdco, ctx->req_pck_min, + return dss_pll_hsdiv_calc_a(ctx->pll, clkdco, ctx->req_pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK), dsi_cm_calc_hsdiv_cb, ctx); } @@ -4491,7 +4490,7 @@ static bool dsi_cm_calc(struct dsi_data *dsi, pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4); pll_max = cfg->hs_clk_max * 4; - return dss_pll_calc(ctx->pll, clkin, + return dss_pll_calc_a(ctx->pll, clkin, pll_min, pll_max, dsi_cm_calc_pll_cb, ctx); } @@ -4750,7 +4749,7 @@ static bool dsi_vm_calc_pll_cb(int n, int m, unsigned long fint, ctx->dsi_cinfo.fint = fint; ctx->dsi_cinfo.clkdco = clkdco; - return dss_pll_hsdiv_calc(ctx->pll, clkdco, ctx->req_pck_min, + return dss_pll_hsdiv_calc_a(ctx->pll, clkdco, ctx->req_pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK), dsi_vm_calc_hsdiv_cb, ctx); } @@ -4792,7 +4791,7 @@ static bool dsi_vm_calc(struct dsi_data *dsi, pll_max = byteclk_max * 4 * 4; } - return dss_pll_calc(ctx->pll, clkin, + return dss_pll_calc_a(ctx->pll, clkin, pll_min, pll_max, dsi_vm_calc_pll_cb, ctx); } @@ -5138,6 +5137,8 @@ static const struct dss_pll_ops dsi_pll_ops = { }; static const struct dss_pll_hw dss_omap3_dsi_pll_hw = { + .type = DSS_PLL_TYPE_A, + .n_max = (1 << 7) - 1, .m_max = (1 << 11) - 1, .mX_max = (1 << 4) - 1, @@ -5163,6 +5164,8 @@ static const struct dss_pll_hw dss_omap3_dsi_pll_hw = { }; static const struct dss_pll_hw dss_omap4_dsi_pll_hw = { + .type = DSS_PLL_TYPE_A, + .n_max = (1 << 8) - 1, .m_max = (1 << 12) - 1, .mX_max = (1 << 5) - 1, @@ -5188,6 +5191,8 @@ static const struct dss_pll_hw dss_omap4_dsi_pll_hw = { }; static const struct dss_pll_hw dss_omap5_dsi_pll_hw = { + .type = DSS_PLL_TYPE_A, + .n_max = (1 << 8) - 1, .m_max = (1 << 12) - 1, .mX_max = (1 << 5) - 1, diff --git a/drivers/gpu/drm/omapdrm/dss/dss-of.c b/drivers/gpu/drm/omapdrm/dss/dss-of.c index bf407b6ba15c..e256d879b25c 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss-of.c +++ b/drivers/gpu/drm/omapdrm/dss/dss-of.c @@ -18,8 +18,7 @@ #include <linux/of.h> #include <linux/seq_file.h> -#include <video/omapdss.h> - +#include "omapdss.h" #include "dss.h" struct device_node * @@ -126,15 +125,16 @@ u32 dss_of_port_get_port_number(struct device_node *port) static struct device_node *omapdss_of_get_remote_port(const struct device_node *node) { - struct device_node *np; + struct device_node *np, *np_parent; np = of_parse_phandle(node, "remote-endpoint", 0); if (!np) return NULL; - np = of_get_next_parent(np); + np_parent = of_get_next_parent(np); + of_node_put(np); - return np; + return np_parent; } struct device_node * diff --git a/drivers/gpu/drm/omapdrm/dss/dss.c b/drivers/gpu/drm/omapdrm/dss/dss.c index 3303cfad4838..14887d5b02e5 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.c +++ b/drivers/gpu/drm/omapdrm/dss/dss.c @@ -42,8 +42,7 @@ #include <linux/suspend.h> #include <linux/component.h> -#include <video/omapdss.h> - +#include "omapdss.h" #include "dss.h" #include "dss_features.h" @@ -76,6 +75,8 @@ struct dss_features { const enum omap_display_type *ports; int num_ports; int (*dpi_select_source)(int port, enum omap_channel channel); + int (*select_lcd_source)(enum omap_channel channel, + enum dss_clk_source clk_src); }; static struct { @@ -92,9 +93,9 @@ static struct { unsigned long cache_prate; struct dispc_clock_info cache_dispc_cinfo; - enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI]; - enum omap_dss_clk_source dispc_clk_source; - enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS]; + enum dss_clk_source dsi_clk_source[MAX_NUM_DSI]; + enum dss_clk_source dispc_clk_source; + enum dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS]; bool ctx_valid; u32 ctx[DSS_SZ_REGS / sizeof(u32)]; @@ -106,11 +107,14 @@ static struct { } dss; static const char * const dss_generic_clk_source_names[] = { - [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC", - [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI", - [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK", - [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DSI_PLL2_HSDIV_DISPC", - [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DSI_PLL2_HSDIV_DSI", + [DSS_CLK_SRC_FCK] = "FCK", + [DSS_CLK_SRC_PLL1_1] = "PLL1:1", + [DSS_CLK_SRC_PLL1_2] = "PLL1:2", + [DSS_CLK_SRC_PLL1_3] = "PLL1:3", + [DSS_CLK_SRC_PLL2_1] = "PLL2:1", + [DSS_CLK_SRC_PLL2_2] = "PLL2:2", + [DSS_CLK_SRC_PLL2_3] = "PLL2:3", + [DSS_CLK_SRC_HDMI_PLL] = "HDMI PLL", }; static bool dss_initialized; @@ -203,68 +207,70 @@ void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable) 1 << shift, val << shift); } -void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id, +static int dss_ctrl_pll_set_control_mux(enum dss_clk_source clk_src, enum omap_channel channel) { unsigned shift, val; if (!dss.syscon_pll_ctrl) - return; + return -EINVAL; switch (channel) { case OMAP_DSS_CHANNEL_LCD: shift = 3; - switch (pll_id) { - case DSS_PLL_VIDEO1: + switch (clk_src) { + case DSS_CLK_SRC_PLL1_1: val = 0; break; - case DSS_PLL_HDMI: + case DSS_CLK_SRC_HDMI_PLL: val = 1; break; default: DSSERR("error in PLL mux config for LCD\n"); - return; + return -EINVAL; } break; case OMAP_DSS_CHANNEL_LCD2: shift = 5; - switch (pll_id) { - case DSS_PLL_VIDEO1: + switch (clk_src) { + case DSS_CLK_SRC_PLL1_3: val = 0; break; - case DSS_PLL_VIDEO2: + case DSS_CLK_SRC_PLL2_3: val = 1; break; - case DSS_PLL_HDMI: + case DSS_CLK_SRC_HDMI_PLL: val = 2; break; default: DSSERR("error in PLL mux config for LCD2\n"); - return; + return -EINVAL; } break; case OMAP_DSS_CHANNEL_LCD3: shift = 7; - switch (pll_id) { - case DSS_PLL_VIDEO1: - val = 1; break; - case DSS_PLL_VIDEO2: + switch (clk_src) { + case DSS_CLK_SRC_PLL2_1: val = 0; break; - case DSS_PLL_HDMI: + case DSS_CLK_SRC_PLL1_3: + val = 1; break; + case DSS_CLK_SRC_HDMI_PLL: val = 2; break; default: DSSERR("error in PLL mux config for LCD3\n"); - return; + return -EINVAL; } break; default: DSSERR("error in PLL mux config\n"); - return; + return -EINVAL; } regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset, 0x3 << shift, val << shift); + + return 0; } void dss_sdi_init(int datapairs) @@ -354,14 +360,14 @@ void dss_sdi_disable(void) REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ } -const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src) +const char *dss_get_clk_source_name(enum dss_clk_source clk_src) { return dss_generic_clk_source_names[clk_src]; } void dss_dump_clocks(struct seq_file *s) { - const char *fclk_name, *fclk_real_name; + const char *fclk_name; unsigned long fclk_rate; if (dss_runtime_get()) @@ -369,12 +375,11 @@ void dss_dump_clocks(struct seq_file *s) seq_printf(s, "- DSS -\n"); - fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK); - fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK); + fclk_name = dss_get_clk_source_name(DSS_CLK_SRC_FCK); fclk_rate = clk_get_rate(dss.dss_clk); - seq_printf(s, "%s (%s) = %lu\n", - fclk_name, fclk_real_name, + seq_printf(s, "%s = %lu\n", + fclk_name, fclk_rate); dss_runtime_put(); @@ -403,19 +408,42 @@ static void dss_dump_regs(struct seq_file *s) #undef DUMPREG } -static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) +static int dss_get_channel_index(enum omap_channel channel) +{ + switch (channel) { + case OMAP_DSS_CHANNEL_LCD: + return 0; + case OMAP_DSS_CHANNEL_LCD2: + return 1; + case OMAP_DSS_CHANNEL_LCD3: + return 2; + default: + WARN_ON(1); + return 0; + } +} + +static void dss_select_dispc_clk_source(enum dss_clk_source clk_src) { int b; u8 start, end; + /* + * We always use PRCM clock as the DISPC func clock, except on DSS3, + * where we don't have separate DISPC and LCD clock sources. + */ + if (WARN_ON(dss_has_feature(FEAT_LCD_CLK_SRC) && + clk_src != DSS_CLK_SRC_FCK)) + return; + switch (clk_src) { - case OMAP_DSS_CLK_SRC_FCK: + case DSS_CLK_SRC_FCK: b = 0; break; - case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: + case DSS_CLK_SRC_PLL1_1: b = 1; break; - case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: + case DSS_CLK_SRC_PLL2_1: b = 2; break; default: @@ -431,19 +459,19 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) } void dss_select_dsi_clk_source(int dsi_module, - enum omap_dss_clk_source clk_src) + enum dss_clk_source clk_src) { int b, pos; switch (clk_src) { - case OMAP_DSS_CLK_SRC_FCK: + case DSS_CLK_SRC_FCK: b = 0; break; - case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI: + case DSS_CLK_SRC_PLL1_2: BUG_ON(dsi_module != 0); b = 1; break; - case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI: + case DSS_CLK_SRC_PLL2_2: BUG_ON(dsi_module != 1); b = 1; break; @@ -458,59 +486,125 @@ void dss_select_dsi_clk_source(int dsi_module, dss.dsi_clk_source[dsi_module] = clk_src; } +static int dss_lcd_clk_mux_dra7(enum omap_channel channel, + enum dss_clk_source clk_src) +{ + const u8 ctrl_bits[] = { + [OMAP_DSS_CHANNEL_LCD] = 0, + [OMAP_DSS_CHANNEL_LCD2] = 12, + [OMAP_DSS_CHANNEL_LCD3] = 19, + }; + + u8 ctrl_bit = ctrl_bits[channel]; + int r; + + if (clk_src == DSS_CLK_SRC_FCK) { + /* LCDx_CLK_SWITCH */ + REG_FLD_MOD(DSS_CONTROL, 0, ctrl_bit, ctrl_bit); + return -EINVAL; + } + + r = dss_ctrl_pll_set_control_mux(clk_src, channel); + if (r) + return r; + + REG_FLD_MOD(DSS_CONTROL, 1, ctrl_bit, ctrl_bit); + + return 0; +} + +static int dss_lcd_clk_mux_omap5(enum omap_channel channel, + enum dss_clk_source clk_src) +{ + const u8 ctrl_bits[] = { + [OMAP_DSS_CHANNEL_LCD] = 0, + [OMAP_DSS_CHANNEL_LCD2] = 12, + [OMAP_DSS_CHANNEL_LCD3] = 19, + }; + const enum dss_clk_source allowed_plls[] = { + [OMAP_DSS_CHANNEL_LCD] = DSS_CLK_SRC_PLL1_1, + [OMAP_DSS_CHANNEL_LCD2] = DSS_CLK_SRC_FCK, + [OMAP_DSS_CHANNEL_LCD3] = DSS_CLK_SRC_PLL2_1, + }; + + u8 ctrl_bit = ctrl_bits[channel]; + + if (clk_src == DSS_CLK_SRC_FCK) { + /* LCDx_CLK_SWITCH */ + REG_FLD_MOD(DSS_CONTROL, 0, ctrl_bit, ctrl_bit); + return -EINVAL; + } + + if (WARN_ON(allowed_plls[channel] != clk_src)) + return -EINVAL; + + REG_FLD_MOD(DSS_CONTROL, 1, ctrl_bit, ctrl_bit); + + return 0; +} + +static int dss_lcd_clk_mux_omap4(enum omap_channel channel, + enum dss_clk_source clk_src) +{ + const u8 ctrl_bits[] = { + [OMAP_DSS_CHANNEL_LCD] = 0, + [OMAP_DSS_CHANNEL_LCD2] = 12, + }; + const enum dss_clk_source allowed_plls[] = { + [OMAP_DSS_CHANNEL_LCD] = DSS_CLK_SRC_PLL1_1, + [OMAP_DSS_CHANNEL_LCD2] = DSS_CLK_SRC_PLL2_1, + }; + + u8 ctrl_bit = ctrl_bits[channel]; + + if (clk_src == DSS_CLK_SRC_FCK) { + /* LCDx_CLK_SWITCH */ + REG_FLD_MOD(DSS_CONTROL, 0, ctrl_bit, ctrl_bit); + return 0; + } + + if (WARN_ON(allowed_plls[channel] != clk_src)) + return -EINVAL; + + REG_FLD_MOD(DSS_CONTROL, 1, ctrl_bit, ctrl_bit); + + return 0; +} + void dss_select_lcd_clk_source(enum omap_channel channel, - enum omap_dss_clk_source clk_src) + enum dss_clk_source clk_src) { - int b, ix, pos; + int idx = dss_get_channel_index(channel); + int r; if (!dss_has_feature(FEAT_LCD_CLK_SRC)) { dss_select_dispc_clk_source(clk_src); + dss.lcd_clk_source[idx] = clk_src; return; } - switch (clk_src) { - case OMAP_DSS_CLK_SRC_FCK: - b = 0; - break; - case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: - BUG_ON(channel != OMAP_DSS_CHANNEL_LCD); - b = 1; - break; - case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: - BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 && - channel != OMAP_DSS_CHANNEL_LCD3); - b = 1; - break; - default: - BUG(); + r = dss.feat->select_lcd_source(channel, clk_src); + if (r) return; - } - - pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : - (channel == OMAP_DSS_CHANNEL_LCD2 ? 12 : 19); - REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* LCDx_CLK_SWITCH */ - ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : - (channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2); - dss.lcd_clk_source[ix] = clk_src; + dss.lcd_clk_source[idx] = clk_src; } -enum omap_dss_clk_source dss_get_dispc_clk_source(void) +enum dss_clk_source dss_get_dispc_clk_source(void) { return dss.dispc_clk_source; } -enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module) +enum dss_clk_source dss_get_dsi_clk_source(int dsi_module) { return dss.dsi_clk_source[dsi_module]; } -enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) +enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) { if (dss_has_feature(FEAT_LCD_CLK_SRC)) { - int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : - (channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2); - return dss.lcd_clk_source[ix]; + int idx = dss_get_channel_index(channel); + return dss.lcd_clk_source[idx]; } else { /* LCD_CLK source is the same as DISPC_FCLK source for * OMAP2 and OMAP3 */ @@ -859,6 +953,7 @@ static const struct dss_features omap44xx_dss_feats = { .dpi_select_source = &dss_dpi_select_source_omap4, .ports = omap2plus_ports, .num_ports = ARRAY_SIZE(omap2plus_ports), + .select_lcd_source = &dss_lcd_clk_mux_omap4, }; static const struct dss_features omap54xx_dss_feats = { @@ -868,6 +963,7 @@ static const struct dss_features omap54xx_dss_feats = { .dpi_select_source = &dss_dpi_select_source_omap5, .ports = omap2plus_ports, .num_ports = ARRAY_SIZE(omap2plus_ports), + .select_lcd_source = &dss_lcd_clk_mux_omap5, }; static const struct dss_features am43xx_dss_feats = { @@ -886,6 +982,7 @@ static const struct dss_features dra7xx_dss_feats = { .dpi_select_source = &dss_dpi_select_source_dra7xx, .ports = dra7xx_ports, .num_ports = ARRAY_SIZE(dra7xx_ports), + .select_lcd_source = &dss_lcd_clk_mux_dra7, }; static int dss_init_features(struct platform_device *pdev) @@ -1143,18 +1240,18 @@ static int dss_bind(struct device *dev) /* Select DPLL */ REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); - dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); + dss_select_dispc_clk_source(DSS_CLK_SRC_FCK); #ifdef CONFIG_OMAP2_DSS_VENC REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ #endif - dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; - dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; - dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK; - dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; - dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; + dss.dsi_clk_source[0] = DSS_CLK_SRC_FCK; + dss.dsi_clk_source[1] = DSS_CLK_SRC_FCK; + dss.dispc_clk_source = DSS_CLK_SRC_FCK; + dss.lcd_clk_source[0] = DSS_CLK_SRC_FCK; + dss.lcd_clk_source[1] = DSS_CLK_SRC_FCK; rev = dss_read_reg(DSS_REVISION); printk(KERN_INFO "OMAP DSS rev %d.%d\n", diff --git a/drivers/gpu/drm/omapdrm/dss/dss.h b/drivers/gpu/drm/omapdrm/dss/dss.h index 38e6ab50142d..4fd06dc41cb3 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss.h +++ b/drivers/gpu/drm/omapdrm/dss/dss.h @@ -102,6 +102,20 @@ enum dss_writeback_channel { DSS_WB_LCD3_MGR = 7, }; +enum dss_clk_source { + DSS_CLK_SRC_FCK = 0, + + DSS_CLK_SRC_PLL1_1, + DSS_CLK_SRC_PLL1_2, + DSS_CLK_SRC_PLL1_3, + + DSS_CLK_SRC_PLL2_1, + DSS_CLK_SRC_PLL2_2, + DSS_CLK_SRC_PLL2_3, + + DSS_CLK_SRC_HDMI_PLL, +}; + enum dss_pll_id { DSS_PLL_DSI1, DSS_PLL_DSI2, @@ -114,6 +128,11 @@ struct dss_pll; #define DSS_PLL_MAX_HSDIVS 4 +enum dss_pll_type { + DSS_PLL_TYPE_A, + DSS_PLL_TYPE_B, +}; + /* * Type-A PLLs: clkout[]/mX[] refer to hsdiv outputs m4, m5, m6, m7. * Type-B PLLs: clkout[0] refers to m2. @@ -140,6 +159,8 @@ struct dss_pll_ops { }; struct dss_pll_hw { + enum dss_pll_type type; + unsigned n_max; unsigned m_min; unsigned m_max; @@ -227,7 +248,7 @@ unsigned long dss_get_dispc_clk_rate(void); int dss_dpi_select_source(int port, enum omap_channel channel); void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); -const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); +const char *dss_get_clk_source_name(enum dss_clk_source clk_src); void dss_dump_clocks(struct seq_file *s); /* DSS VIDEO PLL */ @@ -244,20 +265,18 @@ void dss_debug_dump_clocks(struct seq_file *s); #endif void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable); -void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id, - enum omap_channel channel); void dss_sdi_init(int datapairs); int dss_sdi_enable(void); void dss_sdi_disable(void); void dss_select_dsi_clk_source(int dsi_module, - enum omap_dss_clk_source clk_src); + enum dss_clk_source clk_src); void dss_select_lcd_clk_source(enum omap_channel channel, - enum omap_dss_clk_source clk_src); -enum omap_dss_clk_source dss_get_dispc_clk_source(void); -enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module); -enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel); + enum dss_clk_source clk_src); +enum dss_clk_source dss_get_dispc_clk_source(void); +enum dss_clk_source dss_get_dsi_clk_source(int dsi_module); +enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel); void dss_set_venc_output(enum omap_dss_venc_type type); void dss_set_dac_pwrdn_bgz(bool enable); @@ -409,17 +428,23 @@ typedef bool (*dss_hsdiv_calc_func)(int m_dispc, unsigned long dispc, int dss_pll_register(struct dss_pll *pll); void dss_pll_unregister(struct dss_pll *pll); struct dss_pll *dss_pll_find(const char *name); +struct dss_pll *dss_pll_find_by_src(enum dss_clk_source src); +unsigned dss_pll_get_clkout_idx_for_src(enum dss_clk_source src); int dss_pll_enable(struct dss_pll *pll); void dss_pll_disable(struct dss_pll *pll); int dss_pll_set_config(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo); -bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco, +bool dss_pll_hsdiv_calc_a(const struct dss_pll *pll, unsigned long clkdco, unsigned long out_min, unsigned long out_max, dss_hsdiv_calc_func func, void *data); -bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin, +bool dss_pll_calc_a(const struct dss_pll *pll, unsigned long clkin, unsigned long pll_min, unsigned long pll_max, dss_pll_calc_func func, void *data); + +bool dss_pll_calc_b(const struct dss_pll *pll, unsigned long clkin, + unsigned long target_clkout, struct dss_pll_clock_info *cinfo); + int dss_pll_write_config_type_a(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo); int dss_pll_write_config_type_b(struct dss_pll *pll, diff --git a/drivers/gpu/drm/omapdrm/dss/dss_features.c b/drivers/gpu/drm/omapdrm/dss/dss_features.c index c886a2927f73..ee5b93ce2763 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss_features.c +++ b/drivers/gpu/drm/omapdrm/dss/dss_features.c @@ -23,8 +23,7 @@ #include <linux/err.h> #include <linux/slab.h> -#include <video/omapdss.h> - +#include "omapdss.h" #include "dss.h" #include "dss_features.h" @@ -50,7 +49,6 @@ struct omap_dss_features { const enum omap_dss_output_id *supported_outputs; const enum omap_color_mode *supported_color_modes; const enum omap_overlay_caps *overlay_caps; - const char * const *clksrc_names; const struct dss_param_range *dss_params; const enum omap_dss_rotation_type supported_rotation_types; @@ -389,34 +387,6 @@ static const enum omap_overlay_caps omap4_dss_overlay_caps[] = { OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, }; -static const char * const omap2_dss_clk_source_names[] = { - [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "N/A", - [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "N/A", - [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCLK1", -}; - -static const char * const omap3_dss_clk_source_names[] = { - [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI1_PLL_FCLK", - [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI2_PLL_FCLK", - [OMAP_DSS_CLK_SRC_FCK] = "DSS1_ALWON_FCLK", -}; - -static const char * const omap4_dss_clk_source_names[] = { - [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "PLL1_CLK1", - [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "PLL1_CLK2", - [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCLK", - [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "PLL2_CLK1", - [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2", -}; - -static const char * const omap5_dss_clk_source_names[] = { - [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DPLL_DSI1_A_CLK1", - [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DPLL_DSI1_A_CLK2", - [OMAP_DSS_CLK_SRC_FCK] = "DSS_CLK", - [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DPLL_DSI1_C_CLK1", - [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DPLL_DSI1_C_CLK2", -}; - static const struct dss_param_range omap2_dss_param_range[] = { [FEAT_PARAM_DSS_FCK] = { 0, 133000000 }, [FEAT_PARAM_DSS_PCD] = { 2, 255 }, @@ -631,7 +601,6 @@ static const struct omap_dss_features omap2_dss_features = { .supported_outputs = omap2_dss_supported_outputs, .supported_color_modes = omap2_dss_supported_color_modes, .overlay_caps = omap2_dss_overlay_caps, - .clksrc_names = omap2_dss_clk_source_names, .dss_params = omap2_dss_param_range, .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, .buffer_size_unit = 1, @@ -652,7 +621,6 @@ static const struct omap_dss_features omap3430_dss_features = { .supported_outputs = omap3430_dss_supported_outputs, .supported_color_modes = omap3_dss_supported_color_modes, .overlay_caps = omap3430_dss_overlay_caps, - .clksrc_names = omap3_dss_clk_source_names, .dss_params = omap3_dss_param_range, .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, .buffer_size_unit = 1, @@ -676,7 +644,6 @@ static const struct omap_dss_features am35xx_dss_features = { .supported_outputs = omap3430_dss_supported_outputs, .supported_color_modes = omap3_dss_supported_color_modes, .overlay_caps = omap3430_dss_overlay_caps, - .clksrc_names = omap3_dss_clk_source_names, .dss_params = omap3_dss_param_range, .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, .buffer_size_unit = 1, @@ -696,7 +663,6 @@ static const struct omap_dss_features am43xx_dss_features = { .supported_outputs = am43xx_dss_supported_outputs, .supported_color_modes = omap3_dss_supported_color_modes, .overlay_caps = omap3430_dss_overlay_caps, - .clksrc_names = omap2_dss_clk_source_names, .dss_params = am43xx_dss_param_range, .supported_rotation_types = OMAP_DSS_ROT_DMA, .buffer_size_unit = 1, @@ -716,7 +682,6 @@ static const struct omap_dss_features omap3630_dss_features = { .supported_outputs = omap3630_dss_supported_outputs, .supported_color_modes = omap3_dss_supported_color_modes, .overlay_caps = omap3630_dss_overlay_caps, - .clksrc_names = omap3_dss_clk_source_names, .dss_params = omap3_dss_param_range, .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, .buffer_size_unit = 1, @@ -738,7 +703,6 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = { .supported_outputs = omap4_dss_supported_outputs, .supported_color_modes = omap4_dss_supported_color_modes, .overlay_caps = omap4_dss_overlay_caps, - .clksrc_names = omap4_dss_clk_source_names, .dss_params = omap4_dss_param_range, .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, .buffer_size_unit = 16, @@ -759,7 +723,6 @@ static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = { .supported_outputs = omap4_dss_supported_outputs, .supported_color_modes = omap4_dss_supported_color_modes, .overlay_caps = omap4_dss_overlay_caps, - .clksrc_names = omap4_dss_clk_source_names, .dss_params = omap4_dss_param_range, .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, .buffer_size_unit = 16, @@ -780,7 +743,6 @@ static const struct omap_dss_features omap4_dss_features = { .supported_outputs = omap4_dss_supported_outputs, .supported_color_modes = omap4_dss_supported_color_modes, .overlay_caps = omap4_dss_overlay_caps, - .clksrc_names = omap4_dss_clk_source_names, .dss_params = omap4_dss_param_range, .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, .buffer_size_unit = 16, @@ -801,7 +763,6 @@ static const struct omap_dss_features omap5_dss_features = { .supported_outputs = omap5_dss_supported_outputs, .supported_color_modes = omap4_dss_supported_color_modes, .overlay_caps = omap4_dss_overlay_caps, - .clksrc_names = omap5_dss_clk_source_names, .dss_params = omap5_dss_param_range, .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, .buffer_size_unit = 16, @@ -859,11 +820,6 @@ bool dss_feat_color_mode_supported(enum omap_plane plane, color_mode; } -const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id) -{ - return omap_current_dss_features->clksrc_names[id]; -} - u32 dss_feat_get_buffer_size_unit(void) { return omap_current_dss_features->buffer_size_unit; diff --git a/drivers/gpu/drm/omapdrm/dss/dss_features.h b/drivers/gpu/drm/omapdrm/dss/dss_features.h index 3d67d39f192f..bb4b7f0e642b 100644 --- a/drivers/gpu/drm/omapdrm/dss/dss_features.h +++ b/drivers/gpu/drm/omapdrm/dss/dss_features.h @@ -91,7 +91,6 @@ unsigned long dss_feat_get_param_max(enum dss_range_param param); enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane); bool dss_feat_color_mode_supported(enum omap_plane plane, enum omap_color_mode color_mode); -const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id); u32 dss_feat_get_buffer_size_unit(void); /* in bytes */ u32 dss_feat_get_burst_size_unit(void); /* in bytes */ diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h index 53616b02b613..63e711545865 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi.h +++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h @@ -23,8 +23,9 @@ #include <linux/io.h> #include <linux/platform_device.h> #include <linux/hdmi.h> -#include <video/omapdss.h> +#include <sound/omap-hdmi-audio.h> +#include "omapdss.h" #include "dss.h" /* HDMI Wrapper */ @@ -240,6 +241,7 @@ struct hdmi_pll_data { void __iomem *base; + struct platform_device *pdev; struct hdmi_wp_data *wp; }; @@ -306,8 +308,6 @@ phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp); /* HDMI PLL funcs */ void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s); -void hdmi_pll_compute(struct hdmi_pll_data *pll, - unsigned long target_tmds, struct dss_pll_clock_info *pi); int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll, struct hdmi_wp_data *wp); void hdmi_pll_uninit(struct hdmi_pll_data *hpll); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c index 4d46cdf7a037..cbd28dfdb86a 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c @@ -34,9 +34,9 @@ #include <linux/regulator/consumer.h> #include <linux/component.h> #include <linux/of.h> -#include <video/omapdss.h> #include <sound/omap-hdmi-audio.h> +#include "omapdss.h" #include "hdmi4_core.h" #include "dss.h" #include "dss_features.h" @@ -177,7 +177,11 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) if (p->double_pixel) pc *= 2; - hdmi_pll_compute(&hdmi.pll, pc, &hdmi_cinfo); + /* DSS_HDMI_TCLK is bitclk / 10 */ + pc *= 10; + + dss_pll_calc_b(&hdmi.pll.pll, clk_get_rate(hdmi.pll.pll.clkin), + pc, &hdmi_cinfo); r = dss_pll_enable(&hdmi.pll.pll); if (r) { @@ -204,9 +208,6 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); - /* bypass TV gamma table */ - dispc_enable_gamma_table(0); - /* tv size */ dss_mgr_set_timings(channel, p); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c index 9255c0e1e4a7..0c0a5139a301 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c @@ -39,9 +39,9 @@ #include <linux/regulator/consumer.h> #include <linux/component.h> #include <linux/of.h> -#include <video/omapdss.h> #include <sound/omap-hdmi-audio.h> +#include "omapdss.h" #include "hdmi5_core.h" #include "dss.h" #include "dss_features.h" @@ -189,7 +189,11 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) if (p->double_pixel) pc *= 2; - hdmi_pll_compute(&hdmi.pll, pc, &hdmi_cinfo); + /* DSS_HDMI_TCLK is bitclk / 10 */ + pc *= 10; + + dss_pll_calc_b(&hdmi.pll.pll, clk_get_rate(hdmi.pll.pll.clkin), + pc, &hdmi_cinfo); /* disable and clear irqs */ hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); @@ -221,9 +225,6 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg); - /* bypass TV gamma table */ - dispc_enable_gamma_table(0); - /* tv size */ dss_mgr_set_timings(channel, p); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_common.c b/drivers/gpu/drm/omapdrm/dss/hdmi_common.c index 1b8fcc6c4ba1..4dfb67fe5f6d 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_common.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_common.c @@ -4,8 +4,8 @@ #include <linux/kernel.h> #include <linux/err.h> #include <linux/of.h> -#include <video/omapdss.h> +#include "omapdss.h" #include "hdmi.h" int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep, diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c index f98b750fc499..3ead47cccac5 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_phy.c @@ -14,8 +14,8 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/seq_file.h> -#include <video/omapdss.h> +#include "omapdss.h" #include "dss.h" #include "hdmi.h" diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c index f1015e8b8267..b8bf6a9e5557 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_pll.c @@ -17,9 +17,9 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/seq_file.h> +#include <linux/pm_runtime.h> -#include <video/omapdss.h> - +#include "omapdss.h" #include "dss.h" #include "hdmi.h" @@ -39,71 +39,14 @@ void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) DUMPPLL(PLLCTRL_CFG4); } -void hdmi_pll_compute(struct hdmi_pll_data *pll, - unsigned long target_tmds, struct dss_pll_clock_info *pi) -{ - unsigned long fint, clkdco, clkout; - unsigned long target_bitclk, target_clkdco; - unsigned long min_dco; - unsigned n, m, mf, m2, sd; - unsigned long clkin; - const struct dss_pll_hw *hw = pll->pll.hw; - - clkin = clk_get_rate(pll->pll.clkin); - - DSSDBG("clkin %lu, target tmds %lu\n", clkin, target_tmds); - - target_bitclk = target_tmds * 10; - - /* Fint */ - n = DIV_ROUND_UP(clkin, hw->fint_max); - fint = clkin / n; - - /* adjust m2 so that the clkdco will be high enough */ - min_dco = roundup(hw->clkdco_min, fint); - m2 = DIV_ROUND_UP(min_dco, target_bitclk); - if (m2 == 0) - m2 = 1; - - target_clkdco = target_bitclk * m2; - m = target_clkdco / fint; - - clkdco = fint * m; - - /* adjust clkdco with fractional mf */ - if (WARN_ON(target_clkdco - clkdco > fint)) - mf = 0; - else - mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint); - - if (mf > 0) - clkdco += (u32)div_u64((u64)mf * fint, 262144); - - clkout = clkdco / m2; - - /* sigma-delta */ - sd = DIV_ROUND_UP(fint * m, 250000000); - - DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n", - n, m, mf, m2, sd); - DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout); - - pi->n = n; - pi->m = m; - pi->mf = mf; - pi->mX[0] = m2; - pi->sd = sd; - - pi->fint = fint; - pi->clkdco = clkdco; - pi->clkout[0] = clkout; -} - static int hdmi_pll_enable(struct dss_pll *dsspll) { struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll); struct hdmi_wp_data *wp = pll->wp; - u16 r = 0; + int r; + + r = pm_runtime_get_sync(&pll->pdev->dev); + WARN_ON(r < 0); dss_ctrl_pll_enable(DSS_PLL_HDMI, true); @@ -118,10 +61,14 @@ static void hdmi_pll_disable(struct dss_pll *dsspll) { struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll); struct hdmi_wp_data *wp = pll->wp; + int r; hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); dss_ctrl_pll_enable(DSS_PLL_HDMI, false); + + r = pm_runtime_put_sync(&pll->pdev->dev); + WARN_ON(r < 0 && r != -ENOSYS); } static const struct dss_pll_ops dsi_pll_ops = { @@ -131,6 +78,8 @@ static const struct dss_pll_ops dsi_pll_ops = { }; static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = { + .type = DSS_PLL_TYPE_B, + .n_max = 255, .m_min = 20, .m_max = 4095, @@ -154,6 +103,8 @@ static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = { }; static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = { + .type = DSS_PLL_TYPE_B, + .n_max = 255, .m_min = 20, .m_max = 2045, @@ -225,6 +176,7 @@ int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll, int r; struct resource *res; + pll->pdev = pdev; pll->wp = wp; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll"); diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c index 055f62fca5dc..203694a52d18 100644 --- a/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c +++ b/drivers/gpu/drm/omapdrm/dss/hdmi_wp.c @@ -15,8 +15,8 @@ #include <linux/io.h> #include <linux/platform_device.h> #include <linux/seq_file.h> -#include <video/omapdss.h> +#include "omapdss.h" #include "dss.h" #include "hdmi.h" diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h index d7e7c909bbc2..6eaf1adbd606 100644 --- a/drivers/gpu/drm/omapdrm/dss/omapdss.h +++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h @@ -18,7 +18,872 @@ #ifndef __OMAP_DRM_DSS_H #define __OMAP_DRM_DSS_H -#include <video/omapdss.h> +#include <linux/list.h> +#include <linux/kobject.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <video/videomode.h> +#include <linux/platform_data/omapdss.h> +#include <uapi/drm/drm_mode.h> + +#define DISPC_IRQ_FRAMEDONE (1 << 0) +#define DISPC_IRQ_VSYNC (1 << 1) +#define DISPC_IRQ_EVSYNC_EVEN (1 << 2) +#define DISPC_IRQ_EVSYNC_ODD (1 << 3) +#define DISPC_IRQ_ACBIAS_COUNT_STAT (1 << 4) +#define DISPC_IRQ_PROG_LINE_NUM (1 << 5) +#define DISPC_IRQ_GFX_FIFO_UNDERFLOW (1 << 6) +#define DISPC_IRQ_GFX_END_WIN (1 << 7) +#define DISPC_IRQ_PAL_GAMMA_MASK (1 << 8) +#define DISPC_IRQ_OCP_ERR (1 << 9) +#define DISPC_IRQ_VID1_FIFO_UNDERFLOW (1 << 10) +#define DISPC_IRQ_VID1_END_WIN (1 << 11) +#define DISPC_IRQ_VID2_FIFO_UNDERFLOW (1 << 12) +#define DISPC_IRQ_VID2_END_WIN (1 << 13) +#define DISPC_IRQ_SYNC_LOST (1 << 14) +#define DISPC_IRQ_SYNC_LOST_DIGIT (1 << 15) +#define DISPC_IRQ_WAKEUP (1 << 16) +#define DISPC_IRQ_SYNC_LOST2 (1 << 17) +#define DISPC_IRQ_VSYNC2 (1 << 18) +#define DISPC_IRQ_VID3_END_WIN (1 << 19) +#define DISPC_IRQ_VID3_FIFO_UNDERFLOW (1 << 20) +#define DISPC_IRQ_ACBIAS_COUNT_STAT2 (1 << 21) +#define DISPC_IRQ_FRAMEDONE2 (1 << 22) +#define DISPC_IRQ_FRAMEDONEWB (1 << 23) +#define DISPC_IRQ_FRAMEDONETV (1 << 24) +#define DISPC_IRQ_WBBUFFEROVERFLOW (1 << 25) +#define DISPC_IRQ_WBUNCOMPLETEERROR (1 << 26) +#define DISPC_IRQ_SYNC_LOST3 (1 << 27) +#define DISPC_IRQ_VSYNC3 (1 << 28) +#define DISPC_IRQ_ACBIAS_COUNT_STAT3 (1 << 29) +#define DISPC_IRQ_FRAMEDONE3 (1 << 30) + +struct omap_dss_device; +struct omap_overlay_manager; +struct dss_lcd_mgr_config; +struct snd_aes_iec958; +struct snd_cea_861_aud_if; +struct hdmi_avi_infoframe; + +enum omap_display_type { + OMAP_DISPLAY_TYPE_NONE = 0, + OMAP_DISPLAY_TYPE_DPI = 1 << 0, + OMAP_DISPLAY_TYPE_DBI = 1 << 1, + OMAP_DISPLAY_TYPE_SDI = 1 << 2, + OMAP_DISPLAY_TYPE_DSI = 1 << 3, + OMAP_DISPLAY_TYPE_VENC = 1 << 4, + OMAP_DISPLAY_TYPE_HDMI = 1 << 5, + OMAP_DISPLAY_TYPE_DVI = 1 << 6, +}; + +enum omap_plane { + OMAP_DSS_GFX = 0, + OMAP_DSS_VIDEO1 = 1, + OMAP_DSS_VIDEO2 = 2, + OMAP_DSS_VIDEO3 = 3, + OMAP_DSS_WB = 4, +}; + +enum omap_channel { + OMAP_DSS_CHANNEL_LCD = 0, + OMAP_DSS_CHANNEL_DIGIT = 1, + OMAP_DSS_CHANNEL_LCD2 = 2, + OMAP_DSS_CHANNEL_LCD3 = 3, + OMAP_DSS_CHANNEL_WB = 4, +}; + +enum omap_color_mode { + OMAP_DSS_COLOR_CLUT1 = 1 << 0, /* BITMAP 1 */ + OMAP_DSS_COLOR_CLUT2 = 1 << 1, /* BITMAP 2 */ + OMAP_DSS_COLOR_CLUT4 = 1 << 2, /* BITMAP 4 */ + OMAP_DSS_COLOR_CLUT8 = 1 << 3, /* BITMAP 8 */ + OMAP_DSS_COLOR_RGB12U = 1 << 4, /* RGB12, 16-bit container */ + OMAP_DSS_COLOR_ARGB16 = 1 << 5, /* ARGB16 */ + OMAP_DSS_COLOR_RGB16 = 1 << 6, /* RGB16 */ + OMAP_DSS_COLOR_RGB24U = 1 << 7, /* RGB24, 32-bit container */ + OMAP_DSS_COLOR_RGB24P = 1 << 8, /* RGB24, 24-bit container */ + OMAP_DSS_COLOR_YUV2 = 1 << 9, /* YUV2 4:2:2 co-sited */ + OMAP_DSS_COLOR_UYVY = 1 << 10, /* UYVY 4:2:2 co-sited */ + OMAP_DSS_COLOR_ARGB32 = 1 << 11, /* ARGB32 */ + OMAP_DSS_COLOR_RGBA32 = 1 << 12, /* RGBA32 */ + OMAP_DSS_COLOR_RGBX32 = 1 << 13, /* RGBx32 */ + OMAP_DSS_COLOR_NV12 = 1 << 14, /* NV12 format: YUV 4:2:0 */ + OMAP_DSS_COLOR_RGBA16 = 1 << 15, /* RGBA16 - 4444 */ + OMAP_DSS_COLOR_RGBX16 = 1 << 16, /* RGBx16 - 4444 */ + OMAP_DSS_COLOR_ARGB16_1555 = 1 << 17, /* ARGB16 - 1555 */ + OMAP_DSS_COLOR_XRGB16_1555 = 1 << 18, /* xRGB16 - 1555 */ +}; + +enum omap_dss_load_mode { + OMAP_DSS_LOAD_CLUT_AND_FRAME = 0, + OMAP_DSS_LOAD_CLUT_ONLY = 1, + OMAP_DSS_LOAD_FRAME_ONLY = 2, + OMAP_DSS_LOAD_CLUT_ONCE_FRAME = 3, +}; + +enum omap_dss_trans_key_type { + OMAP_DSS_COLOR_KEY_GFX_DST = 0, + OMAP_DSS_COLOR_KEY_VID_SRC = 1, +}; + +enum omap_rfbi_te_mode { + OMAP_DSS_RFBI_TE_MODE_1 = 1, + OMAP_DSS_RFBI_TE_MODE_2 = 2, +}; + +enum omap_dss_signal_level { + OMAPDSS_SIG_ACTIVE_LOW, + OMAPDSS_SIG_ACTIVE_HIGH, +}; + +enum omap_dss_signal_edge { + OMAPDSS_DRIVE_SIG_FALLING_EDGE, + OMAPDSS_DRIVE_SIG_RISING_EDGE, +}; + +enum omap_dss_venc_type { + OMAP_DSS_VENC_TYPE_COMPOSITE, + OMAP_DSS_VENC_TYPE_SVIDEO, +}; + +enum omap_dss_dsi_pixel_format { + OMAP_DSS_DSI_FMT_RGB888, + OMAP_DSS_DSI_FMT_RGB666, + OMAP_DSS_DSI_FMT_RGB666_PACKED, + OMAP_DSS_DSI_FMT_RGB565, +}; + +enum omap_dss_dsi_mode { + OMAP_DSS_DSI_CMD_MODE = 0, + OMAP_DSS_DSI_VIDEO_MODE, +}; + +enum omap_display_caps { + OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE = 1 << 0, + OMAP_DSS_DISPLAY_CAP_TEAR_ELIM = 1 << 1, +}; + +enum omap_dss_display_state { + OMAP_DSS_DISPLAY_DISABLED = 0, + OMAP_DSS_DISPLAY_ACTIVE, +}; + +enum omap_dss_rotation_type { + OMAP_DSS_ROT_DMA = 1 << 0, + OMAP_DSS_ROT_VRFB = 1 << 1, + OMAP_DSS_ROT_TILER = 1 << 2, +}; + +/* clockwise rotation angle */ +enum omap_dss_rotation_angle { + OMAP_DSS_ROT_0 = 0, + OMAP_DSS_ROT_90 = 1, + OMAP_DSS_ROT_180 = 2, + OMAP_DSS_ROT_270 = 3, +}; + +enum omap_overlay_caps { + OMAP_DSS_OVL_CAP_SCALE = 1 << 0, + OMAP_DSS_OVL_CAP_GLOBAL_ALPHA = 1 << 1, + OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA = 1 << 2, + OMAP_DSS_OVL_CAP_ZORDER = 1 << 3, + OMAP_DSS_OVL_CAP_POS = 1 << 4, + OMAP_DSS_OVL_CAP_REPLICATION = 1 << 5, +}; + +enum omap_overlay_manager_caps { + OMAP_DSS_DUMMY_VALUE, /* add a dummy value to prevent compiler error */ +}; + +enum omap_dss_clk_source { + OMAP_DSS_CLK_SRC_FCK = 0, /* OMAP2/3: DSS1_ALWON_FCLK + * OMAP4: DSS_FCLK */ + OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, /* OMAP3: DSI1_PLL_FCLK + * OMAP4: PLL1_CLK1 */ + OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, /* OMAP3: DSI2_PLL_FCLK + * OMAP4: PLL1_CLK2 */ + OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC, /* OMAP4: PLL2_CLK1 */ + OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI, /* OMAP4: PLL2_CLK2 */ +}; + +enum omap_hdmi_flags { + OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP = 1 << 0, +}; + +enum omap_dss_output_id { + OMAP_DSS_OUTPUT_DPI = 1 << 0, + OMAP_DSS_OUTPUT_DBI = 1 << 1, + OMAP_DSS_OUTPUT_SDI = 1 << 2, + OMAP_DSS_OUTPUT_DSI1 = 1 << 3, + OMAP_DSS_OUTPUT_DSI2 = 1 << 4, + OMAP_DSS_OUTPUT_VENC = 1 << 5, + OMAP_DSS_OUTPUT_HDMI = 1 << 6, +}; + +/* RFBI */ + +struct rfbi_timings { + int cs_on_time; + int cs_off_time; + int we_on_time; + int we_off_time; + int re_on_time; + int re_off_time; + int we_cycle_time; + int re_cycle_time; + int cs_pulse_width; + int access_time; + + int clk_div; + + u32 tim[5]; /* set by rfbi_convert_timings() */ + + int converted; +}; + +/* DSI */ + +enum omap_dss_dsi_trans_mode { + /* Sync Pulses: both sync start and end packets sent */ + OMAP_DSS_DSI_PULSE_MODE, + /* Sync Events: only sync start packets sent */ + OMAP_DSS_DSI_EVENT_MODE, + /* Burst: only sync start packets sent, pixels are time compressed */ + OMAP_DSS_DSI_BURST_MODE, +}; + +struct omap_dss_dsi_videomode_timings { + unsigned long hsclk; + + unsigned ndl; + unsigned bitspp; + + /* pixels */ + u16 hact; + /* lines */ + u16 vact; + + /* DSI video mode blanking data */ + /* Unit: byte clock cycles */ + u16 hss; + u16 hsa; + u16 hse; + u16 hfp; + u16 hbp; + /* Unit: line clocks */ + u16 vsa; + u16 vfp; + u16 vbp; + + /* DSI blanking modes */ + int blanking_mode; + int hsa_blanking_mode; + int hbp_blanking_mode; + int hfp_blanking_mode; + + enum omap_dss_dsi_trans_mode trans_mode; + + bool ddr_clk_always_on; + int window_sync; +}; + +struct omap_dss_dsi_config { + enum omap_dss_dsi_mode mode; + enum omap_dss_dsi_pixel_format pixel_format; + const struct omap_video_timings *timings; + + unsigned long hs_clk_min, hs_clk_max; + unsigned long lp_clk_min, lp_clk_max; + + bool ddr_clk_always_on; + enum omap_dss_dsi_trans_mode trans_mode; +}; + +struct omap_video_timings { + /* Unit: pixels */ + u16 x_res; + /* Unit: pixels */ + u16 y_res; + /* Unit: Hz */ + u32 pixelclock; + /* Unit: pixel clocks */ + u16 hsw; /* Horizontal synchronization pulse width */ + /* Unit: pixel clocks */ + u16 hfp; /* Horizontal front porch */ + /* Unit: pixel clocks */ + u16 hbp; /* Horizontal back porch */ + /* Unit: line clocks */ + u16 vsw; /* Vertical synchronization pulse width */ + /* Unit: line clocks */ + u16 vfp; /* Vertical front porch */ + /* Unit: line clocks */ + u16 vbp; /* Vertical back porch */ + + /* Vsync logic level */ + enum omap_dss_signal_level vsync_level; + /* Hsync logic level */ + enum omap_dss_signal_level hsync_level; + /* Interlaced or Progressive timings */ + bool interlace; + /* Pixel clock edge to drive LCD data */ + enum omap_dss_signal_edge data_pclk_edge; + /* Data enable logic level */ + enum omap_dss_signal_level de_level; + /* Pixel clock edges to drive HSYNC and VSYNC signals */ + enum omap_dss_signal_edge sync_pclk_edge; + + bool double_pixel; +}; + +/* Hardcoded timings for tv modes. Venc only uses these to + * identify the mode, and does not actually use the configs + * itself. However, the configs should be something that + * a normal monitor can also show */ +extern const struct omap_video_timings omap_dss_pal_timings; +extern const struct omap_video_timings omap_dss_ntsc_timings; + +struct omap_dss_cpr_coefs { + s16 rr, rg, rb; + s16 gr, gg, gb; + s16 br, bg, bb; +}; + +struct omap_overlay_info { + dma_addr_t paddr; + dma_addr_t p_uv_addr; /* for NV12 format */ + u16 screen_width; + u16 width; + u16 height; + enum omap_color_mode color_mode; + u8 rotation; + enum omap_dss_rotation_type rotation_type; + bool mirror; + + u16 pos_x; + u16 pos_y; + u16 out_width; /* if 0, out_width == width */ + u16 out_height; /* if 0, out_height == height */ + u8 global_alpha; + u8 pre_mult_alpha; + u8 zorder; +}; + +struct omap_overlay { + struct kobject kobj; + struct list_head list; + + /* static fields */ + const char *name; + enum omap_plane id; + enum omap_color_mode supported_modes; + enum omap_overlay_caps caps; + + /* dynamic fields */ + struct omap_overlay_manager *manager; + + /* + * The following functions do not block: + * + * is_enabled + * set_overlay_info + * get_overlay_info + * + * The rest of the functions may block and cannot be called from + * interrupt context + */ + + int (*enable)(struct omap_overlay *ovl); + int (*disable)(struct omap_overlay *ovl); + bool (*is_enabled)(struct omap_overlay *ovl); + + int (*set_manager)(struct omap_overlay *ovl, + struct omap_overlay_manager *mgr); + int (*unset_manager)(struct omap_overlay *ovl); + + int (*set_overlay_info)(struct omap_overlay *ovl, + struct omap_overlay_info *info); + void (*get_overlay_info)(struct omap_overlay *ovl, + struct omap_overlay_info *info); + + int (*wait_for_go)(struct omap_overlay *ovl); + + struct omap_dss_device *(*get_device)(struct omap_overlay *ovl); +}; + +struct omap_overlay_manager_info { + u32 default_color; + + enum omap_dss_trans_key_type trans_key_type; + u32 trans_key; + bool trans_enabled; + + bool partial_alpha_enabled; + + bool cpr_enable; + struct omap_dss_cpr_coefs cpr_coefs; +}; + +struct omap_overlay_manager { + struct kobject kobj; + + /* static fields */ + const char *name; + enum omap_channel id; + enum omap_overlay_manager_caps caps; + struct list_head overlays; + enum omap_display_type supported_displays; + enum omap_dss_output_id supported_outputs; + + /* dynamic fields */ + struct omap_dss_device *output; + + /* + * The following functions do not block: + * + * set_manager_info + * get_manager_info + * apply + * + * The rest of the functions may block and cannot be called from + * interrupt context + */ + + int (*set_output)(struct omap_overlay_manager *mgr, + struct omap_dss_device *output); + int (*unset_output)(struct omap_overlay_manager *mgr); + + int (*set_manager_info)(struct omap_overlay_manager *mgr, + struct omap_overlay_manager_info *info); + void (*get_manager_info)(struct omap_overlay_manager *mgr, + struct omap_overlay_manager_info *info); + + int (*apply)(struct omap_overlay_manager *mgr); + int (*wait_for_go)(struct omap_overlay_manager *mgr); + int (*wait_for_vsync)(struct omap_overlay_manager *mgr); + + struct omap_dss_device *(*get_device)(struct omap_overlay_manager *mgr); +}; + +/* 22 pins means 1 clk lane and 10 data lanes */ +#define OMAP_DSS_MAX_DSI_PINS 22 + +struct omap_dsi_pin_config { + int num_pins; + /* + * pin numbers in the following order: + * clk+, clk- + * data1+, data1- + * data2+, data2- + * ... + */ + int pins[OMAP_DSS_MAX_DSI_PINS]; +}; + +struct omap_dss_writeback_info { + u32 paddr; + u32 p_uv_addr; + u16 buf_width; + u16 width; + u16 height; + enum omap_color_mode color_mode; + u8 rotation; + enum omap_dss_rotation_type rotation_type; + bool mirror; + u8 pre_mult_alpha; +}; + +struct omapdss_dpi_ops { + int (*connect)(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); + void (*disconnect)(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); + + int (*enable)(struct omap_dss_device *dssdev); + void (*disable)(struct omap_dss_device *dssdev); + + int (*check_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + void (*set_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + void (*get_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + + void (*set_data_lines)(struct omap_dss_device *dssdev, int data_lines); +}; + +struct omapdss_sdi_ops { + int (*connect)(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); + void (*disconnect)(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); + + int (*enable)(struct omap_dss_device *dssdev); + void (*disable)(struct omap_dss_device *dssdev); + + int (*check_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + void (*set_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + void (*get_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + + void (*set_datapairs)(struct omap_dss_device *dssdev, int datapairs); +}; + +struct omapdss_dvi_ops { + int (*connect)(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); + void (*disconnect)(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); + + int (*enable)(struct omap_dss_device *dssdev); + void (*disable)(struct omap_dss_device *dssdev); + + int (*check_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + void (*set_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + void (*get_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); +}; + +struct omapdss_atv_ops { + int (*connect)(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); + void (*disconnect)(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); + + int (*enable)(struct omap_dss_device *dssdev); + void (*disable)(struct omap_dss_device *dssdev); + + int (*check_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + void (*set_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + void (*get_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + + void (*set_type)(struct omap_dss_device *dssdev, + enum omap_dss_venc_type type); + void (*invert_vid_out_polarity)(struct omap_dss_device *dssdev, + bool invert_polarity); + + int (*set_wss)(struct omap_dss_device *dssdev, u32 wss); + u32 (*get_wss)(struct omap_dss_device *dssdev); +}; + +struct omapdss_hdmi_ops { + int (*connect)(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); + void (*disconnect)(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); + + int (*enable)(struct omap_dss_device *dssdev); + void (*disable)(struct omap_dss_device *dssdev); + + int (*check_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + void (*set_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + void (*get_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + + int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len); + bool (*detect)(struct omap_dss_device *dssdev); + + int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode); + int (*set_infoframe)(struct omap_dss_device *dssdev, + const struct hdmi_avi_infoframe *avi); +}; + +struct omapdss_dsi_ops { + int (*connect)(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); + void (*disconnect)(struct omap_dss_device *dssdev, + struct omap_dss_device *dst); + + int (*enable)(struct omap_dss_device *dssdev); + void (*disable)(struct omap_dss_device *dssdev, bool disconnect_lanes, + bool enter_ulps); + + /* bus configuration */ + int (*set_config)(struct omap_dss_device *dssdev, + const struct omap_dss_dsi_config *cfg); + int (*configure_pins)(struct omap_dss_device *dssdev, + const struct omap_dsi_pin_config *pin_cfg); + + void (*enable_hs)(struct omap_dss_device *dssdev, int channel, + bool enable); + int (*enable_te)(struct omap_dss_device *dssdev, bool enable); + + int (*update)(struct omap_dss_device *dssdev, int channel, + void (*callback)(int, void *), void *data); + + void (*bus_lock)(struct omap_dss_device *dssdev); + void (*bus_unlock)(struct omap_dss_device *dssdev); + + int (*enable_video_output)(struct omap_dss_device *dssdev, int channel); + void (*disable_video_output)(struct omap_dss_device *dssdev, + int channel); + + int (*request_vc)(struct omap_dss_device *dssdev, int *channel); + int (*set_vc_id)(struct omap_dss_device *dssdev, int channel, + int vc_id); + void (*release_vc)(struct omap_dss_device *dssdev, int channel); + + /* data transfer */ + int (*dcs_write)(struct omap_dss_device *dssdev, int channel, + u8 *data, int len); + int (*dcs_write_nosync)(struct omap_dss_device *dssdev, int channel, + u8 *data, int len); + int (*dcs_read)(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, + u8 *data, int len); + + int (*gen_write)(struct omap_dss_device *dssdev, int channel, + u8 *data, int len); + int (*gen_write_nosync)(struct omap_dss_device *dssdev, int channel, + u8 *data, int len); + int (*gen_read)(struct omap_dss_device *dssdev, int channel, + u8 *reqdata, int reqlen, + u8 *data, int len); + + int (*bta_sync)(struct omap_dss_device *dssdev, int channel); + + int (*set_max_rx_packet_size)(struct omap_dss_device *dssdev, + int channel, u16 plen); +}; + +struct omap_dss_device { + struct kobject kobj; + struct device *dev; + + struct module *owner; + + struct list_head panel_list; + + /* alias in the form of "display%d" */ + char alias[16]; + + enum omap_display_type type; + enum omap_display_type output_type; + + union { + struct { + u8 data_lines; + } dpi; + + struct { + u8 channel; + u8 data_lines; + } rfbi; + + struct { + u8 datapairs; + } sdi; + + struct { + int module; + } dsi; + + struct { + enum omap_dss_venc_type type; + bool invert_polarity; + } venc; + } phy; + + struct { + struct omap_video_timings timings; + + enum omap_dss_dsi_pixel_format dsi_pix_fmt; + enum omap_dss_dsi_mode dsi_mode; + } panel; + + struct { + u8 pixel_size; + struct rfbi_timings rfbi_timings; + } ctrl; + + const char *name; + + /* used to match device to driver */ + const char *driver_name; + + void *data; + + struct omap_dss_driver *driver; + + union { + const struct omapdss_dpi_ops *dpi; + const struct omapdss_sdi_ops *sdi; + const struct omapdss_dvi_ops *dvi; + const struct omapdss_hdmi_ops *hdmi; + const struct omapdss_atv_ops *atv; + const struct omapdss_dsi_ops *dsi; + } ops; + + /* helper variable for driver suspend/resume */ + bool activate_after_resume; + + enum omap_display_caps caps; + + struct omap_dss_device *src; + + enum omap_dss_display_state state; + + /* OMAP DSS output specific fields */ + + struct list_head list; + + /* DISPC channel for this output */ + enum omap_channel dispc_channel; + bool dispc_channel_connected; + + /* output instance */ + enum omap_dss_output_id id; + + /* the port number in the DT node */ + int port_num; + + /* dynamic fields */ + struct omap_overlay_manager *manager; + + struct omap_dss_device *dst; +}; + +struct omap_dss_driver { + int (*probe)(struct omap_dss_device *); + void (*remove)(struct omap_dss_device *); + + int (*connect)(struct omap_dss_device *dssdev); + void (*disconnect)(struct omap_dss_device *dssdev); + + int (*enable)(struct omap_dss_device *display); + void (*disable)(struct omap_dss_device *display); + int (*run_test)(struct omap_dss_device *display, int test); + + int (*update)(struct omap_dss_device *dssdev, + u16 x, u16 y, u16 w, u16 h); + int (*sync)(struct omap_dss_device *dssdev); + + int (*enable_te)(struct omap_dss_device *dssdev, bool enable); + int (*get_te)(struct omap_dss_device *dssdev); + + u8 (*get_rotate)(struct omap_dss_device *dssdev); + int (*set_rotate)(struct omap_dss_device *dssdev, u8 rotate); + + bool (*get_mirror)(struct omap_dss_device *dssdev); + int (*set_mirror)(struct omap_dss_device *dssdev, bool enable); + + int (*memory_read)(struct omap_dss_device *dssdev, + void *buf, size_t size, + u16 x, u16 y, u16 w, u16 h); + + void (*get_resolution)(struct omap_dss_device *dssdev, + u16 *xres, u16 *yres); + void (*get_dimensions)(struct omap_dss_device *dssdev, + u32 *width, u32 *height); + int (*get_recommended_bpp)(struct omap_dss_device *dssdev); + + int (*check_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + void (*set_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + void (*get_timings)(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + + int (*set_wss)(struct omap_dss_device *dssdev, u32 wss); + u32 (*get_wss)(struct omap_dss_device *dssdev); + + int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len); + bool (*detect)(struct omap_dss_device *dssdev); + + int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode); + int (*set_hdmi_infoframe)(struct omap_dss_device *dssdev, + const struct hdmi_avi_infoframe *avi); +}; + +enum omapdss_version omapdss_get_version(void); +bool omapdss_is_initialized(void); + +int omap_dss_register_driver(struct omap_dss_driver *); +void omap_dss_unregister_driver(struct omap_dss_driver *); + +int omapdss_register_display(struct omap_dss_device *dssdev); +void omapdss_unregister_display(struct omap_dss_device *dssdev); + +struct omap_dss_device *omap_dss_get_device(struct omap_dss_device *dssdev); +void omap_dss_put_device(struct omap_dss_device *dssdev); +#define for_each_dss_dev(d) while ((d = omap_dss_get_next_device(d)) != NULL) +struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from); +struct omap_dss_device *omap_dss_find_device(void *data, + int (*match)(struct omap_dss_device *dssdev, void *data)); +const char *omapdss_get_default_display_name(void); + +void videomode_to_omap_video_timings(const struct videomode *vm, + struct omap_video_timings *ovt); +void omap_video_timings_to_videomode(const struct omap_video_timings *ovt, + struct videomode *vm); + +int dss_feat_get_num_mgrs(void); +int dss_feat_get_num_ovls(void); +enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); + + + +int omap_dss_get_num_overlay_managers(void); +struct omap_overlay_manager *omap_dss_get_overlay_manager(int num); + +int omap_dss_get_num_overlays(void); +struct omap_overlay *omap_dss_get_overlay(int num); + +int omapdss_register_output(struct omap_dss_device *output); +void omapdss_unregister_output(struct omap_dss_device *output); +struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id); +struct omap_dss_device *omap_dss_find_output(const char *name); +struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port); +int omapdss_output_set_device(struct omap_dss_device *out, + struct omap_dss_device *dssdev); +int omapdss_output_unset_device(struct omap_dss_device *out); + +struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev); +struct omap_overlay_manager *omapdss_find_mgr_from_display(struct omap_dss_device *dssdev); + +void omapdss_default_get_resolution(struct omap_dss_device *dssdev, + u16 *xres, u16 *yres); +int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev); +void omapdss_default_get_timings(struct omap_dss_device *dssdev, + struct omap_video_timings *timings); + +typedef void (*omap_dispc_isr_t) (void *arg, u32 mask); +int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask); +int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask); + +int omapdss_compat_init(void); +void omapdss_compat_uninit(void); + +static inline bool omapdss_device_is_connected(struct omap_dss_device *dssdev) +{ + return dssdev->src; +} + +static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev) +{ + return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE; +} + +struct device_node * +omapdss_of_get_next_port(const struct device_node *parent, + struct device_node *prev); + +struct device_node * +omapdss_of_get_next_endpoint(const struct device_node *parent, + struct device_node *prev); + +struct device_node * +omapdss_of_get_first_endpoint(const struct device_node *parent); + +struct omap_dss_device * +omapdss_of_find_source_for_first_ep(struct device_node *node); u32 dispc_read_irqstatus(void); void dispc_clear_irqstatus(u32 mask); @@ -44,6 +909,10 @@ void dispc_mgr_set_timings(enum omap_channel channel, const struct omap_video_timings *timings); void dispc_mgr_setup(enum omap_channel channel, const struct omap_overlay_manager_info *info); +u32 dispc_mgr_gamma_size(enum omap_channel channel); +void dispc_mgr_set_gamma(enum omap_channel channel, + const struct drm_color_lut *lut, + unsigned int length); int dispc_ovl_enable(enum omap_plane plane, bool enable); bool dispc_ovl_enabled(enum omap_plane plane); diff --git a/drivers/gpu/drm/omapdrm/dss/output.c b/drivers/gpu/drm/omapdrm/dss/output.c index 829232ad8c81..24f859488201 100644 --- a/drivers/gpu/drm/omapdrm/dss/output.c +++ b/drivers/gpu/drm/omapdrm/dss/output.c @@ -21,8 +21,7 @@ #include <linux/slab.h> #include <linux/of.h> -#include <video/omapdss.h> - +#include "omapdss.h" #include "dss.h" static LIST_HEAD(output_list); diff --git a/drivers/gpu/drm/omapdrm/dss/pll.c b/drivers/gpu/drm/omapdrm/dss/pll.c index f974ddcd3b6e..0a76c89cdc2e 100644 --- a/drivers/gpu/drm/omapdrm/dss/pll.c +++ b/drivers/gpu/drm/omapdrm/dss/pll.c @@ -22,8 +22,7 @@ #include <linux/regulator/consumer.h> #include <linux/sched.h> -#include <video/omapdss.h> - +#include "omapdss.h" #include "dss.h" #define PLL_CONTROL 0x0000 @@ -76,6 +75,59 @@ struct dss_pll *dss_pll_find(const char *name) return NULL; } +struct dss_pll *dss_pll_find_by_src(enum dss_clk_source src) +{ + struct dss_pll *pll; + + switch (src) { + default: + case DSS_CLK_SRC_FCK: + return NULL; + + case DSS_CLK_SRC_HDMI_PLL: + return dss_pll_find("hdmi"); + + case DSS_CLK_SRC_PLL1_1: + case DSS_CLK_SRC_PLL1_2: + case DSS_CLK_SRC_PLL1_3: + pll = dss_pll_find("dsi0"); + if (!pll) + pll = dss_pll_find("video0"); + return pll; + + case DSS_CLK_SRC_PLL2_1: + case DSS_CLK_SRC_PLL2_2: + case DSS_CLK_SRC_PLL2_3: + pll = dss_pll_find("dsi1"); + if (!pll) + pll = dss_pll_find("video1"); + return pll; + } +} + +unsigned dss_pll_get_clkout_idx_for_src(enum dss_clk_source src) +{ + switch (src) { + case DSS_CLK_SRC_HDMI_PLL: + return 0; + + case DSS_CLK_SRC_PLL1_1: + case DSS_CLK_SRC_PLL2_1: + return 0; + + case DSS_CLK_SRC_PLL1_2: + case DSS_CLK_SRC_PLL2_2: + return 1; + + case DSS_CLK_SRC_PLL1_3: + case DSS_CLK_SRC_PLL2_3: + return 2; + + default: + return 0; + } +} + int dss_pll_enable(struct dss_pll *pll) { int r; @@ -129,7 +181,7 @@ int dss_pll_set_config(struct dss_pll *pll, const struct dss_pll_clock_info *cin return 0; } -bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco, +bool dss_pll_hsdiv_calc_a(const struct dss_pll *pll, unsigned long clkdco, unsigned long out_min, unsigned long out_max, dss_hsdiv_calc_func func, void *data) { @@ -154,7 +206,11 @@ bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco, return false; } -bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin, +/* + * clkdco = clkin / n * m * 2 + * clkoutX = clkdco / mX + */ +bool dss_pll_calc_a(const struct dss_pll *pll, unsigned long clkin, unsigned long pll_min, unsigned long pll_max, dss_pll_calc_func func, void *data) { @@ -195,6 +251,71 @@ bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin, return false; } +/* + * This calculates a PLL config that will provide the target_clkout rate + * for clkout. Additionally clkdco rate will be the same as clkout rate + * when clkout rate is >= min_clkdco. + * + * clkdco = clkin / n * m + clkin / n * mf / 262144 + * clkout = clkdco / m2 + */ +bool dss_pll_calc_b(const struct dss_pll *pll, unsigned long clkin, + unsigned long target_clkout, struct dss_pll_clock_info *cinfo) +{ + unsigned long fint, clkdco, clkout; + unsigned long target_clkdco; + unsigned long min_dco; + unsigned n, m, mf, m2, sd; + const struct dss_pll_hw *hw = pll->hw; + + DSSDBG("clkin %lu, target clkout %lu\n", clkin, target_clkout); + + /* Fint */ + n = DIV_ROUND_UP(clkin, hw->fint_max); + fint = clkin / n; + + /* adjust m2 so that the clkdco will be high enough */ + min_dco = roundup(hw->clkdco_min, fint); + m2 = DIV_ROUND_UP(min_dco, target_clkout); + if (m2 == 0) + m2 = 1; + + target_clkdco = target_clkout * m2; + m = target_clkdco / fint; + + clkdco = fint * m; + + /* adjust clkdco with fractional mf */ + if (WARN_ON(target_clkdco - clkdco > fint)) + mf = 0; + else + mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint); + + if (mf > 0) + clkdco += (u32)div_u64((u64)mf * fint, 262144); + + clkout = clkdco / m2; + + /* sigma-delta */ + sd = DIV_ROUND_UP(fint * m, 250000000); + + DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n", + n, m, mf, m2, sd); + DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout); + + cinfo->n = n; + cinfo->m = m; + cinfo->mf = mf; + cinfo->mX[0] = m2; + cinfo->sd = sd; + + cinfo->fint = fint; + cinfo->clkdco = clkdco; + cinfo->clkout[0] = clkout; + + return true; +} + static int wait_for_bit_change(void __iomem *reg, int bitnum, int value) { unsigned long timeout; diff --git a/drivers/gpu/drm/omapdrm/dss/rfbi.c b/drivers/gpu/drm/omapdrm/dss/rfbi.c index 3796576dfadf..cd53566d75eb 100644 --- a/drivers/gpu/drm/omapdrm/dss/rfbi.c +++ b/drivers/gpu/drm/omapdrm/dss/rfbi.c @@ -38,7 +38,7 @@ #include <linux/pm_runtime.h> #include <linux/component.h> -#include <video/omapdss.h> +#include "omapdss.h" #include "dss.h" struct rfbi_reg { u16 idx; }; diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c index cd6d3bfb041d..0a96c321ce62 100644 --- a/drivers/gpu/drm/omapdrm/dss/sdi.c +++ b/drivers/gpu/drm/omapdrm/dss/sdi.c @@ -29,7 +29,7 @@ #include <linux/of.h> #include <linux/component.h> -#include <video/omapdss.h> +#include "omapdss.h" #include "dss.h" static struct { diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c index 08a2cc778ba9..6eedf2118708 100644 --- a/drivers/gpu/drm/omapdrm/dss/venc.c +++ b/drivers/gpu/drm/omapdrm/dss/venc.c @@ -37,8 +37,7 @@ #include <linux/of.h> #include <linux/component.h> -#include <video/omapdss.h> - +#include "omapdss.h" #include "dss.h" #include "dss_features.h" diff --git a/drivers/gpu/drm/omapdrm/dss/video-pll.c b/drivers/gpu/drm/omapdrm/dss/video-pll.c index b1ec59e42940..7429de928d4e 100644 --- a/drivers/gpu/drm/omapdrm/dss/video-pll.c +++ b/drivers/gpu/drm/omapdrm/dss/video-pll.c @@ -17,8 +17,7 @@ #include <linux/platform_device.h> #include <linux/sched.h> -#include <video/omapdss.h> - +#include "omapdss.h" #include "dss.h" #include "dss_features.h" @@ -108,6 +107,8 @@ static const struct dss_pll_ops dss_pll_ops = { }; static const struct dss_pll_hw dss_dra7_video_pll_hw = { + .type = DSS_PLL_TYPE_A, + .n_max = (1 << 8) - 1, .m_max = (1 << 12) - 1, .mX_max = (1 << 5) - 1, @@ -124,6 +125,10 @@ static const struct dss_pll_hw dss_dra7_video_pll_hw = { .mX_lsb[0] = 21, .mX_msb[1] = 30, .mX_lsb[1] = 26, + .mX_msb[2] = 4, + .mX_lsb[2] = 0, + .mX_msb[3] = 9, + .mX_lsb[3] = 5, .has_refsel = true, }; diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index ce2d67b6a8c7..137fe690a0da 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -32,7 +32,6 @@ struct omap_connector { struct drm_connector base; struct omap_dss_device *dssdev; - struct drm_encoder *encoder; bool hdmi_mode; }; @@ -256,13 +255,6 @@ static int omap_connector_mode_valid(struct drm_connector *connector, return ret; } -struct drm_encoder *omap_connector_attached_encoder( - struct drm_connector *connector) -{ - struct omap_connector *omap_connector = to_omap_connector(connector); - return omap_connector->encoder; -} - static const struct drm_connector_funcs omap_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .reset = drm_atomic_helper_connector_reset, @@ -276,7 +268,6 @@ static const struct drm_connector_funcs omap_connector_funcs = { static const struct drm_connector_helper_funcs omap_connector_helper_funcs = { .get_modes = omap_connector_get_modes, .mode_valid = omap_connector_mode_valid, - .best_encoder = omap_connector_attached_encoder, }; /* initialize connector */ @@ -296,7 +287,6 @@ struct drm_connector *omap_connector_init(struct drm_device *dev, goto fail; omap_connector->dssdev = dssdev; - omap_connector->encoder = encoder; connector = &omap_connector->base; diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 075f2bb44867..180f644e861e 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -372,6 +372,20 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc) copy_timings_drm_to_omap(&omap_crtc->timings, mode); } +static int omap_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + if (state->color_mgmt_changed && state->gamma_lut) { + uint length = state->gamma_lut->length / + sizeof(struct drm_color_lut); + + if (length < 2) + return -EINVAL; + } + + return 0; +} + static void omap_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { @@ -384,6 +398,32 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc, WARN_ON(omap_crtc->vblank_irq.registered); + if (crtc->state->color_mgmt_changed) { + struct drm_color_lut *lut = NULL; + uint length = 0; + + if (crtc->state->gamma_lut) { + lut = (struct drm_color_lut *) + crtc->state->gamma_lut->data; + length = crtc->state->gamma_lut->length / + sizeof(*lut); + } + dispc_mgr_set_gamma(omap_crtc->channel, lut, length); + } + + if (crtc->state->color_mgmt_changed) { + struct drm_color_lut *lut = NULL; + uint length = 0; + + if (crtc->state->gamma_lut) { + lut = (struct drm_color_lut *) + crtc->state->gamma_lut->data; + length = crtc->state->gamma_lut->length / + sizeof(*lut); + } + dispc_mgr_set_gamma(omap_crtc->channel, lut, length); + } + if (dispc_mgr_is_enabled(omap_crtc->channel)) { DBG("%s: GO", omap_crtc->name); @@ -460,6 +500,7 @@ static const struct drm_crtc_funcs omap_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .destroy = omap_crtc_destroy, .page_flip = drm_atomic_helper_page_flip, + .gamma_set = drm_atomic_helper_legacy_gamma_set, .set_property = drm_atomic_helper_crtc_set_property, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, @@ -471,6 +512,7 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = { .mode_set_nofb = omap_crtc_mode_set_nofb, .disable = omap_crtc_disable, .enable = omap_crtc_enable, + .atomic_check = omap_crtc_atomic_check, .atomic_begin = omap_crtc_atomic_begin, .atomic_flush = omap_crtc_atomic_flush, }; @@ -534,6 +576,20 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); + /* The dispc API adapts to what ever size, but the HW supports + * 256 element gamma table for LCDs and 1024 element table for + * OMAP_DSS_CHANNEL_DIGIT. X server assumes 256 element gamma + * tables so lets use that. Size of HW gamma table can be + * extracted with dispc_mgr_gamma_size(). If it returns 0 + * gamma table is not supprted. + */ + if (dispc_mgr_gamma_size(channel)) { + uint gamma_lut_size = 256; + + drm_crtc_enable_color_mgmt(crtc, 0, false, gamma_lut_size); + drm_mode_crtc_set_gamma_size(crtc, gamma_lut_size); + } + omap_plane_install_properties(crtc->primary, &crtc->base); omap_crtcs[channel] = omap_crtc; diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index d86f5479345b..26c6134eb744 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -142,8 +142,9 @@ static int omap_atomic_commit(struct drm_device *dev, { struct omap_drm_private *priv = dev->dev_private; struct omap_atomic_state_commit *commit; - unsigned int i; - int ret; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int i, ret; ret = drm_atomic_helper_prepare_planes(dev, state); if (ret) @@ -163,10 +164,8 @@ static int omap_atomic_commit(struct drm_device *dev, /* Wait until all affected CRTCs have completed previous commits and * mark them as pending. */ - for (i = 0; i < dev->mode_config.num_crtc; ++i) { - if (state->crtcs[i]) - commit->crtcs |= 1 << drm_crtc_index(state->crtcs[i]); - } + for_each_crtc_in_state(state, crtc, crtc_state, i) + commit->crtcs |= drm_crtc_mask(crtc); wait_event(priv->commit.wait, !omap_atomic_is_pending(priv, commit)); @@ -175,7 +174,7 @@ static int omap_atomic_commit(struct drm_device *dev, spin_unlock(&priv->commit.lock); /* Swap the state, this is the point of no return. */ - drm_atomic_helper_swap_state(dev, state); + drm_atomic_helper_swap_state(state, true); if (nonblock) schedule_work(&commit->work); @@ -203,6 +202,8 @@ static int get_connector_type(struct omap_dss_device *dssdev) return DRM_MODE_CONNECTOR_HDMIA; case OMAP_DISPLAY_TYPE_DVI: return DRM_MODE_CONNECTOR_DVID; + case OMAP_DISPLAY_TYPE_DSI: + return DRM_MODE_CONNECTOR_DSI; default: return DRM_MODE_CONNECTOR_Unknown; } @@ -800,7 +801,6 @@ static struct drm_driver omap_drm_driver = { .unload = dev_unload, .open = dev_open, .lastclose = dev_lastclose, - .set_busid = drm_platform_set_busid, .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = omap_irq_enable_vblank, .disable_vblank = omap_irq_disable_vblank, diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 3f823c368912..dcc30a98b9d4 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -24,7 +24,6 @@ #include <linux/platform_data/omap_drm.h> #include <linux/types.h> #include <linux/wait.h> -#include <video/omapdss.h> #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> @@ -183,7 +182,6 @@ struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos); -struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p); int omap_framebuffer_pin(struct drm_framebuffer *fb); void omap_framebuffer_unpin(struct drm_framebuffer *fb); void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, @@ -231,7 +229,6 @@ int omap_gem_rotated_paddr(struct drm_gem_object *obj, uint32_t orient, int x, int y, dma_addr_t *paddr); uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj); size_t omap_gem_mmap_size(struct drm_gem_object *obj); -int omap_gem_tiled_size(struct drm_gem_object *obj, uint16_t *w, uint16_t *h); int omap_gem_tiled_stride(struct drm_gem_object *obj, uint32_t orient); struct dma_buf *omap_gem_prime_export(struct drm_device *dev, @@ -239,17 +236,6 @@ struct dma_buf *omap_gem_prime_export(struct drm_device *dev, struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, struct dma_buf *buffer); -static inline int align_pitch(int pitch, int width, int bpp) -{ - int bytespp = (bpp + 7) / 8; - /* in case someone tries to feed us a completely bogus stride: */ - pitch = max(pitch, width * bytespp); - /* PVR needs alignment to 8 pixels.. right now that is the most - * restrictive stride requirement.. - */ - return roundup(pitch, 8 * bytespp); -} - /* map crtc to vblank mask */ uint32_t pipe2vbl(struct drm_crtc *crtc); struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index f84570d1636c..31f5178c22c7 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -115,24 +115,16 @@ static void omap_framebuffer_destroy(struct drm_framebuffer *fb) for (i = 0; i < n; i++) { struct plane *plane = &omap_fb->planes[i]; - if (plane->bo) - drm_gem_object_unreference_unlocked(plane->bo); + + drm_gem_object_unreference_unlocked(plane->bo); } kfree(omap_fb); } -static int omap_framebuffer_dirty(struct drm_framebuffer *fb, - struct drm_file *file_priv, unsigned flags, unsigned color, - struct drm_clip_rect *clips, unsigned num_clips) -{ - return 0; -} - static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { .create_handle = omap_framebuffer_create_handle, .destroy = omap_framebuffer_destroy, - .dirty = omap_framebuffer_dirty, }; static uint32_t get_linear_addr(struct plane *plane, @@ -320,14 +312,6 @@ void omap_framebuffer_unpin(struct drm_framebuffer *fb) mutex_unlock(&omap_fb->lock); } -struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p) -{ - struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); - if (p >= drm_format_num_planes(fb->pixel_format)) - return NULL; - return omap_fb->planes[p].bo; -} - /* iterate thru all the connectors, returning ones that are attached * to the same fb.. */ diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 89da41ac64d2..adb10fbe918d 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -125,9 +125,8 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, mode_cmd.width = sizes->surface_width; mode_cmd.height = sizes->surface_height; - mode_cmd.pitches[0] = align_pitch( - mode_cmd.width * ((sizes->surface_bpp + 7) / 8), - mode_cmd.width, sizes->surface_bpp); + mode_cmd.pitches[0] = + DIV_ROUND_UP(mode_cmd.width * sizes->surface_bpp, 8); fbdev->ywrap_enabled = priv->has_dmm && ywrap_enabled; if (fbdev->ywrap_enabled) { @@ -280,9 +279,6 @@ struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev) if (ret) goto fini; - /* disable all the possible outputs/crtcs before entering KMS mode */ - drm_helper_disable_unused_functions(dev); - ret = drm_fb_helper_initial_config(helper, 32); if (ret) goto fini; diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 0dbd0f03f9bd..505dee0db973 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -383,18 +383,6 @@ size_t omap_gem_mmap_size(struct drm_gem_object *obj) return size; } -/* get tiled size, returns -EINVAL if not tiled buffer */ -int omap_gem_tiled_size(struct drm_gem_object *obj, uint16_t *w, uint16_t *h) -{ - struct omap_gem_object *omap_obj = to_omap_bo(obj); - if (omap_obj->flags & OMAP_BO_TILED) { - *w = omap_obj->width; - *h = omap_obj->height; - return 0; - } - return -EINVAL; -} - /* ----------------------------------------------------------------------------- * Fault Handling */ @@ -661,7 +649,8 @@ int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev, { union omap_gem_size gsize; - args->pitch = align_pitch(0, args->width, args->bpp); + args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8); + args->size = PAGE_ALIGN(args->pitch * args->height); gsize = (union omap_gem_size){ |