Hi Boris!
Dne ponedeljek, 26. avgust 2019 ob 17:26:46 CEST je Boris Brezillon napisal(a):
Some LVDS encoder might support several input/output bus formats. Add a way to describe the one used on a specific design by adding optional 'data-mapping' properties to the input/output ports.
Signed-off-by: Boris Brezillon boris.brezillon@collabora.com
Changes in v2:
- Make the bus-format negotiation logic more generic
.../display/bridge/lvds-transmitter.txt | 12 ++ drivers/gpu/drm/bridge/lvds-encoder.c | 105 ++++++++++++++++++ 2 files changed, 117 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt index 60091db5dfa5..db51eab216f7 100644 --- a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt +++ b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt @@ -36,6 +36,18 @@ graph bindings specified in Documentation/devicetree/bindings/graph.txt. - Video port 0 for parallel input
- Video port 1 for LVDS output
+Optional port 0 node properties:
+- data-mapping: can be one of the following values
- "rgb-24"
- "rgb-18"
+Optional port 0 node properties:
You probably mean port 1 ^^^ ?
Anyway, devicetree doc changes should be separate patch and be send to DT ML (I can't see it in CC).
Best regards, Jernej
+- data-mapping: can be one of the following values
- "jeida-18"
- "jeida-24"
- "vesa-24"
Example
diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c index 2ab2c234f26c..38cad7a7d828 100644 --- a/drivers/gpu/drm/bridge/lvds-encoder.c +++ b/drivers/gpu/drm/bridge/lvds-encoder.c @@ -6,6 +6,7 @@ #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_graph.h> #include <linux/platform_device.h>
@@ -16,6 +17,8 @@ struct lvds_encoder { struct drm_bridge bridge; struct drm_bridge *panel_bridge; struct gpio_desc *powerdown_gpio;
- u32 output_fmt;
- u32 input_fmt;
};
static int lvds_encoder_attach(struct drm_bridge *bridge) @@ -48,12 +51,86 @@ static void lvds_encoder_disable(struct drm_bridge *bridge) gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 1); }
+static void lvds_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
struct
drm_bridge_state *bridge_state,
struct
drm_crtc_state *crtc_state,
struct
drm_connector_state *conn_state,
u32 output_fmt,
unsigned int
*num_input_fmts,
u32 *input_fmts)
+{
- struct lvds_encoder *lvds_encoder = container_of(bridge,
struct lvds_encoder,
bridge);
- if (output_fmt == MEDIA_BUS_FMT_FIXED ||
output_fmt == lvds_encoder->output_fmt)
*num_input_fmts = 1;
- else
*num_input_fmts = 0;
- if (*num_input_fmts && input_fmts)
input_fmts[0] = lvds_encoder->input_fmt;
+}
+static int lvds_encoder_atomic_check(struct drm_bridge *bridge,
struct drm_bridge_state
*bridge_state,
struct drm_crtc_state
*crtc_state,
struct drm_connector_state
*conn_state)
+{
- /* Propagate the bus_flags. */
- bridge_state->input_bus_cfg.flags = bridge_state-
output_bus_cfg.flags;
- return 0;
+}
static struct drm_bridge_funcs funcs = { .attach = lvds_encoder_attach, .enable = lvds_encoder_enable, .disable = lvds_encoder_disable,
- .atomic_get_input_bus_fmts = lvds_atomic_get_input_bus_fmts,
- .atomic_check = lvds_encoder_atomic_check,
};
+struct of_data_mapping {
- const char *name;
- u32 id;
+};
+static const struct of_data_mapping output_data_mappings[] = {
- { "jeida-18", MEDIA_BUS_FMT_RGB666_1X7X3_SPWG },
- { "jeida-24", MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA },
- { "vesa-24", MEDIA_BUS_FMT_RGB888_1X7X4_SPWG },
+};
+static const struct of_data_mapping input_data_mappings[] = {
- { "rgb-24", MEDIA_BUS_FMT_RGB888_1X24 },
- { "rgb-18", MEDIA_BUS_FMT_RGB666_1X18 },
+};
+static int of_get_data_mapping(struct device_node *port,
const struct of_data_mapping
*mappings,
unsigned int num_mappings,
u32 *fmt)
+{
- const char *name = NULL;
- unsigned int i;
- of_property_read_string(port, "data-mapping", &name);
- if (!name) {
*fmt = MEDIA_BUS_FMT_FIXED;
return 0;
- }
- for (i = 0; i < num_mappings; i++) {
if (!strcmp(mappings[i].name, name)) {
*fmt = mappings[i].id;
return 0;
}
- }
- return -ENOTSUPP;
+}
static int lvds_encoder_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -62,11 +139,15 @@ static int lvds_encoder_probe(struct platform_device *pdev) struct device_node *panel_node; struct drm_panel *panel; struct lvds_encoder *lvds_encoder;
int ret;
lvds_encoder = devm_kzalloc(dev, sizeof(*lvds_encoder),
GFP_KERNEL);
if (!lvds_encoder) return -ENOMEM;
- lvds_encoder->input_fmt = MEDIA_BUS_FMT_FIXED;
- lvds_encoder->output_fmt = MEDIA_BUS_FMT_FIXED;
- lvds_encoder->powerdown_gpio = devm_gpiod_get_optional(dev,
"powerdown",
GPIOD_OUT_HIGH);
if (IS_ERR(lvds_encoder->powerdown_gpio)) { @@ -77,6 +158,21 @@ static int lvds_encoder_probe(struct platform_device *pdev) return err; }
- port = of_graph_get_port_by_id(dev->of_node, 0);
- if (!port) {
dev_dbg(dev, "port 0 not found\n");
return -ENXIO;
- }
- ret = of_get_data_mapping(port, input_data_mappings,
ARRAY_SIZE(input_data_mappings),
&lvds_encoder->input_fmt);
- of_node_put(port);
- if (ret) {
dev_dbg(dev, "unsupported input data-mapping\n");
return ret;
- }
- /* Locate the panel DT node. */ port = of_graph_get_port_by_id(dev->of_node, 1); if (!port) {
@@ -84,6 +180,15 @@ static int lvds_encoder_probe(struct platform_device *pdev) return -ENXIO; }
- ret = of_get_data_mapping(port, output_data_mappings,
ARRAY_SIZE(output_data_mappings),
&lvds_encoder->output_fmt);
- if (ret) {
of_node_put(port);
dev_dbg(dev, "unsupported output data-mapping\n");
return ret;
- }
- endpoint = of_get_child_by_name(port, "endpoint"); of_node_put(port); if (!endpoint) {