Commit ca18e142 authored by Dave Airlie's avatar Dave Airlie

Merge branch 'tilcdc-next' of git://people.freedesktop.org/~robclark/linux into drm-next

KMS driver for TI LCD controller

* 'tilcdc-next' of git://people.freedesktop.org/~robclark/linux:
  drm/tilcdc: add support for LCD panels (v5)
  drm/tilcdc: add encoder slave (v2)
  drm/i2c: nxp-tda998x (v3)
  drm/tilcdc: add TI LCD Controller DRM driver (v4)
  drm/nouveau: use i2c encoder helper wrappers
  drm: i2c encoder helper wrappers
  drm/cma: add debugfs helpers
  drm: small fix in drm_send_vblank_event()
  drm: Don't set the plane->fb to NULL on successfull set_plane
  drm/cma-helper: fixup compilation

Conflicts:
	drivers/gpu/drm/Kconfig
	drivers/gpu/drm/Makefile
	drivers/gpu/drm/drm_fb_cma_helper.c
parents 74e16974 0d4bbaf9
Device-Tree bindings for tilcdc DRM generic panel output driver
Required properties:
- compatible: value should be "ti,tilcdc,panel".
- panel-info: configuration info to configure LCDC correctly for the panel
- ac-bias: AC Bias Pin Frequency
- ac-bias-intrpt: AC Bias Pin Transitions per Interrupt
- dma-burst-sz: DMA burst size
- bpp: Bits per pixel
- fdd: FIFO DMA Request Delay
- sync-edge: Horizontal and Vertical Sync Edge: 0=rising 1=falling
- sync-ctrl: Horizontal and Vertical Sync: Control: 0=ignore
- raster-order: Raster Data Order Select: 1=Most-to-least 0=Least-to-most
- fifo-th: DMA FIFO threshold
- display-timings: typical videomode of lcd panel. Multiple video modes
can be listed if the panel supports multiple timings, but the 'native-mode'
should be the preferred/default resolution. Refer to
Documentation/devicetree/bindings/video/display-timing.txt for display
timing binding details.
Recommended properties:
- pinctrl-names, pinctrl-0: the pincontrol settings to configure
muxing properly for pins that connect to TFP410 device
Example:
/* Settings for CDTech_S035Q01 / LCD3 cape: */
lcd3 {
compatible = "ti,tilcdc,panel";
pinctrl-names = "default";
pinctrl-0 = <&bone_lcd3_cape_lcd_pins>;
panel-info {
ac-bias = <255>;
ac-bias-intrpt = <0>;
dma-burst-sz = <16>;
bpp = <16>;
fdd = <0x80>;
sync-edge = <0>;
sync-ctrl = <1>;
raster-order = <0>;
fifo-th = <0>;
};
display-timings {
native-mode = <&timing0>;
timing0: 320x240 {
hactive = <320>;
vactive = <240>;
hback-porch = <21>;
hfront-porch = <58>;
hsync-len = <47>;
vback-porch = <11>;
vfront-porch = <23>;
vsync-len = <2>;
clock-frequency = <8000000>;
hsync-active = <0>;
vsync-active = <0>;
};
};
};
Device-Tree bindings for tilcdc DRM encoder slave output driver
Required properties:
- compatible: value should be "ti,tilcdc,slave".
- i2c: the phandle for the i2c device the encoder slave is connected to
Recommended properties:
- pinctrl-names, pinctrl-0: the pincontrol settings to configure
muxing properly for pins that connect to TFP410 device
Example:
hdmi {
compatible = "ti,tilcdc,slave";
i2c = <&i2c0>;
pinctrl-names = "default";
pinctrl-0 = <&nxp_hdmi_bonelt_pins>;
};
Device-Tree bindings for tilcdc DRM TFP410 output driver
Required properties:
- compatible: value should be "ti,tilcdc,tfp410".
- i2c: the phandle for the i2c device to use for DDC
Recommended properties:
- pinctrl-names, pinctrl-0: the pincontrol settings to configure
muxing properly for pins that connect to TFP410 device
- powerdn-gpio: the powerdown GPIO, pulled low to power down the
TFP410 device (for DPMS_OFF)
Example:
dvicape {
compatible = "ti,tilcdc,tfp410";
i2c = <&i2c2>;
pinctrl-names = "default";
pinctrl-0 = <&bone_dvi_cape_dvi_00A1_pins>;
powerdn-gpio = <&gpio2 31 0>;
};
Device-Tree bindings for tilcdc DRM driver
Required properties:
- compatible: value should be "ti,am33xx-tilcdc".
- interrupts: the interrupt number
- reg: base address and size of the LCDC device
Recommended properties:
- interrupt-parent: the phandle for the interrupt controller that
services interrupts for this device.
- ti,hwmods: Name of the hwmod associated to the LCDC
Example:
fb: fb@4830e000 {
compatible = "ti,am33xx-tilcdc";
reg = <0x4830e000 0x1000>;
interrupt-parent = <&intc>;
interrupts = <36>;
ti,hwmods = "lcdc";
};
......@@ -217,3 +217,5 @@ source "drivers/gpu/drm/shmobile/Kconfig"
source "drivers/gpu/drm/tegra/Kconfig"
source "drivers/gpu/drm/omapdrm/Kconfig"
source "drivers/gpu/drm/tilcdc/Kconfig"
......@@ -51,4 +51,5 @@ obj-$(CONFIG_DRM_AST) += ast/
obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
obj-$(CONFIG_DRM_TEGRA) += tegra/
obj-$(CONFIG_DRM_OMAP) += omapdrm/
obj-$(CONFIG_DRM_TILCDC) += tilcdc/
obj-y += i2c/
......@@ -123,3 +123,66 @@ void drm_i2c_encoder_destroy(struct drm_encoder *drm_encoder)
module_put(module);
}
EXPORT_SYMBOL(drm_i2c_encoder_destroy);
/*
* Wrapper fxns which can be plugged in to drm_encoder_helper_funcs:
*/
static inline struct drm_encoder_slave_funcs *
get_slave_funcs(struct drm_encoder *enc)
{
return to_encoder_slave(enc)->slave_funcs;
}
void drm_i2c_encoder_dpms(struct drm_encoder *encoder, int mode)
{
get_slave_funcs(encoder)->dpms(encoder, mode);
}
EXPORT_SYMBOL(drm_i2c_encoder_dpms);
bool drm_i2c_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return get_slave_funcs(encoder)->mode_fixup(encoder, mode, adjusted_mode);
}
EXPORT_SYMBOL(drm_i2c_encoder_mode_fixup);
void drm_i2c_encoder_prepare(struct drm_encoder *encoder)
{
drm_i2c_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
}
EXPORT_SYMBOL(drm_i2c_encoder_prepare);
void drm_i2c_encoder_commit(struct drm_encoder *encoder)
{
drm_i2c_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
}
EXPORT_SYMBOL(drm_i2c_encoder_commit);
void drm_i2c_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
get_slave_funcs(encoder)->mode_set(encoder, mode, adjusted_mode);
}
EXPORT_SYMBOL(drm_i2c_encoder_mode_set);
enum drm_connector_status drm_i2c_encoder_detect(struct drm_encoder *encoder,
struct drm_connector *connector)
{
return get_slave_funcs(encoder)->detect(encoder, connector);
}
EXPORT_SYMBOL(drm_i2c_encoder_detect);
void drm_i2c_encoder_save(struct drm_encoder *encoder)
{
get_slave_funcs(encoder)->save(encoder);
}
EXPORT_SYMBOL(drm_i2c_encoder_save);
void drm_i2c_encoder_restore(struct drm_encoder *encoder)
{
get_slave_funcs(encoder)->restore(encoder);
}
EXPORT_SYMBOL(drm_i2c_encoder_restore);
......@@ -180,6 +180,59 @@ struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
}
EXPORT_SYMBOL_GPL(drm_fb_cma_get_gem_obj);
#ifdef CONFIG_DEBUG_FS
/**
* drm_fb_cma_describe() - Helper to dump information about a single
* CMA framebuffer object
*/
void drm_fb_cma_describe(struct drm_framebuffer *fb, struct seq_file *m)
{
struct drm_fb_cma *fb_cma = to_fb_cma(fb);
int i, n = drm_format_num_planes(fb->pixel_format);
seq_printf(m, "fb: %dx%d@%4.4s\n", fb->width, fb->height,
(char *)&fb->pixel_format);
for (i = 0; i < n; i++) {
seq_printf(m, " %d: offset=%d pitch=%d, obj: ",
i, fb->offsets[i], fb->pitches[i]);
drm_gem_cma_describe(fb_cma->obj[i], m);
}
}
EXPORT_SYMBOL_GPL(drm_fb_cma_describe);
/**
* drm_fb_cma_debugfs_show() - Helper to list CMA framebuffer objects
* in debugfs.
*/
int drm_fb_cma_debugfs_show(struct seq_file *m, void *arg)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct drm_framebuffer *fb;
int ret;
ret = mutex_lock_interruptible(&dev->mode_config.mutex);
if (ret)
return ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret) {
mutex_unlock(&dev->mode_config.mutex);
return ret;
}
list_for_each_entry(fb, &dev->mode_config.fb_list, head)
drm_fb_cma_describe(fb, m);
mutex_unlock(&dev->struct_mutex);
mutex_unlock(&dev->mode_config.mutex);
return 0;
}
EXPORT_SYMBOL_GPL(drm_fb_cma_debugfs_show);
#endif
static struct fb_ops drm_fbdev_cma_ops = {
.owner = THIS_MODULE,
.fb_fillrect = sys_fillrect,
......
......@@ -249,3 +249,24 @@ int drm_gem_cma_dumb_destroy(struct drm_file *file_priv,
return drm_gem_handle_delete(file_priv, handle);
}
EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_destroy);
#ifdef CONFIG_DEBUG_FS
void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *m)
{
struct drm_gem_object *obj = &cma_obj->base;
struct drm_device *dev = obj->dev;
uint64_t off = 0;
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
if (obj->map_list.map)
off = (uint64_t)obj->map_list.hash.key;
seq_printf(m, "%2d (%2d) %08llx %08Zx %p %d",
obj->name, obj->refcount.refcount.counter,
off, cma_obj->paddr, cma_obj->vaddr, obj->size);
seq_printf(m, "\n");
}
EXPORT_SYMBOL_GPL(drm_gem_cma_describe);
#endif
......@@ -867,6 +867,7 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc,
now = get_drm_timestamp();
}
e->pipe = crtc;
send_vblank_event(dev, e, seq, &now);
}
EXPORT_SYMBOL(drm_send_vblank_event);
......
......@@ -19,4 +19,10 @@ config DRM_I2C_SIL164
when used in pairs) TMDS transmitters, used in some nVidia
video cards.
config DRM_I2C_NXP_TDA998X
tristate "NXP Semiconductors TDA998X HDMI encoder"
default m if DRM_TILCDC
help
Support for NXP Semiconductors TDA998X HDMI encoders.
endmenu
......@@ -5,3 +5,6 @@ obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o
sil164-y := sil164_drv.o
obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o
tda998x-y := tda998x_drv.o
obj-$(CONFIG_DRM_I2C_NXP_TDA998X) += tda998x.o
This diff is collapsed.
......@@ -184,14 +184,23 @@ static const struct drm_encoder_funcs nv04_tv_funcs = {
.destroy = nv04_tv_destroy,
};
static const struct drm_encoder_helper_funcs nv04_tv_helper_funcs = {
.dpms = nv04_tv_dpms,
.save = drm_i2c_encoder_save,
.restore = drm_i2c_encoder_restore,
.mode_fixup = drm_i2c_encoder_mode_fixup,
.prepare = nv04_tv_prepare,
.commit = nv04_tv_commit,
.mode_set = nv04_tv_mode_set,
.detect = drm_i2c_encoder_detect,
};
int
nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry)
{
struct nouveau_encoder *nv_encoder;
struct drm_encoder *encoder;
struct drm_device *dev = connector->dev;
struct drm_encoder_helper_funcs *hfuncs;
struct drm_encoder_slave_funcs *sfuncs;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_i2c *i2c = nouveau_i2c(drm->device);
struct nouveau_i2c_port *port = i2c->find(i2c, entry->i2c_index);
......@@ -207,17 +216,11 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry)
if (!nv_encoder)
return -ENOMEM;
hfuncs = kzalloc(sizeof(*hfuncs), GFP_KERNEL);
if (!hfuncs) {
ret = -ENOMEM;
goto fail_free;
}
/* Initialize the common members */
encoder = to_drm_encoder(nv_encoder);
drm_encoder_init(dev, encoder, &nv04_tv_funcs, DRM_MODE_ENCODER_TVDAC);
drm_encoder_helper_add(encoder, hfuncs);
drm_encoder_helper_add(encoder, &nv04_tv_helper_funcs);
encoder->possible_crtcs = entry->heads;
encoder->possible_clones = 0;
......@@ -230,30 +233,14 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry)
if (ret < 0)
goto fail_cleanup;
/* Fill the function pointers */
sfuncs = get_slave_funcs(encoder);
*hfuncs = (struct drm_encoder_helper_funcs) {
.dpms = nv04_tv_dpms,
.save = sfuncs->save,
.restore = sfuncs->restore,
.mode_fixup = sfuncs->mode_fixup,
.prepare = nv04_tv_prepare,
.commit = nv04_tv_commit,
.mode_set = nv04_tv_mode_set,
.detect = sfuncs->detect,
};
/* Attach it to the specified connector. */
sfuncs->create_resources(encoder, connector);
get_slave_funcs(encoder)->create_resources(encoder, connector);
drm_mode_connector_attach_encoder(connector, encoder);
return 0;
fail_cleanup:
drm_encoder_cleanup(encoder);
kfree(hfuncs);
fail_free:
kfree(nv_encoder);
return ret;
}
config DRM_TILCDC
tristate "DRM Support for TI LCDC Display Controller"
depends on DRM && OF
select DRM_KMS_HELPER
select DRM_KMS_CMA_HELPER
select DRM_GEM_CMA_HELPER
select OF_VIDEOMODE
select OF_DISPLAY_TIMING
select BACKLIGHT_CLASS_DEVICE
help
Choose this option if you have an TI SoC with LCDC display
controller, for example AM33xx in beagle-bone, DA8xx, or
OMAP-L1xx. This driver replaces the FB_DA8XX fbdev driver.
ccflags-y := -Iinclude/drm -Werror
tilcdc-y := \
tilcdc_crtc.o \
tilcdc_tfp410.o \
tilcdc_slave.o \
tilcdc_panel.o \
tilcdc_drv.o
obj-$(CONFIG_DRM_TILCDC) += tilcdc.o
This diff is collapsed.
This diff is collapsed.
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TILCDC_DRV_H__
#define __TILCDC_DRV_H__
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/list.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
struct tilcdc_drm_private {
void __iomem *mmio;
struct clk *disp_clk; /* display dpll */
struct clk *clk; /* functional clock */
int rev; /* IP revision */
/* don't attempt resolutions w/ higher W * H * Hz: */
uint32_t max_bandwidth;
/* register contents saved across suspend/resume: */
u32 saved_register[12];
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
unsigned int lcd_fck_rate;
#endif
struct workqueue_struct *wq;
struct drm_fbdev_cma *fbdev;
struct drm_crtc *crtc;
unsigned int num_encoders;
struct drm_encoder *encoders[8];
unsigned int num_connectors;
struct drm_connector *connectors[8];
};
/* Sub-module for display. Since we don't know at compile time what panels
* or display adapter(s) might be present (for ex, off chip dvi/tfp410,
* hdmi encoder, various lcd panels), the connector/encoder(s) are split into
* separate drivers. If they are probed and found to be present, they
* register themselves with tilcdc_register_module().
*/
struct tilcdc_module;
struct tilcdc_module_ops {
/* create appropriate encoders/connectors: */
int (*modeset_init)(struct tilcdc_module *mod, struct drm_device *dev);
void (*destroy)(struct tilcdc_module *mod);
#ifdef CONFIG_DEBUG_FS
/* create debugfs nodes (can be NULL): */
int (*debugfs_init)(struct tilcdc_module *mod, struct drm_minor *minor);
/* cleanup debugfs nodes (can be NULL): */
void (*debugfs_cleanup)(struct tilcdc_module *mod, struct drm_minor *minor);
#endif
};
struct tilcdc_module {
const char *name;
struct list_head list;
const struct tilcdc_module_ops *funcs;
};
void tilcdc_module_init(struct tilcdc_module *mod, const char *name,
const struct tilcdc_module_ops *funcs);
void tilcdc_module_cleanup(struct tilcdc_module *mod);
/* Panel config that needs to be set in the crtc, but is not coming from
* the mode timings. The display module is expected to call
* tilcdc_crtc_set_panel_info() to set this during modeset.
*/
struct tilcdc_panel_info {
/* AC Bias Pin Frequency */
uint32_t ac_bias;
/* AC Bias Pin Transitions per Interrupt */
uint32_t ac_bias_intrpt;
/* DMA burst size */
uint32_t dma_burst_sz;
/* Bits per pixel */
uint32_t bpp;
/* FIFO DMA Request Delay */
uint32_t fdd;
/* TFT Alternative Signal Mapping (Only for active) */
bool tft_alt_mode;
/* Invert pixel clock */
bool invert_pxl_clk;
/* Horizontal and Vertical Sync Edge: 0=rising 1=falling */
uint32_t sync_edge;
/* Horizontal and Vertical Sync: Control: 0=ignore */
uint32_t sync_ctrl;
/* Raster Data Order Select: 1=Most-to-least 0=Least-to-most */
uint32_t raster_order;
/* DMA FIFO threshold */
uint32_t fifo_th;
};
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev);
void tilcdc_crtc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc);
void tilcdc_crtc_update_clk(struct drm_crtc *crtc);
void tilcdc_crtc_set_panel_info(struct drm_crtc *crtc,
const struct tilcdc_panel_info *info);
int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode);
int tilcdc_crtc_max_width(struct drm_crtc *crtc);
#endif /* __TILCDC_DRV_H__ */
This diff is collapsed.
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TILCDC_PANEL_H__
#define __TILCDC_PANEL_H__
/* sub-module for generic lcd panel output */
int tilcdc_panel_init(void);
void tilcdc_panel_fini(void);
#endif /* __TILCDC_PANEL_H__ */
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TILCDC_REGS_H__
#define __TILCDC_REGS_H__
/* LCDC register definitions, based on da8xx-fb */
#include <linux/bitops.h>
#include "tilcdc_drv.h"
/* LCDC Status Register */
#define LCDC_END_OF_FRAME1 BIT(9)
#define LCDC_END_OF_FRAME0 BIT(8)
#define LCDC_PL_LOAD_DONE BIT(6)
#define LCDC_FIFO_UNDERFLOW BIT(5)
#define LCDC_SYNC_LOST BIT(2)
#define LCDC_FRAME_DONE BIT(0)
/* LCDC DMA Control Register */
#define LCDC_DMA_BURST_SIZE(x) ((x) << 4)
#define LCDC_DMA_BURST_1 0x0
#define LCDC_DMA_BURST_2 0x1
#define LCDC_DMA_BURST_4 0x2
#define LCDC_DMA_BURST_8 0x3
#define LCDC_DMA_BURST_16 0x4
#define LCDC_V1_END_OF_FRAME_INT_ENA BIT(2)
#define LCDC_V2_END_OF_FRAME0_INT_ENA BIT(8)
#define LCDC_V2_END_OF_FRAME1_INT_ENA BIT(9)
#define LCDC_DUAL_FRAME_BUFFER_ENABLE BIT(0)
/* LCDC Control Register */
#define LCDC_CLK_DIVISOR(x) ((x) << 8)
#define LCDC_RASTER_MODE 0x01
/* LCDC Raster Control Register */
#define LCDC_PALETTE_LOAD_MODE(x) ((x) << 20)
#define PALETTE_AND_DATA 0x00
#define PALETTE_ONLY 0x01
#define DATA_ONLY 0x02
#define LCDC_MONO_8BIT_MODE BIT(9)
#define LCDC_RASTER_ORDER BIT(8)
#define LCDC_TFT_MODE BIT(7)
#define LCDC_V1_UNDERFLOW_INT_ENA BIT(6)
#define LCDC_V2_UNDERFLOW_INT_ENA BIT(5)
#define LCDC_V1_PL_INT_ENA BIT(4)
#define LCDC_V2_PL_INT_ENA BIT(6)
#define LCDC_MONOCHROME_MODE BIT(1)
#define LCDC_RASTER_ENABLE BIT(0)
#define LCDC_TFT_ALT_ENABLE BIT(23)
#define LCDC_STN_565_ENABLE BIT(24)
#define LCDC_V2_DMA_CLK_EN BIT(2)
#define LCDC_V2_LIDD_CLK_EN BIT(1)
#define LCDC_V2_CORE_CLK_EN BIT(0)
#define LCDC_V2_LPP_B10 26
#define LCDC_V2_TFT_24BPP_MODE BIT(25)
#define LCDC_V2_TFT_24BPP_UNPACK BIT(26)
/* LCDC Raster Timing 2 Register */
#define LCDC_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16)
#define LCDC_AC_BIAS_FREQUENCY(x) ((x) << 8)
#define LCDC_SYNC_CTRL BIT(25)
#define LCDC_SYNC_EDGE BIT(24)
#define LCDC_INVERT_PIXEL_CLOCK BIT(22)
#define LCDC_INVERT_HSYNC BIT(21)
#define LCDC_INVERT_VSYNC BIT(20)
/* LCDC Block */
#define LCDC_PID_REG 0x0
#define LCDC_CTRL_REG 0x4
#define LCDC_STAT_REG 0x8
#define LCDC_RASTER_CTRL_REG 0x28
#define LCDC_RASTER_TIMING_0_REG 0x2c
#define LCDC_RASTER_TIMING_1_REG 0x30
#define LCDC_RASTER_TIMING_2_REG 0x34
#define LCDC_DMA_CTRL_REG 0x40
#define LCDC_DMA_FB_BASE_ADDR_0_REG 0x44
#define LCDC_DMA_FB_CEILING_ADDR_0_REG 0x48
#define LCDC_DMA_FB_BASE_ADDR_1_REG 0x4c
#define LCDC_DMA_FB_CEILING_ADDR_1_REG 0x50
/* Interrupt Registers available only in Version 2 */
#define LCDC_RAW_STAT_REG 0x58
#define LCDC_MASKED_STAT_REG 0x5c
#define LCDC_INT_ENABLE_SET_REG 0x60
#define LCDC_INT_ENABLE_CLR_REG 0x64
#define LCDC_END_OF_INT_IND_REG 0x68
/* Clock registers available only on Version 2 */
#define LCDC_CLK_ENABLE_REG 0x6c
#define LCDC_CLK_RESET_REG 0x70
#define LCDC_CLK_MAIN_RESET BIT(3)
/*
* Helpers:
*/
static inline void tilcdc_write(struct drm_device *dev, u32 reg, u32 data)
{
struct tilcdc_drm_private *priv = dev->dev_private;
iowrite32(data, priv->mmio + reg);
}
static inline u32 tilcdc_read(struct drm_device *dev, u32 reg)
{
struct tilcdc_drm_private *priv = dev->dev_private;
return ioread32(priv->mmio + reg);
}
static inline void tilcdc_set(struct drm_device *dev, u32 reg, u32 mask)
{
tilcdc_write(dev, reg, tilcdc_read(dev, reg) | mask);
}
static inline void tilcdc_clear(struct drm_device *dev, u32 reg, u32 mask)
{
tilcdc_write(dev, reg, tilcdc_read(dev, reg) & ~mask);
}
/* the register to read/clear irqstatus differs between v1 and v2 of the IP */
static inline u32 tilcdc_irqstatus_reg(struct drm_device *dev)
{
struct tilcdc_drm_private *priv = dev->dev_private;
return (priv->rev == 2) ? LCDC_MASKED_STAT_REG : LCDC_STAT_REG;
}
static inline u32 tilcdc_read_irqstatus(struct drm_device *dev)
{
return tilcdc_read(dev, tilcdc_irqstatus_reg(dev));
}
static inline void tilcdc_clear_irqstatus(struct drm_device *dev, u32 mask)
{
tilcdc_write(dev, tilcdc_irqstatus_reg(dev), mask);
}
#endif /* __TILCDC_REGS_H__ */
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/i2c.h>
#include <linux/of_i2c.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/consumer.h>
#include <drm/drm_encoder_slave.h>
#include "tilcdc_drv.h"
struct slave_module {
struct tilcdc_module base;
struct i2c_adapter *i2c;
};
#define to_slave_module(x) container_of(x, struct slave_module, base)
static const struct tilcdc_panel_info slave_info = {
.bpp = 16,
.ac_bias = 255,
.ac_bias_intrpt = 0,
.dma_burst_sz = 16,
.fdd = 0x80,
.tft_alt_mode = 0,
.sync_edge = 0,
.sync_ctrl = 1,
.raster_order = 0,
};
/*
* Encoder:
*/
struct slave_encoder {
struct drm_encoder_slave base;
struct slave_module *mod;
};
#define to_slave_encoder(x) container_of(to_encoder_slave(x), struct slave_encoder, base)
static inline struct drm_encoder_slave_funcs *
get_slave_funcs(struct drm_encoder *enc)
{
return to_encoder_slave(enc)->slave_funcs;
}
static void slave_encoder_destroy(struct drm_encoder *encoder)
{
struct slave_encoder *slave_encoder = to_slave_encoder(encoder);
if (get_slave_funcs(encoder))
get_slave_funcs(encoder)->destroy(encoder);
drm_encoder_cleanup(encoder);
kfree(slave_encoder);
}
static void slave_encoder_prepare(struct drm_encoder *encoder)
{
drm_i2c_encoder_prepare(encoder);
tilcdc_crtc_set_panel_info(encoder->crtc, &slave_info);
}
static const struct drm_encoder_funcs slave_encoder_funcs = {
.destroy = slave_encoder_destroy,
};
static const struct drm_encoder_helper_funcs slave_encoder_helper_funcs = {
.dpms = drm_i2c_encoder_dpms,
.mode_fixup = drm_i2c_encoder_mode_fixup,
.prepare = slave_encoder_prepare,
.commit = drm_i2c_encoder_commit,
.mode_set = drm_i2c_encoder_mode_set,
.save = drm_i2c_encoder_save,
.restore = drm_i2c_encoder_restore,
};
static const struct i2c_board_info info = {
I2C_BOARD_INFO("tda998x", 0x70)
};
static struct drm_encoder *slave_encoder_create(struct drm_device *dev,
struct slave_module *mod)
{
struct slave_encoder *slave_encoder;
struct drm_encoder *encoder;
int ret;
slave_encoder = kzalloc(sizeof(*slave_encoder), GFP_KERNEL);
if (!slave_encoder) {
dev_err(dev->dev, "allocation failed\n");
return NULL;
}
slave_encoder->mod = mod;
encoder = &slave_encoder->base.base;
encoder->possible_crtcs = 1;
ret = drm_encoder_init(dev, encoder, &slave_encoder_funcs,
DRM_MODE_ENCODER_TMDS);
if (ret)
goto fail;
drm_encoder_helper_add(encoder, &slave_encoder_helper_funcs);
ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), mod->i2c, &info);
if (ret)
goto fail;
return encoder;
fail:
slave_encoder_destroy(encoder);
return NULL;
}
/*
* Connector:
*/
struct slave_connector {
struct drm_connector base;
struct drm_encoder *encoder; /* our connected encoder */
struct slave_module *mod;
};
#define to_slave_connector(x) container_of(x, struct slave_connector, base)
static void slave_connector_destroy(struct drm_connector *connector)
{
struct slave_connector *slave_connector = to_slave_connector(connector);
drm_connector_cleanup(connector);
kfree(slave_connector);
}
static enum drm_connector_status slave_connector_detect(
struct drm_connector *connector,
bool force)
{
struct drm_encoder *encoder = to_slave_connector(connector)->encoder;
return get_slave_funcs(encoder)->detect(encoder, connector);
}
static int slave_connector_get_modes(struct drm_connector *connector)
{
struct drm_encoder *encoder = to_slave_connector(connector)->encoder;
return get_slave_funcs(encoder)->get_modes(encoder, connector);
}
static int slave_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct drm_encoder *encoder = to_slave_connector(connector)->encoder;
struct tilcdc_drm_private *priv = connector->dev->dev_private;
int ret;
ret = tilcdc_crtc_mode_valid(priv->crtc, mode);
if (ret != MODE_OK)
return ret;
return get_slave_funcs(encoder)->mode_valid(encoder, mode);
}
static struct drm_encoder *slave_connector_best_encoder(
struct drm_connector *connector)
{
struct slave_connector *slave_connector = to_slave_connector(connector);
return slave_connector->encoder;
}
static int slave_connector_set_property(struct drm_connector *connector,
struct drm_property *property, uint64_t value)
{
struct drm_encoder *encoder = to_slave_connector(connector)->encoder;
return get_slave_funcs(encoder)->set_property(encoder,
connector, property, value);
}
static const struct drm_connector_funcs slave_connector_funcs = {
.destroy = slave_connector_destroy,
.dpms = drm_helper_connector_dpms,
.detect = slave_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = slave_connector_set_property,
};
static const struct drm_connector_helper_funcs slave_connector_helper_funcs = {
.get_modes = slave_connector_get_modes,
.mode_valid = slave_connector_mode_valid,
.best_encoder = slave_connector_best_encoder,
};
static struct drm_connector *slave_connector_create(struct drm_device *dev,
struct slave_module *mod, struct drm_encoder *encoder)
{
struct slave_connector *slave_connector;
struct drm_connector *connector;
int ret;
slave_connector = kzalloc(sizeof(*slave_connector), GFP_KERNEL);
if (!slave_connector) {
dev_err(dev->dev, "allocation failed\n");
return NULL;
}
slave_connector->encoder = encoder;
slave_connector->mod = mod;
connector = &slave_connector->base;
drm_connector_init(dev, connector, &slave_connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
drm_connector_helper_add(connector, &slave_connector_helper_funcs);
connector->polled = DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT;
connector->interlace_allowed = 0;
connector->doublescan_allowed = 0;
get_slave_funcs(encoder)->create_resources(encoder, connector);
ret = drm_mode_connector_attach_encoder(connector, encoder);
if (ret)
goto fail;
drm_sysfs_connector_add(connector);
return connector;
fail:
slave_connector_destroy(connector);
return NULL;
}
/*
* Module:
*/
static int slave_modeset_init(struct tilcdc_module *mod, struct drm_device *dev)
{
struct slave_module *slave_mod = to_slave_module(mod);
struct tilcdc_drm_private *priv = dev->dev_private;
struct drm_encoder *encoder;
struct drm_connector *connector;
encoder = slave_encoder_create(dev, slave_mod);
if (!encoder)
return -ENOMEM;
connector = slave_connector_create(dev, slave_mod, encoder);
if (!connector)
return -ENOMEM;
priv->encoders[priv->num_encoders++] = encoder;
priv->connectors[priv->num_connectors++] = connector;
return 0;
}
static void slave_destroy(struct tilcdc_module *mod)
{
struct slave_module *slave_mod = to_slave_module(mod);
tilcdc_module_cleanup(mod);
kfree(slave_mod);
}
static const struct tilcdc_module_ops slave_module_ops = {
.modeset_init = slave_modeset_init,
.destroy = slave_destroy,
};
/*
* Device:
*/
static struct of_device_id slave_of_match[];
static int slave_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct device_node *i2c_node;
struct slave_module *slave_mod;
struct tilcdc_module *mod;
struct pinctrl *pinctrl;
uint32_t i2c_phandle;
int ret = -EINVAL;
/* bail out early if no DT data: */
if (!node) {
dev_err(&pdev->dev, "device-tree data is missing\n");
return -ENXIO;
}
slave_mod = kzalloc(sizeof(*slave_mod), GFP_KERNEL);
if (!slave_mod)
return -ENOMEM;
mod = &slave_mod->base;
tilcdc_module_init(mod, "slave", &slave_module_ops);
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl))
dev_warn(&pdev->dev, "pins are not configured\n");
if (of_property_read_u32(node, "i2c", &i2c_phandle)) {
dev_err(&pdev->dev, "could not get i2c bus phandle\n");
goto fail;
}
i2c_node = of_find_node_by_phandle(i2c_phandle);
if (!i2c_node) {
dev_err(&pdev->dev, "could not get i2c bus node\n");
goto fail;
}
slave_mod->i2c = of_find_i2c_adapter_by_node(i2c_node);
if (!slave_mod->i2c) {
dev_err(&pdev->dev, "could not get i2c\n");
goto fail;
}
of_node_put(i2c_node);
return 0;
fail:
slave_destroy(mod);
return ret;
}
static int slave_remove(struct platform_device *pdev)
{
return 0;
}
static struct of_device_id slave_of_match[] = {
{ .compatible = "ti,tilcdc,slave", },
{ },
};
MODULE_DEVICE_TABLE(of, slave_of_match);
struct platform_driver slave_driver = {
.probe = slave_probe,
.remove = slave_remove,
.driver = {
.owner = THIS_MODULE,
.name = "slave",
.of_match_table = slave_of_match,
},
};
int __init tilcdc_slave_init(void)
{
return platform_driver_register(&slave_driver);
}
void __exit tilcdc_slave_fini(void)
{
platform_driver_unregister(&slave_driver);
}
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TILCDC_SLAVE_H__
#define __TILCDC_SLAVE_H__
/* sub-module for i2c slave encoder output */
int tilcdc_slave_init(void);
void tilcdc_slave_fini(void);
#endif /* __TILCDC_SLAVE_H__ */
This diff is collapsed.
/*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <robdclark@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TILCDC_TFP410_H__
#define __TILCDC_TFP410_H__
/* sub-module for tfp410 dvi adaptor */
int tilcdc_tfp410_init(void);
void tilcdc_tfp410_fini(void);
#endif /* __TILCDC_TFP410_H__ */
......@@ -159,4 +159,24 @@ static inline void drm_i2c_encoder_unregister(struct drm_i2c_encoder_driver *dri
void drm_i2c_encoder_destroy(struct drm_encoder *encoder);
/*
* Wrapper fxns which can be plugged in to drm_encoder_helper_funcs:
*/
void drm_i2c_encoder_dpms(struct drm_encoder *encoder, int mode);
bool drm_i2c_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
void drm_i2c_encoder_prepare(struct drm_encoder *encoder);
void drm_i2c_encoder_commit(struct drm_encoder *encoder);
void drm_i2c_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
enum drm_connector_status drm_i2c_encoder_detect(struct drm_encoder *encoder,
struct drm_connector *connector);
void drm_i2c_encoder_save(struct drm_encoder *encoder);
void drm_i2c_encoder_restore(struct drm_encoder *encoder);
#endif
......@@ -23,5 +23,10 @@ struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev,
struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb,
unsigned int plane);
#ifdef CONFIG_DEBUG_FS
void drm_fb_cma_describe(struct drm_framebuffer *fb, struct seq_file *m);
int drm_fb_cma_debugfs_show(struct seq_file *m, void *arg);
#endif
#endif
......@@ -41,4 +41,8 @@ struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm,
extern const struct vm_operations_struct drm_gem_cma_vm_ops;
#ifdef CONFIG_DEBUG_FS
void drm_gem_cma_describe(struct drm_gem_cma_object *obj, struct seq_file *m);
#endif
#endif /* __DRM_GEM_CMA_HELPER_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment