ret = sprdfb_panel_constructor(pan_node, fb_dev);
if (ret) {
pr_err("%s: failed to construct panel device\n"); // lose __func__
return -EFAULT;
}
%s, __func__, forgot __func__
if (!fb_dev || fb_dev->panel)
return -ENODEV; // Actually, panel pointer is NULL...
pan_node = sprdfb_panel_search(fb_dev);
if (!pan_node) {
pr_warn("can't find panel specified by cmdline, try reading id\n");
}
ret = sprdfb_panel_constructor(pan_node, fb_dev);
if (ret) {
pr_err("%s: failed to construct panel device\n", __func__);
return -EFAULT;
}
panel = fb_dev->panel;
The error log is as following:
7sprdfb_panel: ---- enter: sprdfb_panel_device_register ----
1Unable to handle kernel paging request at virtual address 60000113
1pgd = c0004000
1[60000113] *pgd=00000000
0Internal error: Oops: 5 [#1] PREEMPT SMP ARM
dModules linked in:
dCPU: 1 PID: 1 Comm: swapper/0 Tainted: G W 3.10.17-00026-g6d61c92-dirty #29
dtask: d7098000 ti: d70a0000 task.ti: d70a0000
PC is at strnlen+0x1c/0x30
LR is at string.isra.3+0x34/0xc8
pc : [] lr : [] psr: 20000193 // stopped at printk, actually is pr_err.
sp : d70a1c78 ip : 00000020 fp : d70a1d58
r10: c055827b r9 : c084b0e0 r8 : 00000000
r7 : 60000113 r6 : ffffffff r5 : c084b0e0 r4 : c084ad0a
r3 : 60000113 r2 : 60000113 r1 : 60000112 r0 : 60000113 // 6000113 is a abnormal address!!!
Flags: nzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel
Control: 10c53c7d Table: 8000406a DAC: 00000015
porch = kzalloc(sizeof(struct timing_rgb), GFP_KERNEL);
panel = kzalloc(sizeof(struct panel_spec), GFP_KERNEL);
if (!panel || porch) // judge porch not right, should !porch
goto alloc_panel_mem_error;
name = (char *)of_get_property(pan_node,
"sprdfb,dispc-dsi-panel-name", NULL);
if (!name) {
strlcpy(panel->panel_name, "unspecified", PANEL_NAME_LEN);
ret = -ENXIO;
pr_err("%s:%d, Panel name not specified\n",
__func__, __LINE__);
goto parse_dt_error;
} else {
strlcpy(panel->panel_name, name, PANEL_NAME_LEN);
pr_info("%s: Panel: %s is specified\n",
__func__, panel->panel_name);
}
static int sprdfb_panel_parse_dcs_cmds(const struct device_node *np,
struct dsi_cmds_list *pcmds, char *cmd_key)
{
const char *data;
int dt_len = 0, len;
char *buf, *bp;
struct dsi_cmd_desc *d;
int cnt = 0;
pr_debug("---- enter: %s ----\n", __func__);
data = of_get_property(np, cmd_key, &dt_len);
if (!data) {
pr_err("%s: failed, key=%s\n", __func__, cmd_key);
return -ENOMEM;
}
buf = kzalloc(sizeof(char) * dt_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
memcpy(buf, data, dt_len);
/* scan dcs commands */
bp = buf;
len = dt_len;
d = (struct dsi_cmd_desc *)bp;
d->c_len = ntohs(d->c_len); // If d is NULL, now dereference it, kernel will be dumped.
while (len > (sizeof(*d) + d->c_len)) {
if (d->c_len > len) {
pr_err("%s: dtsi cmd=%x error, len=%d",
__func__, d->data_type, d->c_len);
goto exit_free;
}
pr_debug("data type is %d, cmd len is %d\n",
d->data_type, d->c_len);
bp += sizeof(*d) + d->c_len;
len -= sizeof(*d) + d->c_len;
d = (struct dsi_cmd_desc *)bp;
d->c_len = ntohs(d->c_len);
cnt++;
}
pcmds->cmds_cnt = cnt;
pcmds->cmds = (struct dsi_cmd_desc *)buf;
return 0;
exit_free:
kfree(buf);
return -EFAULT;
}
data = (char *)of_get_property(node,
"sprdfb,dispc-dsi-color-mode-polarity", NULL);
if (data) {
if (!strcmp(data, "negative"))
panel->info.mipi->color_mode_pol = SPRDFB_POLARITY_NEG;
else
panel->info.mipi->color_mode_pol = SPRDFB_POLARITY_POS;
} else
panel->info.mipi->color_mode_pol = SPRDFB_POLARITY_POS;
sprdfb,dispc-dsi-h-sync-polarity = "positive";
sprdfb,dispc-dsi-v-sync-polarity = "positive";
sprdfb,dispc-dsi-de-polarity = "positive";
sprdfb,dispc-dsi-te-polarity = "positive";
sprdfb,dispc-dsi-color-mode-polarity = "negative";
sprdfb,dispc-dsi-shut-down-polarity = "negative";
static int sprdfb_dsi_tx_cmds(struct panel_spec *panel,
struct dsi_cmd_desc **cmds, u32 cmds_len, bool force_lp)
{
int i, time, len;
struct ops_mipi *ops = panel->info.mipi->ops;
u8 *data;
u16 work_mode = panel->info.mipi->work_mode;
pr_info("%s, len: %d\n", __func__, cmds_len);
if (!ops->mipi_set_cmd_mode ||
!ops->mipi_dcs_write ||
!ops->mipi_set_hs_mode ||
!ops->mipi_set_lp_mode ||
!ops->mipi_force_write) {
pr_err("%s: Expected functions are NULL.\n", __func__);
return -EFAULT;
}
if (force_lp) {
if (work_mode == SPRDFB_MIPI_MODE_CMD)
ops->mipi_set_lp_mode();
else
ops->mipi_set_data_lp_mode();
}
ops->mipi_set_cmd_mode();
for (i = 0; i < cmds_len; i++) {
if (cmds[i]->data_type != DCS_SHORT_WRITE_0 &&
cmds[i]->data_type != DCS_SHORT_WRITE_1) {
len = cmds[i]->c_len + sizeof(cmds[i]->c_len);
data = cmds[i]->payload - sizeof(cmds[i]->c_len);
} else {
len = cmds[i]->c_len;
data = cmds[i]->payload;
}
pr_debug("dsi write cmd type: %d, len: %d\n",
cmds[i]->data_type, len);
if (cmds[i]->data_type == GENERIC_LONG_WRITE)
ops->mipi_force_write(GENERIC_LONG_WRITE, data, len);
else
ops->mipi_dcs_write(data, len);
if (cmds[i]->wait_time) {
time = cmds[i]->wait_time * 1000;
usleep_range(time, time);
}
}
if (force_lp) {
if (work_mode == SPRDFB_MIPI_MODE_CMD)
ops->mipi_set_hs_mode();
else
ops->mipi_set_data_hs_mode();
}
return 0;
}
struct dsi_cmds_list {
struct dsi_cmd_desc *cmds[PANEL_MAX_CMDS_LEN];
u32 cmds_cnt;
};
struct dsi_cmd_desc {
u8 data_type; /* BYTE[0] */
u8 reserved; /* BYTE[1]: reserved */
u8 wait_time; /* BYTE[2] */
u16 c_len; /* BYTE[3...4]: cmd lenght */
u8 payload[0]; /* BYTE[5] */
} __packed;
/* 05: DCS short Wr; 39: DCS long Wr; 06: DCS read; 15: DCS short Wr */
#define GENERIC_SHORT_WRITE_0 0x03
#define GENERIC_SHORT_WRITE_1 0x13
#define GENERIC_SHORT_WRITE_2 0x23
#define GENERIC_LONG_WRITE 0x29
#define DCS_SHORT_WRITE_0 0x05
#define DCS_SHORT_WRITE_1 0x15
#define DCS_LONG_WRITE 0x39
#define GENERIC_SHORT_READ_0 0x04
#define GENERIC_SHORT_READ_1 0x14
#define GENERIC_SHORT_READ_2 0x24
#define DCS_READ_0 0x06
#define SET_MAX_RET_PKT_SIZE 0x37
static int sprdfb_panel_parse_dcs_cmds(const struct device_node *np,
struct dsi_cmds_list *pcmds, char *cmd_key)
{
const char *data;
int dt_len = 0, len, header;
char *buf, *bp;
int cnt = 0;
pr_debug("---- enter: %s ----\n", __func__);
data = of_get_property(np, cmd_key, &dt_len);
if (!data) {
pr_err("%s: failed, key=%s\n", __func__, cmd_key);
return -ENOMEM;
}
buf = kzalloc(sizeof(char) * dt_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
memcpy(buf, data, dt_len);
/* scan dcs commands */
bp = buf;
len = dt_len;
header = sizeof(struct dsi_cmd_desc);
while (len > header) {
pcmds->cmds[cnt] = (struct dsi_cmd_desc *)bp;
pcmds->cmds[cnt]->c_len = ntohs(pcmds->cmds[cnt]->c_len);
if (pcmds->cmds[cnt]->c_len > len) {
pr_err("%s: data type is 0x%x error, len=%d\n",
__func__, pcmds->cmds[cnt]->data_type,
pcmds->cmds[cnt]->c_len);
goto exit_free;
}
pr_debug("data type is 0x%x, cmd len is %d, remaining(%d), "
"cnt(%d)\n", pcmds->cmds[cnt]->data_type,
pcmds->cmds[cnt]->c_len, len, cnt + 1);
bp += header;
len -= header;
bp += pcmds->cmds[cnt]->c_len;
len -= pcmds->cmds[cnt]->c_len;
cnt++;
}
pcmds->cmds_cnt = cnt;
return 0;
exit_free:
kfree(buf);
return -EFAULT;
}