You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'atmel-hlcdc-drm-3.20' of https://github.com/bbrezillon/linux-at91 into drm-next
Add atmel HLCDC driver. * tag 'atmel-hlcdc-drm-3.20' of https://github.com/bbrezillon/linux-at91: drm: add DT bindings documentation for atmel-hlcdc-dc driver drm: add Atmel HLCDC Display Controller support drm: panel: simple-panel: add bus format information for foxlink panel drm: panel: simple-panel: add support for bus_format retrieval drm: add bus_formats and num_bus_formats fields to drm_display_info
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
Device-Tree bindings for Atmel's HLCDC (High LCD Controller) DRM driver
|
||||
|
||||
The Atmel HLCDC Display Controller is subdevice of the HLCDC MFD device.
|
||||
See ../mfd/atmel-hlcdc.txt for more details.
|
||||
|
||||
Required properties:
|
||||
- compatible: value should be "atmel,hlcdc-display-controller"
|
||||
- pinctrl-names: the pin control state names. Should contain "default".
|
||||
- pinctrl-0: should contain the default pinctrl states.
|
||||
- #address-cells: should be set to 1.
|
||||
- #size-cells: should be set to 0.
|
||||
|
||||
Required children nodes:
|
||||
Children nodes are encoding available output ports and their connections
|
||||
to external devices using the OF graph reprensentation (see ../graph.txt).
|
||||
At least one port node is required.
|
||||
|
||||
Example:
|
||||
|
||||
hlcdc: hlcdc@f0030000 {
|
||||
compatible = "atmel,sama5d3-hlcdc";
|
||||
reg = <0xf0030000 0x2000>;
|
||||
interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
|
||||
clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
|
||||
clock-names = "periph_clk","sys_clk", "slow_clk";
|
||||
status = "disabled";
|
||||
|
||||
hlcdc-display-controller {
|
||||
compatible = "atmel,hlcdc-display-controller";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
hlcdc_panel_output: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&panel_input>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hlcdc_pwm: hlcdc-pwm {
|
||||
compatible = "atmel,hlcdc-pwm";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_lcd_pwm>;
|
||||
#pwm-cells = <3>;
|
||||
};
|
||||
};
|
||||
@@ -183,6 +183,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/armada/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/atmel-hlcdc/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/rcar-du/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/shmobile/Kconfig"
|
||||
|
||||
@@ -54,6 +54,7 @@ obj-$(CONFIG_DRM_GMA500) += gma500/
|
||||
obj-$(CONFIG_DRM_UDL) += udl/
|
||||
obj-$(CONFIG_DRM_AST) += ast/
|
||||
obj-$(CONFIG_DRM_ARMADA) += armada/
|
||||
obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/
|
||||
obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
|
||||
obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
|
||||
obj-$(CONFIG_DRM_OMAP) += omapdrm/
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
config DRM_ATMEL_HLCDC
|
||||
tristate "DRM Support for ATMEL HLCDC Display Controller"
|
||||
depends on DRM && OF && COMMON_CLK && MFD_ATMEL_HLCDC
|
||||
select DRM_GEM_CMA_HELPER
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_KMS_FB_HELPER
|
||||
select DRM_KMS_CMA_HELPER
|
||||
select DRM_PANEL
|
||||
help
|
||||
Choose this option if you have an ATMEL SoC with an HLCDC display
|
||||
controller (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family).
|
||||
@@ -0,0 +1,7 @@
|
||||
atmel-hlcdc-dc-y := atmel_hlcdc_crtc.o \
|
||||
atmel_hlcdc_dc.o \
|
||||
atmel_hlcdc_layer.o \
|
||||
atmel_hlcdc_output.o \
|
||||
atmel_hlcdc_plane.o
|
||||
|
||||
obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc-dc.o
|
||||
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Traphandler
|
||||
* Copyright (C) 2014 Free Electrons
|
||||
*
|
||||
* Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
|
||||
* Author: Boris BREZILLON <boris.brezillon@free-electrons.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/clk.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drmP.h>
|
||||
|
||||
#include <video/videomode.h>
|
||||
|
||||
#include "atmel_hlcdc_dc.h"
|
||||
|
||||
/**
|
||||
* Atmel HLCDC CRTC structure
|
||||
*
|
||||
* @base: base DRM CRTC structure
|
||||
* @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
|
||||
* @event: pointer to the current page flip event
|
||||
* @id: CRTC id (returned by drm_crtc_index)
|
||||
* @dpms: DPMS mode
|
||||
*/
|
||||
struct atmel_hlcdc_crtc {
|
||||
struct drm_crtc base;
|
||||
struct atmel_hlcdc_dc *dc;
|
||||
struct drm_pending_vblank_event *event;
|
||||
int id;
|
||||
int dpms;
|
||||
};
|
||||
|
||||
static inline struct atmel_hlcdc_crtc *
|
||||
drm_crtc_to_atmel_hlcdc_crtc(struct drm_crtc *crtc)
|
||||
{
|
||||
return container_of(crtc, struct atmel_hlcdc_crtc, base);
|
||||
}
|
||||
|
||||
static void atmel_hlcdc_crtc_dpms(struct drm_crtc *c, int mode)
|
||||
{
|
||||
struct drm_device *dev = c->dev;
|
||||
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
|
||||
struct regmap *regmap = crtc->dc->hlcdc->regmap;
|
||||
unsigned int status;
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON)
|
||||
mode = DRM_MODE_DPMS_OFF;
|
||||
|
||||
if (crtc->dpms == mode)
|
||||
return;
|
||||
|
||||
pm_runtime_get_sync(dev->dev);
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON) {
|
||||
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
|
||||
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
|
||||
(status & ATMEL_HLCDC_DISP))
|
||||
cpu_relax();
|
||||
|
||||
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
|
||||
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
|
||||
(status & ATMEL_HLCDC_SYNC))
|
||||
cpu_relax();
|
||||
|
||||
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
|
||||
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
|
||||
(status & ATMEL_HLCDC_PIXEL_CLK))
|
||||
cpu_relax();
|
||||
|
||||
clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
|
||||
|
||||
pm_runtime_allow(dev->dev);
|
||||
} else {
|
||||
pm_runtime_forbid(dev->dev);
|
||||
|
||||
clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
|
||||
|
||||
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
|
||||
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
|
||||
!(status & ATMEL_HLCDC_PIXEL_CLK))
|
||||
cpu_relax();
|
||||
|
||||
|
||||
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
|
||||
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
|
||||
!(status & ATMEL_HLCDC_SYNC))
|
||||
cpu_relax();
|
||||
|
||||
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
|
||||
while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
|
||||
!(status & ATMEL_HLCDC_DISP))
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
pm_runtime_put_sync(dev->dev);
|
||||
|
||||
crtc->dpms = mode;
|
||||
}
|
||||
|
||||
static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adj,
|
||||
int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
|
||||
struct regmap *regmap = crtc->dc->hlcdc->regmap;
|
||||
struct drm_plane *plane = c->primary;
|
||||
struct drm_framebuffer *fb;
|
||||
unsigned long mode_rate;
|
||||
struct videomode vm;
|
||||
unsigned long prate;
|
||||
unsigned int cfg;
|
||||
int div;
|
||||
|
||||
if (atmel_hlcdc_dc_mode_valid(crtc->dc, adj) != MODE_OK)
|
||||
return -EINVAL;
|
||||
|
||||
vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay;
|
||||
vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end;
|
||||
vm.vsync_len = adj->crtc_vsync_end - adj->crtc_vsync_start;
|
||||
vm.hfront_porch = adj->crtc_hsync_start - adj->crtc_hdisplay;
|
||||
vm.hback_porch = adj->crtc_htotal - adj->crtc_hsync_end;
|
||||
vm.hsync_len = adj->crtc_hsync_end - adj->crtc_hsync_start;
|
||||
|
||||
regmap_write(regmap, ATMEL_HLCDC_CFG(1),
|
||||
(vm.hsync_len - 1) | ((vm.vsync_len - 1) << 16));
|
||||
|
||||
regmap_write(regmap, ATMEL_HLCDC_CFG(2),
|
||||
(vm.vfront_porch - 1) | (vm.vback_porch << 16));
|
||||
|
||||
regmap_write(regmap, ATMEL_HLCDC_CFG(3),
|
||||
(vm.hfront_porch - 1) | ((vm.hback_porch - 1) << 16));
|
||||
|
||||
regmap_write(regmap, ATMEL_HLCDC_CFG(4),
|
||||
(adj->crtc_hdisplay - 1) |
|
||||
((adj->crtc_vdisplay - 1) << 16));
|
||||
|
||||
cfg = ATMEL_HLCDC_CLKPOL;
|
||||
|
||||
prate = clk_get_rate(crtc->dc->hlcdc->sys_clk);
|
||||
mode_rate = mode->crtc_clock * 1000;
|
||||
if ((prate / 2) < mode_rate) {
|
||||
prate *= 2;
|
||||
cfg |= ATMEL_HLCDC_CLKSEL;
|
||||
}
|
||||
|
||||
div = DIV_ROUND_UP(prate, mode_rate);
|
||||
if (div < 2)
|
||||
div = 2;
|
||||
|
||||
cfg |= ATMEL_HLCDC_CLKDIV(div);
|
||||
|
||||
regmap_update_bits(regmap, ATMEL_HLCDC_CFG(0),
|
||||
ATMEL_HLCDC_CLKSEL | ATMEL_HLCDC_CLKDIV_MASK |
|
||||
ATMEL_HLCDC_CLKPOL, cfg);
|
||||
|
||||
cfg = 0;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
|
||||
cfg |= ATMEL_HLCDC_VSPOL;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
|
||||
cfg |= ATMEL_HLCDC_HSPOL;
|
||||
|
||||
regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5),
|
||||
ATMEL_HLCDC_HSPOL | ATMEL_HLCDC_VSPOL |
|
||||
ATMEL_HLCDC_VSPDLYS | ATMEL_HLCDC_VSPDLYE |
|
||||
ATMEL_HLCDC_DISPPOL | ATMEL_HLCDC_DISPDLY |
|
||||
ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO |
|
||||
ATMEL_HLCDC_GUARDTIME_MASK,
|
||||
cfg);
|
||||
|
||||
fb = plane->fb;
|
||||
plane->fb = old_fb;
|
||||
|
||||
return atmel_hlcdc_plane_update_with_mode(plane, c, fb, 0, 0,
|
||||
adj->hdisplay, adj->vdisplay,
|
||||
x << 16, y << 16,
|
||||
adj->hdisplay << 16,
|
||||
adj->vdisplay << 16,
|
||||
adj);
|
||||
}
|
||||
|
||||
int atmel_hlcdc_crtc_mode_set_base(struct drm_crtc *c, int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
struct drm_plane *plane = c->primary;
|
||||
struct drm_framebuffer *fb = plane->fb;
|
||||
struct drm_display_mode *mode = &c->hwmode;
|
||||
|
||||
plane->fb = old_fb;
|
||||
|
||||
return plane->funcs->update_plane(plane, c, fb,
|
||||
0, 0,
|
||||
mode->hdisplay,
|
||||
mode->vdisplay,
|
||||
x << 16, y << 16,
|
||||
mode->hdisplay << 16,
|
||||
mode->vdisplay << 16);
|
||||
}
|
||||
|
||||
static void atmel_hlcdc_crtc_prepare(struct drm_crtc *crtc)
|
||||
{
|
||||
atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
|
||||
static void atmel_hlcdc_crtc_commit(struct drm_crtc *crtc)
|
||||
{
|
||||
atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
|
||||
}
|
||||
|
||||
static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void atmel_hlcdc_crtc_disable(struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_plane *plane;
|
||||
|
||||
atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
|
||||
crtc->primary->funcs->disable_plane(crtc->primary);
|
||||
|
||||
drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) {
|
||||
if (plane->crtc != crtc)
|
||||
continue;
|
||||
|
||||
plane->funcs->disable_plane(crtc->primary);
|
||||
plane->crtc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
|
||||
.mode_fixup = atmel_hlcdc_crtc_mode_fixup,
|
||||
.dpms = atmel_hlcdc_crtc_dpms,
|
||||
.mode_set = atmel_hlcdc_crtc_mode_set,
|
||||
.mode_set_base = atmel_hlcdc_crtc_mode_set_base,
|
||||
.prepare = atmel_hlcdc_crtc_prepare,
|
||||
.commit = atmel_hlcdc_crtc_commit,
|
||||
.disable = atmel_hlcdc_crtc_disable,
|
||||
};
|
||||
|
||||
static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c)
|
||||
{
|
||||
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
|
||||
|
||||
drm_crtc_cleanup(c);
|
||||
kfree(crtc);
|
||||
}
|
||||
|
||||
void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *c,
|
||||
struct drm_file *file)
|
||||
{
|
||||
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
|
||||
struct drm_pending_vblank_event *event;
|
||||
struct drm_device *dev = c->dev;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
event = crtc->event;
|
||||
if (event && event->base.file_priv == file) {
|
||||
event->base.destroy(&event->base);
|
||||
drm_vblank_put(dev, crtc->id);
|
||||
crtc->event = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
}
|
||||
|
||||
static void atmel_hlcdc_crtc_finish_page_flip(struct atmel_hlcdc_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev = crtc->base.dev;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
if (crtc->event) {
|
||||
drm_send_vblank_event(dev, crtc->id, crtc->event);
|
||||
drm_vblank_put(dev, crtc->id);
|
||||
crtc->event = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
}
|
||||
|
||||
void atmel_hlcdc_crtc_irq(struct drm_crtc *c)
|
||||
{
|
||||
drm_handle_vblank(c->dev, 0);
|
||||
atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c));
|
||||
}
|
||||
|
||||
static int atmel_hlcdc_crtc_page_flip(struct drm_crtc *c,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event,
|
||||
uint32_t page_flip_flags)
|
||||
{
|
||||
struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
|
||||
struct atmel_hlcdc_plane_update_req req;
|
||||
struct drm_plane *plane = c->primary;
|
||||
struct drm_device *dev = c->dev;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
if (crtc->event)
|
||||
ret = -EBUSY;
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.crtc_x = 0;
|
||||
req.crtc_y = 0;
|
||||
req.crtc_h = c->mode.crtc_vdisplay;
|
||||
req.crtc_w = c->mode.crtc_hdisplay;
|
||||
req.src_x = c->x << 16;
|
||||
req.src_y = c->y << 16;
|
||||
req.src_w = req.crtc_w << 16;
|
||||
req.src_h = req.crtc_h << 16;
|
||||
req.fb = fb;
|
||||
|
||||
ret = atmel_hlcdc_plane_prepare_update_req(plane, &req, &c->hwmode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (event) {
|
||||
drm_vblank_get(c->dev, crtc->id);
|
||||
spin_lock_irqsave(&dev->event_lock, flags);
|
||||
crtc->event = event;
|
||||
spin_unlock_irqrestore(&dev->event_lock, flags);
|
||||
}
|
||||
|
||||
ret = atmel_hlcdc_plane_apply_update_req(plane, &req);
|
||||
if (ret)
|
||||
crtc->event = NULL;
|
||||
else
|
||||
plane->fb = fb;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
|
||||
.page_flip = atmel_hlcdc_crtc_page_flip,
|
||||
.set_config = drm_crtc_helper_set_config,
|
||||
.destroy = atmel_hlcdc_crtc_destroy,
|
||||
};
|
||||
|
||||
int atmel_hlcdc_crtc_create(struct drm_device *dev)
|
||||
{
|
||||
struct atmel_hlcdc_dc *dc = dev->dev_private;
|
||||
struct atmel_hlcdc_planes *planes = dc->planes;
|
||||
struct atmel_hlcdc_crtc *crtc;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
|
||||
if (!crtc)
|
||||
return -ENOMEM;
|
||||
|
||||
crtc->dpms = DRM_MODE_DPMS_OFF;
|
||||
crtc->dc = dc;
|
||||
|
||||
ret = drm_crtc_init_with_planes(dev, &crtc->base,
|
||||
&planes->primary->base,
|
||||
planes->cursor ? &planes->cursor->base : NULL,
|
||||
&atmel_hlcdc_crtc_funcs);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
crtc->id = drm_crtc_index(&crtc->base);
|
||||
|
||||
if (planes->cursor)
|
||||
planes->cursor->base.possible_crtcs = 1 << crtc->id;
|
||||
|
||||
for (i = 0; i < planes->noverlays; i++)
|
||||
planes->overlays[i]->base.possible_crtcs = 1 << crtc->id;
|
||||
|
||||
drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
|
||||
|
||||
dc->crtc = &crtc->base;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
atmel_hlcdc_crtc_destroy(&crtc->base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Traphandler
|
||||
* Copyright (C) 2014 Free Electrons
|
||||
* Copyright (C) 2014 Atmel
|
||||
*
|
||||
* Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
|
||||
* Author: Boris BREZILLON <boris.brezillon@free-electrons.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 DRM_ATMEL_HLCDC_H
|
||||
#define DRM_ATMEL_HLCDC_H
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/pwm.h>
|
||||
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_crtc_helper.h>
|
||||
#include <drm/drm_fb_cma_helper.h>
|
||||
#include <drm/drm_gem_cma_helper.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drmP.h>
|
||||
|
||||
#include "atmel_hlcdc_layer.h"
|
||||
|
||||
#define ATMEL_HLCDC_MAX_LAYERS 5
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Display Controller description structure.
|
||||
*
|
||||
* This structure describe the HLCDC IP capabilities and depends on the
|
||||
* HLCDC IP version (or Atmel SoC family).
|
||||
*
|
||||
* @min_width: minimum width supported by the Display Controller
|
||||
* @min_height: minimum height supported by the Display Controller
|
||||
* @max_width: maximum width supported by the Display Controller
|
||||
* @max_height: maximum height supported by the Display Controller
|
||||
* @layers: a layer description table describing available layers
|
||||
* @nlayers: layer description table size
|
||||
*/
|
||||
struct atmel_hlcdc_dc_desc {
|
||||
int min_width;
|
||||
int min_height;
|
||||
int max_width;
|
||||
int max_height;
|
||||
const struct atmel_hlcdc_layer_desc *layers;
|
||||
int nlayers;
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Plane properties.
|
||||
*
|
||||
* This structure stores plane property definitions.
|
||||
*
|
||||
* @alpha: alpha blending (or transparency) property
|
||||
* @rotation: rotation property
|
||||
*/
|
||||
struct atmel_hlcdc_plane_properties {
|
||||
struct drm_property *alpha;
|
||||
struct drm_property *rotation;
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Plane.
|
||||
*
|
||||
* @base: base DRM plane structure
|
||||
* @layer: HLCDC layer structure
|
||||
* @properties: pointer to the property definitions structure
|
||||
* @rotation: current rotation status
|
||||
*/
|
||||
struct atmel_hlcdc_plane {
|
||||
struct drm_plane base;
|
||||
struct atmel_hlcdc_layer layer;
|
||||
struct atmel_hlcdc_plane_properties *properties;
|
||||
unsigned int rotation;
|
||||
};
|
||||
|
||||
static inline struct atmel_hlcdc_plane *
|
||||
drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
|
||||
{
|
||||
return container_of(p, struct atmel_hlcdc_plane, base);
|
||||
}
|
||||
|
||||
static inline struct atmel_hlcdc_plane *
|
||||
atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
|
||||
{
|
||||
return container_of(l, struct atmel_hlcdc_plane, layer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Plane update request structure.
|
||||
*
|
||||
* @crtc_x: x position of the plane relative to the CRTC
|
||||
* @crtc_y: y position of the plane relative to the CRTC
|
||||
* @crtc_w: visible width of the plane
|
||||
* @crtc_h: visible height of the plane
|
||||
* @src_x: x buffer position
|
||||
* @src_y: y buffer position
|
||||
* @src_w: buffer width
|
||||
* @src_h: buffer height
|
||||
* @fb: framebuffer object object
|
||||
* @bpp: bytes per pixel deduced from pixel_format
|
||||
* @offsets: offsets to apply to the GEM buffers
|
||||
* @xstride: value to add to the pixel pointer between each line
|
||||
* @pstride: value to add to the pixel pointer between each pixel
|
||||
* @nplanes: number of planes (deduced from pixel_format)
|
||||
*/
|
||||
struct atmel_hlcdc_plane_update_req {
|
||||
int crtc_x;
|
||||
int crtc_y;
|
||||
unsigned int crtc_w;
|
||||
unsigned int crtc_h;
|
||||
uint32_t src_x;
|
||||
uint32_t src_y;
|
||||
uint32_t src_w;
|
||||
uint32_t src_h;
|
||||
struct drm_framebuffer *fb;
|
||||
|
||||
/* These fields are private and should not be touched */
|
||||
int bpp[ATMEL_HLCDC_MAX_PLANES];
|
||||
unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
|
||||
int xstride[ATMEL_HLCDC_MAX_PLANES];
|
||||
int pstride[ATMEL_HLCDC_MAX_PLANES];
|
||||
int nplanes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Planes.
|
||||
*
|
||||
* This structure stores the instantiated HLCDC Planes and can be accessed by
|
||||
* the HLCDC Display Controller or the HLCDC CRTC.
|
||||
*
|
||||
* @primary: primary plane
|
||||
* @cursor: hardware cursor plane
|
||||
* @overlays: overlay plane table
|
||||
* @noverlays: number of overlay planes
|
||||
*/
|
||||
struct atmel_hlcdc_planes {
|
||||
struct atmel_hlcdc_plane *primary;
|
||||
struct atmel_hlcdc_plane *cursor;
|
||||
struct atmel_hlcdc_plane **overlays;
|
||||
int noverlays;
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Display Controller.
|
||||
*
|
||||
* @desc: HLCDC Display Controller description
|
||||
* @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
|
||||
* @fbdev: framebuffer device attached to the Display Controller
|
||||
* @crtc: CRTC provided by the display controller
|
||||
* @planes: instantiated planes
|
||||
* @layers: active HLCDC layer
|
||||
* @wq: display controller workqueue
|
||||
*/
|
||||
struct atmel_hlcdc_dc {
|
||||
const struct atmel_hlcdc_dc_desc *desc;
|
||||
struct atmel_hlcdc *hlcdc;
|
||||
struct drm_fbdev_cma *fbdev;
|
||||
struct drm_crtc *crtc;
|
||||
struct atmel_hlcdc_planes *planes;
|
||||
struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
|
||||
struct workqueue_struct *wq;
|
||||
};
|
||||
|
||||
extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats;
|
||||
extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats;
|
||||
|
||||
int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
|
||||
struct drm_display_mode *mode);
|
||||
|
||||
struct atmel_hlcdc_planes *
|
||||
atmel_hlcdc_create_planes(struct drm_device *dev);
|
||||
|
||||
int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
|
||||
struct atmel_hlcdc_plane_update_req *req,
|
||||
const struct drm_display_mode *mode);
|
||||
|
||||
int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
|
||||
struct atmel_hlcdc_plane_update_req *req);
|
||||
|
||||
int atmel_hlcdc_plane_update_with_mode(struct drm_plane *p,
|
||||
struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
int crtc_x, int crtc_y,
|
||||
unsigned int crtc_w,
|
||||
unsigned int crtc_h,
|
||||
uint32_t src_x, uint32_t src_y,
|
||||
uint32_t src_w, uint32_t src_h,
|
||||
const struct drm_display_mode *mode);
|
||||
|
||||
void atmel_hlcdc_crtc_irq(struct drm_crtc *c);
|
||||
|
||||
void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *crtc,
|
||||
struct drm_file *file);
|
||||
|
||||
int atmel_hlcdc_crtc_create(struct drm_device *dev);
|
||||
|
||||
int atmel_hlcdc_create_outputs(struct drm_device *dev);
|
||||
|
||||
#endif /* DRM_ATMEL_HLCDC_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,398 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Free Electrons
|
||||
* Copyright (C) 2014 Atmel
|
||||
*
|
||||
* Author: Boris BREZILLON <boris.brezillon@free-electrons.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 DRM_ATMEL_HLCDC_LAYER_H
|
||||
#define DRM_ATMEL_HLCDC_LAYER_H
|
||||
|
||||
#include <linux/mfd/atmel-hlcdc.h>
|
||||
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_flip_work.h>
|
||||
#include <drm/drmP.h>
|
||||
|
||||
#define ATMEL_HLCDC_LAYER_CHER 0x0
|
||||
#define ATMEL_HLCDC_LAYER_CHDR 0x4
|
||||
#define ATMEL_HLCDC_LAYER_CHSR 0x8
|
||||
#define ATMEL_HLCDC_LAYER_DMA_CHAN BIT(0)
|
||||
#define ATMEL_HLCDC_LAYER_UPDATE BIT(1)
|
||||
#define ATMEL_HLCDC_LAYER_A2Q BIT(2)
|
||||
#define ATMEL_HLCDC_LAYER_RST BIT(8)
|
||||
|
||||
#define ATMEL_HLCDC_LAYER_IER 0xc
|
||||
#define ATMEL_HLCDC_LAYER_IDR 0x10
|
||||
#define ATMEL_HLCDC_LAYER_IMR 0x14
|
||||
#define ATMEL_HLCDC_LAYER_ISR 0x18
|
||||
#define ATMEL_HLCDC_LAYER_DFETCH BIT(0)
|
||||
#define ATMEL_HLCDC_LAYER_LFETCH BIT(1)
|
||||
#define ATMEL_HLCDC_LAYER_DMA_IRQ BIT(2)
|
||||
#define ATMEL_HLCDC_LAYER_DSCR_IRQ BIT(3)
|
||||
#define ATMEL_HLCDC_LAYER_ADD_IRQ BIT(4)
|
||||
#define ATMEL_HLCDC_LAYER_DONE_IRQ BIT(5)
|
||||
#define ATMEL_HLCDC_LAYER_OVR_IRQ BIT(6)
|
||||
|
||||
#define ATMEL_HLCDC_LAYER_PLANE_HEAD(n) (((n) * 0x10) + 0x1c)
|
||||
#define ATMEL_HLCDC_LAYER_PLANE_ADDR(n) (((n) * 0x10) + 0x20)
|
||||
#define ATMEL_HLCDC_LAYER_PLANE_CTRL(n) (((n) * 0x10) + 0x24)
|
||||
#define ATMEL_HLCDC_LAYER_PLANE_NEXT(n) (((n) * 0x10) + 0x28)
|
||||
#define ATMEL_HLCDC_LAYER_CFG(p, c) (((c) * 4) + ((p)->max_planes * 0x10) + 0x1c)
|
||||
|
||||
#define ATMEL_HLCDC_LAYER_DMA_CFG_ID 0
|
||||
#define ATMEL_HLCDC_LAYER_DMA_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, ATMEL_HLCDC_LAYER_DMA_CFG_ID)
|
||||
#define ATMEL_HLCDC_LAYER_DMA_SIF BIT(0)
|
||||
#define ATMEL_HLCDC_LAYER_DMA_BLEN_MASK GENMASK(5, 4)
|
||||
#define ATMEL_HLCDC_LAYER_DMA_BLEN_SINGLE (0 << 4)
|
||||
#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR4 (1 << 4)
|
||||
#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR8 (2 << 4)
|
||||
#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 (3 << 4)
|
||||
#define ATMEL_HLCDC_LAYER_DMA_DLBO BIT(8)
|
||||
#define ATMEL_HLCDC_LAYER_DMA_ROTDIS BIT(12)
|
||||
#define ATMEL_HLCDC_LAYER_DMA_LOCKDIS BIT(13)
|
||||
|
||||
#define ATMEL_HLCDC_LAYER_FORMAT_CFG_ID 1
|
||||
#define ATMEL_HLCDC_LAYER_FORMAT_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, ATMEL_HLCDC_LAYER_FORMAT_CFG_ID)
|
||||
#define ATMEL_HLCDC_LAYER_RGB (0 << 0)
|
||||
#define ATMEL_HLCDC_LAYER_CLUT (1 << 0)
|
||||
#define ATMEL_HLCDC_LAYER_YUV (2 << 0)
|
||||
#define ATMEL_HLCDC_RGB_MODE(m) (((m) & 0xf) << 4)
|
||||
#define ATMEL_HLCDC_CLUT_MODE(m) (((m) & 0x3) << 8)
|
||||
#define ATMEL_HLCDC_YUV_MODE(m) (((m) & 0xf) << 12)
|
||||
#define ATMEL_HLCDC_YUV422ROT BIT(16)
|
||||
#define ATMEL_HLCDC_YUV422SWP BIT(17)
|
||||
#define ATMEL_HLCDC_DSCALEOPT BIT(20)
|
||||
|
||||
#define ATMEL_HLCDC_XRGB4444_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(0))
|
||||
#define ATMEL_HLCDC_ARGB4444_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(1))
|
||||
#define ATMEL_HLCDC_RGBA4444_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(2))
|
||||
#define ATMEL_HLCDC_RGB565_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(3))
|
||||
#define ATMEL_HLCDC_ARGB1555_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(4))
|
||||
#define ATMEL_HLCDC_XRGB8888_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(9))
|
||||
#define ATMEL_HLCDC_RGB888_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(10))
|
||||
#define ATMEL_HLCDC_ARGB8888_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(12))
|
||||
#define ATMEL_HLCDC_RGBA8888_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(13))
|
||||
|
||||
#define ATMEL_HLCDC_AYUV_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(0))
|
||||
#define ATMEL_HLCDC_YUYV_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(1))
|
||||
#define ATMEL_HLCDC_UYVY_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(2))
|
||||
#define ATMEL_HLCDC_YVYU_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(3))
|
||||
#define ATMEL_HLCDC_VYUY_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(4))
|
||||
#define ATMEL_HLCDC_NV61_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(5))
|
||||
#define ATMEL_HLCDC_YUV422_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(6))
|
||||
#define ATMEL_HLCDC_NV21_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(7))
|
||||
#define ATMEL_HLCDC_YUV420_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(8))
|
||||
|
||||
#define ATMEL_HLCDC_LAYER_POS_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.pos)
|
||||
#define ATMEL_HLCDC_LAYER_SIZE_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.size)
|
||||
#define ATMEL_HLCDC_LAYER_MEMSIZE_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.memsize)
|
||||
#define ATMEL_HLCDC_LAYER_XSTRIDE_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.xstride)
|
||||
#define ATMEL_HLCDC_LAYER_PSTRIDE_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.pstride)
|
||||
#define ATMEL_HLCDC_LAYER_DFLTCOLOR_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.default_color)
|
||||
#define ATMEL_HLCDC_LAYER_CRKEY_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.chroma_key)
|
||||
#define ATMEL_HLCDC_LAYER_CRKEY_MASK_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.chroma_key_mask)
|
||||
|
||||
#define ATMEL_HLCDC_LAYER_GENERAL_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.general_config)
|
||||
#define ATMEL_HLCDC_LAYER_CRKEY BIT(0)
|
||||
#define ATMEL_HLCDC_LAYER_INV BIT(1)
|
||||
#define ATMEL_HLCDC_LAYER_ITER2BL BIT(2)
|
||||
#define ATMEL_HLCDC_LAYER_ITER BIT(3)
|
||||
#define ATMEL_HLCDC_LAYER_REVALPHA BIT(4)
|
||||
#define ATMEL_HLCDC_LAYER_GAEN BIT(5)
|
||||
#define ATMEL_HLCDC_LAYER_LAEN BIT(6)
|
||||
#define ATMEL_HLCDC_LAYER_OVR BIT(7)
|
||||
#define ATMEL_HLCDC_LAYER_DMA BIT(8)
|
||||
#define ATMEL_HLCDC_LAYER_REP BIT(9)
|
||||
#define ATMEL_HLCDC_LAYER_DSTKEY BIT(10)
|
||||
#define ATMEL_HLCDC_LAYER_DISCEN BIT(11)
|
||||
#define ATMEL_HLCDC_LAYER_GA_SHIFT 16
|
||||
#define ATMEL_HLCDC_LAYER_GA_MASK GENMASK(23, ATMEL_HLCDC_LAYER_GA_SHIFT)
|
||||
|
||||
#define ATMEL_HLCDC_LAYER_CSC_CFG(p, o) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.csc + o)
|
||||
|
||||
#define ATMEL_HLCDC_LAYER_DISC_POS_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.disc_pos)
|
||||
|
||||
#define ATMEL_HLCDC_LAYER_DISC_SIZE_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.disc_size)
|
||||
|
||||
#define ATMEL_HLCDC_MAX_PLANES 3
|
||||
|
||||
#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_RESERVED BIT(0)
|
||||
#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED BIT(1)
|
||||
#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE BIT(2)
|
||||
#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN BIT(3)
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Layer registers layout structure
|
||||
*
|
||||
* Each HLCDC layer has its own register organization and a given register
|
||||
* can be placed differently on 2 different layers depending on its
|
||||
* capabilities.
|
||||
* This structure stores common registers layout for a given layer and is
|
||||
* used by HLCDC layer code to choose the appropriate register to write to
|
||||
* or to read from.
|
||||
*
|
||||
* For all fields, a value of zero means "unsupported".
|
||||
*
|
||||
* See Atmel's datasheet for a detailled description of these registers.
|
||||
*
|
||||
* @xstride: xstride registers
|
||||
* @pstride: pstride registers
|
||||
* @pos: position register
|
||||
* @size: displayed size register
|
||||
* @memsize: memory size register
|
||||
* @default_color: default color register
|
||||
* @chroma_key: chroma key register
|
||||
* @chroma_key_mask: chroma key mask register
|
||||
* @general_config: general layer config register
|
||||
* @disc_pos: discard area position register
|
||||
* @disc_size: discard area size register
|
||||
* @csc: color space conversion register
|
||||
*/
|
||||
struct atmel_hlcdc_layer_cfg_layout {
|
||||
int xstride[ATMEL_HLCDC_MAX_PLANES];
|
||||
int pstride[ATMEL_HLCDC_MAX_PLANES];
|
||||
int pos;
|
||||
int size;
|
||||
int memsize;
|
||||
int default_color;
|
||||
int chroma_key;
|
||||
int chroma_key_mask;
|
||||
int general_config;
|
||||
int disc_pos;
|
||||
int disc_size;
|
||||
int csc;
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC framebuffer flip structure
|
||||
*
|
||||
* This structure is allocated when someone asked for a layer update (most
|
||||
* likely a DRM plane update, either primary, overlay or cursor plane) and
|
||||
* released when the layer do not need to reference the framebuffer object
|
||||
* anymore (i.e. the layer was disabled or updated).
|
||||
*
|
||||
* @dscrs: DMA descriptors
|
||||
* @fb: the referenced framebuffer object
|
||||
* @ngems: number of GEM objects referenced by the fb element
|
||||
* @status: fb flip operation status
|
||||
*/
|
||||
struct atmel_hlcdc_layer_fb_flip {
|
||||
struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_MAX_PLANES];
|
||||
struct drm_flip_task *task;
|
||||
struct drm_framebuffer *fb;
|
||||
int ngems;
|
||||
u32 status;
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC DMA descriptor structure
|
||||
*
|
||||
* This structure is used by the HLCDC DMA engine to schedule a DMA transfer.
|
||||
*
|
||||
* The structure fields must remain in this specific order, because they're
|
||||
* used by the HLCDC DMA engine, which expect them in this order.
|
||||
* HLCDC DMA descriptors must be aligned on 64 bits.
|
||||
*
|
||||
* @addr: buffer DMA address
|
||||
* @ctrl: DMA transfer options
|
||||
* @next: next DMA descriptor to fetch
|
||||
* @gem_flip: the attached gem_flip operation
|
||||
*/
|
||||
struct atmel_hlcdc_dma_channel_dscr {
|
||||
dma_addr_t addr;
|
||||
u32 ctrl;
|
||||
dma_addr_t next;
|
||||
u32 status;
|
||||
} __aligned(sizeof(u64));
|
||||
|
||||
/**
|
||||
* Atmel HLCDC layer types
|
||||
*/
|
||||
enum atmel_hlcdc_layer_type {
|
||||
ATMEL_HLCDC_BASE_LAYER,
|
||||
ATMEL_HLCDC_OVERLAY_LAYER,
|
||||
ATMEL_HLCDC_CURSOR_LAYER,
|
||||
ATMEL_HLCDC_PP_LAYER,
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Supported formats structure
|
||||
*
|
||||
* This structure list all the formats supported by a given layer.
|
||||
*
|
||||
* @nformats: number of supported formats
|
||||
* @formats: supported formats
|
||||
*/
|
||||
struct atmel_hlcdc_formats {
|
||||
int nformats;
|
||||
uint32_t *formats;
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Layer description structure
|
||||
*
|
||||
* This structure describe the capabilities provided by a given layer.
|
||||
*
|
||||
* @name: layer name
|
||||
* @type: layer type
|
||||
* @id: layer id
|
||||
* @regs_offset: offset of the layer registers from the HLCDC registers base
|
||||
* @nconfigs: number of config registers provided by this layer
|
||||
* @formats: supported formats
|
||||
* @layout: config registers layout
|
||||
* @max_width: maximum width supported by this layer (0 means unlimited)
|
||||
* @max_height: maximum height supported by this layer (0 means unlimited)
|
||||
*/
|
||||
struct atmel_hlcdc_layer_desc {
|
||||
const char *name;
|
||||
enum atmel_hlcdc_layer_type type;
|
||||
int id;
|
||||
int regs_offset;
|
||||
int nconfigs;
|
||||
struct atmel_hlcdc_formats *formats;
|
||||
struct atmel_hlcdc_layer_cfg_layout layout;
|
||||
int max_width;
|
||||
int max_height;
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Layer Update Slot structure
|
||||
*
|
||||
* This structure stores layer update requests to be applied on next frame.
|
||||
* This is the base structure behind the atomic layer update infrastructure.
|
||||
*
|
||||
* Atomic layer update provides a way to update all layer's parameters
|
||||
* simultaneously. This is needed to avoid incompatible sequential updates
|
||||
* like this one:
|
||||
* 1) update layer format from RGB888 (1 plane/buffer) to YUV422
|
||||
* (2 planes/buffers)
|
||||
* 2) the format update is applied but the DMA channel for the second
|
||||
* plane/buffer is not enabled
|
||||
* 3) enable the DMA channel for the second plane
|
||||
*
|
||||
* @fb_flip: fb_flip object
|
||||
* @updated_configs: bitmask used to record modified configs
|
||||
* @configs: new config values
|
||||
*/
|
||||
struct atmel_hlcdc_layer_update_slot {
|
||||
struct atmel_hlcdc_layer_fb_flip *fb_flip;
|
||||
unsigned long *updated_configs;
|
||||
u32 *configs;
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Layer Update structure
|
||||
*
|
||||
* This structure provides a way to queue layer update requests.
|
||||
*
|
||||
* At a given time there is at most:
|
||||
* - one pending update request, which means the update request has been
|
||||
* committed (or validated) and is waiting for the DMA channel(s) to be
|
||||
* available
|
||||
* - one request being prepared, which means someone started a layer update
|
||||
* but has not committed it yet. There cannot be more than one started
|
||||
* request, because the update lock is taken when starting a layer update
|
||||
* and release when committing or rolling back the request.
|
||||
*
|
||||
* @slots: update slots. One is used for pending request and the other one
|
||||
* for started update request
|
||||
* @pending: the pending slot index or -1 if no request is pending
|
||||
* @next: the started update slot index or -1 no update has been started
|
||||
*/
|
||||
struct atmel_hlcdc_layer_update {
|
||||
struct atmel_hlcdc_layer_update_slot slots[2];
|
||||
int pending;
|
||||
int next;
|
||||
};
|
||||
|
||||
enum atmel_hlcdc_layer_dma_channel_status {
|
||||
ATMEL_HLCDC_LAYER_DISABLED,
|
||||
ATMEL_HLCDC_LAYER_ENABLED,
|
||||
ATMEL_HLCDC_LAYER_DISABLING,
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Layer DMA channel structure
|
||||
*
|
||||
* This structure stores information on the DMA channel associated to a
|
||||
* given layer.
|
||||
*
|
||||
* @status: DMA channel status
|
||||
* @cur: current framebuffer
|
||||
* @queue: next framebuffer
|
||||
* @dscrs: allocated DMA descriptors
|
||||
*/
|
||||
struct atmel_hlcdc_layer_dma_channel {
|
||||
enum atmel_hlcdc_layer_dma_channel_status status;
|
||||
struct atmel_hlcdc_layer_fb_flip *cur;
|
||||
struct atmel_hlcdc_layer_fb_flip *queue;
|
||||
struct atmel_hlcdc_dma_channel_dscr *dscrs;
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Layer structure
|
||||
*
|
||||
* This structure stores information on the layer instance.
|
||||
*
|
||||
* @desc: layer description
|
||||
* @max_planes: maximum planes/buffers that can be associated with this layer.
|
||||
* This depends on the supported formats.
|
||||
* @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
|
||||
* @dma: dma channel
|
||||
* @gc: fb flip garbage collector
|
||||
* @update: update handler
|
||||
* @lock: layer lock
|
||||
*/
|
||||
struct atmel_hlcdc_layer {
|
||||
const struct atmel_hlcdc_layer_desc *desc;
|
||||
int max_planes;
|
||||
struct atmel_hlcdc *hlcdc;
|
||||
struct workqueue_struct *wq;
|
||||
struct drm_flip_work gc;
|
||||
struct atmel_hlcdc_layer_dma_channel dma;
|
||||
struct atmel_hlcdc_layer_update update;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer);
|
||||
|
||||
int atmel_hlcdc_layer_init(struct drm_device *dev,
|
||||
struct atmel_hlcdc_layer *layer,
|
||||
const struct atmel_hlcdc_layer_desc *desc);
|
||||
|
||||
void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
|
||||
struct atmel_hlcdc_layer *layer);
|
||||
|
||||
int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer);
|
||||
|
||||
int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer);
|
||||
|
||||
void atmel_hlcdc_layer_update_cfg(struct atmel_hlcdc_layer *layer, int cfg,
|
||||
u32 mask, u32 val);
|
||||
|
||||
void atmel_hlcdc_layer_update_set_fb(struct atmel_hlcdc_layer *layer,
|
||||
struct drm_framebuffer *fb,
|
||||
unsigned int *offsets);
|
||||
|
||||
void atmel_hlcdc_layer_update_set_finished(struct atmel_hlcdc_layer *layer,
|
||||
void (*finished)(void *data),
|
||||
void *finished_data);
|
||||
|
||||
void atmel_hlcdc_layer_update_rollback(struct atmel_hlcdc_layer *layer);
|
||||
|
||||
void atmel_hlcdc_layer_update_commit(struct atmel_hlcdc_layer *layer);
|
||||
|
||||
#endif /* DRM_ATMEL_HLCDC_LAYER_H */
|
||||
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Traphandler
|
||||
* Copyright (C) 2014 Free Electrons
|
||||
* Copyright (C) 2014 Atmel
|
||||
*
|
||||
* Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
|
||||
* Author: Boris BREZILLON <boris.brezillon@free-electrons.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/of_graph.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include "atmel_hlcdc_dc.h"
|
||||
|
||||
/**
|
||||
* Atmel HLCDC RGB output mode
|
||||
*/
|
||||
enum atmel_hlcdc_connector_rgb_mode {
|
||||
ATMEL_HLCDC_CONNECTOR_RGB444,
|
||||
ATMEL_HLCDC_CONNECTOR_RGB565,
|
||||
ATMEL_HLCDC_CONNECTOR_RGB666,
|
||||
ATMEL_HLCDC_CONNECTOR_RGB888,
|
||||
};
|
||||
|
||||
/**
|
||||
* Atmel HLCDC RGB connector structure
|
||||
*
|
||||
* This structure stores RGB slave device information.
|
||||
*
|
||||
* @connector: DRM connector
|
||||
* @encoder: DRM encoder
|
||||
* @dc: pointer to the atmel_hlcdc_dc structure
|
||||
* @dpms: current DPMS mode
|
||||
*/
|
||||
struct atmel_hlcdc_rgb_output {
|
||||
struct drm_connector connector;
|
||||
struct drm_encoder encoder;
|
||||
struct atmel_hlcdc_dc *dc;
|
||||
int dpms;
|
||||
};
|
||||
|
||||
static inline struct atmel_hlcdc_rgb_output *
|
||||
drm_connector_to_atmel_hlcdc_rgb_output(struct drm_connector *connector)
|
||||
{
|
||||
return container_of(connector, struct atmel_hlcdc_rgb_output,
|
||||
connector);
|
||||
}
|
||||
|
||||
static inline struct atmel_hlcdc_rgb_output *
|
||||
drm_encoder_to_atmel_hlcdc_rgb_output(struct drm_encoder *encoder)
|
||||
{
|
||||
return container_of(encoder, struct atmel_hlcdc_rgb_output, encoder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Atmel HLCDC Panel device structure
|
||||
*
|
||||
* This structure is specialization of the slave device structure to
|
||||
* interface with drm panels.
|
||||
*
|
||||
* @base: base slave device fields
|
||||
* @panel: drm panel attached to this slave device
|
||||
*/
|
||||
struct atmel_hlcdc_panel {
|
||||
struct atmel_hlcdc_rgb_output base;
|
||||
struct drm_panel *panel;
|
||||
};
|
||||
|
||||
static inline struct atmel_hlcdc_panel *
|
||||
atmel_hlcdc_rgb_output_to_panel(struct atmel_hlcdc_rgb_output *output)
|
||||
{
|
||||
return container_of(output, struct atmel_hlcdc_panel, base);
|
||||
}
|
||||
|
||||
static void atmel_hlcdc_panel_encoder_dpms(struct drm_encoder *encoder,
|
||||
int mode)
|
||||
{
|
||||
struct atmel_hlcdc_rgb_output *rgb =
|
||||
drm_encoder_to_atmel_hlcdc_rgb_output(encoder);
|
||||
struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb);
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON)
|
||||
mode = DRM_MODE_DPMS_OFF;
|
||||
|
||||
if (mode == rgb->dpms)
|
||||
return;
|
||||
|
||||
if (mode != DRM_MODE_DPMS_ON)
|
||||
drm_panel_disable(panel->panel);
|
||||
else
|
||||
drm_panel_enable(panel->panel);
|
||||
|
||||
rgb->dpms = mode;
|
||||
}
|
||||
|
||||
static bool
|
||||
atmel_hlcdc_panel_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void atmel_hlcdc_panel_encoder_prepare(struct drm_encoder *encoder)
|
||||
{
|
||||
atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
|
||||
static void atmel_hlcdc_panel_encoder_commit(struct drm_encoder *encoder)
|
||||
{
|
||||
atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
|
||||
}
|
||||
|
||||
static void
|
||||
atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted)
|
||||
{
|
||||
struct atmel_hlcdc_rgb_output *rgb =
|
||||
drm_encoder_to_atmel_hlcdc_rgb_output(encoder);
|
||||
struct drm_display_info *info = &rgb->connector.display_info;
|
||||
unsigned int cfg;
|
||||
|
||||
cfg = 0;
|
||||
|
||||
if (info->num_bus_formats) {
|
||||
switch (info->bus_formats[0]) {
|
||||
case MEDIA_BUS_FMT_RGB666_1X18:
|
||||
cfg |= ATMEL_HLCDC_CONNECTOR_RGB666 << 8;
|
||||
break;
|
||||
case MEDIA_BUS_FMT_RGB888_1X24:
|
||||
cfg |= ATMEL_HLCDC_CONNECTOR_RGB888 << 8;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
regmap_update_bits(rgb->dc->hlcdc->regmap, ATMEL_HLCDC_CFG(5),
|
||||
ATMEL_HLCDC_MODE_MASK,
|
||||
cfg);
|
||||
}
|
||||
|
||||
static struct drm_encoder_helper_funcs atmel_hlcdc_panel_encoder_helper_funcs = {
|
||||
.dpms = atmel_hlcdc_panel_encoder_dpms,
|
||||
.mode_fixup = atmel_hlcdc_panel_encoder_mode_fixup,
|
||||
.prepare = atmel_hlcdc_panel_encoder_prepare,
|
||||
.commit = atmel_hlcdc_panel_encoder_commit,
|
||||
.mode_set = atmel_hlcdc_rgb_encoder_mode_set,
|
||||
};
|
||||
|
||||
static void atmel_hlcdc_rgb_encoder_destroy(struct drm_encoder *encoder)
|
||||
{
|
||||
drm_encoder_cleanup(encoder);
|
||||
memset(encoder, 0, sizeof(*encoder));
|
||||
}
|
||||
|
||||
static const struct drm_encoder_funcs atmel_hlcdc_panel_encoder_funcs = {
|
||||
.destroy = atmel_hlcdc_rgb_encoder_destroy,
|
||||
};
|
||||
|
||||
static int atmel_hlcdc_panel_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct atmel_hlcdc_rgb_output *rgb =
|
||||
drm_connector_to_atmel_hlcdc_rgb_output(connector);
|
||||
struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb);
|
||||
|
||||
return panel->panel->funcs->get_modes(panel->panel);
|
||||
}
|
||||
|
||||
static int atmel_hlcdc_rgb_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct atmel_hlcdc_rgb_output *rgb =
|
||||
drm_connector_to_atmel_hlcdc_rgb_output(connector);
|
||||
|
||||
return atmel_hlcdc_dc_mode_valid(rgb->dc, mode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct drm_encoder *
|
||||
atmel_hlcdc_rgb_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
struct atmel_hlcdc_rgb_output *rgb =
|
||||
drm_connector_to_atmel_hlcdc_rgb_output(connector);
|
||||
|
||||
return &rgb->encoder;
|
||||
}
|
||||
|
||||
static struct drm_connector_helper_funcs atmel_hlcdc_panel_connector_helper_funcs = {
|
||||
.get_modes = atmel_hlcdc_panel_get_modes,
|
||||
.mode_valid = atmel_hlcdc_rgb_mode_valid,
|
||||
.best_encoder = atmel_hlcdc_rgb_best_encoder,
|
||||
};
|
||||
|
||||
static enum drm_connector_status
|
||||
atmel_hlcdc_panel_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
static void
|
||||
atmel_hlcdc_panel_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
struct atmel_hlcdc_rgb_output *rgb =
|
||||
drm_connector_to_atmel_hlcdc_rgb_output(connector);
|
||||
struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb);
|
||||
|
||||
drm_panel_detach(panel->panel);
|
||||
drm_connector_cleanup(connector);
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs atmel_hlcdc_panel_connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.detect = atmel_hlcdc_panel_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = atmel_hlcdc_panel_connector_destroy,
|
||||
};
|
||||
|
||||
static int atmel_hlcdc_create_panel_output(struct drm_device *dev,
|
||||
struct of_endpoint *ep)
|
||||
{
|
||||
struct atmel_hlcdc_dc *dc = dev->dev_private;
|
||||
struct device_node *np;
|
||||
struct drm_panel *p = NULL;
|
||||
struct atmel_hlcdc_panel *panel;
|
||||
int ret;
|
||||
|
||||
np = of_graph_get_remote_port_parent(ep->local_node);
|
||||
if (!np)
|
||||
return -EINVAL;
|
||||
|
||||
p = of_drm_find_panel(np);
|
||||
of_node_put(np);
|
||||
|
||||
if (!p)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
panel = devm_kzalloc(dev->dev, sizeof(*panel), GFP_KERNEL);
|
||||
if (!panel)
|
||||
return -EINVAL;
|
||||
|
||||
panel->base.dpms = DRM_MODE_DPMS_OFF;
|
||||
|
||||
panel->base.dc = dc;
|
||||
|
||||
drm_encoder_helper_add(&panel->base.encoder,
|
||||
&atmel_hlcdc_panel_encoder_helper_funcs);
|
||||
ret = drm_encoder_init(dev, &panel->base.encoder,
|
||||
&atmel_hlcdc_panel_encoder_funcs,
|
||||
DRM_MODE_ENCODER_LVDS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
panel->base.connector.dpms = DRM_MODE_DPMS_OFF;
|
||||
panel->base.connector.polled = DRM_CONNECTOR_POLL_CONNECT;
|
||||
drm_connector_helper_add(&panel->base.connector,
|
||||
&atmel_hlcdc_panel_connector_helper_funcs);
|
||||
ret = drm_connector_init(dev, &panel->base.connector,
|
||||
&atmel_hlcdc_panel_connector_funcs,
|
||||
DRM_MODE_CONNECTOR_LVDS);
|
||||
if (ret)
|
||||
goto err_encoder_cleanup;
|
||||
|
||||
drm_mode_connector_attach_encoder(&panel->base.connector,
|
||||
&panel->base.encoder);
|
||||
panel->base.encoder.possible_crtcs = 0x1;
|
||||
|
||||
drm_panel_attach(p, &panel->base.connector);
|
||||
panel->panel = p;
|
||||
|
||||
return 0;
|
||||
|
||||
err_encoder_cleanup:
|
||||
drm_encoder_cleanup(&panel->base.encoder);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int atmel_hlcdc_create_outputs(struct drm_device *dev)
|
||||
{
|
||||
struct device_node *port_np, *np;
|
||||
struct of_endpoint ep;
|
||||
int ret;
|
||||
|
||||
port_np = of_get_child_by_name(dev->dev->of_node, "port");
|
||||
if (!port_np)
|
||||
return -EINVAL;
|
||||
|
||||
np = of_get_child_by_name(port_np, "endpoint");
|
||||
of_node_put(port_np);
|
||||
|
||||
if (!np)
|
||||
return -EINVAL;
|
||||
|
||||
ret = of_graph_parse_endpoint(np, &ep);
|
||||
of_node_put(port_np);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* We currently only support panel output */
|
||||
return atmel_hlcdc_create_panel_output(dev, &ep);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -761,6 +761,40 @@ static void drm_mode_remove(struct drm_connector *connector,
|
||||
drm_mode_destroy(connector->dev, mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_display_info_set_bus_formats - set the supported bus formats
|
||||
* @info: display info to store bus formats in
|
||||
* @fmts: array containing the supported bus formats
|
||||
* @nfmts: the number of entries in the fmts array
|
||||
*
|
||||
* Store the supported bus formats in display info structure.
|
||||
* See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for
|
||||
* a full list of available formats.
|
||||
*/
|
||||
int drm_display_info_set_bus_formats(struct drm_display_info *info,
|
||||
const u32 *formats,
|
||||
unsigned int num_formats)
|
||||
{
|
||||
u32 *fmts = NULL;
|
||||
|
||||
if (!formats && num_formats)
|
||||
return -EINVAL;
|
||||
|
||||
if (formats && num_formats) {
|
||||
fmts = kmemdup(formats, sizeof(*formats) * num_formats,
|
||||
GFP_KERNEL);
|
||||
if (!formats)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
kfree(info->bus_formats);
|
||||
info->bus_formats = fmts;
|
||||
info->num_bus_formats = num_formats;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_display_info_set_bus_formats);
|
||||
|
||||
/**
|
||||
* drm_connector_get_cmdline_mode - reads the user's cmdline mode
|
||||
* @connector: connector to quwery
|
||||
@@ -923,6 +957,7 @@ void drm_connector_cleanup(struct drm_connector *connector)
|
||||
ida_remove(&drm_connector_enum_list[connector->connector_type].ida,
|
||||
connector->connector_type_id);
|
||||
|
||||
kfree(connector->display_info.bus_formats);
|
||||
drm_mode_object_put(dev, &connector->base);
|
||||
kfree(connector->name);
|
||||
connector->name = NULL;
|
||||
|
||||
@@ -61,6 +61,8 @@ struct panel_desc {
|
||||
unsigned int disable;
|
||||
unsigned int unprepare;
|
||||
} delay;
|
||||
|
||||
u32 bus_format;
|
||||
};
|
||||
|
||||
struct panel_simple {
|
||||
@@ -111,6 +113,9 @@ static int panel_simple_get_fixed_modes(struct panel_simple *panel)
|
||||
connector->display_info.bpc = panel->desc->bpc;
|
||||
connector->display_info.width_mm = panel->desc->size.width;
|
||||
connector->display_info.height_mm = panel->desc->size.height;
|
||||
if (panel->desc->bus_format)
|
||||
drm_display_info_set_bus_formats(&connector->display_info,
|
||||
&panel->desc->bus_format, 1);
|
||||
|
||||
return num;
|
||||
}
|
||||
@@ -558,6 +563,7 @@ static const struct panel_desc foxlink_fl500wvr00_a0t = {
|
||||
.width = 108,
|
||||
.height = 65,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode hannstar_hsd070pww1_mode = {
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/idr.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/hdmi.h>
|
||||
#include <linux/media-bus-format.h>
|
||||
#include <uapi/drm/drm_mode.h>
|
||||
#include <uapi/drm/drm_fourcc.h>
|
||||
#include <drm/drm_modeset_lock.h>
|
||||
@@ -139,6 +140,9 @@ struct drm_display_info {
|
||||
enum subpixel_order subpixel_order;
|
||||
u32 color_formats;
|
||||
|
||||
const u32 *bus_formats;
|
||||
unsigned int num_bus_formats;
|
||||
|
||||
/* Mask of supported hdmi deep color modes */
|
||||
u8 edid_hdmi_dc_modes;
|
||||
|
||||
@@ -1282,6 +1286,10 @@ int drm_mode_connector_set_tile_property(struct drm_connector *connector);
|
||||
extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
|
||||
const struct edid *edid);
|
||||
|
||||
extern int drm_display_info_set_bus_formats(struct drm_display_info *info,
|
||||
const u32 *formats,
|
||||
unsigned int num_formats);
|
||||
|
||||
static inline bool drm_property_type_is(struct drm_property *property,
|
||||
uint32_t type)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user