tilcdc fixes for v4.9

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJXyIizAAoJEJA2s1DX1hlBo8cP/0vc+JVWGV3+hGT1WlJs16nI
 bU+IywJO4gV1vgnui9uIFBx650c3Rv3a9lUhORO2RCWtgSOElyXco1zjr9ujUHnl
 LnqZPhQnsPHxx14pJ0MKiMpUKwWwzVcstRVzo/nHbixNgmKhjmKIS6JxpI8a+YRs
 cMCdqaG/2nRmVIDpmbTOoQmZY5FYcIjEpZbUWHFXq6TSZG3q9GgdJp97jqwn7bX/
 MsowD5789ogGOFA3b7kmLG5AkX1EMsT09m5k3oDaP6XcWYG8Ir58tFcyo3MvaaBj
 Hk+9mqg9Y8NIHtGIz9QuwJJnxQNS2ATHVMJeRXlwgL4A/VwoEnW7YK7AvxqAatDL
 WhKGWBOr/A8YQhRhIE6JCRxvz793w9cT86j4Yh/OL77iXjKLGrQFBIbaAy69SEq6
 BDYlLwf+wAaIsr0TPFZjcylOAnEjtZDSJU+B/Z+D9zFb+miJEGcuNfAq9yCJPdYb
 gMj8hPg/5JAp4fLShvwsDW5GuLFAUL2yL2YAhqKTjFbmrXsRIaYs4iievxezrdss
 LqdhKJVCYYy80+KgC6Aq3JR2KrnkWlL2lACrzvcQiBIdtddheHgP9f9ys9f8XeFf
 pEt7PMIN1174Q70Zo/lvvUrHOS8lBoJQPubY/u7VZKgDI+A7P+g2/NO1UDqbDcan
 9sy1R+CB05AH1UAgOkY0
 =E9Ep
 -----END PGP SIGNATURE-----

Merge tag 'tilcdc-4.9-fixes' of https://github.com/jsarha/linux into drm-next

tilcdc fixes for v4.9

* tag 'tilcdc-4.9-fixes' of https://github.com/jsarha/linux:
  drm/tilcdc: Choose console BPP that supports RGB
  drm/tilcdc: Add blue-and-red-crossed devicetree property
  drm/tilcdc: Write DMA base and ceiling address with single instruction
  drm/tilcdc: Remove drm_helper_disable_unused_functions() call
  drm/tilcdc: Enable EOF interrupts for v1 LCDC
  drm/tilcdc: Adjust the FB_CEILING address
  drm/tilcdc: Fix check for remote port parent
This commit is contained in:
Dave Airlie 2016-09-02 15:50:51 +10:00
commit eb97027f07
10 changed files with 104 additions and 30 deletions

View File

@ -17,6 +17,18 @@ Optional properties:
the lcd controller. the lcd controller.
- max-pixelclock: The maximum pixel clock that can be supported - max-pixelclock: The maximum pixel clock that can be supported
by the lcd controller in KHz. by the lcd controller in KHz.
- blue-and-red-wiring: Recognized values "default", "straight" or
"crossed". This property deals with the LCDC revision 2 (found on
AM335x) color errata [1].
- "straight" indicates normal wiring that supports RGB565,
BGR888, and XBGR8888 color formats.
- "crossed" indicates wiring that has blue and red wires
crossed. This setup supports BGR565, RGB888 and XRGB8888
formats.
- If the property is not present or its value is not recognized
the legacy mode is assumed. This configuration supports RGB565,
RGB888 and XRGB8888 formats. However, depending on wiring, the red
and blue colors are swapped in either 16 or 24-bit color modes.
Optional nodes: Optional nodes:
@ -28,6 +40,14 @@ Optional nodes:
Documentation/devicetree/bindings/display/tilcdc/tfp410.txt for connecting Documentation/devicetree/bindings/display/tilcdc/tfp410.txt for connecting
tfp410 DVI encoder or lcd panel to lcdc tfp410 DVI encoder or lcd panel to lcdc
[1] There is an errata about AM335x color wiring. For 16-bit color mode
the wires work as they should (LCD_DATA[0:4] is for Blue[3:7]),
but for 24 bit color modes the wiring of blue and red components is
crossed and LCD_DATA[0:4] is for Red[3:7] and LCD_DATA[11:15] is
for Blue[3-7]. For more details see section 3.1.1 in AM335x
Silicon Errata:
http://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=sprz360
Example: Example:
fb: fb@4830e000 { fb: fb@4830e000 {
@ -37,6 +57,8 @@ Example:
interrupts = <36>; interrupts = <36>;
ti,hwmods = "lcdc"; ti,hwmods = "lcdc";
blue-and-red-wiring = "crossed";
port { port {
lcdc_0: endpoint@0 { lcdc_0: endpoint@0 {
remote-endpoint = <&hdmi_0>; remote-endpoint = <&hdmi_0>;

View File

@ -69,6 +69,7 @@ static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb)
struct drm_gem_cma_object *gem; struct drm_gem_cma_object *gem;
unsigned int depth, bpp; unsigned int depth, bpp;
dma_addr_t start, end; dma_addr_t start, end;
u64 dma_base_and_ceiling;
drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp); drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp);
gem = drm_fb_cma_get_gem_obj(fb, 0); gem = drm_fb_cma_get_gem_obj(fb, 0);
@ -79,8 +80,13 @@ static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb)
end = start + (crtc->mode.vdisplay * fb->pitches[0]); end = start + (crtc->mode.vdisplay * fb->pitches[0]);
tilcdc_write(dev, LCDC_DMA_FB_BASE_ADDR_0_REG, start); /* Write LCDC_DMA_FB_BASE_ADDR_0_REG and LCDC_DMA_FB_CEILING_ADDR_0_REG
tilcdc_write(dev, LCDC_DMA_FB_CEILING_ADDR_0_REG, end); * with a single insruction, if available. This should make it more
* unlikely that LCDC would fetch the DMA addresses in the middle of
* an update.
*/
dma_base_and_ceiling = (u64)(end - 1) << 32 | start;
tilcdc_write64(dev, LCDC_DMA_FB_BASE_ADDR_0_REG, dma_base_and_ceiling);
if (tilcdc_crtc->curr_fb) if (tilcdc_crtc->curr_fb)
drm_flip_work_queue(&tilcdc_crtc->unref_work, drm_flip_work_queue(&tilcdc_crtc->unref_work,
@ -98,6 +104,8 @@ static void tilcdc_crtc_enable_irqs(struct drm_device *dev)
if (priv->rev == 1) { if (priv->rev == 1) {
tilcdc_set(dev, LCDC_RASTER_CTRL_REG, tilcdc_set(dev, LCDC_RASTER_CTRL_REG,
LCDC_V1_UNDERFLOW_INT_ENA); LCDC_V1_UNDERFLOW_INT_ENA);
tilcdc_set(dev, LCDC_DMA_CTRL_REG,
LCDC_V1_END_OF_FRAME_INT_ENA);
} else { } else {
tilcdc_write(dev, LCDC_INT_ENABLE_SET_REG, tilcdc_write(dev, LCDC_INT_ENABLE_SET_REG,
LCDC_V2_UNDERFLOW_INT_ENA | LCDC_V2_UNDERFLOW_INT_ENA |

View File

@ -33,6 +33,20 @@
static LIST_HEAD(module_list); static LIST_HEAD(module_list);
static const u32 tilcdc_rev1_formats[] = { DRM_FORMAT_RGB565 };
static const u32 tilcdc_straight_formats[] = { DRM_FORMAT_RGB565,
DRM_FORMAT_BGR888,
DRM_FORMAT_XBGR8888 };
static const u32 tilcdc_crossed_formats[] = { DRM_FORMAT_BGR565,
DRM_FORMAT_RGB888,
DRM_FORMAT_XRGB8888 };
static const u32 tilcdc_legacy_formats[] = { DRM_FORMAT_RGB565,
DRM_FORMAT_RGB888,
DRM_FORMAT_XRGB8888 };
void tilcdc_module_init(struct tilcdc_module *mod, const char *name, void tilcdc_module_init(struct tilcdc_module *mod, const char *name,
const struct tilcdc_module_ops *funcs) const struct tilcdc_module_ops *funcs)
{ {
@ -226,7 +240,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
struct platform_device *pdev = dev->platformdev; struct platform_device *pdev = dev->platformdev;
struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node;
struct tilcdc_drm_private *priv; struct tilcdc_drm_private *priv;
struct tilcdc_module *mod;
struct resource *res; struct resource *res;
u32 bpp = 0; u32 bpp = 0;
int ret; int ret;
@ -318,6 +331,37 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
pm_runtime_put_sync(dev->dev); pm_runtime_put_sync(dev->dev);
if (priv->rev == 1) {
DBG("Revision 1 LCDC supports only RGB565 format");
priv->pixelformats = tilcdc_rev1_formats;
priv->num_pixelformats = ARRAY_SIZE(tilcdc_rev1_formats);
bpp = 16;
} else {
const char *str = "\0";
of_property_read_string(node, "blue-and-red-wiring", &str);
if (0 == strcmp(str, "crossed")) {
DBG("Configured for crossed blue and red wires");
priv->pixelformats = tilcdc_crossed_formats;
priv->num_pixelformats =
ARRAY_SIZE(tilcdc_crossed_formats);
bpp = 32; /* Choose bpp with RGB support for fbdef */
} else if (0 == strcmp(str, "straight")) {
DBG("Configured for straight blue and red wires");
priv->pixelformats = tilcdc_straight_formats;
priv->num_pixelformats =
ARRAY_SIZE(tilcdc_straight_formats);
bpp = 16; /* Choose bpp with RGB support for fbdef */
} else {
DBG("Blue and red wiring '%s' unknown, use legacy mode",
str);
priv->pixelformats = tilcdc_legacy_formats;
priv->num_pixelformats =
ARRAY_SIZE(tilcdc_legacy_formats);
bpp = 16; /* This is just a guess */
}
}
ret = modeset_init(dev); ret = modeset_init(dev);
if (ret < 0) { if (ret < 0) {
dev_err(dev->dev, "failed to initialize mode setting\n"); dev_err(dev->dev, "failed to initialize mode setting\n");
@ -331,7 +375,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
if (ret < 0) if (ret < 0)
goto fail_mode_config_cleanup; goto fail_mode_config_cleanup;
ret = tilcdc_add_external_encoders(dev, &bpp); ret = tilcdc_add_external_encoders(dev);
if (ret < 0) if (ret < 0)
goto fail_component_cleanup; goto fail_component_cleanup;
} }
@ -354,15 +398,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
goto fail_vblank_cleanup; goto fail_vblank_cleanup;
} }
list_for_each_entry(mod, &module_list, list) {
DBG("%s: preferred_bpp: %d", mod->name, mod->preferred_bpp);
bpp = mod->preferred_bpp;
if (bpp > 0)
break;
}
drm_helper_disable_unused_functions(dev);
drm_mode_config_reset(dev); drm_mode_config_reset(dev);
priv->fbdev = drm_fbdev_cma_init(dev, bpp, priv->fbdev = drm_fbdev_cma_init(dev, bpp,

View File

@ -65,6 +65,10 @@ struct tilcdc_drm_private {
*/ */
uint32_t max_width; uint32_t max_width;
/* Supported pixel formats */
const uint32_t *pixelformats;
uint32_t num_pixelformats;
/* The context for pm susped/resume cycle is stored here */ /* The context for pm susped/resume cycle is stored here */
struct drm_atomic_state *saved_state; struct drm_atomic_state *saved_state;
@ -112,7 +116,6 @@ struct tilcdc_module {
const char *name; const char *name;
struct list_head list; struct list_head list;
const struct tilcdc_module_ops *funcs; const struct tilcdc_module_ops *funcs;
unsigned int preferred_bpp;
}; };
void tilcdc_module_init(struct tilcdc_module *mod, const char *name, void tilcdc_module_init(struct tilcdc_module *mod, const char *name,

View File

@ -52,7 +52,7 @@ static int tilcdc_external_mode_valid(struct drm_connector *connector,
return MODE_OK; return MODE_OK;
} }
static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp, static int tilcdc_add_external_encoder(struct drm_device *dev,
struct drm_connector *connector) struct drm_connector *connector)
{ {
struct tilcdc_drm_private *priv = dev->dev_private; struct tilcdc_drm_private *priv = dev->dev_private;
@ -64,7 +64,6 @@ static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp,
/* Only tda998x is supported at the moment. */ /* Only tda998x is supported at the moment. */
tilcdc_crtc_set_simulate_vesa_sync(priv->crtc, true); tilcdc_crtc_set_simulate_vesa_sync(priv->crtc, true);
tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_tda998x); tilcdc_crtc_set_panel_info(priv->crtc, &panel_info_tda998x);
*bpp = panel_info_tda998x.bpp;
connector_funcs = devm_kzalloc(dev->dev, sizeof(*connector_funcs), connector_funcs = devm_kzalloc(dev->dev, sizeof(*connector_funcs),
GFP_KERNEL); GFP_KERNEL);
@ -94,7 +93,7 @@ static int tilcdc_add_external_encoder(struct drm_device *dev, int *bpp,
return 0; return 0;
} }
int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp) int tilcdc_add_external_encoders(struct drm_device *dev)
{ {
struct tilcdc_drm_private *priv = dev->dev_private; struct tilcdc_drm_private *priv = dev->dev_private;
struct drm_connector *connector; struct drm_connector *connector;
@ -108,7 +107,7 @@ int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp)
if (connector == priv->connectors[i]) if (connector == priv->connectors[i])
found = true; found = true;
if (!found) { if (!found) {
ret = tilcdc_add_external_encoder(dev, bpp, connector); ret = tilcdc_add_external_encoder(dev, connector);
if (ret) if (ret)
return ret; return ret;
} }
@ -154,7 +153,7 @@ int tilcdc_get_external_components(struct device *dev,
while ((ep = of_graph_get_next_endpoint(dev->of_node, ep))) { while ((ep = of_graph_get_next_endpoint(dev->of_node, ep))) {
node = of_graph_get_remote_port_parent(ep); node = of_graph_get_remote_port_parent(ep);
if (!node && !of_device_is_available(node)) { if (!node || !of_device_is_available(node)) {
of_node_put(node); of_node_put(node);
continue; continue;
} }

View File

@ -18,7 +18,7 @@
#ifndef __TILCDC_EXTERNAL_H__ #ifndef __TILCDC_EXTERNAL_H__
#define __TILCDC_EXTERNAL_H__ #define __TILCDC_EXTERNAL_H__
int tilcdc_add_external_encoders(struct drm_device *dev, int *bpp); int tilcdc_add_external_encoders(struct drm_device *dev);
void tilcdc_remove_external_encoders(struct drm_device *dev); void tilcdc_remove_external_encoders(struct drm_device *dev);
int tilcdc_get_external_components(struct device *dev, int tilcdc_get_external_components(struct device *dev,
struct component_match **match); struct component_match **match);

View File

@ -397,8 +397,6 @@ static int panel_probe(struct platform_device *pdev)
goto fail_timings; goto fail_timings;
} }
mod->preferred_bpp = panel_mod->info->bpp;
return 0; return 0;
fail_timings: fail_timings:

View File

@ -24,10 +24,6 @@
#include "tilcdc_drv.h" #include "tilcdc_drv.h"
static const u32 tilcdc_formats[] = { DRM_FORMAT_RGB565,
DRM_FORMAT_RGB888,
DRM_FORMAT_XRGB8888 };
static struct drm_plane_funcs tilcdc_plane_funcs = { static struct drm_plane_funcs tilcdc_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane, .update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane, .disable_plane = drm_atomic_helper_disable_plane,
@ -114,12 +110,13 @@ static const struct drm_plane_helper_funcs plane_helper_funcs = {
int tilcdc_plane_init(struct drm_device *dev, int tilcdc_plane_init(struct drm_device *dev,
struct drm_plane *plane) struct drm_plane *plane)
{ {
struct tilcdc_drm_private *priv = dev->dev_private;
int ret; int ret;
ret = drm_plane_init(dev, plane, 1, ret = drm_plane_init(dev, plane, 1,
&tilcdc_plane_funcs, &tilcdc_plane_funcs,
tilcdc_formats, priv->pixelformats,
ARRAY_SIZE(tilcdc_formats), priv->num_pixelformats,
true); true);
if (ret) { if (ret) {
dev_err(dev->dev, "Failed to initialize plane: %d\n", ret); dev_err(dev->dev, "Failed to initialize plane: %d\n", ret);

View File

@ -119,6 +119,20 @@ static inline void tilcdc_write(struct drm_device *dev, u32 reg, u32 data)
iowrite32(data, priv->mmio + reg); iowrite32(data, priv->mmio + reg);
} }
static inline void tilcdc_write64(struct drm_device *dev, u32 reg, u64 data)
{
struct tilcdc_drm_private *priv = dev->dev_private;
volatile void __iomem *addr = priv->mmio + reg;
#ifdef iowrite64
iowrite64(data, addr);
#else
__iowmb();
/* This compiles to strd (=64-bit write) on ARM7 */
*(volatile u64 __force *)addr = __cpu_to_le64(data);
#endif
}
static inline u32 tilcdc_read(struct drm_device *dev, u32 reg) static inline u32 tilcdc_read(struct drm_device *dev, u32 reg)
{ {
struct tilcdc_drm_private *priv = dev->dev_private; struct tilcdc_drm_private *priv = dev->dev_private;

View File

@ -327,8 +327,6 @@ static int tfp410_probe(struct platform_device *pdev)
goto fail; goto fail;
} }
mod->preferred_bpp = dvi_info.bpp;
i2c_node = of_find_node_by_phandle(i2c_phandle); i2c_node = of_find_node_by_phandle(i2c_phandle);
if (!i2c_node) { if (!i2c_node) {
dev_err(&pdev->dev, "could not get i2c bus node\n"); dev_err(&pdev->dev, "could not get i2c bus node\n");