linux-stable/drivers/staging/sm750fb/ddk750_display.c
Mike Rapoport 85e4db5347 staging: sm750fb: share common bits in display control registers
The display control registers for primary and secondary display share some
of the bits and those bits can be defined in a single place and then used
for manipulations of the relevant registers.

Signed-off-by: Mike Rapoport <mike.rapoport@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2016-02-11 19:52:37 -08:00

233 lines
7 KiB
C

#include "ddk750_reg.h"
#include "ddk750_help.h"
#include "ddk750_display.h"
#include "ddk750_power.h"
#include "ddk750_dvi.h"
#define primaryWaitVerticalSync(delay) waitNextVerticalSync(0, delay)
static void setDisplayControl(int ctrl, int disp_state)
{
/* state != 0 means turn on both timing & plane en_bit */
unsigned long reg, reserved;
int cnt;
cnt = 0;
/* Set the primary display control */
if (!ctrl) {
reg = PEEK32(PANEL_DISPLAY_CTRL);
/* Turn on/off the Panel display control */
if (disp_state) {
/* Timing should be enabled first before enabling the plane
* because changing at the same time does not guarantee that
* the plane will also enabled or disabled.
*/
reg = FIELD_SET(reg, DISPLAY_CTRL, TIMING, ENABLE);
POKE32(PANEL_DISPLAY_CTRL, reg);
reg = FIELD_SET(reg, DISPLAY_CTRL, PLANE, ENABLE);
/* Added some masks to mask out the reserved bits.
* Sometimes, the reserved bits are set/reset randomly when
* writing to the PRIMARY_DISPLAY_CTRL, therefore, the register
* reserved bits are needed to be masked out.
*/
reserved = FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_1_MASK, ENABLE) |
FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_2_MASK, ENABLE) |
FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE);
/* Somehow the register value on the plane is not set
* until a few delay. Need to write
* and read it a couple times
*/
do {
cnt++;
POKE32(PANEL_DISPLAY_CTRL, reg);
} while ((PEEK32(PANEL_DISPLAY_CTRL) & ~reserved) !=
(reg & ~reserved));
printk("Set Panel Plane enbit:after tried %d times\n", cnt);
} else {
/* When turning off, there is no rule on the programming
* sequence since whenever the clock is off, then it does not
* matter whether the plane is enabled or disabled.
* Note: Modifying the plane bit will take effect on the
* next vertical sync. Need to find out if it is necessary to
* wait for 1 vsync before modifying the timing enable bit.
* */
reg = FIELD_SET(reg, DISPLAY_CTRL, PLANE, DISABLE);
POKE32(PANEL_DISPLAY_CTRL, reg);
reg = FIELD_SET(reg, DISPLAY_CTRL, TIMING, DISABLE);
POKE32(PANEL_DISPLAY_CTRL, reg);
}
} else {
/* Set the secondary display control */
reg = PEEK32(CRT_DISPLAY_CTRL);
if (disp_state) {
/* Timing should be enabled first before enabling the plane because changing at the
same time does not guarantee that the plane will also enabled or disabled.
*/
reg = FIELD_SET(reg, DISPLAY_CTRL, TIMING, ENABLE);
POKE32(CRT_DISPLAY_CTRL, reg);
reg = FIELD_SET(reg, DISPLAY_CTRL, PLANE, ENABLE);
/* Added some masks to mask out the reserved bits.
* Sometimes, the reserved bits are set/reset randomly when
* writing to the PRIMARY_DISPLAY_CTRL, therefore, the register
* reserved bits are needed to be masked out.
*/
reserved = FIELD_SET(0, CRT_DISPLAY_CTRL, RESERVED_1_MASK, ENABLE) |
FIELD_SET(0, CRT_DISPLAY_CTRL, RESERVED_2_MASK, ENABLE) |
FIELD_SET(0, CRT_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE) |
FIELD_SET(0, CRT_DISPLAY_CTRL, RESERVED_4_MASK, ENABLE);
do {
cnt++;
POKE32(CRT_DISPLAY_CTRL, reg);
} while ((PEEK32(CRT_DISPLAY_CTRL) & ~reserved) !=
(reg & ~reserved));
printk("Set Crt Plane enbit:after tried %d times\n", cnt);
} else {
/* When turning off, there is no rule on the programming
* sequence since whenever the clock is off, then it does not
* matter whether the plane is enabled or disabled.
* Note: Modifying the plane bit will take effect on the next
* vertical sync. Need to find out if it is necessary to
* wait for 1 vsync before modifying the timing enable bit.
*/
reg = FIELD_SET(reg, DISPLAY_CTRL, PLANE, DISABLE);
POKE32(CRT_DISPLAY_CTRL, reg);
reg = FIELD_SET(reg, DISPLAY_CTRL, TIMING, DISABLE);
POKE32(CRT_DISPLAY_CTRL, reg);
}
}
}
static void waitNextVerticalSync(int ctrl, int delay)
{
unsigned int status;
if (!ctrl) {
/* primary controller */
/* Do not wait when the Primary PLL is off or display control is already off.
This will prevent the software to wait forever. */
if (!(PEEK32(PANEL_PLL_CTRL) & PLL_CTRL_POWER) ||
(FIELD_GET(PEEK32(PANEL_DISPLAY_CTRL),
DISPLAY_CTRL, TIMING) ==
DISPLAY_CTRL_TIMING_DISABLE)) {
return;
}
while (delay-- > 0) {
/* Wait for end of vsync. */
do {
status = PEEK32(SYSTEM_CTRL);
} while (status & SYSTEM_CTRL_PANEL_VSYNC_ACTIVE);
/* Wait for start of vsync. */
do {
status = PEEK32(SYSTEM_CTRL);
} while (!(status & SYSTEM_CTRL_PANEL_VSYNC_ACTIVE));
}
} else {
/* Do not wait when the Primary PLL is off or display control is already off.
This will prevent the software to wait forever. */
if (!(PEEK32(CRT_PLL_CTRL) & PLL_CTRL_POWER) ||
(FIELD_GET(PEEK32(CRT_DISPLAY_CTRL),
DISPLAY_CTRL, TIMING) ==
DISPLAY_CTRL_TIMING_DISABLE)) {
return;
}
while (delay-- > 0) {
/* Wait for end of vsync. */
do {
status = PEEK32(SYSTEM_CTRL);
} while (status & SYSTEM_CTRL_PANEL_VSYNC_ACTIVE);
/* Wait for start of vsync. */
do {
status = PEEK32(SYSTEM_CTRL);
} while (!(status & SYSTEM_CTRL_PANEL_VSYNC_ACTIVE));
}
}
}
static void swPanelPowerSequence(int disp, int delay)
{
unsigned int reg;
/* disp should be 1 to open sequence */
reg = PEEK32(PANEL_DISPLAY_CTRL);
reg = FIELD_VALUE(reg, PANEL_DISPLAY_CTRL, FPEN, disp);
POKE32(PANEL_DISPLAY_CTRL, reg);
primaryWaitVerticalSync(delay);
reg = PEEK32(PANEL_DISPLAY_CTRL);
reg = FIELD_VALUE(reg, PANEL_DISPLAY_CTRL, DATA, disp);
POKE32(PANEL_DISPLAY_CTRL, reg);
primaryWaitVerticalSync(delay);
reg = PEEK32(PANEL_DISPLAY_CTRL);
reg = FIELD_VALUE(reg, PANEL_DISPLAY_CTRL, VBIASEN, disp);
POKE32(PANEL_DISPLAY_CTRL, reg);
primaryWaitVerticalSync(delay);
reg = PEEK32(PANEL_DISPLAY_CTRL);
reg = FIELD_VALUE(reg, PANEL_DISPLAY_CTRL, FPEN, disp);
POKE32(PANEL_DISPLAY_CTRL, reg);
primaryWaitVerticalSync(delay);
}
void ddk750_setLogicalDispOut(disp_output_t output)
{
unsigned int reg;
if (output & PNL_2_USAGE) {
/* set panel path controller select */
reg = PEEK32(PANEL_DISPLAY_CTRL);
reg = FIELD_VALUE(reg, PANEL_DISPLAY_CTRL, SELECT, (output & PNL_2_MASK)>>PNL_2_OFFSET);
POKE32(PANEL_DISPLAY_CTRL, reg);
}
if (output & CRT_2_USAGE) {
/* set crt path controller select */
reg = PEEK32(CRT_DISPLAY_CTRL);
reg = FIELD_VALUE(reg, CRT_DISPLAY_CTRL, SELECT, (output & CRT_2_MASK)>>CRT_2_OFFSET);
/*se blank off */
reg = FIELD_SET(reg, CRT_DISPLAY_CTRL, BLANK, OFF);
POKE32(CRT_DISPLAY_CTRL, reg);
}
if (output & PRI_TP_USAGE) {
/* set primary timing and plane en_bit */
setDisplayControl(0, (output & PRI_TP_MASK) >> PRI_TP_OFFSET);
}
if (output & SEC_TP_USAGE) {
/* set secondary timing and plane en_bit*/
setDisplayControl(1, (output & SEC_TP_MASK) >> SEC_TP_OFFSET);
}
if (output & PNL_SEQ_USAGE) {
/* set panel sequence */
swPanelPowerSequence((output & PNL_SEQ_MASK) >> PNL_SEQ_OFFSET, 4);
}
if (output & DAC_USAGE)
setDAC((output & DAC_MASK) >> DAC_OFFSET);
if (output & DPMS_USAGE)
ddk750_setDPMS((output & DPMS_MASK) >> DPMS_OFFSET);
}