|
|
|
@ -56,30 +56,6 @@
|
|
|
|
|
|
|
|
|
|
#include "epdc_regs.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* define the default parameters for the histogram registers
|
|
|
|
|
*/
|
|
|
|
|
#define EPDC_HIST1_P4N_PARAM (0x00000000)
|
|
|
|
|
#define EPDC_HIST2_P4N_PARAM (0x00000f00)
|
|
|
|
|
#define EPDC_HIST4_P4N_PARAM (0x0f0a0500)
|
|
|
|
|
#define EPDC_HIST8_P4N_PARAM0 (0x06040200)
|
|
|
|
|
#define EPDC_HIST8_P4N_PARAM1 (0x0f0d0b09)
|
|
|
|
|
#define EPDC_HIST16_P4N_PARAM0 (0x03020100)
|
|
|
|
|
#define EPDC_HIST16_P4N_PARAM1 (0x07060504)
|
|
|
|
|
#define EPDC_HIST16_P4N_PARAM2 (0x0b0a0908)
|
|
|
|
|
#define EPDC_HIST16_P4N_PARAM3 (0x0f0e0d0c)
|
|
|
|
|
|
|
|
|
|
#define EPDC_HIST1_P5N_PARAM (EPDC_HIST1_P4N_PARAM << 1)
|
|
|
|
|
#define EPDC_HIST2_P5N_PARAM (EPDC_HIST2_P4N_PARAM << 1)
|
|
|
|
|
#define EPDC_HIST4_P5N_PARAM (EPDC_HIST4_P4N_PARAM << 1)
|
|
|
|
|
#define EPDC_HIST8_P5N_PARAM0 (EPDC_HIST8_P4N_PARAM0 << 1)
|
|
|
|
|
#define EPDC_HIST8_P5N_PARAM1 (EPDC_HIST8_P4N_PARAM1 << 1)
|
|
|
|
|
#define EPDC_HIST16_P5N_PARAM0 (EPDC_HIST16_P4N_PARAM0 << 1)
|
|
|
|
|
#define EPDC_HIST16_P5N_PARAM1 (EPDC_HIST16_P4N_PARAM1 << 1)
|
|
|
|
|
#define EPDC_HIST16_P5N_PARAM2 (EPDC_HIST16_P4N_PARAM2 << 1)
|
|
|
|
|
#define EPDC_HIST16_P5N_PARAM3 (EPDC_HIST16_P4N_PARAM3 << 1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Enable this define to have a default panel
|
|
|
|
|
* loaded during driver initialization
|
|
|
|
@ -154,7 +130,7 @@ struct mxc_epdc_fb_data {
|
|
|
|
|
struct fb_var_screeninfo epdc_fb_var; /* Internal copy of screeninfo
|
|
|
|
|
so we can sync changes to it */
|
|
|
|
|
u32 pseudo_palette[16];
|
|
|
|
|
char fw_str[64];
|
|
|
|
|
char fw_str[24];
|
|
|
|
|
struct list_head list;
|
|
|
|
|
struct imx_epdc_fb_mode *cur_mode;
|
|
|
|
|
struct imx_epdc_fb_platform_data *pdata;
|
|
|
|
@ -201,7 +177,6 @@ struct mxc_epdc_fb_data {
|
|
|
|
|
unsigned long last_time_temp_auto_update;
|
|
|
|
|
int temp_index;
|
|
|
|
|
u8 *temp_range_bounds;
|
|
|
|
|
int buf_pix_fmt;
|
|
|
|
|
struct mxcfb_waveform_modes wv_modes;
|
|
|
|
|
bool wv_modes_update;
|
|
|
|
|
u32 *waveform_buffer_virt;
|
|
|
|
@ -242,14 +217,6 @@ struct mxc_epdc_fb_data {
|
|
|
|
|
bool restrict_width; /* work around rev >=2.0 width and
|
|
|
|
|
stride restriction */
|
|
|
|
|
|
|
|
|
|
/* FB elements related to gen2 waveform data */
|
|
|
|
|
u8 *waveform_vcd_buffer;
|
|
|
|
|
u8 *waveform_acd_buffer;
|
|
|
|
|
u32 waveform_magic_number;
|
|
|
|
|
u8 *waveform_xwi_buffer;
|
|
|
|
|
u32 waveform_mc;
|
|
|
|
|
u32 waveform_trc;
|
|
|
|
|
|
|
|
|
|
/* FB elements related to PxP DMA */
|
|
|
|
|
struct completion pxp_tx_cmpl;
|
|
|
|
|
struct pxp_channel *pxp_chan;
|
|
|
|
@ -275,7 +242,7 @@ struct waveform_data_header {
|
|
|
|
|
unsigned int luts:8;
|
|
|
|
|
unsigned int mc:8;
|
|
|
|
|
unsigned int trc:8;
|
|
|
|
|
unsigned int awv:8;
|
|
|
|
|
unsigned int reserved0_0:8;
|
|
|
|
|
unsigned int eb:8;
|
|
|
|
|
unsigned int sb:8;
|
|
|
|
|
unsigned int reserved0_1:8;
|
|
|
|
@ -359,14 +326,14 @@ static struct fb_videomode e97_v110_mode = {
|
|
|
|
|
.flag = 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct fb_videomode es103td1_mode = {
|
|
|
|
|
.name = "ES103TD1",
|
|
|
|
|
static struct fb_videomode es103cs1_mode = {
|
|
|
|
|
.name = "ES103CS1",
|
|
|
|
|
.refresh = 85,
|
|
|
|
|
.xres = 1872,
|
|
|
|
|
.yres = 1404,
|
|
|
|
|
.pixclock = 162500000,
|
|
|
|
|
.pixclock = 160000000,
|
|
|
|
|
.left_margin = 32,
|
|
|
|
|
.right_margin = 334,
|
|
|
|
|
.right_margin = 326,
|
|
|
|
|
.upper_margin = 4,
|
|
|
|
|
.lower_margin = 12,
|
|
|
|
|
.hsync_len = 44,
|
|
|
|
@ -376,18 +343,19 @@ static struct fb_videomode es103td1_mode = {
|
|
|
|
|
.flag = 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct imx_epdc_fb_mode panel_modes[] = {
|
|
|
|
|
{
|
|
|
|
|
&es103td1_mode,
|
|
|
|
|
&es103cs1_mode,
|
|
|
|
|
4, /* vscan_holdoff */
|
|
|
|
|
10, /* sdoed_width */
|
|
|
|
|
20, /* sdoed_delay */
|
|
|
|
|
10, /* sdoez_width */
|
|
|
|
|
20, /* sdoez_delay */
|
|
|
|
|
1048, /* gdclk_hp_offs */
|
|
|
|
|
767, /* gdsp_offs */
|
|
|
|
|
1042, /* gdclk_hp_offs */
|
|
|
|
|
762, /* gdsp_offs */
|
|
|
|
|
0, /* gdoe_offs */
|
|
|
|
|
92, /* gdclk_offs */
|
|
|
|
|
91, /* gdclk_offs */
|
|
|
|
|
1, /* num_ce */
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -933,11 +901,11 @@ static inline int epdc_get_next_lut(void)
|
|
|
|
|
|
|
|
|
|
static int epdc_choose_next_lut(int rev, int *next_lut)
|
|
|
|
|
{
|
|
|
|
|
u64 luts_status, unprocessed_luts;
|
|
|
|
|
bool next_lut_found = false;
|
|
|
|
|
u64 luts_status, unprocessed_luts, used_luts;
|
|
|
|
|
/* Available LUTs are reduced to 16 in 5-bit waveform mode */
|
|
|
|
|
u32 format_p5n = __raw_readl(EPDC_FORMAT) &
|
|
|
|
|
EPDC_FORMAT_BUF_PIXEL_FORMAT_P5N;
|
|
|
|
|
bool format_p5n = ((__raw_readl(EPDC_FORMAT) &
|
|
|
|
|
EPDC_FORMAT_BUF_PIXEL_FORMAT_MASK) ==
|
|
|
|
|
EPDC_FORMAT_BUF_PIXEL_FORMAT_P5N);
|
|
|
|
|
|
|
|
|
|
luts_status = __raw_readl(EPDC_STATUS_LUTS);
|
|
|
|
|
if ((rev < 20) || format_p5n)
|
|
|
|
@ -954,48 +922,43 @@ static int epdc_choose_next_lut(int rev, int *next_lut)
|
|
|
|
|
unprocessed_luts &= 0xFFFF;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (!next_lut_found) {
|
|
|
|
|
/*
|
|
|
|
|
* Selecting a LUT to minimize incidence of TCE Underrun Error
|
|
|
|
|
* --------------------------------------------------------
|
|
|
|
|
* We want to find the lowest order LUT that is of greater
|
|
|
|
|
* order than all other active LUTs. If highest order LUT
|
|
|
|
|
* is active, then we want to choose the lowest order
|
|
|
|
|
* available LUT.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: For EPDC version 2.0 and later, TCE Underrun error
|
|
|
|
|
* bug is fixed, so it doesn't matter which LUT is used.
|
|
|
|
|
*/
|
|
|
|
|
*next_lut = fls64(luts_status);
|
|
|
|
|
/*
|
|
|
|
|
* Note on unprocessed_luts: There is a race condition
|
|
|
|
|
* where a LUT completes, but has not been processed by
|
|
|
|
|
* IRQ handler workqueue, and then a new update request
|
|
|
|
|
* attempts to use that LUT. We prevent that here by
|
|
|
|
|
* ensuring that the LUT we choose doesn't have its IRQ
|
|
|
|
|
* bit set (indicating it has completed but not yet been
|
|
|
|
|
* processed).
|
|
|
|
|
*/
|
|
|
|
|
used_luts = luts_status | unprocessed_luts;
|
|
|
|
|
|
|
|
|
|
if ((rev < 20) || format_p5n) {
|
|
|
|
|
if (*next_lut > 15)
|
|
|
|
|
*next_lut = ffz(luts_status);
|
|
|
|
|
} else {
|
|
|
|
|
if (*next_lut > 63) {
|
|
|
|
|
*next_lut = ffz((u32)luts_status);
|
|
|
|
|
if (*next_lut == -1)
|
|
|
|
|
*next_lut =
|
|
|
|
|
ffz((u32)(luts_status >> 32)) + 32;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Selecting a LUT to minimize incidence of TCE Underrun Error
|
|
|
|
|
* --------------------------------------------------------
|
|
|
|
|
* We want to find the lowest order LUT that is of greater
|
|
|
|
|
* order than all other active LUTs. If highest order LUT
|
|
|
|
|
* is active, then we want to choose the lowest order
|
|
|
|
|
* available LUT.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: For EPDC version 2.0 and later, TCE Underrun error
|
|
|
|
|
* bug is fixed, so it doesn't matter which LUT is used.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Note on unprocessed_luts: There is a race condition
|
|
|
|
|
* where a LUT completes, but has not been processed by
|
|
|
|
|
* IRQ handler workqueue, and then a new update request
|
|
|
|
|
* attempts to use that LUT. We prevent that here by
|
|
|
|
|
* ensuring that the LUT we choose doesn't have its IRQ
|
|
|
|
|
* bit set (indicating it has completed but not yet been
|
|
|
|
|
* processed).
|
|
|
|
|
*/
|
|
|
|
|
if ((1 << *next_lut) & unprocessed_luts)
|
|
|
|
|
luts_status |= (1 << *next_lut);
|
|
|
|
|
if ((rev < 20) || format_p5n) {
|
|
|
|
|
*next_lut = fls64(used_luts);
|
|
|
|
|
if (*next_lut > 15)
|
|
|
|
|
*next_lut = ffz(used_luts);
|
|
|
|
|
} else {
|
|
|
|
|
if ((u32)used_luts != ~0UL)
|
|
|
|
|
*next_lut = ffz((u32)used_luts);
|
|
|
|
|
else if ((u32)(used_luts >> 32) != ~0UL)
|
|
|
|
|
*next_lut = ffz((u32)(used_luts >> 32)) + 32;
|
|
|
|
|
else
|
|
|
|
|
next_lut_found = true;
|
|
|
|
|
*next_lut = INVALID_LUT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (luts_status & 0x8000)
|
|
|
|
|
if (used_luts & 0x8000)
|
|
|
|
|
return 1;
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
@ -1033,7 +996,7 @@ static inline bool epdc_is_collision(void)
|
|
|
|
|
|
|
|
|
|
static inline u64 epdc_get_colliding_luts(int rev)
|
|
|
|
|
{
|
|
|
|
|
u64 val = __raw_readl(EPDC_STATUS_COL);
|
|
|
|
|
u32 val = __raw_readl(EPDC_STATUS_COL);
|
|
|
|
|
if (rev >= 20)
|
|
|
|
|
val |= (u64)__raw_readl(EPDC_STATUS_COL2) << 32;
|
|
|
|
|
return val;
|
|
|
|
@ -1101,9 +1064,9 @@ static void epdc_init_settings(struct mxc_epdc_fb_data *fb_data)
|
|
|
|
|
reg_val |= EPDC_CTRL_LUT_DATA_SWIZZLE_NO_SWAP;
|
|
|
|
|
__raw_writel(reg_val, EPDC_CTRL_SET);
|
|
|
|
|
|
|
|
|
|
/* EPDC_FORMAT - 2bit TFT and buf_pix_fmt Buf pixel format */
|
|
|
|
|
/* EPDC_FORMAT - 2bit TFT and 4bit Buf pixel format */
|
|
|
|
|
reg_val = EPDC_FORMAT_TFT_PIXEL_FORMAT_2BIT
|
|
|
|
|
| fb_data->buf_pix_fmt
|
|
|
|
|
| EPDC_FORMAT_BUF_PIXEL_FORMAT_P4N
|
|
|
|
|
| ((0x0 << EPDC_FORMAT_DEFAULT_TFT_PIXEL_OFFSET) &
|
|
|
|
|
EPDC_FORMAT_DEFAULT_TFT_PIXEL_MASK);
|
|
|
|
|
__raw_writel(reg_val, EPDC_FORMAT);
|
|
|
|
@ -1119,7 +1082,7 @@ static void epdc_init_settings(struct mxc_epdc_fb_data *fb_data)
|
|
|
|
|
__raw_writel(reg_val, EPDC_FIFOCTRL);
|
|
|
|
|
|
|
|
|
|
/* EPDC_TEMP - Use default temp to get index */
|
|
|
|
|
epdc_set_temp(fb_data->temp_index = mxc_epdc_fb_get_temp_index(fb_data, DEFAULT_TEMP));
|
|
|
|
|
epdc_set_temp(mxc_epdc_fb_get_temp_index(fb_data, DEFAULT_TEMP));
|
|
|
|
|
|
|
|
|
|
/* EPDC_RES */
|
|
|
|
|
epdc_set_screen_res(epdc_mode->vmode->xres, epdc_mode->vmode->yres);
|
|
|
|
@ -1250,33 +1213,6 @@ static void epdc_init_settings(struct mxc_epdc_fb_data *fb_data)
|
|
|
|
|
__raw_writel(fb_data->working_buffer_phys, EPDC_WB_ADDR);
|
|
|
|
|
__raw_writel(fb_data->working_buffer_phys, EPDC_WB_ADDR_TCE);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* init histogram registers according to the buffer pixel format
|
|
|
|
|
*/
|
|
|
|
|
if (fb_data->buf_pix_fmt == EPDC_FORMAT_BUF_PIXEL_FORMAT_P4N) {
|
|
|
|
|
__raw_writel(EPDC_HIST1_P4N_PARAM, EPDC_HIST1_PARAM);
|
|
|
|
|
__raw_writel(EPDC_HIST2_P4N_PARAM, EPDC_HIST2_PARAM);
|
|
|
|
|
__raw_writel(EPDC_HIST4_P4N_PARAM, EPDC_HIST4_PARAM);
|
|
|
|
|
__raw_writel(EPDC_HIST8_P4N_PARAM0, EPDC_HIST8_PARAM0);
|
|
|
|
|
__raw_writel(EPDC_HIST8_P4N_PARAM1, EPDC_HIST8_PARAM1);
|
|
|
|
|
__raw_writel(EPDC_HIST16_P4N_PARAM0, EPDC_HIST16_PARAM0);
|
|
|
|
|
__raw_writel(EPDC_HIST16_P4N_PARAM1, EPDC_HIST16_PARAM1);
|
|
|
|
|
__raw_writel(EPDC_HIST16_P4N_PARAM2, EPDC_HIST16_PARAM2);
|
|
|
|
|
__raw_writel(EPDC_HIST16_P4N_PARAM3, EPDC_HIST16_PARAM3);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
__raw_writel(EPDC_HIST1_P5N_PARAM, EPDC_HIST1_PARAM);
|
|
|
|
|
__raw_writel(EPDC_HIST2_P5N_PARAM, EPDC_HIST2_PARAM);
|
|
|
|
|
__raw_writel(EPDC_HIST4_P5N_PARAM, EPDC_HIST4_PARAM);
|
|
|
|
|
__raw_writel(EPDC_HIST8_P5N_PARAM0, EPDC_HIST8_PARAM0);
|
|
|
|
|
__raw_writel(EPDC_HIST8_P5N_PARAM1, EPDC_HIST8_PARAM1);
|
|
|
|
|
__raw_writel(EPDC_HIST16_P5N_PARAM0, EPDC_HIST16_PARAM0);
|
|
|
|
|
__raw_writel(EPDC_HIST16_P5N_PARAM1, EPDC_HIST16_PARAM1);
|
|
|
|
|
__raw_writel(EPDC_HIST16_P5N_PARAM2, EPDC_HIST16_PARAM2);
|
|
|
|
|
__raw_writel(EPDC_HIST16_P5N_PARAM3, EPDC_HIST16_PARAM3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Disable clock */
|
|
|
|
|
clk_disable_unprepare(fb_data->epdc_clk_axi);
|
|
|
|
|
clk_disable_unprepare(fb_data->epdc_clk_pix);
|
|
|
|
@ -1326,7 +1262,7 @@ static void epdc_powerup(struct mxc_epdc_fb_data *fb_data)
|
|
|
|
|
ret = regulator_enable(fb_data->display_regulator);
|
|
|
|
|
if (IS_ERR((void *)ret)) {
|
|
|
|
|
dev_err(fb_data->dev, "Unable to enable DISPLAY regulator."
|
|
|
|
|
"err = %ld\n", PTR_ERR((void*)ret));
|
|
|
|
|
"err = %d\n", PTR_ERR(ret));
|
|
|
|
|
mutex_unlock(&fb_data->power_mutex);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
@ -1737,26 +1673,28 @@ static int mxc_epdc_fb_set_par(struct fb_info *info)
|
|
|
|
|
* If requested video mode does not match current video
|
|
|
|
|
* mode, search for a matching panel.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (fb_data->cur_mode &&
|
|
|
|
|
fb_mode_is_equal(&cur_mode, &mode)) {
|
|
|
|
|
found_match = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
|
|
/* Match videomode against epdc modes */
|
|
|
|
|
for (i = 0; i < fb_data->pdata->num_modes; i++) {
|
|
|
|
|
if (!fb_mode_is_equal(epdc_modes[i].vmode, &mode))
|
|
|
|
|
cur_mode = *(epdc_modes[i].vmode);
|
|
|
|
|
cur_mode.pixclock = 1000000000/(fb_data->cur_mode->vmode->pixclock/1000);
|
|
|
|
|
if (!fb_mode_is_equal(&cur_mode, &mode))
|
|
|
|
|
continue;
|
|
|
|
|
fb_data->cur_mode = &epdc_modes[i];
|
|
|
|
|
found_match = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found_match) {
|
|
|
|
|
dev_err(fb_data->dev,
|
|
|
|
|
"Failed to match requested video mode\n");
|
|
|
|
|
return EINVAL;
|
|
|
|
|
if (!found_match) {
|
|
|
|
|
dev_err(fb_data->dev,
|
|
|
|
|
"Failed to match requested video mode\n");
|
|
|
|
|
return EINVAL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Found a match - Grab timing params */
|
|
|
|
@ -1960,13 +1898,12 @@ static int mxc_epdc_fb_get_temp_index(struct mxc_epdc_fb_data *fb_data, int temp
|
|
|
|
|
|
|
|
|
|
if (fb_data->trt_entries == 0) {
|
|
|
|
|
dev_err(fb_data->dev,
|
|
|
|
|
"No TRT index match (%d)...using default temp index\n",
|
|
|
|
|
temp);
|
|
|
|
|
"No TRT exists...using default temp index\n");
|
|
|
|
|
return DEFAULT_TEMP_INDEX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Search temperature ranges for a match */
|
|
|
|
|
for (i = 0; i < fb_data->trt_entries; i++) {
|
|
|
|
|
for (i = 0; i < fb_data->trt_entries - 1; i++) {
|
|
|
|
|
if ((temp >= fb_data->temp_range_bounds[i])
|
|
|
|
|
&& (temp < fb_data->temp_range_bounds[i+1])) {
|
|
|
|
|
index = i;
|
|
|
|
@ -1983,11 +1920,6 @@ static int mxc_epdc_fb_get_temp_index(struct mxc_epdc_fb_data *fb_data, int temp
|
|
|
|
|
dev_dbg(fb_data->dev, "temperature >= maximum range\n");
|
|
|
|
|
return fb_data->trt_entries-1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev_err(fb_data->dev,
|
|
|
|
|
"No TRT index match (%d)...using default temp index\n",
|
|
|
|
|
temp);
|
|
|
|
|
|
|
|
|
|
return DEFAULT_TEMP_INDEX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2393,9 +2325,6 @@ static int epdc_process_update(struct update_data_list *upd_data_list,
|
|
|
|
|
if (fb_data->epdc_fb_var.grayscale == GRAYSCALE_8BIT_INVERTED)
|
|
|
|
|
fb_data->pxp_conf.proc_data.lut_transform ^= PXP_LUT_INVERT;
|
|
|
|
|
|
|
|
|
|
/* Disable PxP LUT option to configure pixel data for AA processing */
|
|
|
|
|
fb_data->pxp_conf.proc_data.lut_transform |= PXP_LUT_AA;
|
|
|
|
|
|
|
|
|
|
/* This is a blocking call, so upon return PxP tx should be done */
|
|
|
|
|
ret = pxp_process_update(fb_data, src_width, src_height,
|
|
|
|
|
&pxp_upd_region);
|
|
|
|
@ -2540,6 +2469,7 @@ static int epdc_submit_merge(struct update_desc_list *upd_desc_list,
|
|
|
|
|
|
|
|
|
|
static void epdc_submit_work_func(struct work_struct *work)
|
|
|
|
|
{
|
|
|
|
|
int temp_index;
|
|
|
|
|
struct update_data_list *next_update, *temp_update;
|
|
|
|
|
struct update_desc_list *next_desc, *temp_desc;
|
|
|
|
|
struct update_marker_data *next_marker, *temp_marker;
|
|
|
|
@ -2692,18 +2622,14 @@ static void epdc_submit_work_func(struct work_struct *work)
|
|
|
|
|
* - FB unrotated
|
|
|
|
|
* - FB pixel format = 8-bit grayscale
|
|
|
|
|
* - No look-up transformations (inversion, posterization, etc.)
|
|
|
|
|
* - No advance algorithms, which requires a look-up transformation
|
|
|
|
|
* to convert from 4-bit to 5-bit lookup mode
|
|
|
|
|
*
|
|
|
|
|
* Note: A bug with EPDC stride prevents us from skipping
|
|
|
|
|
* PxP in versions 2.0 and earlier of EPDC.
|
|
|
|
|
*/
|
|
|
|
|
is_transform = (upd_data_list->update_desc->upd_data.flags &
|
|
|
|
|
(EPDC_FLAG_ENABLE_INVERSION |
|
|
|
|
|
EPDC_FLAG_USE_DITHERING_Y1 | EPDC_FLAG_USE_DITHERING_Y4 |
|
|
|
|
|
EPDC_FLAG_FORCE_MONOCHROME | EPDC_FLAG_USE_CMAP)) ||
|
|
|
|
|
(fb_data->buf_pix_fmt == EPDC_FORMAT_BUF_PIXEL_FORMAT_P5N) ?
|
|
|
|
|
true : false;
|
|
|
|
|
is_transform = upd_data_list->update_desc->upd_data.flags &
|
|
|
|
|
(EPDC_FLAG_ENABLE_INVERSION | EPDC_FLAG_USE_DITHERING_Y1 |
|
|
|
|
|
EPDC_FLAG_USE_DITHERING_Y4 | EPDC_FLAG_FORCE_MONOCHROME |
|
|
|
|
|
EPDC_FLAG_USE_CMAP) ? true : false;
|
|
|
|
|
|
|
|
|
|
if ((fb_data->epdc_fb_var.rotate == FB_ROTATE_UR) &&
|
|
|
|
|
(fb_data->epdc_fb_var.grayscale == GRAYSCALE_8BIT) &&
|
|
|
|
@ -2799,7 +2725,7 @@ static void epdc_submit_work_func(struct work_struct *work)
|
|
|
|
|
err_dist = kzalloc((fb_data->info.var.xres_virtual + 3) * 3
|
|
|
|
|
* sizeof(int), GFP_KERNEL);
|
|
|
|
|
|
|
|
|
|
/* Dithering Y8 -> Y4 */
|
|
|
|
|
/* Dithering Y8 -> Y1 */
|
|
|
|
|
do_dithering_processing_Y1_v1_0(
|
|
|
|
|
(uint8_t *)(upd_data_list->virt_addr +
|
|
|
|
|
upd_data_list->update_desc->epdc_offs),
|
|
|
|
@ -2833,7 +2759,6 @@ static void epdc_submit_work_func(struct work_struct *work)
|
|
|
|
|
kfree(err_dist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If there are no LUTs available,
|
|
|
|
|
* then we must wait for the resource to become free.
|
|
|
|
@ -2920,10 +2845,12 @@ static void epdc_submit_work_func(struct work_struct *work)
|
|
|
|
|
epdc_working_buf_intr(true);
|
|
|
|
|
|
|
|
|
|
/* Program EPDC update to process buffer */
|
|
|
|
|
if (upd_data_list->update_desc->upd_data.temp != TEMP_USE_AMBIENT)
|
|
|
|
|
fb_data->temp_index = mxc_epdc_fb_get_temp_index(fb_data,
|
|
|
|
|
if (upd_data_list->update_desc->upd_data.temp != TEMP_USE_AMBIENT) {
|
|
|
|
|
temp_index = mxc_epdc_fb_get_temp_index(fb_data,
|
|
|
|
|
upd_data_list->update_desc->upd_data.temp);
|
|
|
|
|
epdc_set_temp(fb_data->temp_index);
|
|
|
|
|
epdc_set_temp(temp_index);
|
|
|
|
|
} else
|
|
|
|
|
epdc_set_temp(fb_data->temp_index);
|
|
|
|
|
epdc_set_update_addr(update_addr);
|
|
|
|
|
epdc_set_update_coord(adj_update_region.left, adj_update_region.top);
|
|
|
|
|
epdc_set_update_dimensions(adj_update_region.width,
|
|
|
|
@ -2937,8 +2864,6 @@ static void epdc_submit_work_func(struct work_struct *work)
|
|
|
|
|
fb_data->wv_modes_update = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__raw_writel(fb_data->working_buffer_phys, EPDC_WB_ADDR_TCE);
|
|
|
|
|
|
|
|
|
|
epdc_submit_update(upd_data_list->lut_num,
|
|
|
|
|
upd_data_list->update_desc->upd_data.waveform_mode,
|
|
|
|
|
upd_data_list->update_desc->upd_data.update_mode,
|
|
|
|
@ -2957,6 +2882,7 @@ static int mxc_epdc_fb_send_single_update(struct mxcfb_update_data *upd_data,
|
|
|
|
|
(struct mxc_epdc_fb_data *)info:g_fb_data;
|
|
|
|
|
struct update_data_list *upd_data_list = NULL;
|
|
|
|
|
struct mxcfb_rect *screen_upd_region; /* Region on screen to update */
|
|
|
|
|
int temp_index;
|
|
|
|
|
int ret;
|
|
|
|
|
struct update_desc_list *upd_desc;
|
|
|
|
|
struct update_marker_data *marker_data, *next_marker, *temp_marker;
|
|
|
|
@ -3230,10 +3156,12 @@ static int mxc_epdc_fb_send_single_update(struct mxcfb_update_data *upd_data,
|
|
|
|
|
screen_upd_region->height);
|
|
|
|
|
if (fb_data->rev > 20)
|
|
|
|
|
epdc_set_update_stride(upd_desc->epdc_stride);
|
|
|
|
|
if (upd_desc->upd_data.temp != TEMP_USE_AMBIENT)
|
|
|
|
|
fb_data->temp_index = mxc_epdc_fb_get_temp_index(fb_data,
|
|
|
|
|
if (upd_desc->upd_data.temp != TEMP_USE_AMBIENT) {
|
|
|
|
|
temp_index = mxc_epdc_fb_get_temp_index(fb_data,
|
|
|
|
|
upd_desc->upd_data.temp);
|
|
|
|
|
epdc_set_temp(fb_data->temp_index);
|
|
|
|
|
epdc_set_temp(temp_index);
|
|
|
|
|
} else
|
|
|
|
|
epdc_set_temp(fb_data->temp_index);
|
|
|
|
|
if (fb_data->wv_modes_update &&
|
|
|
|
|
(upd_desc->upd_data.waveform_mode == WAVEFORM_MODE_AUTO)) {
|
|
|
|
|
epdc_set_update_waveform(&fb_data->wv_modes);
|
|
|
|
@ -3244,7 +3172,8 @@ static int mxc_epdc_fb_send_single_update(struct mxcfb_update_data *upd_data,
|
|
|
|
|
upd_desc->upd_data.waveform_mode,
|
|
|
|
|
upd_desc->upd_data.update_mode,
|
|
|
|
|
(upd_desc->upd_data.flags
|
|
|
|
|
& EPDC_FLAG_TEST_COLLISION) ? true : false, false, 0);
|
|
|
|
|
& EPDC_FLAG_TEST_COLLISION) ? true : false,
|
|
|
|
|
false, 0);
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&fb_data->queue_mutex);
|
|
|
|
|
return 0;
|
|
|
|
@ -3494,6 +3423,47 @@ static int mxc_epdc_fb_ioctl(struct fb_info *info, unsigned int cmd,
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case MXCFB_GET_WORK_BUFFER:
|
|
|
|
|
{
|
|
|
|
|
/* copy the epdc working buffer to the user space */
|
|
|
|
|
struct mxc_epdc_fb_data *fb_data = info ?
|
|
|
|
|
(struct mxc_epdc_fb_data *)info:g_fb_data;
|
|
|
|
|
flush_cache_all();
|
|
|
|
|
outer_flush_range(fb_data->working_buffer_phys,
|
|
|
|
|
fb_data->working_buffer_phys +
|
|
|
|
|
fb_data->working_buffer_size);
|
|
|
|
|
if (copy_to_user((void __user *)arg,
|
|
|
|
|
(const void *) fb_data->working_buffer_virt,
|
|
|
|
|
fb_data->working_buffer_size))
|
|
|
|
|
ret = -EFAULT;
|
|
|
|
|
else
|
|
|
|
|
ret = 0;
|
|
|
|
|
flush_cache_all();
|
|
|
|
|
outer_flush_range(fb_data->working_buffer_phys,
|
|
|
|
|
fb_data->working_buffer_phys +
|
|
|
|
|
fb_data->working_buffer_size);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case MXCFB_DISABLE_EPDC_ACCESS:
|
|
|
|
|
{
|
|
|
|
|
struct mxc_epdc_fb_data *fb_data = info ?
|
|
|
|
|
(struct mxc_epdc_fb_data *)info:g_fb_data;
|
|
|
|
|
mxc_epdc_fb_flush_updates(fb_data);
|
|
|
|
|
/* disable handling any user update request */
|
|
|
|
|
mutex_lock(&hard_lock);
|
|
|
|
|
ret = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case MXCFB_ENABLE_EPDC_ACCESS:
|
|
|
|
|
{
|
|
|
|
|
/* enable user update handling again */
|
|
|
|
|
mutex_unlock(&hard_lock);
|
|
|
|
|
ret = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -3826,6 +3796,7 @@ static void epdc_intr_work_func(struct work_struct *work)
|
|
|
|
|
struct mxcfb_rect *next_upd_region;
|
|
|
|
|
struct update_marker_data *next_marker;
|
|
|
|
|
struct update_marker_data *temp;
|
|
|
|
|
int temp_index;
|
|
|
|
|
u64 temp_mask;
|
|
|
|
|
u32 lut;
|
|
|
|
|
bool ignore_collision = false;
|
|
|
|
@ -3833,14 +3804,12 @@ static void epdc_intr_work_func(struct work_struct *work)
|
|
|
|
|
bool wb_lut_done = false;
|
|
|
|
|
bool free_update = true;
|
|
|
|
|
int next_lut, epdc_next_lut_15;
|
|
|
|
|
u32 epdc_luts_active, epdc_wb_busy, epdc_upd_done, epdc_luts_avail;
|
|
|
|
|
u32 epdc_lut_cancelled;
|
|
|
|
|
u32 epdc_luts_active, epdc_wb_busy, epdc_luts_avail, epdc_lut_cancelled;
|
|
|
|
|
u32 epdc_collision;
|
|
|
|
|
u64 epdc_irq_stat;
|
|
|
|
|
bool epdc_waiting_on_wb;
|
|
|
|
|
u32 coll_coord, coll_size;
|
|
|
|
|
struct mxcfb_rect coll_region;
|
|
|
|
|
bool update_is_valid = true;
|
|
|
|
|
|
|
|
|
|
/* Protect access to buffer queues and to update HW */
|
|
|
|
|
mutex_lock(&fb_data->queue_mutex);
|
|
|
|
@ -3848,7 +3817,6 @@ static void epdc_intr_work_func(struct work_struct *work)
|
|
|
|
|
/* Capture EPDC status one time to limit exposure to race conditions */
|
|
|
|
|
epdc_luts_active = epdc_any_luts_active(fb_data->rev);
|
|
|
|
|
epdc_wb_busy = epdc_is_working_buffer_busy();
|
|
|
|
|
epdc_upd_done = __raw_readl(EPDC_IRQ) & EPDC_IRQ_UPD_DONE_IRQ;
|
|
|
|
|
epdc_lut_cancelled = epdc_is_lut_cancelled();
|
|
|
|
|
epdc_luts_avail = epdc_any_luts_available();
|
|
|
|
|
epdc_collision = epdc_is_collision();
|
|
|
|
@ -3877,7 +3845,7 @@ static void epdc_intr_work_func(struct work_struct *work)
|
|
|
|
|
list_for_each_entry(collision_update,
|
|
|
|
|
&fb_data->upd_buf_collision_list, list) {
|
|
|
|
|
collision_update->collision_mask =
|
|
|
|
|
collision_update->collision_mask & ~(1ULL << i);
|
|
|
|
|
collision_update->collision_mask & ~(1 << i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
epdc_clear_lut_complete_irq(fb_data->rev, i);
|
|
|
|
@ -3972,13 +3940,6 @@ static void epdc_intr_work_func(struct work_struct *work)
|
|
|
|
|
fb_data->waiting_for_wb = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Handle 3 possible events exclusive of each other, in
|
|
|
|
|
* the following priority order:
|
|
|
|
|
* 1) This is a collision test update
|
|
|
|
|
* 2) The LUT was cancelled (no pixels changing)
|
|
|
|
|
* 3) The update is being paused after WB processing
|
|
|
|
|
*/
|
|
|
|
|
if (fb_data->cur_update->update_desc->upd_data.flags
|
|
|
|
|
& EPDC_FLAG_TEST_COLLISION) {
|
|
|
|
|
/* This was a dry run to test for collision */
|
|
|
|
@ -4007,8 +3968,6 @@ static void epdc_intr_work_func(struct work_struct *work)
|
|
|
|
|
"for dry-run - %d\n",
|
|
|
|
|
next_marker->update_marker);
|
|
|
|
|
complete(&next_marker->update_completion);
|
|
|
|
|
|
|
|
|
|
update_is_valid = false;
|
|
|
|
|
}
|
|
|
|
|
} else if (epdc_lut_cancelled && !epdc_collision) {
|
|
|
|
|
/*
|
|
|
|
@ -4054,15 +4013,8 @@ static void epdc_intr_work_func(struct work_struct *work)
|
|
|
|
|
else
|
|
|
|
|
kfree(next_marker);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
update_is_valid = false;
|
|
|
|
|
} else {
|
|
|
|
|
dev_dbg(fb_data->dev,
|
|
|
|
|
"\nNo pausing this time folks!\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (epdc_collision & update_is_valid) {
|
|
|
|
|
/* aa update (no dry-run), collision occurred */
|
|
|
|
|
} else if (epdc_collision) {
|
|
|
|
|
/* Real update (no dry-run), collision occurred */
|
|
|
|
|
|
|
|
|
|
/* Check list of colliding LUTs, and add to our collision mask */
|
|
|
|
|
fb_data->cur_update->collision_mask =
|
|
|
|
@ -4336,10 +4288,12 @@ static void epdc_intr_work_func(struct work_struct *work)
|
|
|
|
|
next_upd_region =
|
|
|
|
|
&fb_data->cur_update->update_desc->upd_data.update_region;
|
|
|
|
|
if (fb_data->cur_update->update_desc->upd_data.temp
|
|
|
|
|
!= TEMP_USE_AMBIENT)
|
|
|
|
|
fb_data->temp_index = mxc_epdc_fb_get_temp_index(fb_data,
|
|
|
|
|
!= TEMP_USE_AMBIENT) {
|
|
|
|
|
temp_index = mxc_epdc_fb_get_temp_index(fb_data,
|
|
|
|
|
fb_data->cur_update->update_desc->upd_data.temp);
|
|
|
|
|
epdc_set_temp(fb_data->temp_index);
|
|
|
|
|
epdc_set_temp(temp_index);
|
|
|
|
|
} else
|
|
|
|
|
epdc_set_temp(fb_data->temp_index);
|
|
|
|
|
epdc_set_update_addr(fb_data->cur_update->phys_addr +
|
|
|
|
|
fb_data->cur_update->update_desc->epdc_offs);
|
|
|
|
|
epdc_set_update_coord(next_upd_region->left, next_upd_region->top);
|
|
|
|
@ -4447,16 +4401,13 @@ static void mxc_epdc_fb_fw_handler(const struct firmware *fw,
|
|
|
|
|
|
|
|
|
|
/* Get size and allocate temperature range table */
|
|
|
|
|
fb_data->trt_entries = wv_file->wdh.trc + 1;
|
|
|
|
|
fb_data->temp_range_bounds = kzalloc(fb_data->trt_entries + 1,
|
|
|
|
|
GFP_KERNEL);
|
|
|
|
|
fb_data->temp_range_bounds = kzalloc(fb_data->trt_entries, GFP_KERNEL);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i <= fb_data->trt_entries; i++)
|
|
|
|
|
dev_dbg(fb_data->dev, "trt entry #%d = 0x%x\n", i,
|
|
|
|
|
*((u8 *)&wv_file->data + i));
|
|
|
|
|
for (i = 0; i < fb_data->trt_entries; i++)
|
|
|
|
|
dev_dbg(fb_data->dev, "trt entry #%d = 0x%x\n", i, *((u8 *)&wv_file->data + i));
|
|
|
|
|
|
|
|
|
|
/* Copy TRT data */
|
|
|
|
|
memcpy(fb_data->temp_range_bounds, &wv_file->data,
|
|
|
|
|
fb_data->trt_entries + 1);
|
|
|
|
|
memcpy(fb_data->temp_range_bounds, &wv_file->data, fb_data->trt_entries);
|
|
|
|
|
|
|
|
|
|
/* Set default temperature index using TRT and room temp */
|
|
|
|
|
fb_data->temp_index = mxc_epdc_fb_get_temp_index(fb_data, DEFAULT_TEMP);
|
|
|
|
@ -4468,164 +4419,6 @@ static void mxc_epdc_fb_fw_handler(const struct firmware *fw,
|
|
|
|
|
wv_data_offs = sizeof(wv_file->wdh) + fb_data->trt_entries + 1;
|
|
|
|
|
fb_data->waveform_buffer_size = fw->size - wv_data_offs;
|
|
|
|
|
|
|
|
|
|
/* process 2nd generation waveform data which may contain
|
|
|
|
|
* the voltage control data, advance waveform data,
|
|
|
|
|
* and extra waveform data
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
int awv, wmc, wtrc, xwia;
|
|
|
|
|
u64 longOffset;
|
|
|
|
|
u32 bufferSize;
|
|
|
|
|
u8 *fwDataBuffer = (u8 *)(fw->data) + wv_data_offs;
|
|
|
|
|
|
|
|
|
|
wtrc = wv_file->wdh.trc + 1;
|
|
|
|
|
wmc = wv_file->wdh.mc + 1;
|
|
|
|
|
awv = wv_file->wdh.awv;
|
|
|
|
|
xwia = wv_file->wdh.xwia;
|
|
|
|
|
memcpy (&longOffset,fwDataBuffer,8);
|
|
|
|
|
if ((unsigned) longOffset > (8*wmc))
|
|
|
|
|
{
|
|
|
|
|
u64 avcOffset, acdOffset, acdMagic, xwiOffset;
|
|
|
|
|
avcOffset = acdOffset = acdMagic = xwiOffset = 0l;
|
|
|
|
|
/* look at the advance waveform flags */
|
|
|
|
|
switch ( awv ) {
|
|
|
|
|
case 0 : /* voltage control flag is set */
|
|
|
|
|
if (xwia > 0) {
|
|
|
|
|
/* extra waveform information */
|
|
|
|
|
memcpy (&xwiOffset,fwDataBuffer + (8*wmc),8);
|
|
|
|
|
bufferSize = (unsigned)(fb_data->waveform_buffer_size - xwiOffset);
|
|
|
|
|
fb_data->waveform_xwi_buffer = kmalloc(bufferSize, GFP_KERNEL);
|
|
|
|
|
memcpy(fb_data->waveform_xwi_buffer, fwDataBuffer+xwiOffset, bufferSize );
|
|
|
|
|
fb_data->waveform_buffer_size = xwiOffset;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 1 : /* voltage control flag is set */
|
|
|
|
|
memcpy (&avcOffset,fwDataBuffer + (8*wmc),8);
|
|
|
|
|
if (xwia > 0) {
|
|
|
|
|
/* extra waveform information */
|
|
|
|
|
memcpy (&xwiOffset,fwDataBuffer + (8*wmc) +8,8);
|
|
|
|
|
bufferSize = (unsigned)(fb_data->waveform_buffer_size - xwiOffset);
|
|
|
|
|
fb_data->waveform_xwi_buffer = kmalloc(bufferSize, GFP_KERNEL);
|
|
|
|
|
/* voltage control data */
|
|
|
|
|
memcpy(fb_data->waveform_xwi_buffer, fwDataBuffer+xwiOffset, bufferSize );
|
|
|
|
|
bufferSize = (unsigned)(xwiOffset - avcOffset);
|
|
|
|
|
fb_data->waveform_vcd_buffer = kmalloc(bufferSize, GFP_KERNEL);
|
|
|
|
|
memcpy(fb_data->waveform_vcd_buffer, fwDataBuffer+avcOffset, bufferSize );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* voltage control data */
|
|
|
|
|
bufferSize = (unsigned)(fb_data->waveform_buffer_size - avcOffset);
|
|
|
|
|
fb_data->waveform_vcd_buffer = kmalloc(bufferSize, GFP_KERNEL);
|
|
|
|
|
memcpy(fb_data->waveform_vcd_buffer, fwDataBuffer+avcOffset, bufferSize );
|
|
|
|
|
}
|
|
|
|
|
fb_data->waveform_buffer_size = avcOffset;
|
|
|
|
|
break;
|
|
|
|
|
case 2 : /* voltage control flag is set */
|
|
|
|
|
memcpy (&acdOffset,fwDataBuffer + (8*wmc),8);
|
|
|
|
|
memcpy (&acdMagic,fwDataBuffer + (8*wmc) + 8,8);
|
|
|
|
|
if (xwia > 0) {
|
|
|
|
|
/* extra waveform information */
|
|
|
|
|
memcpy (&xwiOffset,fwDataBuffer + (8*wmc) + 16,8);
|
|
|
|
|
bufferSize = (unsigned)(fb_data->waveform_buffer_size - xwiOffset);
|
|
|
|
|
fb_data->waveform_xwi_buffer = kmalloc(bufferSize, GFP_KERNEL);
|
|
|
|
|
memcpy(fb_data->waveform_xwi_buffer, fwDataBuffer+xwiOffset, bufferSize );
|
|
|
|
|
/* algorithm control data */
|
|
|
|
|
bufferSize = (unsigned)(xwiOffset - acdOffset);
|
|
|
|
|
fb_data->waveform_acd_buffer = kmalloc(bufferSize, GFP_KERNEL);
|
|
|
|
|
memcpy(fb_data->waveform_acd_buffer, fwDataBuffer+acdOffset, bufferSize );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* algorithm control data */
|
|
|
|
|
bufferSize = (unsigned)(fb_data->waveform_buffer_size - acdOffset);
|
|
|
|
|
fb_data->waveform_acd_buffer = kmalloc(bufferSize, GFP_KERNEL);
|
|
|
|
|
memcpy(fb_data->waveform_acd_buffer, fwDataBuffer+acdOffset, bufferSize );
|
|
|
|
|
}
|
|
|
|
|
fb_data->waveform_buffer_size = acdOffset;
|
|
|
|
|
break;
|
|
|
|
|
case 3 : /* voltage control flag is set */
|
|
|
|
|
memcpy (&avcOffset,fwDataBuffer + (8*wmc),8);
|
|
|
|
|
memcpy (&acdOffset,fwDataBuffer + (8*wmc) + 8,8);
|
|
|
|
|
memcpy (&acdMagic,fwDataBuffer + (8*wmc) + 16,8);
|
|
|
|
|
if (xwia > 0) {
|
|
|
|
|
/* extra waveform information */
|
|
|
|
|
memcpy (&xwiOffset,fwDataBuffer + (8*wmc) + 24,8);
|
|
|
|
|
bufferSize = (unsigned)(fb_data->waveform_buffer_size - xwiOffset);
|
|
|
|
|
fb_data->waveform_xwi_buffer = kmalloc(bufferSize, GFP_KERNEL);
|
|
|
|
|
memcpy(fb_data->waveform_xwi_buffer, fwDataBuffer+xwiOffset, bufferSize );
|
|
|
|
|
/* algorithm control data */
|
|
|
|
|
bufferSize = (unsigned)(xwiOffset - acdOffset);
|
|
|
|
|
fb_data->waveform_acd_buffer = kmalloc(bufferSize, GFP_KERNEL);
|
|
|
|
|
memcpy(fb_data->waveform_acd_buffer, fwDataBuffer+acdOffset, bufferSize );
|
|
|
|
|
/* voltage control data */
|
|
|
|
|
bufferSize = (unsigned)(acdOffset - avcOffset);
|
|
|
|
|
fb_data->waveform_vcd_buffer = kmalloc(bufferSize, GFP_KERNEL);
|
|
|
|
|
memcpy(fb_data->waveform_vcd_buffer, fwDataBuffer+avcOffset, bufferSize );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* algorithm control data */
|
|
|
|
|
bufferSize = (unsigned)(fb_data->waveform_buffer_size - acdOffset);
|
|
|
|
|
fb_data->waveform_acd_buffer = kmalloc(bufferSize, GFP_KERNEL);
|
|
|
|
|
memcpy(fb_data->waveform_acd_buffer, fwDataBuffer+avcOffset, bufferSize );
|
|
|
|
|
/* voltage control data */
|
|
|
|
|
bufferSize = (unsigned)(acdOffset - avcOffset);
|
|
|
|
|
fb_data->waveform_vcd_buffer = kmalloc(bufferSize, GFP_KERNEL);
|
|
|
|
|
memcpy(fb_data->waveform_vcd_buffer, fwDataBuffer+avcOffset, bufferSize );
|
|
|
|
|
}
|
|
|
|
|
fb_data->waveform_buffer_size = avcOffset;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (acdMagic) fb_data->waveform_magic_number = acdMagic;
|
|
|
|
|
/* store the waveform mode count and waveform temperature range count
|
|
|
|
|
*/
|
|
|
|
|
fb_data->waveform_mc = wmc;
|
|
|
|
|
fb_data->waveform_trc =wtrc;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* get the extra waveform info and display it - This can be removed! It is here for illustration only */
|
|
|
|
|
/*if (fb_data->waveform_xwi_buffer) {
|
|
|
|
|
char *xwiString;
|
|
|
|
|
unsigned strLength = mxc_epdc_fb_fetch_wxi_data(fb_data->waveform_xwi_buffer, NULL);
|
|
|
|
|
|
|
|
|
|
dev_info(fb_data->dev, " --- Extra Waveform Data length: %d bytes---\n",strLength);
|
|
|
|
|
if (strLength > 0) {
|
|
|
|
|
xwiString = (char *) kmalloc(strLength + 1, GFP_KERNEL);
|
|
|
|
|
if (mxc_epdc_fb_fetch_wxi_data(fb_data->waveform_xwi_buffer, xwiString) > 0) {
|
|
|
|
|
xwiString[strLength+1] = '\0';
|
|
|
|
|
dev_info(fb_data->dev, " Extra Waveform Data: %s\n",xwiString);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
dev_err(fb_data->dev, " *** Extra Waveform Data checksum error ***\n");
|
|
|
|
|
|
|
|
|
|
kfree(xwiString);
|
|
|
|
|
}
|
|
|
|
|
}*/
|
|
|
|
|
/* fetch and display the voltage control data for waveform mode 0, temp range 0 - This can be removed! It is here for illustration only */
|
|
|
|
|
#if 0
|
|
|
|
|
if (fb_data->waveform_vcd_buffer) {
|
|
|
|
|
struct {
|
|
|
|
|
unsigned version:16;
|
|
|
|
|
unsigned v1:16;
|
|
|
|
|
unsigned v2:16;
|
|
|
|
|
unsigned v3:16;
|
|
|
|
|
unsigned v4:16;
|
|
|
|
|
unsigned v5:16;
|
|
|
|
|
unsigned v6:16;
|
|
|
|
|
unsigned v7:8;
|
|
|
|
|
u8 cs:8;
|
|
|
|
|
} vcd;
|
|
|
|
|
|
|
|
|
|
/* fetch the voltage control data */
|
|
|
|
|
if (mxc_epdc_fb_fetch_vc_data( fb_data->waveform_vcd_buffer, 0, 0, fb_data->waveform_mc, fb_data->waveform_trc, (unsigned char *) &vcd) < 0)
|
|
|
|
|
dev_err(fb_data->dev, " *** Extra Waveform Data checksum error ***\n");
|
|
|
|
|
else
|
|
|
|
|
dev_info(fb_data->dev, " -- VC Data: v1 =%d, v2 = %d, v3 = %d, v4 = %d, v5 = %d, v6 = %d, v7 = %d --\n",
|
|
|
|
|
vcd.v1, vcd.v2, vcd.v3, vcd.v4, vcd.v5, vcd.v6, vcd.v7 );
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/* Allocate memory for waveform data */
|
|
|
|
|
fb_data->waveform_buffer_virt = dma_alloc_coherent(fb_data->dev,
|
|
|
|
|
fb_data->waveform_buffer_size,
|
|
|
|
@ -4639,15 +4432,6 @@ static void mxc_epdc_fb_fw_handler(const struct firmware *fw,
|
|
|
|
|
memcpy(fb_data->waveform_buffer_virt, (u8 *)(fw->data) + wv_data_offs,
|
|
|
|
|
fb_data->waveform_buffer_size);
|
|
|
|
|
|
|
|
|
|
/* Read field to determine if 4-bit or 5-bit mode */
|
|
|
|
|
if ((wv_file->wdh.luts & 0xC) == 0x4) {
|
|
|
|
|
dev_warn(fb_data->dev, "It is p5n\n");
|
|
|
|
|
fb_data->buf_pix_fmt = EPDC_FORMAT_BUF_PIXEL_FORMAT_P5N;
|
|
|
|
|
} else {
|
|
|
|
|
dev_warn(fb_data->dev, "It is p4n\n");
|
|
|
|
|
fb_data->buf_pix_fmt = EPDC_FORMAT_BUF_PIXEL_FORMAT_P4N;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
release_firmware(fw);
|
|
|
|
|
|
|
|
|
|
/* Enable clocks to access EPDC regs */
|
|
|
|
@ -4817,9 +4601,8 @@ int mxc_epdc_fb_probe(struct platform_device *pdev)
|
|
|
|
|
x_mem_size = memparse(opt + 6, NULL);
|
|
|
|
|
else if (!strncmp(opt, "tce_prevent", 11))
|
|
|
|
|
fb_data->tce_prevent = 1;
|
|
|
|
|
else if (panel_str == NULL)
|
|
|
|
|
else
|
|
|
|
|
panel_str = opt;
|
|
|
|
|
else dev_err(fb_data->dev, " --> invalid epdc options - %s\n", opt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fb_data->dev = &pdev->dev;
|
|
|
|
@ -4830,19 +4613,14 @@ int mxc_epdc_fb_probe(struct platform_device *pdev)
|
|
|
|
|
/* Set default (first defined mode) before searching for a match */
|
|
|
|
|
fb_data->cur_mode = &fb_data->pdata->epdc_mode[0];
|
|
|
|
|
|
|
|
|
|
if(panel_str) printk("-> requested panel string %s\n",panel_str);
|
|
|
|
|
|
|
|
|
|
if (panel_str)
|
|
|
|
|
for (i = 0; i < fb_data->pdata->num_modes; i++) {
|
|
|
|
|
printk("-> epdc modes[%d] - %s\n", i, fb_data->pdata->epdc_mode[i].vmode->name);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < fb_data->pdata->num_modes; i++)
|
|
|
|
|
if (!strcmp(fb_data->pdata->epdc_mode[i].vmode->name,
|
|
|
|
|
panel_str)) {
|
|
|
|
|
fb_data->cur_mode =
|
|
|
|
|
&fb_data->pdata->epdc_mode[i];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vmode = fb_data->cur_mode->vmode;
|
|
|
|
|
|
|
|
|
@ -5113,13 +4891,13 @@ int mxc_epdc_fb_probe(struct platform_device *pdev)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fb_data->working_buffer_size = vmode->yres * vmode->xres * 2;
|
|
|
|
|
/* Allocate EPDC working buffer */
|
|
|
|
|
/* Allocate memory for EPDC working buffer */
|
|
|
|
|
fb_data->working_buffer_virt =
|
|
|
|
|
dma_alloc_coherent(&pdev->dev, fb_data->working_buffer_size,
|
|
|
|
|
&fb_data->working_buffer_phys,
|
|
|
|
|
GFP_DMA | GFP_KERNEL);
|
|
|
|
|
dma_alloc_coherent(&pdev->dev, fb_data->working_buffer_size,
|
|
|
|
|
&fb_data->working_buffer_phys,
|
|
|
|
|
GFP_DMA | GFP_KERNEL);
|
|
|
|
|
if (fb_data->working_buffer_virt == NULL) {
|
|
|
|
|
dev_err(&pdev->dev, "Can't allocate mem for working!\n");
|
|
|
|
|
dev_err(&pdev->dev, "Can't allocate mem for working buf!\n");
|
|
|
|
|
ret = -ENOMEM;
|
|
|
|
|
goto out_copybuffer;
|
|
|
|
|
}
|
|
|
|
@ -5129,7 +4907,7 @@ int mxc_epdc_fb_probe(struct platform_device *pdev)
|
|
|
|
|
if (IS_ERR(pinctrl)) {
|
|
|
|
|
dev_err(&pdev->dev, "can't get/select pinctrl\n");
|
|
|
|
|
ret = PTR_ERR(pinctrl);
|
|
|
|
|
goto out_dma_work_buf;
|
|
|
|
|
goto out_copybuffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fb_data->in_init = false;
|
|
|
|
@ -5143,7 +4921,7 @@ int mxc_epdc_fb_probe(struct platform_device *pdev)
|
|
|
|
|
*/
|
|
|
|
|
fb_data->wv_modes.mode_init = 0;
|
|
|
|
|
fb_data->wv_modes.mode_du = 1;
|
|
|
|
|
fb_data->wv_modes.mode_gc4 = 2;
|
|
|
|
|
fb_data->wv_modes.mode_gc4 = 3;
|
|
|
|
|
fb_data->wv_modes.mode_gc8 = 2;
|
|
|
|
|
fb_data->wv_modes.mode_gc16 = 2;
|
|
|
|
|
fb_data->wv_modes.mode_gc32 = 2;
|
|
|
|
@ -5360,7 +5138,7 @@ out_lutmap:
|
|
|
|
|
kfree(fb_data->pxp_conf.proc_data.lut_map);
|
|
|
|
|
out_dma_work_buf:
|
|
|
|
|
dma_free_writecombine(&pdev->dev, fb_data->working_buffer_size,
|
|
|
|
|
fb_data->working_buffer_virt, fb_data->working_buffer_phys);
|
|
|
|
|
fb_data->working_buffer_virt, fb_data->working_buffer_phys);
|
|
|
|
|
out_copybuffer:
|
|
|
|
|
dma_free_writecombine(&pdev->dev, fb_data->max_pix_size*2,
|
|
|
|
|
fb_data->virt_addr_copybuf,
|
|
|
|
@ -5413,8 +5191,8 @@ static int mxc_epdc_fb_remove(struct platform_device *pdev)
|
|
|
|
|
kfree(fb_data->phys_addr_updbuf);
|
|
|
|
|
|
|
|
|
|
dma_free_writecombine(&pdev->dev, fb_data->working_buffer_size,
|
|
|
|
|
fb_data->working_buffer_virt,
|
|
|
|
|
fb_data->working_buffer_phys);
|
|
|
|
|
fb_data->working_buffer_virt,
|
|
|
|
|
fb_data->working_buffer_phys);
|
|
|
|
|
if (fb_data->waveform_buffer_virt != NULL)
|
|
|
|
|
dma_free_writecombine(&pdev->dev, fb_data->waveform_buffer_size,
|
|
|
|
|
fb_data->waveform_buffer_virt,
|
|
|
|
@ -5423,15 +5201,6 @@ static int mxc_epdc_fb_remove(struct platform_device *pdev)
|
|
|
|
|
dma_free_writecombine(&pdev->dev, fb_data->max_pix_size*2,
|
|
|
|
|
fb_data->virt_addr_copybuf,
|
|
|
|
|
fb_data->phys_addr_copybuf);
|
|
|
|
|
|
|
|
|
|
if (fb_data->temp_range_bounds) kfree(fb_data->temp_range_bounds);
|
|
|
|
|
kfree(fb_data->pxp_conf.proc_data.lut_map);
|
|
|
|
|
|
|
|
|
|
/* release gen2 waveform buffers */
|
|
|
|
|
if (fb_data->waveform_vcd_buffer) kfree (fb_data->waveform_vcd_buffer);
|
|
|
|
|
if (fb_data->waveform_acd_buffer) kfree (fb_data->waveform_acd_buffer);
|
|
|
|
|
if (fb_data->waveform_xwi_buffer) kfree (fb_data->waveform_xwi_buffer);
|
|
|
|
|
|
|
|
|
|
list_for_each_entry_safe(plist, temp_list, &fb_data->upd_buf_free_list,
|
|
|
|
|
list) {
|
|
|
|
|
list_del(&plist->list);
|
|
|
|
@ -5808,7 +5577,7 @@ static void do_dithering_processing_Y1_v1_0(
|
|
|
|
|
bwPix = *(err_dist_l0 + col) + *y8buf;
|
|
|
|
|
|
|
|
|
|
if (bwPix >= 128) {
|
|
|
|
|
*y8buf++ = 0xf0;
|
|
|
|
|
*y8buf++ = 0xff;
|
|
|
|
|
distrib_error = (bwPix - 255) >> 3;
|
|
|
|
|
} else {
|
|
|
|
|
*y8buf++ = 0;
|
|
|
|
|