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 : [<c01e5e20>] lr : [<c01e6e34>] 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; }