123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667 |
- /* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
- #include <linux/delay.h>
- #include <linux/io.h>
- #include <linux/dma-mapping.h>
- #include <linux/slab.h>
- #include <linux/iopoll.h>
- #include <linux/of_device.h>
- #include <linux/of_gpio.h>
- #include "dsi_v2.h"
- static struct dsi_interface dsi_intf;
- static int dsi_off(struct mdss_panel_data *pdata)
- {
- int rc = 0;
- pr_debug("turn off dsi controller\n");
- if (dsi_intf.off)
- rc = dsi_intf.off(pdata);
- if (rc) {
- pr_err("mdss_dsi_off DSI failed %d\n", rc);
- return rc;
- }
- return rc;
- }
- static int dsi_on(struct mdss_panel_data *pdata)
- {
- int rc = 0;
- pr_debug("dsi_on DSI controller on\n");
- if (dsi_intf.on)
- rc = dsi_intf.on(pdata);
- if (rc) {
- pr_err("mdss_dsi_on DSI failed %d\n", rc);
- return rc;
- }
- return rc;
- }
- static int dsi_update_pconfig(struct mdss_panel_data *pdata,
- int mode)
- {
- int ret = 0;
- struct mdss_panel_info *pinfo = &pdata->panel_info;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- if (!pdata)
- return -ENODEV;
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
- if (mode == DSI_CMD_MODE) {
- pinfo->mipi.mode = DSI_CMD_MODE;
- pinfo->type = MIPI_CMD_PANEL;
- pinfo->mipi.vsync_enable = 1;
- pinfo->mipi.hw_vsync_mode = 1;
- } else {
- pinfo->mipi.mode = DSI_VIDEO_MODE;
- pinfo->type = MIPI_VIDEO_PANEL;
- pinfo->mipi.vsync_enable = 0;
- pinfo->mipi.hw_vsync_mode = 0;
- }
- ctrl_pdata->panel_mode = pinfo->mipi.mode;
- mdss_panel_get_dst_fmt(pinfo->bpp, pinfo->mipi.mode,
- pinfo->mipi.pixel_packing, &(pinfo->mipi.dst_format));
- pinfo->cont_splash_enabled = 0;
- return ret;
- }
- static int dsi_panel_handler(struct mdss_panel_data *pdata, int enable)
- {
- int rc = 0;
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- pr_info("%s+: enable=%d\n", __func__, enable);
- pr_debug("dsi_panel_handler enable=%d\n", enable);
- if (!pdata)
- return -ENODEV;
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
- if (enable) {
- if (!pdata->panel_info.dynamic_switch_pending) {
- if (pdata->panel_info.type == MIPI_CMD_PANEL)
- dsi_ctrl_gpio_request(ctrl_pdata);
- mdss_dsi_panel_reset(pdata, 1);
- }
- pdata->panel_info.panel_power_on = 1;
- if (!pdata->panel_info.dynamic_switch_pending) {
- rc = ctrl_pdata->on(pdata);
- if (rc)
- pr_err("%s: panel on failed!\n", __func__);
- }
- if (pdata->panel_info.type == MIPI_CMD_PANEL &&
- pdata->panel_info.dynamic_switch_pending) {
- dsi_ctrl_gpio_request(ctrl_pdata);
- mdss_dsi_set_tear_on(ctrl_pdata);
- }
- } else {
- msm_dsi_sw_reset();
- if (dsi_intf.op_mode_config)
- dsi_intf.op_mode_config(DSI_CMD_MODE, pdata);
- if (pdata->panel_info.dynamic_switch_pending) {
- pr_info("%s: switching to %s mode\n", __func__,
- (pdata->panel_info.mipi.mode ? "video" : "command"));
- if (pdata->panel_info.type == MIPI_CMD_PANEL) {
- ctrl_pdata->switch_mode(pdata, DSI_VIDEO_MODE);
- dsi_ctrl_gpio_free(ctrl_pdata);
- } else if (pdata->panel_info.type == MIPI_VIDEO_PANEL) {
- ctrl_pdata->switch_mode(pdata, DSI_CMD_MODE);
- dsi_ctrl_gpio_request(ctrl_pdata);
- mdss_dsi_set_tear_off(ctrl_pdata);
- dsi_ctrl_gpio_free(ctrl_pdata);
- }
- }
- if (!pdata->panel_info.dynamic_switch_pending)
- rc = ctrl_pdata->off(pdata);
- pdata->panel_info.panel_power_on = 0;
- if (!pdata->panel_info.dynamic_switch_pending) {
- if (pdata->panel_info.type == MIPI_CMD_PANEL)
- dsi_ctrl_gpio_free(ctrl_pdata);
- mdss_dsi_panel_reset(pdata, 0);
- }
- }
- pr_info("%s-:\n", __func__);
- return rc;
- }
- static int dsi_splash_on(struct mdss_panel_data *pdata)
- {
- int rc = 0;
- pr_debug("%s:\n", __func__);
- if (dsi_intf.cont_on)
- rc = dsi_intf.cont_on(pdata);
- if (rc) {
- pr_err("mdss_dsi_on DSI failed %d\n", rc);
- return rc;
- }
- return rc;
- }
- static int dsi_clk_ctrl(struct mdss_panel_data *pdata, int enable)
- {
- int rc = 0;
- pr_debug("%s:\n", __func__);
- if (dsi_intf.clk_ctrl)
- rc = dsi_intf.clk_ctrl(pdata, enable);
- return rc;
- }
- #if defined(CONFIG_GET_LCD_ATTACHED)
- extern int get_lcd_attached(void);
- #endif
- static int dsi_event_handler(struct mdss_panel_data *pdata,
- int event, void *arg)
- {
- int rc = 0;
- #if defined(CONFIG_MDSS_DSI_EVENT_HANDLER_PANEL)
- struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
- #endif
- if (!pdata) {
- pr_err("%s: Invalid input data\n", __func__);
- return -ENODEV;
- }
- #if defined(CONFIG_MDSS_DSI_EVENT_HANDLER_PANEL)
- ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
- panel_data);
- #endif
- #if defined(CONFIG_GET_LCD_ATTACHED)
- if (get_lcd_attached() == 0)
- {
- pr_err("%s: get_lcd_attached(0)!\n",__func__);
- return 0;
- }
- #endif
- pr_info("%s : event = %d\n", __func__, event);
- switch (event) {
- case MDSS_EVENT_UNBLANK:
- rc = dsi_on(pdata);
- break;
- case MDSS_EVENT_BLANK:
- rc = dsi_off(pdata);
- break;
- case MDSS_EVENT_PANEL_ON:
- rc = dsi_panel_handler(pdata, 1);
- break;
- case MDSS_EVENT_PANEL_OFF:
- rc = dsi_panel_handler(pdata, 0);
- break;
- case MDSS_EVENT_CONT_SPLASH_BEGIN:
- rc = dsi_splash_on(pdata);
- break;
- case MDSS_EVENT_PANEL_CLK_CTRL:
- rc = dsi_clk_ctrl(pdata, (int)arg);
- break;
- case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
- rc = dsi_update_pconfig(pdata, (int)(unsigned long) arg);
- break;
- #if defined(CONFIG_MDSS_DSI_EVENT_HANDLER_PANEL)
- case MDSS_EVENT_FB_REGISTERED:
- if (ctrl_pdata->registered) {
- pr_debug("%s:event=%d, calling panel registered callback \n",
- __func__, event);
- rc = ctrl_pdata->registered(pdata);
- /*
- * Okay, since framebuffer is registered, display the kernel logo if needed
- */
- }
- break;
- default:
- if(ctrl_pdata->event_handler) {
- rc = ctrl_pdata->event_handler(event);
- } else {
- pr_err("%s: unhandled event=%d\n", __func__, event);
- }
- break;
- #else
- default:
- pr_debug("%s: unhandled event=%d\n", __func__, event);
- break;
- #endif
- }
- return rc;
- }
- static int dsi_parse_gpio(struct platform_device *pdev,
- struct mdss_dsi_ctrl_pdata *ctrl_pdata)
- {
- struct device_node *np = pdev->dev.of_node;
- ctrl_pdata->disp_en_gpio = of_get_named_gpio(np,
- "qcom,platform-enable-gpio", 0);
- if (!gpio_is_valid(ctrl_pdata->disp_en_gpio))
- pr_err("%s:%d, Disp_en gpio not specified\n",
- __func__, __LINE__);
- ctrl_pdata->disp_te_gpio = -1;
- if (ctrl_pdata->panel_data.panel_info.mipi.mode == DSI_CMD_MODE ||
- ctrl_pdata->panel_data.panel_info.mipi.dynamic_switch_enabled) {
- ctrl_pdata->disp_te_gpio = of_get_named_gpio(np,
- "qcom,platform-te-gpio", 0);
- if (!gpio_is_valid(ctrl_pdata->disp_te_gpio))
- pr_err("%s:%d, Disp_te gpio not specified\n",
- __func__, __LINE__);
- }
- ctrl_pdata->rst_gpio = of_get_named_gpio(np,
- "qcom,platform-reset-gpio", 0);
- if (!gpio_is_valid(ctrl_pdata->rst_gpio))
- pr_err("%s:%d, reset gpio not specified\n",
- __func__, __LINE__);
- ctrl_pdata->mode_gpio = -1;
- if (ctrl_pdata->panel_data.panel_info.mode_gpio_state !=
- MODE_GPIO_NOT_VALID) {
- ctrl_pdata->mode_gpio = of_get_named_gpio(np,
- "qcom,platform-mode-gpio", 0);
- if (!gpio_is_valid(ctrl_pdata->mode_gpio))
- pr_info("%s:%d, reset gpio not specified\n",
- __func__, __LINE__);
- }
- return 0;
- }
- void dsi_ctrl_config_deinit(struct platform_device *pdev,
- struct mdss_dsi_ctrl_pdata *ctrl_pdata)
- {
- struct dss_module_power *module_power = &(ctrl_pdata->power_data);
- if (!module_power) {
- pr_err("%s: invalid input\n", __func__);
- return;
- }
- if (module_power->vreg_config) {
- devm_kfree(&(pdev->dev), module_power->vreg_config);
- module_power->vreg_config = NULL;
- }
- module_power->num_vreg = 0;
- }
- int dsi_ctrl_gpio_request(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
- {
- int rc = 0;
- if (gpio_is_valid(ctrl_pdata->disp_te_gpio)) {
- rc = gpio_request(ctrl_pdata->disp_te_gpio, "disp_te");
- if (rc)
- ctrl_pdata->disp_te_gpio_requested = 0;
- else
- ctrl_pdata->disp_te_gpio_requested = 1;
- }
- return rc;
- }
- void dsi_ctrl_gpio_free(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
- {
- if (ctrl_pdata->disp_te_gpio_requested) {
- gpio_free(ctrl_pdata->disp_te_gpio);
- ctrl_pdata->disp_te_gpio_requested = 0;
- }
- }
- static int dsi_parse_vreg(struct device *dev, struct dss_module_power *mp)
- {
- int i = 0, rc = 0;
- u32 tmp = 0;
- struct device_node *supply_node = NULL;
- struct device_node *np = NULL;
- if (!dev || !mp) {
- pr_err("%s: invalid input\n", __func__);
- rc = -EINVAL;
- return rc;
- }
- np = dev->of_node;
- mp->num_vreg = 0;
- for_each_child_of_node(np, supply_node) {
- if (!strncmp(supply_node->name, "qcom,platform-supply-entry",
- strlen("qcom,platform-supply-entry")))
- ++mp->num_vreg;
- }
- if (mp->num_vreg == 0) {
- pr_err("%s: no vreg\n", __func__);
- goto novreg;
- } else {
- pr_debug("%s: vreg found. count=%d\n", __func__, mp->num_vreg);
- }
- mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
- mp->num_vreg, GFP_KERNEL);
- if (!mp->vreg_config) {
- pr_err("%s: can't alloc vreg mem\n", __func__);
- rc = -ENOMEM;
- goto error;
- }
- for_each_child_of_node(np, supply_node) {
- if (!strncmp(supply_node->name, "qcom,platform-supply-entry",
- strlen("qcom,platform-supply-entry"))) {
- const char *st = NULL;
- /* vreg-name */
- rc = of_property_read_string(supply_node,
- "qcom,supply-name", &st);
- if (rc) {
- pr_err("%s: error reading name. rc=%d\n",
- __func__, rc);
- goto error;
- }
- strlcpy(mp->vreg_config[i].vreg_name, st,
- sizeof(mp->vreg_config[i].vreg_name));
- /* vreg-min-voltage */
- rc = of_property_read_u32(supply_node,
- "qcom,supply-min-voltage", &tmp);
- if (rc) {
- pr_err("%s: error reading min volt. rc=%d\n",
- __func__, rc);
- goto error;
- }
- mp->vreg_config[i].min_voltage = tmp;
- /* vreg-max-voltage */
- rc = of_property_read_u32(supply_node,
- "qcom,supply-max-voltage", &tmp);
- if (rc) {
- pr_err("%s: error reading max volt. rc=%d\n",
- __func__, rc);
- goto error;
- }
- mp->vreg_config[i].max_voltage = tmp;
- /* enable-load */
- rc = of_property_read_u32(supply_node,
- "qcom,supply-enable-load", &tmp);
- if (rc) {
- pr_err("%s: error reading enable load. rc=%d\n",
- __func__, rc);
- goto error;
- }
- mp->vreg_config[i].enable_load = tmp;
- /* disable-load */
- rc = of_property_read_u32(supply_node,
- "qcom,supply-disable-load", &tmp);
- if (rc) {
- pr_err("%s: error reading disable load. rc=%d\n",
- __func__, rc);
- goto error;
- }
- mp->vreg_config[i].disable_load = tmp;
- /* pre-sleep */
- rc = of_property_read_u32(supply_node,
- "qcom,supply-pre-on-sleep", &tmp);
- if (rc) {
- pr_debug("%s: error reading supply pre sleep value. rc=%d\n",
- __func__, rc);
- }
- mp->vreg_config[i].pre_on_sleep = (!rc ? tmp : 0);
- rc = of_property_read_u32(supply_node,
- "qcom,supply-pre-off-sleep", &tmp);
- if (rc) {
- pr_debug("%s: error reading supply pre sleep value. rc=%d\n",
- __func__, rc);
- }
- mp->vreg_config[i].pre_off_sleep = (!rc ? tmp : 0);
- /* post-sleep */
- rc = of_property_read_u32(supply_node,
- "qcom,supply-post-on-sleep", &tmp);
- if (rc) {
- pr_debug("%s: error reading supply post sleep value. rc=%d\n",
- __func__, rc);
- }
- mp->vreg_config[i].post_on_sleep = (!rc ? tmp : 0);
- rc = of_property_read_u32(supply_node,
- "qcom,supply-post-off-sleep", &tmp);
- if (rc) {
- pr_debug("%s: error reading supply post sleep value. rc=%d\n",
- __func__, rc);
- }
- mp->vreg_config[i].post_off_sleep = (!rc ? tmp : 0);
- pr_debug("%s: %s min=%d, max=%d, enable=%d, disable=%d, preonsleep=%d, postonsleep=%d, preoffsleep=%d, postoffsleep=%d\n",
- __func__,
- mp->vreg_config[i].vreg_name,
- mp->vreg_config[i].min_voltage,
- mp->vreg_config[i].max_voltage,
- mp->vreg_config[i].enable_load,
- mp->vreg_config[i].disable_load,
- mp->vreg_config[i].pre_on_sleep,
- mp->vreg_config[i].post_on_sleep,
- mp->vreg_config[i].pre_off_sleep,
- mp->vreg_config[i].post_off_sleep
- );
- ++i;
- }
- }
- return 0;
- error:
- if (mp->vreg_config) {
- devm_kfree(dev, mp->vreg_config);
- mp->vreg_config = NULL;
- }
- novreg:
- mp->num_vreg = 0;
- return rc;
- }
- static int dsi_parse_phy(struct platform_device *pdev,
- struct mdss_dsi_ctrl_pdata *ctrl_pdata)
- {
- struct device_node *np = pdev->dev.of_node;
- int i, len;
- const char *data;
- struct mdss_dsi_phy_ctrl *phy_db
- = &(ctrl_pdata->panel_data.panel_info.mipi.dsi_phy_db);
- data = of_get_property(np, "qcom,platform-regulator-settings", &len);
- if ((!data) || (len != 6)) {
- pr_err("%s:%d, Unable to read Phy regulator settings",
- __func__, __LINE__);
- return -EINVAL;
- }
- for (i = 0; i < len; i++)
- phy_db->regulator[i] = data[i];
- data = of_get_property(np, "qcom,platform-strength-ctrl", &len);
- if ((!data) || (len != 2)) {
- pr_err("%s:%d, Unable to read Phy Strength ctrl settings",
- __func__, __LINE__);
- return -EINVAL;
- }
- phy_db->strength[0] = data[0];
- phy_db->strength[1] = data[1];
- data = of_get_property(np, "qcom,platform-bist-ctrl", &len);
- if ((!data) || (len != 6)) {
- pr_err("%s:%d, Unable to read Phy Bist Ctrl settings",
- __func__, __LINE__);
- return -EINVAL;
- }
- for (i = 0; i < len; i++)
- phy_db->bistctrl[i] = data[i];
- data = of_get_property(np, "qcom,platform-lane-config", &len);
- if ((!data) || (len != 30)) {
- pr_err("%s:%d, Unable to read Phy lane configure settings",
- __func__, __LINE__);
- return -EINVAL;
- }
- for (i = 0; i < len; i++)
- phy_db->lanecfg[i] = data[i];
- return 0;
- }
- int dsi_ctrl_config_init(struct platform_device *pdev,
- struct mdss_dsi_ctrl_pdata *ctrl_pdata)
- {
- int rc;
- rc = dsi_parse_vreg(&pdev->dev, &ctrl_pdata->power_data);
- if (rc) {
- pr_err("%s:%d unable to get the regulator resources",
- __func__, __LINE__);
- return rc;
- }
- rc = dsi_parse_gpio(pdev, ctrl_pdata);
- if (rc) {
- pr_err("fail to parse panel GPIOs\n");
- return rc;
- }
- rc = dsi_parse_phy(pdev, ctrl_pdata);
- if (rc) {
- pr_err("fail to parse DSI PHY settings\n");
- return rc;
- }
- return 0;
- }
- int dsi_panel_device_register_v2(struct platform_device *dev,
- struct mdss_dsi_ctrl_pdata *ctrl_pdata)
- {
- struct mipi_panel_info *mipi;
- int rc;
- u8 lanes = 0, bpp;
- u32 h_period, v_period;
- struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
- h_period = ((pinfo->lcdc.h_pulse_width)
- + (pinfo->lcdc.h_back_porch)
- + (pinfo->xres)
- + (pinfo->lcdc.h_front_porch));
- v_period = ((pinfo->lcdc.v_pulse_width)
- + (pinfo->lcdc.v_back_porch)
- + (pinfo->yres)
- + (pinfo->lcdc.v_front_porch));
- mipi = &pinfo->mipi;
- pinfo->type =
- ((mipi->mode == DSI_VIDEO_MODE)
- ? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL);
- if (mipi->data_lane3)
- lanes += 1;
- if (mipi->data_lane2)
- lanes += 1;
- if (mipi->data_lane1)
- lanes += 1;
- if (mipi->data_lane0)
- lanes += 1;
- if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888)
- || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB888)
- || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB666_LOOSE))
- bpp = 3;
- else if ((mipi->dst_format == DSI_CMD_DST_FORMAT_RGB565)
- || (mipi->dst_format == DSI_VIDEO_DST_FORMAT_RGB565))
- bpp = 2;
- else
- bpp = 3; /* Default format set to RGB888 */
- if (pinfo->type == MIPI_VIDEO_PANEL &&
- !pinfo->clk_rate) {
- h_period += pinfo->lcdc.xres_pad;
- v_period += pinfo->lcdc.yres_pad;
- if (lanes > 0) {
- pinfo->clk_rate =
- ((h_period * v_period * (mipi->frame_rate) * bpp * 8)
- / lanes);
- } else {
- pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
- pinfo->clk_rate =
- (h_period * v_period
- * (mipi->frame_rate) * bpp * 8);
- }
- }
- ctrl_pdata->panel_data.event_handler = dsi_event_handler;
- /*
- * register in mdp driver
- */
- rc = mdss_register_panel(dev, &(ctrl_pdata->panel_data));
- if (rc) {
- dev_err(&dev->dev, "unable to register MIPI DSI panel\n");
- return rc;
- }
- pr_debug("%s: Panal data initialized\n", __func__);
- return 0;
- }
- void dsi_register_interface(struct dsi_interface *intf)
- {
- dsi_intf = *intf;
- }
- int dsi_buf_alloc(struct dsi_buf *dp, int size)
- {
- dp->start = kmalloc(size, GFP_KERNEL);
- if (dp->start == NULL) {
- pr_err("%s:%u\n", __func__, __LINE__);
- return -ENOMEM;
- }
- dp->end = dp->start + size;
- dp->size = size;
- if ((int)dp->start & 0x07) {
- pr_err("%s: buf NOT 8 bytes aligned\n", __func__);
- return -EINVAL;
- }
- dp->data = dp->start;
- dp->len = 0;
- return 0;
- }
|