Merge "msm: adsprpc: Update to retrieve the physical address for ION buffer"
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index af841dd..99274d5 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -28,6 +28,8 @@
- interrupt-names : Optional interrupt resource entries are:
"hs_phy_irq" : Interrupt from HSPHY for asynchronous events in LPM.
This is not used if wakeup events are received externally (e.g. PMIC)
+- qcom,dwc-usb3-msm-otg-capability: If present then depends on PMIC
+ for VBUS notifications, otherwise depends on PHY.
Example MSM USB3.0 controller device node :
usb@f9200000 {
diff --git a/arch/arm/boot/dts/msm8974-mtp.dts b/arch/arm/boot/dts/msm8974-mtp.dts
index b63595b..c5fabab 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dts
+++ b/arch/arm/boot/dts/msm8974-mtp.dts
@@ -177,6 +177,10 @@
qcom,hsusb-otg-otg-control = <2>;
};
+&usb3 {
+ qcom,dwc-usb3-msm-otg-capability;
+};
+
&pm8941_chg {
status = "ok";
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 3509e01..00b69ea 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -630,12 +630,12 @@
l2_hfpll_b-supply = <&pm8941_l12_ao>;
};
- qcom,ssusb@f9200000 {
+ usb3: qcom,ssusb@f9200000 {
compatible = "qcom,dwc-usb3-msm";
reg = <0xf9200000 0xfc000>,
<0xfd4ab000 0x4>;
- interrupts = <0 131 0 0 179 0>;
- interrupt-names = "irq", "otg_irq";
+ interrupts = <0 131 0>, <0 179 0>, <0 133 0>;
+ interrupt-names = "irq", "otg_irq", "hs_phy_irq";
SSUSB_VDDCX-supply = <&pm8841_s2>;
SSUSB_1p8-supply = <&pm8941_l6>;
HSUSB_VDDCX-supply = <&pm8841_s2>;
@@ -1044,7 +1044,7 @@
qcom,dst-bam-physical-address = <0xf9304000>;
qcom,dst-bam-pipe-index = <2>;
qcom,data-fifo-offset = <0xf0000>;
- qcom,data-fifo-size = <0x4000>;
+ qcom,data-fifo-size = <0x1800>;
qcom,descriptor-fifo-offset = <0xf4000>;
qcom,descriptor-fifo-size = <0x1400>;
};
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 53e6260..ec00b68 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -367,6 +367,7 @@
CONFIG_S5K3L1YX=y
CONFIG_IMX091=y
CONFIG_MSM_WFD=y
+CONFIG_IMX135=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
# CONFIG_DVB_FE_CUSTOMISE is not set
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 5770859..33f7987 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -371,6 +371,7 @@
CONFIG_S5K3L1YX=y
CONFIG_IMX091=y
CONFIG_MSM_WFD=y
+CONFIG_IMX135=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
# CONFIG_DVB_FE_CUSTOMISE is not set
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index 379d7ae..28f7f63 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -383,6 +383,14 @@
apq8064_sdc3_pdata->pin_data->pad_data->\
drv->on[i].val = GPIO_CFG_10MA;
}
+ if (machine_is_mpq8064_hrd() || machine_is_mpq8064_dtv()) {
+ apq8064_sdc3_pdata->pin_data->pad_data->\
+ drv->on[0].val = GPIO_CFG_16MA;
+ apq8064_sdc3_pdata->pin_data->pad_data->\
+ drv->on[1].val = GPIO_CFG_10MA;
+ apq8064_sdc3_pdata->pin_data->pad_data->\
+ drv->on[2].val = GPIO_CFG_10MA;
+ }
apq8064_add_sdcc(3, apq8064_sdc3_pdata);
}
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index f33f894..1b1f0ac 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2538,6 +2538,9 @@
KGSL_LOG_DUMP(device, "POWER: INTERVAL TIMEOUT = %08X ",
pwr->interval_timeout);
+ KGSL_LOG_DUMP(device, "POWER: NAP ALLOWED = %d | START_STOP_SLEEP_WAKE = %d\n",
+ pwr->nap_allowed, pwr->strtstp_sleepwake);
+
KGSL_LOG_DUMP(device, "GRP_CLK = %lu ",
kgsl_get_clkrate(pwr->grp_clks[0]));
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 739dcb5..422bd55 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -23,6 +23,7 @@
#include "kgsl_pwrscale.h"
#include "kgsl_device.h"
#include "kgsl_trace.h"
+#include "kgsl_sharedmem.h"
#define KGSL_PWRFLAGS_POWER_ON 0
#define KGSL_PWRFLAGS_CLK_ON 1
@@ -951,6 +952,11 @@
void kgsl_pwrctrl_wake(struct kgsl_device *device)
{
int status;
+ unsigned int context_id;
+ unsigned int state = device->state;
+ unsigned int ts_processed = 0xdeaddead;
+ struct kgsl_context *context;
+
kgsl_pwrctrl_request_state(device, KGSL_STATE_ACTIVE);
switch (device->state) {
case KGSL_STATE_SLUMBER:
@@ -964,6 +970,17 @@
case KGSL_STATE_SLEEP:
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
kgsl_pwrscale_wake(device);
+ kgsl_sharedmem_readl(&device->memstore,
+ (unsigned int *) &context_id,
+ KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
+ current_context));
+ context = idr_find(&device->context_idr, context_id);
+ if (context)
+ ts_processed = kgsl_readtimestamp(device, context,
+ KGSL_TIMESTAMP_RETIRED);
+ KGSL_PWR_INFO(device, "Wake from %s state. CTXT: %d RTRD TS: %08X\n",
+ kgsl_pwrstate_to_str(state),
+ context ? context->id : -1, ts_processed);
/* fall through */
case KGSL_STATE_NAP:
/* Turn on the core clocks */
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 3aa38d2..48516b6 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2639,7 +2639,9 @@
mmc_card_is_removable(host))
return err;
- mmc_claim_host(host);
+ if (!mmc_try_claim_host(host))
+ return -EBUSY;
+
if (card && mmc_card_mmc(card) &&
(card->ext_csd.cache_size > 0)) {
enable = !!enable;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 0fd9ab5..0531f83 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -33,6 +33,7 @@
#include <linux/usb/gadget.h>
#include <linux/usb/msm_hsusb.h>
#include <linux/regulator/consumer.h>
+#include <linux/power_supply.h>
#include <mach/rpm-regulator.h>
#include <mach/msm_xo.h>
@@ -157,6 +158,11 @@
u8 dcd_retries;
u32 bus_perf_client;
struct msm_bus_scale_pdata *bus_scale_table;
+ struct power_supply usb_psy;
+ unsigned int online;
+ unsigned int host_mode;
+ unsigned int current_max;
+ bool vbus_active;
};
#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
@@ -1281,6 +1287,10 @@
dev_err(mdwc->dev, "Failed to reset bus bw vote\n");
}
+ if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability)
+ dwc3_hsusb_ldo_enable(0);
+
+ dwc3_hsusb_config_vddcx(0);
wake_unlock(&mdwc->wlock);
atomic_set(&mdwc->in_lpm, 1);
@@ -1315,6 +1325,10 @@
dev_err(mdwc->dev, "%s failed to vote for TCXO buffer%d\n",
__func__, ret);
+ if (mdwc->otg_xceiv && mdwc->ext_xceiv.otg_capability)
+ dwc3_hsusb_ldo_enable(1);
+
+ dwc3_hsusb_config_vddcx(1);
clk_prepare_enable(mdwc->ref_clk);
usleep_range(1000, 1200);
@@ -1373,10 +1387,13 @@
mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
DWC3_EVENT_PHY_RESUME);
pm_runtime_put_sync(mdwc->dev);
+ if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability))
+ mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
+ DWC3_EVENT_XCEIV_STATE);
}
}
-static bool debug_id, debug_bsv, debug_connect;
+static u32 debug_id, debug_bsv, debug_connect;
static int dwc3_connect_show(struct seq_file *s, void *unused)
{
@@ -1446,11 +1463,11 @@
return;
if (!debugfs_create_bool("id", S_IRUGO | S_IWUSR, dwc3_debugfs_root,
- (u32 *)&debug_id))
+ &debug_id))
goto error;
if (!debugfs_create_bool("bsv", S_IRUGO | S_IWUSR, dwc3_debugfs_root,
- (u32 *)&debug_bsv))
+ &debug_bsv))
goto error;
if (!debugfs_create_file("connect", S_IRUGO | S_IWUSR,
@@ -1479,6 +1496,90 @@
return IRQ_HANDLED;
}
+static int dwc3_msm_power_get_property_usb(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm,
+ usb_psy);
+ switch (psp) {
+ case POWER_SUPPLY_PROP_SCOPE:
+ val->intval = mdwc->host_mode;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ val->intval = mdwc->current_max;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = mdwc->vbus_active;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = mdwc->online;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dwc3_msm_power_set_property_usb(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ static bool init;
+ struct dwc3_msm *mdwc = container_of(psy, struct dwc3_msm,
+ usb_psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_SCOPE:
+ mdwc->host_mode = val->intval;
+ break;
+ /* Process PMIC notification in PRESENT prop */
+ case POWER_SUPPLY_PROP_PRESENT:
+ dev_dbg(mdwc->dev, "%s: notify xceiv event\n", __func__);
+ if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability ||
+ !init)) {
+ mdwc->ext_xceiv.bsv = val->intval;
+ mdwc->ext_xceiv.id = DWC3_ID_FLOAT;
+ if (atomic_read(&mdwc->in_lpm)) {
+ dev_dbg(mdwc->dev,
+ "%s received in LPM\n", __func__);
+ queue_delayed_work(system_nrt_wq,
+ &mdwc->resume_work, 0);
+ } else {
+ mdwc->ext_xceiv.notify_ext_events(
+ mdwc->otg_xceiv->otg,
+ DWC3_EVENT_XCEIV_STATE);
+ }
+ }
+ if (!init)
+ init = true;
+ mdwc->vbus_active = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ mdwc->online = val->intval;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_MAX:
+ mdwc->current_max = val->intval;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ power_supply_changed(&mdwc->usb_psy);
+ return 0;
+}
+
+static char *dwc3_msm_pm_power_supplied_to[] = {
+ "battery",
+};
+
+static enum power_supply_property dwc3_msm_pm_power_props_usb[] = {
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_SCOPE,
+};
+
static int __devinit dwc3_msm_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -1639,19 +1740,24 @@
goto free_hs_ldo_init;
}
- /* DWC3 has separate IRQ line for OTG events (ID/BSV etc.) */
- msm->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
- if (msm->hs_phy_irq < 0) {
- dev_dbg(&pdev->dev, "platform_get_irq for hs_phy_irq failed\n");
- msm->hs_phy_irq = 0;
- } else {
- ret = request_irq(msm->hs_phy_irq, msm_dwc3_irq,
- IRQF_TRIGGER_RISING, "msm_dwc3", msm);
- if (ret) {
- dev_err(&pdev->dev, "request irq failed (HSPHY INT)\n");
- goto disable_hs_ldo;
+ msm->ext_xceiv.otg_capability = of_property_read_bool(node,
+ "qcom,dwc-usb3-msm-otg-capability");
+
+ if (!msm->ext_xceiv.otg_capability) {
+ /* DWC3 has separate IRQ line for OTG events (ID/BSV etc.) */
+ msm->hs_phy_irq = platform_get_irq_byname(pdev, "hs_phy_irq");
+ if (msm->hs_phy_irq < 0) {
+ dev_dbg(&pdev->dev, "pget_irq for hs_phy_irq failed\n");
+ msm->hs_phy_irq = 0;
+ } else {
+ ret = request_irq(msm->hs_phy_irq, msm_dwc3_irq,
+ IRQF_TRIGGER_RISING, "msm_dwc3", msm);
+ if (ret) {
+ dev_err(&pdev->dev, "irqreq HSPHYINT failed\n");
+ goto disable_hs_ldo;
+ }
+ enable_irq_wake(msm->hs_phy_irq);
}
- enable_irq_wake(msm->hs_phy_irq);
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -1742,17 +1848,35 @@
goto put_pdev;
}
+ msm->usb_psy.name = "usb";
+ msm->usb_psy.type = POWER_SUPPLY_TYPE_USB;
+ msm->usb_psy.supplied_to = dwc3_msm_pm_power_supplied_to;
+ msm->usb_psy.num_supplicants = ARRAY_SIZE(
+ dwc3_msm_pm_power_supplied_to);
+ msm->usb_psy.properties = dwc3_msm_pm_power_props_usb;
+ msm->usb_psy.num_properties = ARRAY_SIZE(dwc3_msm_pm_power_props_usb);
+ msm->usb_psy.get_property = dwc3_msm_power_get_property_usb;
+ msm->usb_psy.set_property = dwc3_msm_power_set_property_usb;
+
+ ret = power_supply_register(&pdev->dev, &msm->usb_psy);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "%s:power_supply_register usb failed\n",
+ __func__);
+ goto put_pdev;
+ }
+
ret = platform_device_add_resources(dwc3, pdev->resource,
pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
- goto put_pdev;
+ goto put_psupply;
}
ret = platform_device_add(dwc3);
if (ret) {
dev_err(&pdev->dev, "failed to register dwc3 device\n");
- goto put_pdev;
+ goto put_psupply;
}
msm->bus_scale_table = msm_bus_cl_get_pdata(pdev);
@@ -1805,6 +1929,8 @@
put_xcvr:
usb_put_transceiver(msm->otg_xceiv);
platform_device_del(dwc3);
+put_psupply:
+ power_supply_unregister(&msm->usb_psy);
put_pdev:
platform_device_put(dwc3);
free_hsphy_irq:
@@ -1906,9 +2032,14 @@
pm_runtime_enable(dev);
/* Let OTG know about resume event and update pm_count */
- if (mdwc->otg_xceiv)
+ if (mdwc->otg_xceiv) {
mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
DWC3_EVENT_PHY_RESUME);
+ if (mdwc->ext_xceiv.otg_capability)
+ mdwc->ext_xceiv.notify_ext_events(
+ mdwc->otg_xceiv->otg,
+ DWC3_EVENT_XCEIV_STATE);
+ }
}
return ret;
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index f96b88a..1aa8519 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -25,6 +25,9 @@
static void dwc3_otg_reset(struct dwc3_otg *dotg);
+static void dwc3_otg_notify_host_mode(struct usb_otg *otg, int host_mode);
+static void dwc3_otg_reset(struct dwc3_otg *dotg);
+
/**
* dwc3_otg_set_host_regs - reset dwc3 otg registers to host operation.
*
@@ -124,6 +127,7 @@
return ret;
}
+ dwc3_otg_notify_host_mode(otg, on);
ret = regulator_enable(dotg->vbus_otg);
if (ret) {
dev_err(otg->phy->dev, "unable to enable vbus_otg\n");
@@ -143,6 +147,7 @@
dev_err(otg->phy->dev, "unable to disable vbus_otg\n");
return ret;
}
+ dwc3_otg_notify_host_mode(otg, on);
/* re-init core and OTG register as XHCI reset clears it */
dwc3_post_host_reset_core_init(dotg->dwc);
@@ -290,9 +295,11 @@
static void dwc3_ext_event_notify(struct usb_otg *otg,
enum dwc3_ext_events event)
{
+ static bool init;
struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
struct usb_phy *phy = dotg->otg.phy;
+ int ret = 0;
if (event == DWC3_EVENT_PHY_RESUME) {
if (!pm_runtime_status_suspended(phy->dev)) {
@@ -300,7 +307,16 @@
} else {
dev_dbg(phy->dev, "ext PHY_RESUME event received\n");
/* ext_xceiver would have taken h/w out of LPM by now */
- pm_runtime_get(phy->dev);
+ ret = pm_runtime_get(phy->dev);
+ if (ret == -EACCES) {
+ /* pm_runtime_get may fail during system
+ resume with -EACCES error */
+ pm_runtime_disable(phy->dev);
+ pm_runtime_set_active(phy->dev);
+ pm_runtime_enable(phy->dev);
+ } else if (ret < 0) {
+ dev_warn(phy->dev, "pm_runtime_get failed!\n");
+ }
}
} else if (event == DWC3_EVENT_XCEIV_STATE) {
if (ext_xceiv->id == DWC3_ID_FLOAT)
@@ -308,11 +324,20 @@
else
clear_bit(ID, &dotg->inputs);
- if (ext_xceiv->bsv)
+ if (ext_xceiv->bsv) {
+ dev_dbg(phy->dev, "XCVR: BSV set\n");
set_bit(B_SESS_VLD, &dotg->inputs);
- else
+ } else {
+ dev_dbg(phy->dev, "XCVR: BSV clear\n");
clear_bit(B_SESS_VLD, &dotg->inputs);
+ }
+ if (!init) {
+ init = true;
+ complete(&dotg->dwc3_xcvr_vbus_init);
+ dev_dbg(phy->dev, "XCVR: BSV init complete\n");
+ return;
+ }
schedule_work(&dotg->sm_work);
}
}
@@ -335,6 +360,72 @@
return 0;
}
+static void dwc3_otg_notify_host_mode(struct usb_otg *otg, int host_mode)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ if (!dotg->psy) {
+ dev_err(otg->phy->dev, "no usb power supply registered\n");
+ return;
+ }
+
+ if (host_mode)
+ power_supply_set_scope(dotg->psy, POWER_SUPPLY_SCOPE_SYSTEM);
+ else
+ power_supply_set_scope(dotg->psy, POWER_SUPPLY_SCOPE_DEVICE);
+}
+
+static int dwc3_otg_set_power(struct usb_phy *phy, unsigned mA)
+{
+ static int power_supply_type;
+ struct dwc3_otg *dotg = container_of(phy->otg, struct dwc3_otg, otg);
+
+
+ if (!dotg->psy) {
+ dev_err(phy->dev, "no usb power supply registered\n");
+ return 0;
+ }
+
+ if (dotg->charger->chg_type == DWC3_SDP_CHARGER)
+ power_supply_type = POWER_SUPPLY_TYPE_USB;
+ else if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
+ power_supply_type = POWER_SUPPLY_TYPE_USB_CDP;
+ else if (dotg->charger->chg_type == DWC3_DCP_CHARGER)
+ power_supply_type = POWER_SUPPLY_TYPE_USB_DCP;
+ else
+ power_supply_type = POWER_SUPPLY_TYPE_BATTERY;
+
+ power_supply_set_supply_type(dotg->psy, power_supply_type);
+
+ if (dotg->charger->max_power == mA)
+ return 0;
+
+ dev_info(phy->dev, "Avail curr from USB = %u\n", mA);
+
+ if (dotg->charger->max_power <= 2 && mA > 2) {
+ /* Enable charging */
+ if (power_supply_set_online(dotg->psy, true))
+ goto psy_error;
+ if (power_supply_set_current_limit(dotg->psy, 1000*mA))
+ goto psy_error;
+ } else if (dotg->charger->max_power > 0 && (mA == 0 || mA == 2)) {
+ /* Disable charging */
+ if (power_supply_set_online(dotg->psy, false))
+ goto psy_error;
+ /* Set max current limit */
+ if (power_supply_set_current_limit(dotg->psy, 0))
+ goto psy_error;
+ }
+
+ power_supply_changed(dotg->psy);
+ dotg->charger->max_power = mA;
+ return 0;
+
+psy_error:
+ dev_dbg(phy->dev, "power supply error when setting property\n");
+ return -ENXIO;
+}
+
/* IRQs which OTG driver is interested in handling */
#define DWC3_OEVT_MASK (DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT | \
DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)
@@ -401,23 +492,32 @@
{
u32 osts = dwc3_readl(dotg->regs, DWC3_OSTS);
struct usb_phy *phy = dotg->otg.phy;
-
- /*
- * TODO: If using external notifications then wait here till initial
- * state is reported
- */
+ struct dwc3_ext_xceiv *ext_xceiv;
+ int ret;
dev_dbg(phy->dev, "Initialize OTG inputs, osts: 0x%x\n", osts);
- if (osts & DWC3_OTG_OSTS_CONIDSTS)
- set_bit(ID, &dotg->inputs);
- else
- clear_bit(ID, &dotg->inputs);
+ /*
+ * VBUS initial state is reported after PMIC
+ * driver initialization. Wait for it.
+ */
+ ret = wait_for_completion_timeout(&dotg->dwc3_xcvr_vbus_init, HZ * 5);
+ if (!ret)
+ dev_err(phy->dev, "%s: completion timeout\n", __func__);
- if (osts & DWC3_OTG_OSTS_BSESVALID)
- set_bit(B_SESS_VLD, &dotg->inputs);
- else
- clear_bit(B_SESS_VLD, &dotg->inputs);
+ ext_xceiv = dotg->ext_xceiv;
+ dwc3_otg_reset(dotg);
+ if (ext_xceiv && !ext_xceiv->otg_capability) {
+ if (osts & DWC3_OTG_OSTS_CONIDSTS)
+ set_bit(ID, &dotg->inputs);
+ else
+ clear_bit(ID, &dotg->inputs);
+
+ if (osts & DWC3_OTG_OSTS_BSESVALID)
+ set_bit(B_SESS_VLD, &dotg->inputs);
+ else
+ clear_bit(B_SESS_VLD, &dotg->inputs);
+ }
}
/**
@@ -442,6 +542,14 @@
switch (phy->state) {
case OTG_STATE_UNDEFINED:
dwc3_otg_init_sm(dotg);
+ if (!dotg->psy) {
+ dotg->psy = power_supply_get_by_name("usb");
+
+ if (!dotg->psy)
+ dev_err(phy->dev,
+ "couldn't get usb power supply\n");
+ }
+
/* Switch to A or B-Device according to ID / BSV */
if (!test_bit(ID, &dotg->inputs)) {
dev_dbg(phy->dev, "!id\n");
@@ -478,9 +586,13 @@
switch (charger->chg_type) {
case DWC3_DCP_CHARGER:
dev_dbg(phy->dev, "lpm, DCP charger\n");
+ dwc3_otg_set_power(phy,
+ DWC3_IDEV_CHG_MAX);
pm_runtime_put_sync(phy->dev);
break;
case DWC3_CDP_CHARGER:
+ dwc3_otg_set_power(phy,
+ DWC3_IDEV_CHG_MAX);
dwc3_otg_start_peripheral(&dotg->otg,
1);
phy->state = OTG_STATE_B_PERIPHERAL;
@@ -521,6 +633,7 @@
charger->chg_type =
DWC3_INVALID_CHARGER;
}
+ dwc3_otg_set_power(phy, 0);
dev_dbg(phy->dev, "No device, trying to suspend\n");
pm_runtime_put_sync(phy->dev);
}
@@ -587,6 +700,8 @@
static void dwc3_otg_reset(struct dwc3_otg *dotg)
{
static int once;
+ struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
+
/*
* OCFG[2] - OTG-Version = 1
* OCFG[1] - HNPCap = 0
@@ -612,9 +727,10 @@
dwc3_writel(dotg->regs, DWC3_OEVT, 0xFFFF);
/* Enable ID/BSV StsChngEn event*/
- dwc3_writel(dotg->regs, DWC3_OEVTEN,
- DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT |
- DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT);
+ if (ext_xceiv && !ext_xceiv->otg_capability)
+ dwc3_writel(dotg->regs, DWC3_OEVTEN,
+ DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT |
+ DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT);
}
/**
@@ -687,6 +803,7 @@
dotg->dwc = dwc;
dotg->otg.phy->otg = &dotg->otg;
dotg->otg.phy->dev = dwc->dev;
+ dotg->otg.phy->set_power = dwc3_otg_set_power;
ret = usb_set_transceiver(dotg->otg.phy);
if (ret) {
@@ -696,10 +813,9 @@
goto err2;
}
- dwc3_otg_reset(dotg);
-
dotg->otg.phy->state = OTG_STATE_UNDEFINED;
+ init_completion(&dotg->dwc3_xcvr_vbus_init);
INIT_WORK(&dotg->sm_work, dwc3_otg_sm_work);
ret = request_irq(dotg->irq, dwc3_otg_interrupt, IRQF_SHARED,
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
index dd4cdf4..4384888 100644
--- a/drivers/usb/dwc3/dwc3_otg.h
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -17,9 +17,12 @@
#define __LINUX_USB_DWC3_OTG_H
#include <linux/workqueue.h>
+#include <linux/power_supply.h>
#include <linux/usb/otg.h>
+#define DWC3_IDEV_CHG_MAX 1500
+
struct dwc3_charger;
/**
@@ -43,6 +46,8 @@
#define ID 0
#define B_SESS_VLD 1
unsigned long inputs;
+ struct power_supply *psy;
+ struct completion dwc3_xcvr_vbus_init;
};
/**
@@ -64,6 +69,7 @@
struct dwc3_charger {
enum dwc3_chg_type chg_type;
+ unsigned max_power;
/* start/stop charger detection, provided by external charger module */
void (*start_detection)(struct dwc3_charger *charger, bool start);
@@ -91,6 +97,7 @@
struct dwc3_ext_xceiv {
enum dwc3_id_state id;
bool bsv;
+ bool otg_capability;
/* to notify OTG about LPM exit event, provided by OTG */
void (*notify_ext_events)(struct usb_otg *otg,
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 451de18..9c1ebf8 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1455,6 +1455,17 @@
return 0;
}
+static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned mA)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+ struct dwc3_otg *dotg = dwc->dotg;
+
+ if (dotg && dotg->otg.phy)
+ return usb_phy_set_power(dotg->otg.phy, mA);
+
+ return -ENOTSUPP;
+}
+
static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
{
struct dwc3 *dwc = gadget_to_dwc(g);
@@ -1658,6 +1669,7 @@
.wakeup = dwc3_gadget_wakeup,
.set_selfpowered = dwc3_gadget_set_selfpowered,
.vbus_session = dwc3_gadget_vbus_session,
+ .vbus_draw = dwc3_gadget_vbus_draw,
.pullup = dwc3_gadget_pullup,
.udc_start = dwc3_gadget_start,
.udc_stop = dwc3_gadget_stop,
@@ -2083,6 +2095,7 @@
static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
{
u32 reg;
+ struct dwc3_otg *dotg = dwc->dotg;
dev_vdbg(dwc->dev, "%s\n", __func__);
@@ -2127,6 +2140,9 @@
dwc3_gadget_usb3_phy_suspend(dwc, false);
}
+ if (dotg && dotg->otg.phy)
+ usb_phy_set_power(dotg->otg.phy, 0);
+
if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
dwc3_disconnect_gadget(dwc);
@@ -2334,6 +2350,13 @@
}
}
+ if (next == DWC3_LINK_STATE_U0) {
+ if (dwc->link_state == DWC3_LINK_STATE_U3)
+ dwc->gadget_driver->resume(&dwc->gadget);
+ } else if (next == DWC3_LINK_STATE_U3) {
+ dwc->gadget_driver->suspend(&dwc->gadget);
+ }
+
dwc->link_state = next;
dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 712d41b..c7f9e55 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -2873,7 +2873,7 @@
pdata->on = mdp4_dtv_on;
pdata->off = mdp4_dtv_off;
mfd->hw_refresh = TRUE;
- mfd->cursor_update = mdp_hw_cursor_update;
+ mfd->cursor_update = mdp_hw_cursor_sync_update;
mfd->dma_fnc = mdp4_dtv_overlay;
mfd->dma = &dma_e_data;
mfd->do_histogram = mdp_do_histogram;
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index 516722e..ee9ca3c 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -630,6 +630,7 @@
if (panel & MDP4_PANEL_ATV)
mdp4_overlay1_done_atv();
#endif
+ mdp_hw_cursor_done();
}
#if defined(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL)
if (isr & INTR_OVERLAY2_DONE) {
diff --git a/drivers/video/msm/mdp_cursor.c b/drivers/video/msm/mdp_cursor.c
index f8c08e3..b5930a1 100644
--- a/drivers/video/msm/mdp_cursor.c
+++ b/drivers/video/msm/mdp_cursor.c
@@ -52,7 +52,11 @@
/* disable vsync */
spin_lock_irqsave(&mdp_spin_lock, flag);
- mdp_disable_irq(MDP_OVERLAY0_TERM);
+ if (hdmi_prim_display)
+ mdp_disable_irq(MDP_OVERLAY1_TERM);
+ else
+ mdp_disable_irq(MDP_OVERLAY0_TERM);
+
spin_unlock_irqrestore(&mdp_spin_lock, flag);
}
@@ -78,29 +82,37 @@
*
* Moving this code out of the ISR will cause the MDP to underrun!
*/
+ uint32_t base = 0;
+
+ if (hdmi_prim_display)
+ base = ((uint32_t)(MDP_BASE + 0xB0000));
+ else
+ base = ((uint32_t)(MDP_BASE + 0x90000));
+
+
spin_lock(&mdp_spin_lock);
if (sync_disabled) {
spin_unlock(&mdp_spin_lock);
return;
}
- MDP_OUTP(MDP_BASE + 0x90044, (height << 16) | width);
- MDP_OUTP(MDP_BASE + 0x90048, cursor_buf_phys);
+ MDP_OUTP(base + 0x44, (height << 16) | width);
+ MDP_OUTP(base + 0x48, cursor_buf_phys);
- MDP_OUTP(MDP_BASE + 0x90060,
+ MDP_OUTP(base + 0x60,
(transp_en << 3) | (calpha_en << 1) |
- (inp32(MDP_BASE + 0x90060) & 0x1));
+ (inp32(base + 0x60) & 0x1));
- MDP_OUTP(MDP_BASE + 0x90064, (alpha << 24));
- MDP_OUTP(MDP_BASE + 0x90068, (0xffffff & bg_color));
- MDP_OUTP(MDP_BASE + 0x9006C, (0xffffff & bg_color));
+ MDP_OUTP(base + 0x64, (alpha << 24));
+ MDP_OUTP(base + 0x68, (0xffffff & bg_color));
+ MDP_OUTP(base + 0x6C, (0xffffff & bg_color));
/* enable/disable the cursor as per the last request */
- if (cursor_enabled && !(inp32(MDP_BASE + 0x90060) & (0x1)))
- MDP_OUTP(MDP_BASE + 0x90060, inp32(MDP_BASE + 0x90060) | 0x1);
- else if (!cursor_enabled && (inp32(MDP_BASE + 0x90060) & (0x1)))
- MDP_OUTP(MDP_BASE + 0x90060,
- inp32(MDP_BASE + 0x90060) & (~0x1));
+ if (cursor_enabled && !(inp32(base + 0x60) & (0x1)))
+ MDP_OUTP(base + 0x60, inp32(base + 0x60) | 0x1);
+ else if (!cursor_enabled && (inp32(base + 0x60) & (0x1)))
+ MDP_OUTP(base + 0x60,
+ inp32(base + 0x60) & (~0x1));
/* enqueue the task to disable MDP interrupts */
queue_work(mdp_cursor_ctrl_wq, &mdp_cursor_ctrl_worker);
@@ -119,17 +131,26 @@
if (sync_disabled) {
/* cancel pending task to disable MDP interrupts */
- if (work_pending(&mdp_cursor_ctrl_worker))
+ if (work_pending(&mdp_cursor_ctrl_worker)) {
cancel_work_sync(&mdp_cursor_ctrl_worker);
- else
+ } else {
/* enable irq */
- mdp_enable_irq(MDP_OVERLAY0_TERM);
+ if (hdmi_prim_display)
+ mdp_enable_irq(MDP_OVERLAY1_TERM);
+ else
+ mdp_enable_irq(MDP_OVERLAY0_TERM);
+ }
sync_disabled = 0;
/* enable vsync intr */
- outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE);
- mdp_intr_mask |= INTR_OVERLAY0_DONE;
+ if (hdmi_prim_display) {
+ outp32(MDP_INTR_CLEAR, INTR_OVERLAY1_DONE);
+ mdp_intr_mask |= INTR_OVERLAY1_DONE;
+ } else {
+ outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE);
+ mdp_intr_mask |= INTR_OVERLAY0_DONE;
+ }
outp32(MDP_INTR_ENABLE, mdp_intr_mask);
}
}
@@ -140,14 +161,20 @@
struct fb_image *img = &cursor->image;
unsigned long flag;
int sync_needed = 0, ret = 0;
+ uint32_t base = 0;
if ((img->width > MDP_CURSOR_WIDTH) ||
(img->height > MDP_CURSOR_HEIGHT) ||
(img->depth != 32))
return -EINVAL;
+ if (hdmi_prim_display)
+ base = ((uint32_t)(MDP_BASE + 0xB0000));
+ else
+ base = ((uint32_t)(MDP_BASE + 0x90000));
+
if (cursor->set & FB_CUR_SETPOS)
- MDP_OUTP(MDP_BASE + 0x9004c, (img->dy << 16) | img->dx);
+ MDP_OUTP(base + 0x4c, (img->dy << 16) | img->dx);
if (cursor->set & FB_CUR_SETIMAGE) {
ret = copy_from_user(mfd->cursor_buf, img->data,