mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-09-21 11:53:01 +00:00
usb: dwc3-msm: DBM refactoring
Refactoring of DBM code to allow easy support for future DBM versions. All DBM specific operation are now defined in dbm.h, and implemented in a dbm specific version module. Note that only a single instance of DBM is currently supported. Change-Id: I751300240951a84a42358c3b8b5222e73c537653 Signed-off-by: Bar Weiner <bweiner@codeaurora.org>
This commit is contained in:
parent
f82aaf71a3
commit
3bc20703e5
11
Documentation/devicetree/bindings/usb/msm-dbm.txt
Normal file
11
Documentation/devicetree/bindings/usb/msm-dbm.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
MSM DBM (Device Bus Manager)
|
||||
|
||||
Required properties :
|
||||
- compatible : should be "qcom,usb-dbm-<dbm version number>"
|
||||
- reg : offset and length of the register set in the memory map.
|
||||
|
||||
Example MSM DBM (Device Bus Manager) device node :
|
||||
dbm_1p4: dbm@f92f8000 {
|
||||
compatible = "qcom,usb-dbm-1p4";
|
||||
reg = <0xf92f8000 0x1000>;
|
||||
};
|
|
@ -11,10 +11,6 @@ Required properties :
|
|||
"vbus_dwc3" : vbus supply for host mode when DWC3 operating as DRD.
|
||||
This can be left as optional if "host-only-mode" is selected in the
|
||||
'dwc3' sub node for "DWC3-USB3 Core device".
|
||||
- qcom,dwc-usb3-msm-dbm-eps: Number of endpoints avaliable for
|
||||
the DBM (Device Bus Manager). The DBM is HW unit which is part of
|
||||
the MSM USB3.0 core (which also includes the Synopsys DesignWare
|
||||
USB3.0 controller)
|
||||
|
||||
Optional properties :
|
||||
- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
|
||||
|
@ -52,6 +48,7 @@ Optional properties :
|
|||
being reset in initialization.
|
||||
- qcom,no-suspend-resume: If present, the device will not perform any activity
|
||||
during suspend/resume
|
||||
- qcom,usb-dbm : phandle for the DBM device
|
||||
|
||||
Sub nodes:
|
||||
- Sub node for "DWC3- USB3 controller".
|
||||
|
@ -71,6 +68,7 @@ Example MSM USB3.0 controller device node :
|
|||
qcom,dwc_usb3-adc_tm = <&pm8941_adc_tm>;
|
||||
qcom,dwc-usb3-msm-tx-fifo-size = <29696>;
|
||||
qcom,dwc-usb3-msm-qdss-tx-fifo-size = <16384>;
|
||||
qcom,usb-dbm = <&dbm_1p4>;
|
||||
|
||||
qcom,msm_bus,name = "usb3";
|
||||
qcom,msm_bus,num_cases = <2>;
|
||||
|
|
|
@ -1928,12 +1928,12 @@
|
|||
interrupt-names = "hs_phy_irq", "pmic_id_irq";
|
||||
|
||||
USB3_GDSC-supply = <&gdsc_usb30>;
|
||||
qcom,dwc-usb3-msm-dbm-eps = <4>;
|
||||
qcom,dwc-usb3-msm-tx-fifo-size = <29696>;
|
||||
qcom,dwc-usb3-msm-qdss-tx-fifo-size = <8192>;
|
||||
qcom,otg-capability;
|
||||
qcom,misc-ref = <&pma8084_misc>;
|
||||
qcom,restore-sec-cfg-for-scm-dev-id = <9>;
|
||||
qcom,usb-dbm = <&dbm0_1p4>;
|
||||
|
||||
qcom,msm-bus,name = "usb3";
|
||||
qcom,msm-bus,num-cases = <2>;
|
||||
|
@ -2006,6 +2006,11 @@
|
|||
qcom,vbus-valid-override;
|
||||
};
|
||||
|
||||
dbm0_1p4: dbm@f92f8000 {
|
||||
compatible = "qcom,usb-dbm-1p4";
|
||||
reg = <0xf92f8000 0x1000>;
|
||||
};
|
||||
|
||||
hsphy1: hsphy@f94f8800 {
|
||||
compatible = "qcom,usb-hsphy";
|
||||
reg = <0xf94f8800 0x3ff>;
|
||||
|
|
|
@ -301,9 +301,9 @@
|
|||
|
||||
vbus_dwc3-supply = <&usb3_otg>;
|
||||
qcom,charging-disabled;
|
||||
qcom,dwc-usb3-msm-dbm-eps = <4>;
|
||||
qcom,dwc-usb3-msm-tx-fifo-size = <29696>;
|
||||
qcom,dwc-usb3-msm-qdss-tx-fifo-size = <8192>;
|
||||
qcom,usb-dbm = <&dbm0_1p4>;
|
||||
|
||||
qcom,msm-bus,name = "usb3";
|
||||
qcom,msm-bus,num-cases = <2>;
|
||||
|
@ -343,6 +343,11 @@
|
|||
qcom,vdd-voltage-level = <1 5 7>;
|
||||
};
|
||||
|
||||
dbm0_1p4: dbm@f92f8000 {
|
||||
compatible = "qcom,usb-dbm-1p4";
|
||||
reg = <0xf92f8000 0x1000>;
|
||||
};
|
||||
|
||||
spmi_bus: qcom,spmi@fc4c0000 {
|
||||
cell-index = <0>;
|
||||
compatible = "qcom,spmi-pmic-arb";
|
||||
|
|
|
@ -1647,11 +1647,11 @@
|
|||
interrupt-names = "hs_phy_irq", "pmic_id_irq";
|
||||
|
||||
vbus_dwc3-supply = <&pm8941_mvs1>;
|
||||
qcom,dwc-usb3-msm-dbm-eps = <4>;
|
||||
qcom,misc-ref = <&pm8941_misc>;
|
||||
dwc_usb3-adc_tm = <&pm8941_adc_tm>;
|
||||
qcom,dwc-usb3-msm-tx-fifo-size = <29696>;
|
||||
qcom,dwc-usb3-msm-qdss-tx-fifo-size = <8192>;
|
||||
qcom,usb-dbm = <&dbm_1p4>;
|
||||
|
||||
qcom,msm-bus,name = "usb3";
|
||||
qcom,msm-bus,num-cases = <2>;
|
||||
|
@ -1689,6 +1689,10 @@
|
|||
qcom,vdd-voltage-level = <1 5 7>;
|
||||
};
|
||||
|
||||
dbm_1p4: dbm@f92f8000 {
|
||||
compatible = "qcom,usb-dbm-1p4";
|
||||
reg = <0xf92f8000 0x1000>;
|
||||
};
|
||||
ehci: qcom,ehci-host@f9a55000 {
|
||||
compatible = "qcom,ehci-host";
|
||||
status = "disabled";
|
||||
|
|
|
@ -38,7 +38,7 @@ endif
|
|||
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3-omap.o
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3-exynos.o
|
||||
obj-$(CONFIG_USB_DWC3_MSM) += dwc3-msm.o
|
||||
obj-$(CONFIG_USB_DWC3_MSM) += dbm-1_4.o dwc3-msm.o dbm.o
|
||||
|
||||
ifneq ($(CONFIG_PCI),)
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3-pci.o
|
||||
|
|
428
drivers/usb/dwc3/dbm-1_4.c
Normal file
428
drivers/usb/dwc3/dbm-1_4.c
Normal file
|
@ -0,0 +1,428 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2013, 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/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "dbm.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* USB DBM Hardware registers.
|
||||
*
|
||||
*/
|
||||
|
||||
#define DBM_EP_CFG(n) (0x00 + 4 * (n))
|
||||
#define DBM_DATA_FIFO(n) (0x10 + 4 * (n))
|
||||
#define DBM_DATA_FIFO_SIZE(n) (0x20 + 4 * (n))
|
||||
#define DBM_DATA_FIFO_EN (0x30)
|
||||
#define DBM_GEVNTADR (0x34)
|
||||
#define DBM_GEVNTSIZ (0x38)
|
||||
#define DBM_DBG_CNFG (0x3C)
|
||||
#define DBM_HW_TRB0_EP(n) (0x40 + 4 * (n))
|
||||
#define DBM_HW_TRB1_EP(n) (0x50 + 4 * (n))
|
||||
#define DBM_HW_TRB2_EP(n) (0x60 + 4 * (n))
|
||||
#define DBM_HW_TRB3_EP(n) (0x70 + 4 * (n))
|
||||
#define DBM_PIPE_CFG (0x80)
|
||||
#define DBM_SOFT_RESET (0x84)
|
||||
#define DBM_GEN_CFG (0x88)
|
||||
#define DBM_GEVNTADR_LSB (0x98)
|
||||
#define DBM_GEVNTADR_MSB (0x9C)
|
||||
#define DBM_DATA_FIFO_LSB(n) (0xA0 + 8 * (n))
|
||||
#define DBM_DATA_FIFO_MSB(n) (0xA4 + 8 * (n))
|
||||
|
||||
#define DBM_1_4_NUM_EP 4
|
||||
|
||||
struct dbm_data {
|
||||
void __iomem *base;
|
||||
|
||||
int dbm_num_eps;
|
||||
u8 ep_num_mapping[DBM_1_4_NUM_EP];
|
||||
};
|
||||
|
||||
static struct dbm_data *dbm_data;
|
||||
|
||||
/**
|
||||
* Write register masked field with debug info.
|
||||
*
|
||||
* @base - DWC3 base virtual address.
|
||||
* @offset - register offset.
|
||||
* @mask - register bitmask.
|
||||
* @val - value to write.
|
||||
*
|
||||
*/
|
||||
static inline void msm_dbm_write_reg_field(void *base, u32 offset,
|
||||
const u32 mask, u32 val)
|
||||
{
|
||||
u32 shift = find_first_bit((void *)&mask, 32);
|
||||
u32 tmp = ioread32(base + offset);
|
||||
|
||||
tmp &= ~mask; /* clear written bits */
|
||||
val = tmp | (val << shift);
|
||||
iowrite32(val, base + offset);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Read register with debug info.
|
||||
*
|
||||
* @base - DWC3 base virtual address.
|
||||
* @offset - register offset.
|
||||
*
|
||||
* @return u32
|
||||
*/
|
||||
static inline u32 msm_dbm_read_reg(void *base, u32 offset)
|
||||
{
|
||||
u32 val = ioread32(base + offset);
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Write register with debug info.
|
||||
*
|
||||
* @base - DWC3 base virtual address.
|
||||
* @offset - register offset.
|
||||
* @val - value to write.
|
||||
*
|
||||
*/
|
||||
static inline void msm_dbm_write_reg(void *base, u32 offset, u32 val)
|
||||
{
|
||||
iowrite32(val, base + offset);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return DBM EP number according to usb endpoint number.
|
||||
*
|
||||
*/
|
||||
static int msm_dbm_find_matching_dbm_ep(u8 usb_ep)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dbm_data->dbm_num_eps; i++)
|
||||
if (dbm_data->ep_num_mapping[i] == usb_ep)
|
||||
return i;
|
||||
|
||||
return -ENODEV; /* Not found */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reset the DBM registers upon initialization.
|
||||
*
|
||||
*/
|
||||
static int soft_reset(bool reset)
|
||||
{
|
||||
pr_debug("%s DBM reset\n", (reset ? "Enter" : "Exit"));
|
||||
|
||||
msm_dbm_write_reg_field(dbm_data->base, DBM_SOFT_RESET,
|
||||
DBM_SFT_RST_MASK, reset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Soft reset specific DBM ep.
|
||||
* This function is called by the function driver upon events
|
||||
* such as transfer aborting, USB re-enumeration and USB
|
||||
* disconnection.
|
||||
*
|
||||
* @dbm_ep - DBM ep number.
|
||||
* @enter_reset - should we enter a reset state or get out of it.
|
||||
*
|
||||
*/
|
||||
static int dbm_ep_soft_reset(u8 dbm_ep, bool enter_reset)
|
||||
{
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
if (dbm_ep >= dbm_data->dbm_num_eps) {
|
||||
pr_err("%s: Invalid DBM ep index\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (enter_reset) {
|
||||
msm_dbm_write_reg_field(dbm_data->base, DBM_SOFT_RESET,
|
||||
DBM_SFT_RST_EPS_MASK & 1 << dbm_ep, 1);
|
||||
} else {
|
||||
msm_dbm_write_reg_field(dbm_data->base, DBM_SOFT_RESET,
|
||||
DBM_SFT_RST_EPS_MASK & 1 << dbm_ep, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configure a USB DBM ep to work in BAM mode.
|
||||
*
|
||||
*
|
||||
* @usb_ep - USB physical EP number.
|
||||
* @producer - producer/consumer.
|
||||
* @disable_wb - disable write back to system memory.
|
||||
* @internal_mem - use internal USB memory for data fifo.
|
||||
* @ioc - enable interrupt on completion.
|
||||
*
|
||||
* @return int - DBM ep number.
|
||||
*/
|
||||
static int ep_config(u8 usb_ep, u8 bam_pipe, bool producer, bool disable_wb,
|
||||
bool internal_mem, bool ioc)
|
||||
{
|
||||
int dbm_ep;
|
||||
u32 ep_cfg;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
dbm_ep = msm_dbm_find_matching_dbm_ep(usb_ep);
|
||||
|
||||
if (dbm_ep < 0) {
|
||||
pr_err("%s: Invalid usb ep index\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* First, reset the dbm endpoint */
|
||||
dbm_ep_soft_reset(dbm_ep, 0);
|
||||
|
||||
/* Set ioc bit for dbm_ep if needed */
|
||||
msm_dbm_write_reg_field(dbm_data->base, DBM_DBG_CNFG,
|
||||
DBM_ENABLE_IOC_MASK & 1 << dbm_ep, ioc ? 1 : 0);
|
||||
|
||||
ep_cfg = (producer ? DBM_PRODUCER : 0) |
|
||||
(disable_wb ? DBM_DISABLE_WB : 0) |
|
||||
(internal_mem ? DBM_INT_RAM_ACC : 0);
|
||||
|
||||
msm_dbm_write_reg_field(dbm_data->base, DBM_EP_CFG(dbm_ep),
|
||||
DBM_PRODUCER | DBM_DISABLE_WB | DBM_INT_RAM_ACC, ep_cfg >> 8);
|
||||
|
||||
msm_dbm_write_reg_field(dbm_data->base, DBM_EP_CFG(dbm_ep), USB3_EPNUM,
|
||||
usb_ep);
|
||||
msm_dbm_write_reg_field(dbm_data->base, DBM_EP_CFG(dbm_ep),
|
||||
DBM_BAM_PIPE_NUM, bam_pipe);
|
||||
msm_dbm_write_reg_field(dbm_data->base, DBM_PIPE_CFG, 0x000000ff,
|
||||
0xe4);
|
||||
msm_dbm_write_reg_field(dbm_data->base, DBM_EP_CFG(dbm_ep), DBM_EN_EP,
|
||||
1);
|
||||
|
||||
return dbm_ep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a USB DBM ep to work in normal mode.
|
||||
*
|
||||
* @usb_ep - USB ep number.
|
||||
*
|
||||
*/
|
||||
static int ep_unconfig(u8 usb_ep)
|
||||
{
|
||||
int dbm_ep;
|
||||
u32 data;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
dbm_ep = msm_dbm_find_matching_dbm_ep(usb_ep);
|
||||
|
||||
if (dbm_ep < 0) {
|
||||
pr_err("%s: Invalid usb ep index\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dbm_data->ep_num_mapping[dbm_ep] = 0;
|
||||
|
||||
data = msm_dbm_read_reg(dbm_data->base, DBM_EP_CFG(dbm_ep));
|
||||
data &= (~0x1);
|
||||
msm_dbm_write_reg(dbm_data->base, DBM_EP_CFG(dbm_ep), data);
|
||||
|
||||
/* Reset the dbm endpoint */
|
||||
dbm_ep_soft_reset(dbm_ep, true);
|
||||
/*
|
||||
* 10 usec delay is required before deasserting DBM endpoint reset
|
||||
* according to hardware programming guide.
|
||||
*/
|
||||
udelay(10);
|
||||
dbm_ep_soft_reset(dbm_ep, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of configured DBM endpoints.
|
||||
*
|
||||
*/
|
||||
static int get_num_of_eps_configured(void)
|
||||
{
|
||||
int i;
|
||||
int count = 0;
|
||||
|
||||
for (i = 0; i < dbm_data->dbm_num_eps; i++)
|
||||
if (dbm_data->ep_num_mapping[i])
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the DBM with the USB3 core event buffer.
|
||||
* This function is called by the SNPS UDC upon initialization.
|
||||
*
|
||||
* @addr - address of the event buffer.
|
||||
* @size - size of the event buffer.
|
||||
*
|
||||
*/
|
||||
static int event_buffer_config(u32 addr_lo, u32 addr_hi, int size)
|
||||
{
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
if (size < 0) {
|
||||
pr_err("%s: Invalid size. size = %d", __func__, size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sizeof(phys_addr_t) > sizeof(u32)) {
|
||||
msm_dbm_write_reg(dbm_data->base, DBM_GEVNTADR_LSB, addr_lo);
|
||||
msm_dbm_write_reg(dbm_data->base, DBM_GEVNTADR_MSB, addr_hi);
|
||||
} else {
|
||||
msm_dbm_write_reg(dbm_data->base, DBM_GEVNTADR, addr_lo);
|
||||
}
|
||||
msm_dbm_write_reg_field(dbm_data->base, DBM_GEVNTSIZ,
|
||||
DBM_GEVNTSIZ_MASK, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int data_fifo_config(u8 dep_num, phys_addr_t addr,
|
||||
u32 size, u8 dst_pipe_idx)
|
||||
{
|
||||
u8 dbm_ep;
|
||||
dbm_ep = dst_pipe_idx;
|
||||
|
||||
dbm_data->ep_num_mapping[dbm_ep] = dep_num;
|
||||
|
||||
if (sizeof(addr) > sizeof(u32)) {
|
||||
u32 lo = lower_32_bits(addr);
|
||||
u32 hi = upper_32_bits(addr);
|
||||
msm_dbm_write_reg(dbm_data->base,
|
||||
DBM_DATA_FIFO_LSB(dbm_ep), lo);
|
||||
msm_dbm_write_reg(dbm_data->base,
|
||||
DBM_DATA_FIFO_MSB(dbm_ep), hi);
|
||||
} else {
|
||||
msm_dbm_write_reg(dbm_data->base,
|
||||
DBM_DATA_FIFO(dbm_ep), addr);
|
||||
}
|
||||
msm_dbm_write_reg_field(dbm_data->base, DBM_DATA_FIFO_SIZE(dbm_ep),
|
||||
DBM_DATA_FIFO_SIZE_MASK, size);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static void set_speed(bool speed)
|
||||
{
|
||||
msm_dbm_write_reg(dbm_data->base, DBM_GEN_CFG, speed >> 2);
|
||||
}
|
||||
|
||||
static void enable(void) {}
|
||||
|
||||
|
||||
static int msm_dbm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dbm *dbm;
|
||||
struct resource *res;
|
||||
int ret = 0;
|
||||
|
||||
dbm_data = devm_kzalloc(dev, sizeof(*dbm_data), GFP_KERNEL);
|
||||
if (!dbm_data)
|
||||
return -ENOMEM;
|
||||
dbm_data->dbm_num_eps = DBM_1_4_NUM_EP;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "missing memory base resource\n");
|
||||
ret = -ENODEV;
|
||||
goto free_dbm_data;
|
||||
}
|
||||
|
||||
dbm_data->base = devm_ioremap_nocache(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (!dbm_data->base) {
|
||||
dev_err(&pdev->dev, "ioremap failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_dbm_data;
|
||||
}
|
||||
|
||||
|
||||
dbm = devm_kzalloc(dev, sizeof(*dbm), GFP_KERNEL);
|
||||
if (!dbm) {
|
||||
dev_err(&pdev->dev, "not enough memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_dbm_data;
|
||||
}
|
||||
|
||||
dbm->dev = dev;
|
||||
|
||||
dbm->soft_reset = soft_reset;
|
||||
dbm->ep_config = ep_config;
|
||||
dbm->ep_unconfig = ep_unconfig;
|
||||
dbm->get_num_of_eps_configured = get_num_of_eps_configured;
|
||||
dbm->event_buffer_config = event_buffer_config;
|
||||
dbm->data_fifo_config = data_fifo_config;
|
||||
dbm->set_speed = set_speed;
|
||||
dbm->enable = enable;
|
||||
|
||||
platform_set_drvdata(pdev, dbm);
|
||||
|
||||
return usb_add_dbm(dbm);
|
||||
|
||||
free_dbm_data:
|
||||
kfree(dbm_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_dbm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dbm *dbm = platform_get_drvdata(pdev);
|
||||
|
||||
kfree(dbm);
|
||||
kfree(dbm_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id msm_dbm_1_4_id_table[] = {
|
||||
{
|
||||
.compatible = "qcom,usb-dbm-1p4",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, msm_dbm_1_4_id_table);
|
||||
|
||||
static struct platform_driver msm_dbm_driver = {
|
||||
.probe = msm_dbm_probe,
|
||||
.remove = msm_dbm_remove,
|
||||
.driver = {
|
||||
.name = "msm-usb-dbm-1-4",
|
||||
.of_match_table = of_match_ptr(msm_dbm_1_4_id_table),
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(msm_dbm_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MSM USB DBM 1.4 driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
70
drivers/usb/dwc3/dbm.c
Normal file
70
drivers/usb/dwc3/dbm.c
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2013, 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/err.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "dbm.h"
|
||||
|
||||
struct dbm_manager {
|
||||
struct list_head dbm_list;
|
||||
};
|
||||
|
||||
static struct dbm_manager dbm_manager = {
|
||||
.dbm_list = LIST_HEAD_INIT(dbm_manager.dbm_list)
|
||||
};
|
||||
|
||||
|
||||
static struct dbm *of_usb_find_dbm(struct device_node *node)
|
||||
{
|
||||
struct dbm *dbm;
|
||||
|
||||
list_for_each_entry(dbm, &dbm_manager.dbm_list, head) {
|
||||
if (node != dbm->dev->of_node)
|
||||
continue;
|
||||
return dbm;
|
||||
}
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
struct dbm *usb_get_dbm_by_phandle(struct device *dev,
|
||||
const char *phandle, u8 index)
|
||||
{
|
||||
struct device_node *node;
|
||||
|
||||
if (!dev->of_node) {
|
||||
dev_dbg(dev, "device does not have a device node entry\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
node = of_parse_phandle(dev->of_node, phandle, index);
|
||||
if (!node) {
|
||||
dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle,
|
||||
dev->of_node->full_name);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
return of_usb_find_dbm(node);
|
||||
}
|
||||
EXPORT_SYMBOL(usb_get_dbm_by_phandle);
|
||||
|
||||
|
||||
int usb_add_dbm(struct dbm *x)
|
||||
{
|
||||
list_add_tail(&x->head, &dbm_manager.dbm_list);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_add_dbm);
|
||||
|
||||
|
164
drivers/usb/dwc3/dbm.h
Normal file
164
drivers/usb/dwc3/dbm.h
Normal file
|
@ -0,0 +1,164 @@
|
|||
/* Copyright (c) 2012-2013, 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.
|
||||
*/
|
||||
|
||||
#ifndef __DBM_H
|
||||
#define __DBM_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
/**
|
||||
* USB DBM Hardware registers bitmask.
|
||||
*
|
||||
*/
|
||||
/* DBM_EP_CFG */
|
||||
#define DBM_EN_EP 0x00000001
|
||||
#define USB3_EPNUM 0x0000003E
|
||||
#define DBM_BAM_PIPE_NUM 0x000000C0
|
||||
#define DBM_PRODUCER 0x00000100
|
||||
#define DBM_DISABLE_WB 0x00000200
|
||||
#define DBM_INT_RAM_ACC 0x00000400
|
||||
|
||||
/* DBM_DATA_FIFO_SIZE */
|
||||
#define DBM_DATA_FIFO_SIZE_MASK 0x0000ffff
|
||||
|
||||
/* DBM_GEVNTSIZ */
|
||||
#define DBM_GEVNTSIZ_MASK 0x0000ffff
|
||||
|
||||
/* DBM_DBG_CNFG */
|
||||
#define DBM_ENABLE_IOC_MASK 0x0000000f
|
||||
|
||||
/* DBM_SOFT_RESET */
|
||||
#define DBM_SFT_RST_EP0 0x00000001
|
||||
#define DBM_SFT_RST_EP1 0x00000002
|
||||
#define DBM_SFT_RST_EP2 0x00000004
|
||||
#define DBM_SFT_RST_EP3 0x00000008
|
||||
#define DBM_SFT_RST_EPS_MASK 0x0000000F
|
||||
#define DBM_SFT_RST_MASK 0x80000000
|
||||
#define DBM_EN_MASK 0x00000002
|
||||
|
||||
/* DBM TRB configurations */
|
||||
#define DBM_TRB_BIT 0x80000000
|
||||
#define DBM_TRB_DATA_SRC 0x40000000
|
||||
#define DBM_TRB_DMA 0x20000000
|
||||
#define DBM_TRB_EP_NUM(ep) (ep<<24)
|
||||
|
||||
|
||||
struct dbm {
|
||||
struct device *dev;
|
||||
struct list_head head;
|
||||
|
||||
/* Reset the DBM registers upon initialization */
|
||||
int (*soft_reset)(bool reset);
|
||||
|
||||
/* Configure a USB DBM ep to work in BAM mode */
|
||||
int (*ep_config)(u8 usb_ep, u8 bam_pipe,
|
||||
bool producer, bool disable_wb,
|
||||
bool internal_mem, bool ioc);
|
||||
|
||||
/* Configure a USB DBM ep to work in normal mode */
|
||||
int (*ep_unconfig)(u8 usb_ep);
|
||||
|
||||
/* Return number of configured DBM endpoints */
|
||||
int (*get_num_of_eps_configured)(void);
|
||||
|
||||
/* Configure the DBM with the USB3 core event buffer */
|
||||
int (*event_buffer_config)(u32 addr_lo, u32 addr_hi, int size);
|
||||
|
||||
/* Configure the DBM with the BAM's data fifo */
|
||||
int (*data_fifo_config)(u8 dep_num, phys_addr_t addr,
|
||||
u32 size, u8 dst_pipe_idx);
|
||||
|
||||
/* Configure DBM speed : hs/ss */
|
||||
void (*set_speed)(bool speed);
|
||||
|
||||
/* Enable DBM */
|
||||
void (*enable)(void);
|
||||
|
||||
};
|
||||
|
||||
struct dbm *usb_get_dbm_by_phandle(struct device *dev,
|
||||
const char *phandle, u8 index);
|
||||
int usb_add_dbm(struct dbm *x);
|
||||
|
||||
|
||||
|
||||
#define CHECK_DBM_PTR_INT(dbm) do { \
|
||||
if (!(dbm)) { \
|
||||
pr_err("Can't call %s, dbp pointer == NULL\n", __func__); \
|
||||
return -EPERM; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_DBM_PTR_VOID(dbm) do { \
|
||||
if (!(dbm)) { \
|
||||
pr_err("Can't call %s, dbp pointer == NULL\n", __func__); \
|
||||
return; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline int dbm_soft_reset(struct dbm *dbm, bool enter_reset)
|
||||
{
|
||||
CHECK_DBM_PTR_INT(dbm);
|
||||
return dbm->soft_reset(enter_reset);
|
||||
}
|
||||
|
||||
static inline int dbm_ep_config(struct dbm *dbm, u8 usb_ep, u8 bam_pipe,
|
||||
bool producer, bool disable_wb, bool internal_mem,
|
||||
bool ioc)
|
||||
{
|
||||
CHECK_DBM_PTR_INT(dbm);
|
||||
return dbm->ep_config(usb_ep, bam_pipe, producer, disable_wb,
|
||||
internal_mem, ioc);
|
||||
|
||||
}
|
||||
|
||||
static inline int dbm_ep_unconfig(struct dbm *dbm, u8 usb_ep)
|
||||
{
|
||||
CHECK_DBM_PTR_INT(dbm);
|
||||
return dbm->ep_unconfig(usb_ep);
|
||||
}
|
||||
|
||||
static inline int dbm_get_num_of_eps_configured(struct dbm *dbm)
|
||||
{
|
||||
CHECK_DBM_PTR_INT(dbm);
|
||||
return dbm->get_num_of_eps_configured();
|
||||
}
|
||||
|
||||
static inline int dbm_event_buffer_config(struct dbm *dbm, u32 addr_lo,
|
||||
u32 addr_hi, int size)
|
||||
{
|
||||
CHECK_DBM_PTR_INT(dbm);
|
||||
return dbm->event_buffer_config(addr_lo, addr_hi, size);
|
||||
}
|
||||
|
||||
static inline int dbm_data_fifo_config(struct dbm *dbm, u8 dep_num,
|
||||
phys_addr_t addr, u32 size, u8 dst_pipe_idx)
|
||||
{
|
||||
CHECK_DBM_PTR_INT(dbm);
|
||||
return dbm->data_fifo_config(dep_num, addr, size, dst_pipe_idx);
|
||||
}
|
||||
|
||||
static inline void dbm_set_speed(struct dbm *dbm, bool speed)
|
||||
{
|
||||
CHECK_DBM_PTR_VOID(dbm);
|
||||
dbm->set_speed(speed);
|
||||
}
|
||||
|
||||
static inline void dbm_enable(struct dbm *dbm)
|
||||
{
|
||||
CHECK_DBM_PTR_VOID(dbm);
|
||||
dbm->enable();
|
||||
}
|
||||
|
||||
|
||||
#endif /* __DBM_H */
|
|
@ -51,6 +51,7 @@
|
|||
#include "dwc3_otg.h"
|
||||
#include "core.h"
|
||||
#include "gadget.h"
|
||||
#include "dbm.h"
|
||||
#include "debug.h"
|
||||
|
||||
/* ADC threshold values */
|
||||
|
@ -75,68 +76,6 @@ static bool prop_chg_detect;
|
|||
module_param(prop_chg_detect, bool, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(prop_chg_detect, "Enable Proprietary charger detection");
|
||||
|
||||
/**
|
||||
* USB DBM Hardware registers.
|
||||
*
|
||||
*/
|
||||
#define DBM_BASE 0x000F8000
|
||||
#define DBM_EP_CFG(n) (DBM_BASE + (0x00 + 4 * (n)))
|
||||
#define DBM_DATA_FIFO(n) (DBM_BASE + (0x10 + 4 * (n)))
|
||||
#define DBM_DATA_FIFO_SIZE(n) (DBM_BASE + (0x20 + 4 * (n)))
|
||||
#define DBM_DATA_FIFO_EN (DBM_BASE + (0x30))
|
||||
#define DBM_GEVNTADR (DBM_BASE + (0x34))
|
||||
#define DBM_GEVNTSIZ (DBM_BASE + (0x38))
|
||||
#define DBM_DBG_CNFG (DBM_BASE + (0x3C))
|
||||
#define DBM_HW_TRB0_EP(n) (DBM_BASE + (0x40 + 4 * (n)))
|
||||
#define DBM_HW_TRB1_EP(n) (DBM_BASE + (0x50 + 4 * (n)))
|
||||
#define DBM_HW_TRB2_EP(n) (DBM_BASE + (0x60 + 4 * (n)))
|
||||
#define DBM_HW_TRB3_EP(n) (DBM_BASE + (0x70 + 4 * (n)))
|
||||
#define DBM_PIPE_CFG (DBM_BASE + (0x80))
|
||||
#define DBM_SOFT_RESET (DBM_BASE + (0x84))
|
||||
#define DBM_GEN_CFG (DBM_BASE + (0x88))
|
||||
#define DBM_GEVNTADR_LSB (DBM_BASE + (0x98))
|
||||
#define DBM_GEVNTADR_MSB (DBM_BASE + (0x9C))
|
||||
#define DBM_DATA_FIFO_LSB(n) (DBM_BASE + (0xA0 + 8 * (n)))
|
||||
#define DBM_DATA_FIFO_MSB(n) (DBM_BASE + (0xA4 + 8 * (n)))
|
||||
|
||||
/**
|
||||
* USB DBM Hardware registers bitmask.
|
||||
*
|
||||
*/
|
||||
/* DBM_EP_CFG */
|
||||
#define DBM_EN_EP 0x00000001
|
||||
#define USB3_EPNUM 0x0000003E
|
||||
#define DBM_BAM_PIPE_NUM 0x000000C0
|
||||
#define DBM_PRODUCER 0x00000100
|
||||
#define DBM_DISABLE_WB 0x00000200
|
||||
#define DBM_INT_RAM_ACC 0x00000400
|
||||
|
||||
/* DBM_DATA_FIFO_SIZE */
|
||||
#define DBM_DATA_FIFO_SIZE_MASK 0x0000ffff
|
||||
|
||||
/* DBM_GEVNTSIZ */
|
||||
#define DBM_GEVNTSIZ_MASK 0x0000ffff
|
||||
|
||||
/* DBM_DBG_CNFG */
|
||||
#define DBM_ENABLE_IOC_MASK 0x0000000f
|
||||
|
||||
/* DBM_SOFT_RESET */
|
||||
#define DBM_SFT_RST_EP0 0x00000001
|
||||
#define DBM_SFT_RST_EP1 0x00000002
|
||||
#define DBM_SFT_RST_EP2 0x00000004
|
||||
#define DBM_SFT_RST_EP3 0x00000008
|
||||
#define DBM_SFT_RST_EPS_MASK 0x0000000F
|
||||
#define DBM_SFT_RST_MASK 0x80000000
|
||||
#define DBM_EN_MASK 0x00000002
|
||||
|
||||
#define DBM_MAX_EPS 8
|
||||
|
||||
/* DBM TRB configurations */
|
||||
#define DBM_TRB_BIT 0x80000000
|
||||
#define DBM_TRB_DATA_SRC 0x40000000
|
||||
#define DBM_TRB_DMA 0x20000000
|
||||
#define DBM_TRB_EP_NUM(ep) (ep<<24)
|
||||
|
||||
#define USB3_PORTSC (0x430)
|
||||
#define PORT_PE (0x1 << 1)
|
||||
/**
|
||||
|
@ -185,8 +124,6 @@ struct dwc3_msm {
|
|||
void __iomem *base;
|
||||
struct resource *io_res;
|
||||
struct platform_device *dwc3;
|
||||
int dbm_num_eps;
|
||||
u8 ep_num_mapping[DBM_MAX_EPS];
|
||||
const struct usb_ep_ops *original_ep_ops[DWC3_ENDPOINTS_NUM];
|
||||
struct list_head req_complete_list;
|
||||
struct clk *xo_clk;
|
||||
|
@ -201,6 +138,8 @@ struct dwc3_msm {
|
|||
|
||||
struct usb_phy *hs_phy, *ss_phy;
|
||||
|
||||
struct dbm *dbm;
|
||||
|
||||
/* VBUS regulator if no OTG and running in host only mode */
|
||||
struct regulator *vbus_otg;
|
||||
struct dwc3_ext_xceiv ext_xceiv;
|
||||
|
@ -394,207 +333,6 @@ static void dwc3_msm_dump_phy_info(struct dwc3_msm *mdwc)
|
|||
PWR_EVNT_IRQ_MASK_REG));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return DBM EP number according to usb endpoint number.
|
||||
*
|
||||
*/
|
||||
static int dwc3_msm_find_matching_dbm_ep(struct dwc3_msm *mdwc, u8 usb_ep)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mdwc->dbm_num_eps; i++)
|
||||
if (mdwc->ep_num_mapping[i] == usb_ep)
|
||||
return i;
|
||||
|
||||
return -ENODEV; /* Not found */
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of configured DBM endpoints.
|
||||
*
|
||||
*/
|
||||
static int dwc3_msm_configured_dbm_ep_num(struct dwc3_msm *mdwc)
|
||||
{
|
||||
int i;
|
||||
int count = 0;
|
||||
|
||||
for (i = 0; i < mdwc->dbm_num_eps; i++)
|
||||
if (mdwc->ep_num_mapping[i])
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the DBM with the USB3 core event buffer.
|
||||
* This function is called by the SNPS UDC upon initialization.
|
||||
*
|
||||
* @addr - address of the event buffer.
|
||||
* @size - size of the event buffer.
|
||||
*
|
||||
*/
|
||||
static int dwc3_msm_event_buffer_config(struct dwc3_msm *mdwc,
|
||||
u32 addr_lo, u32 addr_hi, u16 size)
|
||||
{
|
||||
dev_dbg(mdwc->dev, "%s\n", __func__);
|
||||
|
||||
if (sizeof(phys_addr_t) > sizeof(u32)) {
|
||||
dwc3_msm_write_reg(mdwc->base, DBM_GEVNTADR_LSB, addr_lo);
|
||||
dwc3_msm_write_reg(mdwc->base, DBM_GEVNTADR_MSB, addr_hi);
|
||||
} else {
|
||||
dwc3_msm_write_reg(mdwc->base, DBM_GEVNTADR, addr_lo);
|
||||
}
|
||||
dwc3_msm_write_reg_field(mdwc->base, DBM_GEVNTSIZ,
|
||||
DBM_GEVNTSIZ_MASK, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the DBM registers upon initialization.
|
||||
*
|
||||
*/
|
||||
static int dwc3_msm_dbm_soft_reset(struct dwc3_msm *mdwc, int enter_reset)
|
||||
{
|
||||
dev_dbg(mdwc->dev, "%s\n", __func__);
|
||||
if (enter_reset) {
|
||||
dev_dbg(mdwc->dev, "enter DBM reset\n");
|
||||
dwc3_msm_write_reg_field(mdwc->base, DBM_SOFT_RESET,
|
||||
DBM_SFT_RST_MASK, 1);
|
||||
} else {
|
||||
dev_dbg(mdwc->dev, "exit DBM reset\n");
|
||||
dwc3_msm_write_reg_field(mdwc->base, DBM_SOFT_RESET,
|
||||
DBM_SFT_RST_MASK, 0);
|
||||
/*enable DBM*/
|
||||
dwc3_msm_write_reg_field(mdwc->base, QSCRATCH_GENERAL_CFG,
|
||||
DBM_EN_MASK, 0x1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Soft reset specific DBM ep.
|
||||
* This function is called by the function driver upon events
|
||||
* such as transfer aborting, USB re-enumeration and USB
|
||||
* disconnection.
|
||||
*
|
||||
* @dbm_ep - DBM ep number.
|
||||
* @enter_reset - should we enter a reset state or get out of it.
|
||||
*
|
||||
*/
|
||||
static int dwc3_msm_dbm_ep_soft_reset(struct dwc3_msm *mdwc,
|
||||
u8 dbm_ep, bool enter_reset)
|
||||
{
|
||||
dev_dbg(mdwc->dev, "%s\n", __func__);
|
||||
|
||||
if (dbm_ep >= mdwc->dbm_num_eps) {
|
||||
dev_err(mdwc->dev, "%s: Invalid DBM ep index\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (enter_reset) {
|
||||
dwc3_msm_write_reg_field(mdwc->base, DBM_SOFT_RESET,
|
||||
DBM_SFT_RST_EPS_MASK & 1 << dbm_ep, 1);
|
||||
} else {
|
||||
dwc3_msm_write_reg_field(mdwc->base, DBM_SOFT_RESET,
|
||||
DBM_SFT_RST_EPS_MASK & 1 << dbm_ep, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a USB DBM ep to work in BAM mode.
|
||||
*
|
||||
*
|
||||
* @usb_ep - USB physical EP number.
|
||||
* @producer - producer/consumer.
|
||||
* @disable_wb - disable write back to system memory.
|
||||
* @internal_mem - use internal USB memory for data fifo.
|
||||
* @ioc - enable interrupt on completion.
|
||||
*
|
||||
* @return int - DBM ep number.
|
||||
*/
|
||||
static int dwc3_msm_dbm_ep_config(struct dwc3_msm *mdwc, u8 usb_ep, u8 bam_pipe,
|
||||
bool producer, bool disable_wb,
|
||||
bool internal_mem, bool ioc)
|
||||
{
|
||||
int dbm_ep;
|
||||
u32 ep_cfg;
|
||||
|
||||
dev_dbg(mdwc->dev, "%s\n", __func__);
|
||||
|
||||
dbm_ep = dwc3_msm_find_matching_dbm_ep(mdwc, usb_ep);
|
||||
|
||||
if (dbm_ep < 0) {
|
||||
dev_err(mdwc->dev,
|
||||
"%s: Invalid usb ep index\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
/* First, reset the dbm endpoint */
|
||||
dwc3_msm_dbm_ep_soft_reset(mdwc, dbm_ep, 0);
|
||||
|
||||
/* Set ioc bit for dbm_ep if needed */
|
||||
dwc3_msm_write_reg_field(mdwc->base, DBM_DBG_CNFG,
|
||||
DBM_ENABLE_IOC_MASK & 1 << dbm_ep, ioc ? 1 : 0);
|
||||
|
||||
ep_cfg = (producer ? DBM_PRODUCER : 0) |
|
||||
(disable_wb ? DBM_DISABLE_WB : 0) |
|
||||
(internal_mem ? DBM_INT_RAM_ACC : 0);
|
||||
|
||||
dwc3_msm_write_reg_field(mdwc->base, DBM_EP_CFG(dbm_ep),
|
||||
DBM_PRODUCER | DBM_DISABLE_WB | DBM_INT_RAM_ACC, ep_cfg >> 8);
|
||||
|
||||
dwc3_msm_write_reg_field(mdwc->base, DBM_EP_CFG(dbm_ep), USB3_EPNUM,
|
||||
usb_ep);
|
||||
dwc3_msm_write_reg_field(mdwc->base, DBM_EP_CFG(dbm_ep),
|
||||
DBM_BAM_PIPE_NUM, bam_pipe);
|
||||
dwc3_msm_write_reg_field(mdwc->base, DBM_PIPE_CFG, 0x000000ff,
|
||||
0xe4);
|
||||
dwc3_msm_write_reg_field(mdwc->base, DBM_EP_CFG(dbm_ep), DBM_EN_EP,
|
||||
1);
|
||||
|
||||
return dbm_ep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a USB DBM ep to work in normal mode.
|
||||
*
|
||||
* @usb_ep - USB ep number.
|
||||
*
|
||||
*/
|
||||
static int dwc3_msm_dbm_ep_unconfig(struct dwc3_msm *mdwc, u8 usb_ep)
|
||||
{
|
||||
int dbm_ep;
|
||||
u32 data;
|
||||
|
||||
dev_dbg(mdwc->dev, "%s\n", __func__);
|
||||
|
||||
dbm_ep = dwc3_msm_find_matching_dbm_ep(mdwc, usb_ep);
|
||||
|
||||
if (dbm_ep < 0) {
|
||||
dev_err(mdwc->dev, "%s: Invalid usb ep index\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mdwc->ep_num_mapping[dbm_ep] = 0;
|
||||
|
||||
data = dwc3_msm_read_reg(mdwc->base, DBM_EP_CFG(dbm_ep));
|
||||
data &= (~0x1);
|
||||
dwc3_msm_write_reg(mdwc->base, DBM_EP_CFG(dbm_ep), data);
|
||||
|
||||
/* Reset the dbm endpoint */
|
||||
dwc3_msm_dbm_ep_soft_reset(mdwc, dbm_ep, true);
|
||||
/*
|
||||
* 10 usec delay is required before deasserting DBM endpoint reset
|
||||
* according to hardware programming guide.
|
||||
*/
|
||||
udelay(10);
|
||||
dwc3_msm_dbm_ep_soft_reset(mdwc, dbm_ep, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the DBM with the BAM's data fifo.
|
||||
|
@ -609,31 +347,17 @@ static int dwc3_msm_dbm_ep_unconfig(struct dwc3_msm *mdwc, u8 usb_ep)
|
|||
int msm_data_fifo_config(struct usb_ep *ep, phys_addr_t addr,
|
||||
u32 size, u8 dst_pipe_idx)
|
||||
{
|
||||
u8 dbm_ep;
|
||||
struct dwc3_ep *dep = to_dwc3_ep(ep);
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
|
||||
u8 bam_pipe = dst_pipe_idx;
|
||||
|
||||
dev_dbg(mdwc->dev, "%s\n", __func__);
|
||||
|
||||
dbm_ep = bam_pipe;
|
||||
mdwc->ep_num_mapping[dbm_ep] = dep->number;
|
||||
|
||||
if (sizeof(addr) > sizeof(u32)) {
|
||||
u32 lo = lower_32_bits(addr);
|
||||
u32 hi = upper_32_bits(addr);
|
||||
dwc3_msm_write_reg(mdwc->base, DBM_DATA_FIFO_LSB(dbm_ep), lo);
|
||||
dwc3_msm_write_reg(mdwc->base, DBM_DATA_FIFO_MSB(dbm_ep), hi);
|
||||
} else {
|
||||
dwc3_msm_write_reg(mdwc->base, DBM_DATA_FIFO(dbm_ep), addr);
|
||||
}
|
||||
dwc3_msm_write_reg_field(mdwc->base, DBM_DATA_FIFO_SIZE(dbm_ep),
|
||||
DBM_DATA_FIFO_SIZE_MASK, size);
|
||||
|
||||
return 0;
|
||||
return dbm_data_fifo_config(mdwc->dbm, dep->number, addr, size,
|
||||
dst_pipe_idx);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cleanups for msm endpoint on request complete.
|
||||
*
|
||||
|
@ -642,7 +366,7 @@ int msm_data_fifo_config(struct usb_ep *ep, phys_addr_t addr,
|
|||
* @usb_ep - pointer to usb_ep instance.
|
||||
* @request - pointer to usb_request instance.
|
||||
*
|
||||
* @return int - 0 on success, negetive on error.
|
||||
* @return int - 0 on success, negative on error.
|
||||
*/
|
||||
static void dwc3_msm_req_complete_func(struct usb_ep *ep,
|
||||
struct usb_request *request)
|
||||
|
@ -672,14 +396,14 @@ static void dwc3_msm_req_complete_func(struct usb_ep *ep,
|
|||
dep->busy_slot++;
|
||||
|
||||
/* Unconfigure dbm ep */
|
||||
dwc3_msm_dbm_ep_unconfig(mdwc, dep->number);
|
||||
dbm_ep_unconfig(mdwc->dbm, dep->number);
|
||||
|
||||
/*
|
||||
* If this is the last endpoint we unconfigured, than reset also
|
||||
* the event buffers.
|
||||
*/
|
||||
if (0 == dwc3_msm_configured_dbm_ep_num(mdwc))
|
||||
dwc3_msm_event_buffer_config(mdwc, 0, 0, 0);
|
||||
if (0 == dbm_get_num_of_eps_configured(mdwc->dbm))
|
||||
dbm_event_buffer_config(mdwc->dbm, 0, 0, 0);
|
||||
|
||||
/*
|
||||
* Call original complete function, notice that dwc->lock is already
|
||||
|
@ -699,7 +423,7 @@ static void dwc3_msm_req_complete_func(struct usb_ep *ep,
|
|||
* @dwc3_ep - pointer to dwc3_ep instance.
|
||||
* @req - pointer to dwc3_request instance.
|
||||
*
|
||||
* @return int - 0 on success, negetive on error.
|
||||
* @return int - 0 on success, negative on error.
|
||||
*/
|
||||
static int __dwc3_msm_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
{
|
||||
|
@ -727,7 +451,8 @@ static int __dwc3_msm_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
req->trb = trb;
|
||||
trb->bph = DBM_TRB_BIT | DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
|
||||
trb->size = DWC3_TRB_SIZE_LENGTH(req->request.length);
|
||||
trb->ctrl = DWC3_TRBCTL_NORMAL | DWC3_TRB_CTRL_HWO | DWC3_TRB_CTRL_CHN;
|
||||
trb->ctrl = DWC3_TRBCTL_NORMAL | DWC3_TRB_CTRL_HWO |
|
||||
DWC3_TRB_CTRL_CHN | (req->direction ? 0 : DWC3_TRB_CTRL_CSP);
|
||||
req->trb_dma = dwc3_trb_dma_offset(dep, trb);
|
||||
|
||||
/* Second, prepare a Link TRB that points to the first TRB*/
|
||||
|
@ -770,7 +495,7 @@ static int __dwc3_msm_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
* was enabled by the ep_enable.
|
||||
*
|
||||
* This function prepares special structure of TRBs which
|
||||
* is familier with the DBM HW, so it will possible to use
|
||||
* is familiar with the DBM HW, so it will possible to use
|
||||
* this endpoint in DBM mode.
|
||||
*
|
||||
* The TRBs prepared by this function, is one normal TRB
|
||||
|
@ -784,7 +509,7 @@ static int __dwc3_msm_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||
* @request - pointer to usb_request instance.
|
||||
* @gfp_flags - possible flags.
|
||||
*
|
||||
* @return int - 0 on success, negetive on error.
|
||||
* @return int - 0 on success, negative on error.
|
||||
*/
|
||||
static int dwc3_msm_ep_queue(struct usb_ep *ep,
|
||||
struct usb_request *request, gfp_t gfp_flags)
|
||||
|
@ -862,13 +587,11 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep,
|
|||
internal_mem = ((request->udc_priv & MSM_INTERNAL_MEM) ? true : false);
|
||||
ioc = ((request->udc_priv & MSM_ETD_IOC) ? true : false);
|
||||
|
||||
ret = dwc3_msm_dbm_ep_config(mdwc, dep->number,
|
||||
bam_pipe, producer,
|
||||
disable_wb, internal_mem, ioc);
|
||||
ret = dbm_ep_config(mdwc->dbm, dep->number, bam_pipe, producer,
|
||||
disable_wb, internal_mem, ioc);
|
||||
if (ret < 0) {
|
||||
dev_err(mdwc->dev,
|
||||
"error %d after calling dwc3_msm_dbm_ep_config\n",
|
||||
ret);
|
||||
"error %d after calling dbm_ep_config\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -892,7 +615,7 @@ static int dwc3_msm_ep_queue(struct usb_ep *ep,
|
|||
}
|
||||
|
||||
speed = dwc3_readl(dwc->regs, DWC3_DSTS) & DWC3_DSTS_CONNECTSPD;
|
||||
dwc3_msm_write_reg(mdwc->base, DBM_GEN_CFG, speed >> 2);
|
||||
dbm_set_speed(mdwc->dbm, speed >> 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -918,10 +641,6 @@ int msm_ep_config(struct usb_ep *ep)
|
|||
struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
|
||||
struct usb_ep_ops *new_ep_ops;
|
||||
|
||||
dwc3_msm_event_buffer_config(mdwc,
|
||||
dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRLO(0)),
|
||||
dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRHI(0)),
|
||||
dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTSIZ(0)));
|
||||
|
||||
/* Save original ep ops for future restore*/
|
||||
if (mdwc->original_ep_ops[dep->number]) {
|
||||
|
@ -962,7 +681,7 @@ EXPORT_SYMBOL(msm_ep_config);
|
|||
*
|
||||
* @ep - a pointer to some usb_ep instance
|
||||
*
|
||||
* @return int - 0 on success, negetive on error.
|
||||
* @return int - 0 on success, negative on error.
|
||||
*/
|
||||
int msm_ep_unconfig(struct usb_ep *ep)
|
||||
{
|
||||
|
@ -1285,9 +1004,20 @@ static void dwc3_msm_block_reset(struct dwc3_ext_xceiv *xceiv, bool core_reset)
|
|||
}
|
||||
|
||||
/* Reset the DBM */
|
||||
dwc3_msm_dbm_soft_reset(mdwc, 1);
|
||||
dbm_soft_reset(mdwc->dbm, 1);
|
||||
usleep_range(1000, 1200);
|
||||
dwc3_msm_dbm_soft_reset(mdwc, 0);
|
||||
dbm_soft_reset(mdwc->dbm, 0);
|
||||
|
||||
|
||||
/*enable DBM*/
|
||||
dwc3_msm_write_reg_field(mdwc->base, QSCRATCH_GENERAL_CFG,
|
||||
DBM_EN_MASK, 0x1);
|
||||
dbm_event_buffer_config(mdwc->dbm,
|
||||
dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRLO(0)),
|
||||
dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTADRHI(0)),
|
||||
dwc3_msm_read_reg(mdwc->base, DWC3_GEVNTSIZ(0)));
|
||||
dbm_enable(mdwc->dbm);
|
||||
|
||||
}
|
||||
|
||||
static void dwc3_block_reset_usb_work(struct work_struct *w)
|
||||
|
@ -2623,21 +2353,16 @@ static int dwc3_msm_probe(struct platform_device *pdev)
|
|||
|
||||
mdwc->io_res = res; /* used to calculate chg block offset */
|
||||
|
||||
if (of_property_read_u32(node, "qcom,dwc-usb3-msm-dbm-eps",
|
||||
&mdwc->dbm_num_eps)) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to read platform data num of dbm eps\n");
|
||||
mdwc->dbm_num_eps = DBM_MAX_EPS;
|
||||
}
|
||||
if (of_get_property(pdev->dev.of_node, "qcom,usb-dbm", NULL)) {
|
||||
mdwc->dbm = usb_get_dbm_by_phandle(&pdev->dev, "qcom,usb-dbm",
|
||||
0);
|
||||
if (IS_ERR(mdwc->dbm)) {
|
||||
dev_err(&pdev->dev, "unable to get dbm device\n");
|
||||
ret = -EPROBE_DEFER;
|
||||
goto disable_ref_clk;
|
||||
}
|
||||
}
|
||||
|
||||
if (mdwc->dbm_num_eps > DBM_MAX_EPS) {
|
||||
dev_err(&pdev->dev,
|
||||
"Driver doesn't support number of DBM EPs. "
|
||||
"max: %d, dbm_num_eps: %d\n",
|
||||
DBM_MAX_EPS, mdwc->dbm_num_eps);
|
||||
ret = -ENODEV;
|
||||
goto disable_ref_clk;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(node, "qcom,dwc-usb3-msm-tx-fifo-size",
|
||||
&mdwc->tx_fifo_size))
|
||||
|
|
Loading…
Reference in a new issue