Skip to content

Commit

Permalink
drm: sti: add DVO output connector
Browse files Browse the repository at this point in the history
Digital Video Out connector driver LCD panels.
Like HDMI and HDA it create bridge, encoder and connector
drm object.
Add binding description.

Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
  • Loading branch information
Benjamin Gaignard committed Dec 30, 2014
1 parent 4e0cd68 commit f32c4c5
Show file tree
Hide file tree
Showing 6 changed files with 920 additions and 0 deletions.
29 changes: 29 additions & 0 deletions Documentation/devicetree/bindings/gpu/st,stih4xx.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,22 @@ sti-hda:
- clock-names: names of the clocks listed in clocks property in the same
order.

sti-dvo:
Required properties:
must be a child of sti-tvout
- compatible: "st,stih<chip>-dvo"
- reg: Physical base address of the IP registers and length of memory mapped region.
- reg-names: names of the mapped memory regions listed in regs property in
the same order.
- clocks: from common clock binding: handle hardware IP needed clocks, the
number of clocks may depend of the SoC type.
See ../clocks/clock-bindings.txt for details.
- clock-names: names of the clocks listed in clocks property in the same
order.
- pinctrl-0: pin control handle
- pinctrl-name: names of the pin control to use
- sti,panel: phandle of the panel connected to the DVO output

sti-hqvdp:
must be a child of sti-display-subsystem
Required properties:
Expand Down Expand Up @@ -198,6 +214,19 @@ Example:
clock-names = "pix", "hddac";
clocks = <&clockgen_c_vcc CLK_S_PIX_HD>, <&clockgen_c_vcc CLK_S_HDDAC>;
};

sti-dvo@8d00400 {
compatible = "st,stih407-dvo";
reg = <0x8d00400 0x200>;
reg-names = "dvo-reg";
clock-names = "dvo_pix", "dvo",
"main_parent", "aux_parent";
clocks = <&clk_s_d2_flexgen CLK_PIX_DVO>, <&clk_s_d2_flexgen CLK_DVO>,
<&clk_s_d2_quadfs 0>, <&clk_s_d2_quadfs 1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_dvo>;
sti,panel = <&panel_dvo>;
};
};

sti-hqvdp@9c000000 {
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/sti/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ stihdmi-y := sti_hdmi.o \
sti_hdmi_tx3g0c55phy.o \
sti_hdmi_tx3g4c28phy.o \

stidvo-y := sti_dvo.o \
sti_awg_utils.o

obj-$(CONFIG_DRM_STI) = \
sti_vtg.o \
sti_vtac.o \
Expand All @@ -20,4 +23,5 @@ obj-$(CONFIG_DRM_STI) = \
sti_tvout.o \
sticompositor.o \
sti_hqvdp.o \
stidvo.o \
sti_drm_drv.o
184 changes: 184 additions & 0 deletions drivers/gpu/drm/sti/sti_awg_utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
* License terms: GNU General Public License (GPL), version 2
*/

#include "sti_awg_utils.h"

#define AWG_OPCODE_OFFSET 10

enum opcode {
SET,
RPTSET,
RPLSET,
SKIP,
STOP,
REPEAT,
REPLAY,
JUMP,
HOLD,
};

static int awg_generate_instr(enum opcode opcode,
long int arg,
long int mux_sel,
long int data_en,
struct awg_code_generation_params *fwparams)
{
u32 instruction = 0;
u32 mux = (mux_sel << 8) & 0x1ff;
u32 data_enable = (data_en << 9) & 0x2ff;
long int arg_tmp = arg;

/* skip, repeat and replay arg should not exceed 1023.
* If user wants to exceed this value, the instruction should be
* duplicate and arg should be adjust for each duplicated instruction.
*/

while (arg_tmp > 0) {
arg = arg_tmp;
if (fwparams->instruction_offset >= AWG_MAX_INST) {
DRM_ERROR("too many number of instructions\n");
return -EINVAL;
}

switch (opcode) {
case SKIP:
/* leave 'arg' + 1 pixel elapsing without changing
* output bus */
arg--; /* pixel adjustment */
arg_tmp--;

if (arg < 0) {
/* SKIP instruction not needed */
return 0;
}

if (arg == 0) {
/* SKIP 0 not permitted but we want to skip 1
* pixel. So we transform SKIP into SET
* instruction */
opcode = SET;
arg = (arg << 24) >> 24;
arg &= (0x0ff);
break;
}

mux = 0;
data_enable = 0;
arg = (arg << 22) >> 22;
arg &= (0x3ff);
break;
case REPEAT:
case REPLAY:
if (arg == 0) {
/* REPEAT or REPLAY instruction not needed */
return 0;
}

mux = 0;
data_enable = 0;
arg = (arg << 22) >> 22;
arg &= (0x3ff);
break;
case JUMP:
mux = 0;
data_enable = 0;
arg |= 0x40; /* for jump instruction 7th bit is 1 */
arg = (arg << 22) >> 22;
arg &= 0x3ff;
break;
case STOP:
arg = 0;
break;
case SET:
case RPTSET:
case RPLSET:
case HOLD:
arg = (arg << 24) >> 24;
arg &= (0x0ff);
break;
default:
DRM_ERROR("instruction %d does not exist\n", opcode);
return -EINVAL;
}

arg_tmp = arg_tmp - arg;

arg = ((arg + mux) + data_enable);

instruction = ((opcode) << AWG_OPCODE_OFFSET) | arg;
fwparams->ram_code[fwparams->instruction_offset] =
instruction & (0x3fff);
fwparams->instruction_offset++;
}
return 0;
}

int sti_awg_generate_code_data_enable_mode(
struct awg_code_generation_params *fwparams,
struct awg_timing *timing)
{
long int val;
long int data_en;
int ret = 0;

if (timing->trailing_lines > 0) {
/* skip trailing lines */
val = timing->blanking_level;
data_en = 0;
ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);

val = timing->trailing_lines - 1;
data_en = 0;
ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
}

if (timing->trailing_pixels > 0) {
/* skip trailing pixel */
val = timing->blanking_level;
data_en = 0;
ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);

val = timing->trailing_pixels - 1;
data_en = 0;
ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
}

/* set DE signal high */
val = timing->blanking_level;
data_en = 1;
ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET,
val, 0, data_en, fwparams);

if (timing->blanking_pixels > 0) {
/* skip the number of active pixel */
val = timing->active_pixels - 1;
data_en = 1;
ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);

/* set DE signal low */
val = timing->blanking_level;
data_en = 0;
ret |= awg_generate_instr(SET, val, 0, data_en, fwparams);
}

/* replay the sequence as many active lines defined */
val = timing->active_lines - 1;
data_en = 0;
ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);

if (timing->blanking_lines > 0) {
/* skip blanking lines */
val = timing->blanking_level;
data_en = 0;
ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);

val = timing->blanking_lines - 1;
data_en = 0;
ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
}

return ret;
}
34 changes: 34 additions & 0 deletions drivers/gpu/drm/sti/sti_awg_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (C) STMicroelectronics SA 2014
* Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
* License terms: GNU General Public License (GPL), version 2
*/

#ifndef _STI_AWG_UTILS_H_
#define _STI_AWG_UTILS_H_

#include <drm/drmP.h>

#define AWG_MAX_INST 64

struct awg_code_generation_params {
u32 *ram_code;
u8 instruction_offset;
};

struct awg_timing {
u32 total_lines;
u32 active_lines;
u32 blanking_lines;
u32 trailing_lines;
u32 total_pixels;
u32 active_pixels;
u32 blanking_pixels;
u32 trailing_pixels;
u32 blanking_level;
};

int sti_awg_generate_code_data_enable_mode(
struct awg_code_generation_params *fw_gen_params,
struct awg_timing *timing);
#endif
Loading

0 comments on commit f32c4c5

Please sign in to comment.