Commit 2601a15d authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-vc4-next-2016-12-09' of https://github.com/anholt/linux into drm-next

This pull request brings in VEC (TV-out) support for vc4, along with a
pageflipping race fix.

* tag 'drm-vc4-next-2016-12-09' of https://github.com/anholt/linux:
  drm/vc4: Don't use drm_put_dev
  drm/vc4: Document VEC DT binding
  drm/vc4: Add support for the VEC (Video Encoder) IP
  drm: Add TV connector states to drm_connector_state
  drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into an enum
  drm/vc4: Fix ->clock_select setting for the VEC encoder
  drm/vc4: Fix race between page flip completion event and clean-up
parents 25dfd7cf c167df44
...@@ -43,6 +43,13 @@ Required properties for DPI: ...@@ -43,6 +43,13 @@ Required properties for DPI:
- port: Port node with a single endpoint connecting to the panel - port: Port node with a single endpoint connecting to the panel
device, as defined in [1] device, as defined in [1]
Required properties for VEC:
- compatible: Should be "brcm,bcm2835-vec"
- reg: Physical base address and length of the registers
- clocks: The core clock the unit runs on
- interrupts: The interrupt number
See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
Required properties for V3D: Required properties for V3D:
- compatible: Should be "brcm,bcm2835-v3d" - compatible: Should be "brcm,bcm2835-v3d"
- reg: Physical base address and length of the V3D's registers - reg: Physical base address and length of the V3D's registers
...@@ -92,6 +99,13 @@ dpi: dpi@7e208000 { ...@@ -92,6 +99,13 @@ dpi: dpi@7e208000 {
}; };
}; };
vec: vec@7e806000 {
compatible = "brcm,bcm2835-vec";
reg = <0x7e806000 0x1000>;
clocks = <&clocks BCM2835_CLOCK_VEC>;
interrupts = <2 27>;
};
v3d: v3d@7ec00000 { v3d: v3d@7ec00000 {
compatible = "brcm,bcm2835-v3d"; compatible = "brcm,bcm2835-v3d";
reg = <0x7ec00000 0x1000>; reg = <0x7ec00000 0x1000>;
......
...@@ -1087,12 +1087,38 @@ int drm_atomic_connector_set_property(struct drm_connector *connector, ...@@ -1087,12 +1087,38 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
* now?) atomic writes to DPMS property: * now?) atomic writes to DPMS property:
*/ */
return -EINVAL; return -EINVAL;
} else if (property == config->tv_select_subconnector_property) {
state->tv.subconnector = val;
} else if (property == config->tv_left_margin_property) {
state->tv.margins.left = val;
} else if (property == config->tv_right_margin_property) {
state->tv.margins.right = val;
} else if (property == config->tv_top_margin_property) {
state->tv.margins.top = val;
} else if (property == config->tv_bottom_margin_property) {
state->tv.margins.bottom = val;
} else if (property == config->tv_mode_property) {
state->tv.mode = val;
} else if (property == config->tv_brightness_property) {
state->tv.brightness = val;
} else if (property == config->tv_contrast_property) {
state->tv.contrast = val;
} else if (property == config->tv_flicker_reduction_property) {
state->tv.flicker_reduction = val;
} else if (property == config->tv_overscan_property) {
state->tv.overscan = val;
} else if (property == config->tv_saturation_property) {
state->tv.saturation = val;
} else if (property == config->tv_hue_property) {
state->tv.hue = val;
} else if (connector->funcs->atomic_set_property) { } else if (connector->funcs->atomic_set_property) {
return connector->funcs->atomic_set_property(connector, return connector->funcs->atomic_set_property(connector,
state, property, val); state, property, val);
} else { } else {
return -EINVAL; return -EINVAL;
} }
return 0;
} }
EXPORT_SYMBOL(drm_atomic_connector_set_property); EXPORT_SYMBOL(drm_atomic_connector_set_property);
...@@ -1135,6 +1161,30 @@ drm_atomic_connector_get_property(struct drm_connector *connector, ...@@ -1135,6 +1161,30 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
*val = (state->crtc) ? state->crtc->base.id : 0; *val = (state->crtc) ? state->crtc->base.id : 0;
} else if (property == config->dpms_property) { } else if (property == config->dpms_property) {
*val = connector->dpms; *val = connector->dpms;
} else if (property == config->tv_select_subconnector_property) {
*val = state->tv.subconnector;
} else if (property == config->tv_left_margin_property) {
*val = state->tv.margins.left;
} else if (property == config->tv_right_margin_property) {
*val = state->tv.margins.right;
} else if (property == config->tv_top_margin_property) {
*val = state->tv.margins.top;
} else if (property == config->tv_bottom_margin_property) {
*val = state->tv.margins.bottom;
} else if (property == config->tv_mode_property) {
*val = state->tv.mode;
} else if (property == config->tv_brightness_property) {
*val = state->tv.brightness;
} else if (property == config->tv_contrast_property) {
*val = state->tv.contrast;
} else if (property == config->tv_flicker_reduction_property) {
*val = state->tv.flicker_reduction;
} else if (property == config->tv_overscan_property) {
*val = state->tv.overscan;
} else if (property == config->tv_saturation_property) {
*val = state->tv.saturation;
} else if (property == config->tv_hue_property) {
*val = state->tv.hue;
} else if (connector->funcs->atomic_get_property) { } else if (connector->funcs->atomic_get_property) {
return connector->funcs->atomic_get_property(connector, return connector->funcs->atomic_get_property(connector,
state, property, val); state, property, val);
......
...@@ -11,6 +11,7 @@ vc4-y := \ ...@@ -11,6 +11,7 @@ vc4-y := \
vc4_kms.o \ vc4_kms.o \
vc4_gem.o \ vc4_gem.o \
vc4_hdmi.o \ vc4_hdmi.o \
vc4_vec.o \
vc4_hvs.o \ vc4_hvs.o \
vc4_irq.o \ vc4_irq.o \
vc4_plane.o \ vc4_plane.o \
......
...@@ -83,8 +83,7 @@ struct vc4_crtc_data { ...@@ -83,8 +83,7 @@ struct vc4_crtc_data {
/* Which channel of the HVS this pixelvalve sources from. */ /* Which channel of the HVS this pixelvalve sources from. */
int hvs_channel; int hvs_channel;
enum vc4_encoder_type encoder0_type; enum vc4_encoder_type encoder_types[4];
enum vc4_encoder_type encoder1_type;
}; };
#define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset)) #define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset))
...@@ -669,6 +668,14 @@ void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id) ...@@ -669,6 +668,14 @@ void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id)
CRTC_WRITE(PV_INTEN, 0); CRTC_WRITE(PV_INTEN, 0);
} }
/* Must be called with the event lock held */
bool vc4_event_pending(struct drm_crtc *crtc)
{
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
return !!vc4_crtc->event;
}
static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc) static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
{ {
struct drm_crtc *crtc = &vc4_crtc->base; struct drm_crtc *crtc = &vc4_crtc->base;
...@@ -859,20 +866,26 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { ...@@ -859,20 +866,26 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
static const struct vc4_crtc_data pv0_data = { static const struct vc4_crtc_data pv0_data = {
.hvs_channel = 0, .hvs_channel = 0,
.encoder0_type = VC4_ENCODER_TYPE_DSI0, .encoder_types = {
.encoder1_type = VC4_ENCODER_TYPE_DPI, [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0,
[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI,
},
}; };
static const struct vc4_crtc_data pv1_data = { static const struct vc4_crtc_data pv1_data = {
.hvs_channel = 2, .hvs_channel = 2,
.encoder0_type = VC4_ENCODER_TYPE_DSI1, .encoder_types = {
.encoder1_type = VC4_ENCODER_TYPE_SMI, [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1,
[PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI,
},
}; };
static const struct vc4_crtc_data pv2_data = { static const struct vc4_crtc_data pv2_data = {
.hvs_channel = 1, .hvs_channel = 1,
.encoder0_type = VC4_ENCODER_TYPE_VEC, .encoder_types = {
.encoder1_type = VC4_ENCODER_TYPE_HDMI, [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI,
[PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC,
},
}; };
static const struct of_device_id vc4_crtc_dt_match[] = { static const struct of_device_id vc4_crtc_dt_match[] = {
...@@ -886,17 +899,20 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm, ...@@ -886,17 +899,20 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm,
struct drm_crtc *crtc) struct drm_crtc *crtc)
{ {
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
const struct vc4_crtc_data *crtc_data = vc4_crtc->data;
const enum vc4_encoder_type *encoder_types = crtc_data->encoder_types;
struct drm_encoder *encoder; struct drm_encoder *encoder;
drm_for_each_encoder(encoder, drm) { drm_for_each_encoder(encoder, drm) {
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder); struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
int i;
if (vc4_encoder->type == vc4_crtc->data->encoder0_type) {
vc4_encoder->clock_select = 0; for (i = 0; i < ARRAY_SIZE(crtc_data->encoder_types); i++) {
encoder->possible_crtcs |= drm_crtc_mask(crtc); if (vc4_encoder->type == encoder_types[i]) {
} else if (vc4_encoder->type == vc4_crtc->data->encoder1_type) { vc4_encoder->clock_select = i;
vc4_encoder->clock_select = 1; encoder->possible_crtcs |= drm_crtc_mask(crtc);
encoder->possible_crtcs |= drm_crtc_mask(crtc); break;
}
} }
} }
} }
......
...@@ -19,6 +19,7 @@ static const struct drm_info_list vc4_debugfs_list[] = { ...@@ -19,6 +19,7 @@ static const struct drm_info_list vc4_debugfs_list[] = {
{"bo_stats", vc4_bo_stats_debugfs, 0}, {"bo_stats", vc4_bo_stats_debugfs, 0},
{"dpi_regs", vc4_dpi_debugfs_regs, 0}, {"dpi_regs", vc4_dpi_debugfs_regs, 0},
{"hdmi_regs", vc4_hdmi_debugfs_regs, 0}, {"hdmi_regs", vc4_hdmi_debugfs_regs, 0},
{"vec_regs", vc4_vec_debugfs_regs, 0},
{"hvs_regs", vc4_hvs_debugfs_regs, 0}, {"hvs_regs", vc4_hvs_debugfs_regs, 0},
{"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0}, {"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0},
{"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1}, {"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1},
......
...@@ -277,12 +277,14 @@ static void vc4_drm_unbind(struct device *dev) ...@@ -277,12 +277,14 @@ static void vc4_drm_unbind(struct device *dev)
struct drm_device *drm = platform_get_drvdata(pdev); struct drm_device *drm = platform_get_drvdata(pdev);
struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_dev *vc4 = to_vc4_dev(drm);
drm_dev_unregister(drm);
if (vc4->fbdev) if (vc4->fbdev)
drm_fbdev_cma_fini(vc4->fbdev); drm_fbdev_cma_fini(vc4->fbdev);
drm_mode_config_cleanup(drm); drm_mode_config_cleanup(drm);
drm_put_dev(drm); drm_dev_unref(drm);
} }
static const struct component_master_ops vc4_drm_ops = { static const struct component_master_ops vc4_drm_ops = {
...@@ -292,6 +294,7 @@ static const struct component_master_ops vc4_drm_ops = { ...@@ -292,6 +294,7 @@ static const struct component_master_ops vc4_drm_ops = {
static struct platform_driver *const component_drivers[] = { static struct platform_driver *const component_drivers[] = {
&vc4_hdmi_driver, &vc4_hdmi_driver,
&vc4_vec_driver,
&vc4_dpi_driver, &vc4_dpi_driver,
&vc4_hvs_driver, &vc4_hvs_driver,
&vc4_crtc_driver, &vc4_crtc_driver,
......
...@@ -17,6 +17,7 @@ struct vc4_dev { ...@@ -17,6 +17,7 @@ struct vc4_dev {
struct vc4_crtc *crtc[3]; struct vc4_crtc *crtc[3];
struct vc4_v3d *v3d; struct vc4_v3d *v3d;
struct vc4_dpi *dpi; struct vc4_dpi *dpi;
struct vc4_vec *vec;
struct drm_fbdev_cma *fbdev; struct drm_fbdev_cma *fbdev;
...@@ -194,6 +195,7 @@ to_vc4_plane(struct drm_plane *plane) ...@@ -194,6 +195,7 @@ to_vc4_plane(struct drm_plane *plane)
} }
enum vc4_encoder_type { enum vc4_encoder_type {
VC4_ENCODER_TYPE_NONE,
VC4_ENCODER_TYPE_HDMI, VC4_ENCODER_TYPE_HDMI,
VC4_ENCODER_TYPE_VEC, VC4_ENCODER_TYPE_VEC,
VC4_ENCODER_TYPE_DSI0, VC4_ENCODER_TYPE_DSI0,
...@@ -442,6 +444,7 @@ int vc4_bo_stats_debugfs(struct seq_file *m, void *arg); ...@@ -442,6 +444,7 @@ int vc4_bo_stats_debugfs(struct seq_file *m, void *arg);
extern struct platform_driver vc4_crtc_driver; extern struct platform_driver vc4_crtc_driver;
int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id); int vc4_enable_vblank(struct drm_device *dev, unsigned int crtc_id);
void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id); void vc4_disable_vblank(struct drm_device *dev, unsigned int crtc_id);
bool vc4_event_pending(struct drm_crtc *crtc);
int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg); int vc4_crtc_debugfs_regs(struct seq_file *m, void *arg);
int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id, int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
unsigned int flags, int *vpos, int *hpos, unsigned int flags, int *vpos, int *hpos,
...@@ -485,6 +488,10 @@ int vc4_queue_seqno_cb(struct drm_device *dev, ...@@ -485,6 +488,10 @@ int vc4_queue_seqno_cb(struct drm_device *dev,
extern struct platform_driver vc4_hdmi_driver; extern struct platform_driver vc4_hdmi_driver;
int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused); int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused);
/* vc4_hdmi.c */
extern struct platform_driver vc4_vec_driver;
int vc4_vec_debugfs_regs(struct seq_file *m, void *unused);
/* vc4_irq.c */ /* vc4_irq.c */
irqreturn_t vc4_irq(int irq, void *arg); irqreturn_t vc4_irq(int irq, void *arg);
void vc4_irq_preinstall(struct drm_device *dev); void vc4_irq_preinstall(struct drm_device *dev);
......
...@@ -119,17 +119,34 @@ static int vc4_atomic_commit(struct drm_device *dev, ...@@ -119,17 +119,34 @@ static int vc4_atomic_commit(struct drm_device *dev,
/* Make sure that any outstanding modesets have finished. */ /* Make sure that any outstanding modesets have finished. */
if (nonblock) { if (nonblock) {
ret = down_trylock(&vc4->async_modeset); struct drm_crtc *crtc;
if (ret) { struct drm_crtc_state *crtc_state;
unsigned long flags;
bool busy = false;
/*
* If there's an undispatched event to send then we're
* obviously still busy. If there isn't, then we can
* unconditionally wait for the semaphore because it
* shouldn't be contended (for long).
*
* This is to prevent a race where queuing a new flip
* from userspace immediately on receipt of an event
* beats our clean-up and returns EBUSY.
*/
spin_lock_irqsave(&dev->event_lock, flags);
for_each_crtc_in_state(state, crtc, crtc_state, i)
busy |= vc4_event_pending(crtc);
spin_unlock_irqrestore(&dev->event_lock, flags);
if (busy) {
kfree(c); kfree(c);
return -EBUSY; return -EBUSY;
} }
} else { }
ret = down_interruptible(&vc4->async_modeset); ret = down_interruptible(&vc4->async_modeset);
if (ret) { if (ret) {
kfree(c); kfree(c);
return ret; return ret;
}
} }
ret = drm_atomic_helper_prepare_planes(dev, state); ret = drm_atomic_helper_prepare_planes(dev, state);
......
...@@ -177,8 +177,9 @@ ...@@ -177,8 +177,9 @@
# define PV_CONTROL_WAIT_HSTART BIT(12) # define PV_CONTROL_WAIT_HSTART BIT(12)
# define PV_CONTROL_PIXEL_REP_MASK VC4_MASK(5, 4) # define PV_CONTROL_PIXEL_REP_MASK VC4_MASK(5, 4)
# define PV_CONTROL_PIXEL_REP_SHIFT 4 # define PV_CONTROL_PIXEL_REP_SHIFT 4
# define PV_CONTROL_CLK_SELECT_DSI_VEC 0 # define PV_CONTROL_CLK_SELECT_DSI 0
# define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI 1 # define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI 1
# define PV_CONTROL_CLK_SELECT_VEC 2
# define PV_CONTROL_CLK_SELECT_MASK VC4_MASK(3, 2) # define PV_CONTROL_CLK_SELECT_MASK VC4_MASK(3, 2)
# define PV_CONTROL_CLK_SELECT_SHIFT 2 # define PV_CONTROL_CLK_SELECT_SHIFT 2
# define PV_CONTROL_FIFO_CLR BIT(1) # define PV_CONTROL_FIFO_CLR BIT(1)
......
This diff is collapsed.
...@@ -194,11 +194,41 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info, ...@@ -194,11 +194,41 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info,
const u32 *formats, const u32 *formats,
unsigned int num_formats); unsigned int num_formats);
/**
* struct drm_tv_connector_state - TV connector related states
* @subconnector: selected subconnector
* @margins: left/right/top/bottom margins
* @mode: TV mode
* @brightness: brightness in percent
* @contrast: contrast in percent
* @flicker_reduction: flicker reduction in percent
* @overscan: overscan in percent
* @saturation: saturation in percent
* @hue: hue in percent
*/
struct drm_tv_connector_state {
enum drm_mode_subconnector subconnector;
struct {
unsigned int left;
unsigned int right;
unsigned int top;
unsigned int bottom;
} margins;
unsigned int mode;
unsigned int brightness;
unsigned int contrast;
unsigned int flicker_reduction;
unsigned int overscan;
unsigned int saturation;
unsigned int hue;
};
/** /**
* struct drm_connector_state - mutable connector state * struct drm_connector_state - mutable connector state
* @connector: backpointer to the connector * @connector: backpointer to the connector
* @best_encoder: can be used by helpers and drivers to select the encoder * @best_encoder: can be used by helpers and drivers to select the encoder
* @state: backpointer to global drm_atomic_state * @state: backpointer to global drm_atomic_state
* @tv: TV connector state
*/ */
struct drm_connector_state { struct drm_connector_state {
struct drm_connector *connector; struct drm_connector *connector;
...@@ -214,6 +244,8 @@ struct drm_connector_state { ...@@ -214,6 +244,8 @@ struct drm_connector_state {
struct drm_encoder *best_encoder; struct drm_encoder *best_encoder;
struct drm_atomic_state *state; struct drm_atomic_state *state;
struct drm_tv_connector_state tv;
}; };
/** /**
......
...@@ -236,14 +236,16 @@ struct drm_mode_get_encoder { ...@@ -236,14 +236,16 @@ struct drm_mode_get_encoder {
/* This is for connectors with multiple signal types. */ /* This is for connectors with multiple signal types. */
/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */ /* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */
#define DRM_MODE_SUBCONNECTOR_Automatic 0 enum drm_mode_subconnector {
#define DRM_MODE_SUBCONNECTOR_Unknown 0 DRM_MODE_SUBCONNECTOR_Automatic = 0,
#define DRM_MODE_SUBCONNECTOR_DVID 3 DRM_MODE_SUBCONNECTOR_Unknown = 0,
#define DRM_MODE_SUBCONNECTOR_DVIA 4 DRM_MODE_SUBCONNECTOR_DVID = 3,
#define DRM_MODE_SUBCONNECTOR_Composite 5 DRM_MODE_SUBCONNECTOR_DVIA = 4,
#define DRM_MODE_SUBCONNECTOR_SVIDEO 6 DRM_MODE_SUBCONNECTOR_Composite = 5,
#define DRM_MODE_SUBCONNECTOR_Component 8 DRM_MODE_SUBCONNECTOR_SVIDEO = 6,
#define DRM_MODE_SUBCONNECTOR_SCART 9 DRM_MODE_SUBCONNECTOR_Component = 8,
DRM_MODE_SUBCONNECTOR_SCART = 9,
};
#define DRM_MODE_CONNECTOR_Unknown 0 #define DRM_MODE_CONNECTOR_Unknown 0
#define DRM_MODE_CONNECTOR_VGA 1 #define DRM_MODE_CONNECTOR_VGA 1
......
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