blob: ee8b2c035d515a93283327fcd25424f8eb8e445b [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
#include <clk.h>
#include <common.h>
#include <dm.h>
#include <dt-bindings/clock/mt8516-clk.h>
#include "musb_core.h"
#define USB_L1INTS (0x00a0) /* USB level 1 interrupt status register */
#define USB_L1INTM (0x00a4) /* USB level 1 interrupt mask register */
#define USB_L1INTP (0x00a8) /* USB level 1 interrupt polarity register */
#define TX_INT_STATUS (1<<0)
#define RX_INT_STATUS (1<<1)
#define USBCOM_INT_STATUS (1<<2)
#define DMA_INT_STATUS (1<<3)
#define PSR_INT_STATUS (1<<4)
#define QINT_STATUS (1<<5)
#define QHIF_INT_STATUS (1<<6)
#define DPDM_INT_STATUS (1<<7)
#define VBUSVALID_INT_STATUS (1<<8)
#define IDDIG_INT_STATUS (1<<9)
#define DRVVBUS_INT_STATUS (1<<10)
/*EP Fifo Config*/
static struct musb_fifo_cfg fifo_cfg[] __initdata = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE},
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE},
{ .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE},
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE},
{ .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE},
{ .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE},
{ .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE},
{ .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE},
{ .hw_ep_num = 5, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_SINGLE},
{ .hw_ep_num = 5, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_SINGLE},
{ .hw_ep_num = 6, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_SINGLE},
{ .hw_ep_num = 6, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_SINGLE},
{ .hw_ep_num = 7, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_SINGLE},
{ .hw_ep_num = 7, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_SINGLE},
{ .hw_ep_num = 8, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE},
{ .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE},
};
static struct musb_hdrc_config mt8xx_musb_hdrc_config = {
.multipoint = true,
.dyn_fifo = true,
.num_eps = 16,
.ram_bits = 16,
.fifo_cfg = fifo_cfg,
.fifo_cfg_size = ARRAY_SIZE(fifo_cfg),
};
struct omap_musb_board_data {
u8 interface_type;
struct udevice *dev;
void (*set_phy_power)(struct udevice *dev, u8 on);
void (*clear_irq)(struct udevice *dev);
void (*reset)(struct udevice *dev);
};
struct mt8xx_glue {
struct device *dev;
struct platform_device *usb_phy;
void *base;
struct musb *musb;
struct omap_musb_board_data otg_board_data;
struct musb_hdrc_platform_data musb_pdata;
};
#define glue_to_musb(g) platform_get_drvdata(g->musb)
static irqreturn_t mt8xx_musb_interrupt(int irq, void *__hci)
{
unsigned long flags;
irqreturn_t retval = IRQ_NONE;
struct musb *musb = __hci;
u32 l1ints, l1intm;
l1ints = musb_readl(musb->mregs, USB_L1INTS);
l1intm = musb_readl(musb->mregs, USB_L1INTM);
if (!(l1ints & l1intm))
return IRQ_HANDLED;
spin_lock_irqsave(&musb->lock, flags);
musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
mb(); /* */
musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
if (musb->int_usb & (1 << 2)) {
musb_writew(musb->mregs, 0x74, 3);
spin_unlock_irqrestore(&musb->lock, flags);
return 0;
}
if (musb->int_usb || musb->int_tx || musb->int_rx)
retval = musb_interrupt(musb);
spin_unlock_irqrestore(&musb->lock, flags);
return retval;
}
static void mt8xx_phy_poweron(void)
{
#if 0
udelay(50);
writeb(readb(0x11110000 + 0x81d) & ~0x10, (char*) 0x11110000 + 0x81d);
writeb(readb(0x11110000 + 0x86b) & ~0x04, (char*) 0x11110000 + 0x86b);
writeb(readb(0x11110000 + 0x86e) & ~0x01, (char*) 0x11110000 + 0x86e);
writeb(readb(0x11110000 + 0x86a) & ~0x04, (char*) 0x11110000 + 0x86a);
writeb(readb(0x11110000 + 0x821) & ~0x03, (char*) 0x11110000 + 0x821);
writeb(readb(0x11110000 + 0x868) & ~0x40, (char*) 0x11110000 + 0x868);
writeb(readb(0x11110000 + 0x868) & ~0x80, (char*) 0x11110000 + 0x868);
writeb(readb(0x11110000 + 0x868) & ~0x30, (char*) 0x11110000 + 0x868);
writeb(readb(0x11110000 + 0x868) & ~0x04, (char*) 0x11110000 + 0x868);
writeb(readb(0x11110000 + 0x869) & ~0x3c, (char*) 0x11110000 + 0x869);
writeb(readb(0x11110000 + 0x86a) & ~0x10, (char*) 0x11110000 + 0x86a);
writeb(readb(0x11110000 + 0x86a) & ~0x20, (char*) 0x11110000 + 0x86a);
writeb(readb(0x11110000 + 0x86a) & ~0x08, (char*) 0x11110000 + 0x86a);
writeb(readb(0x11110000 + 0x86a) & ~0x02, (char*) 0x11110000 + 0x86a);
writeb(readb(0x11110000 + 0x86a) & ~0x80, (char*) 0x11110000 + 0x86a);
writeb(readb(0x11110000 + 0x81a) & ~0x80, (char*) 0x11110000 + 0x81a);
writeb(readb(0x11110000 + 0x81a) | 0x10, (char*) 0x11110000 + 0x81a);
writeb(readb(0x11110000 + 0x818) & ~0x08, (char*) 0x11110000 + 0x818);
writeb(readb(0x11110000 + 0x818) | 0x06, (char*) 0x11110000 + 0x818);
udelay(800);
writeb(readb(0x11110000 + 0x86c) & ~0x10, (char*) 0x11110000 + 0x86c);
writeb(readb(0x11110000 + 0x86c) | 0x2e, (char*) 0x11110000 + 0x86c);
writeb(readb(0x11110000 + 0x86d) | 0x3e, (char*) 0x11110000 + 0x86d);
#endif
#define USBPHY_CLR8(reg, val) writeb(readb(0x11110800 + reg) & ~val, 0x11110800 + reg)
#define USBPHY_SET8(reg, val) writeb(readb(0x11110800 + reg) | val, 0x11110800 + reg)
/*
* swtich to USB function.
* (system register, force ip into usb mode).
*/
USBPHY_CLR8(0x6b, 0x04);
USBPHY_CLR8(0x6e, 0x01);
USBPHY_CLR8(0x21, 0x03);
/* RG_USB20_BC11_SW_EN = 1'b0 */
USBPHY_SET8(0x22, 0x04);
USBPHY_CLR8(0x1a, 0x80);
/* RG_USB20_DP_100K_EN = 1'b0 */
/* RG_USB20_DP_100K_EN = 1'b0 */
USBPHY_CLR8(0x22, 0x03);
/*OTG enable*/
USBPHY_SET8(0x20, 0x10);
/* release force suspendm */
USBPHY_CLR8(0x6a, 0x04);
udelay(800);
/* force enter device mode */
USBPHY_CLR8(0x6c, 0x10);
USBPHY_SET8(0x6c, 0x2E);
USBPHY_SET8(0x6d, 0x3E);
/*** recover *****/
USBPHY_CLR8(0x1d, 0x10);
/* force_uart_en = 1'b0 */
USBPHY_CLR8(0x6b, 0x04);
/* RG_UART_EN = 1'b0 */
USBPHY_CLR8(0x6e, 0x01);
/* force_uart_en = 1'b0 */
USBPHY_CLR8(0x6a, 0x04);
USBPHY_CLR8(0x21, 0x03);
USBPHY_CLR8(0x68, 0xf4);
/* RG_DATAIN[3:0] = 4'b0000 */
USBPHY_CLR8(0x69, 0x3c);
USBPHY_CLR8(0x6a, 0xba);
/* RG_USB20_BC11_SW_EN = 1'b0 */
USBPHY_CLR8(0x1a, 0x80);
/* RG_USB20_OTG_VBUSSCMP_EN = 1'b1 */
USBPHY_SET8(0x1a, 0x10);
//HQA adjustment
USBPHY_CLR8(0x18, 0x08);
USBPHY_SET8(0x18, 0x06);
udelay(800);
}
static int mt8xx_musb_init(struct musb *musb)
{
int ret;
int status;
// musb_writew(musb->mregs, 0x74, 3);
musb->isr = mt8xx_musb_interrupt;
musb_writel(musb->mregs, USB_L1INTM,
TX_INT_STATUS | RX_INT_STATUS | USBCOM_INT_STATUS |
DMA_INT_STATUS);
return 0;
}
static int mt8xx_musb_exit(struct musb *musb)
{
return 0;
}
static int mt8xx_musb_enable(struct musb *musb)
{
unsigned long flags;
mt8xx_phy_poweron();
flags = musb_readl(musb->mregs, USB_L1INTM);
musb_writel(musb->mregs, USB_L1INTM, (~IDDIG_INT_STATUS) & flags);
mdelay(10);
musb_writel(musb->mregs, USB_L1INTM, flags);
return 0;
}
static const struct musb_platform_ops mt8xx_ops = {
.init = mt8xx_musb_init,
.exit = mt8xx_musb_exit,
.enable = mt8xx_musb_enable,
};
static void mt_usb_phy_recover(void)
{
/* clean PUPD_BIST_EN */
/* PUPD_BIST_EN = 1'b0 */
/* PMIC will use it to detect charger type */
USBPHY_CLR8(0x1d, 0x10);
/* force_uart_en = 1'b0 */
USBPHY_CLR8(0x6b, 0x04);
/* RG_UART_EN = 1'b0 */
USBPHY_CLR8(0x6e, 0x01);
/* force_uart_en = 1'b0 */
USBPHY_CLR8(0x6a, 0x04);
USBPHY_CLR8(0x21, 0x03);
USBPHY_CLR8(0x68, 0xf4);
/* RG_DATAIN[3:0] = 4'b0000 */
USBPHY_CLR8(0x69, 0x3c);
USBPHY_CLR8(0x6a, 0xba);
/* RG_USB20_BC11_SW_EN = 1'b0 */
USBPHY_CLR8(0x1a, 0x80);
/* RG_USB20_OTG_VBUSSCMP_EN = 1'b1 */
USBPHY_SET8(0x1a, 0x10);
//HQA adjustment
USBPHY_CLR8(0x18, 0x08);
USBPHY_SET8(0x18, 0x06);
udelay(800);
/* force enter device mode */
//USBPHY_CLR8(0x6c, 0x10);
//USBPHY_SET8(0x6c, 0x2E);
//USBPHY_SET8(0x6d, 0x3E);
}
static int mt8xx_probe(struct udevice *udev)
{
struct mt8xx_glue *glue = dev_get_platdata(udev);
struct udevice *clk_dev;
struct udevice *clk_cg_dev;
int ret;
int i;
unsigned long usb_clk[] = {
CLK_TOP_USB_PHY48M,
CLK_TOP_USB_78M,
CLK_TOP_USBIF,
CLK_TOP_USB,
CLK_TOP_USB_1P,
};
ret = uclass_get_device_by_driver(UCLASS_CLK,
DM_GET_DRIVER(mtk_clk_topckgen), &clk_dev);
if (ret)
return ret;
ret = uclass_get_device_by_driver(UCLASS_CLK,
DM_GET_DRIVER(mtk_clk_topckgen_cg), &clk_cg_dev);
if (ret)
return ret;
#if 1
for (i = 0; i < ARRAY_SIZE(usb_clk); i++) {
struct clk clk = { .id = usb_clk[i], .dev = clk_dev };
if (i != 0)
clk.dev = clk_cg_dev;
ret = clk_enable(&clk);
if (ret)
return ret;
ret = clk_disable(&clk);
if (ret)
return ret;
}
for (i = 0; i < ARRAY_SIZE(usb_clk); i++) {
struct clk clk = { .id = usb_clk[i], .dev = clk_dev };
if (i != 0)
clk.dev = clk_cg_dev;
ret = clk_enable(&clk);
if (ret)
return ret;
}
struct clk clk1 = { .id = CLK_TOP_USB_78M_SEL, .dev = clk_dev };
struct clk clk2 = { .id = CLK_TOP_UNIVPLL_D16, .dev = clk_dev };
clk_set_parent(&clk1, &clk2);
#endif
u32 l1ints, l1intm;
u8 tmpReg8;
/* connect */
tmpReg8 = musb_readb(glue->base, MUSB_POWER);
tmpReg8 &= ~MUSB_POWER_SOFTCONN;
musb_writeb(glue->base, MUSB_POWER, tmpReg8);
mt_usb_phy_recover();
glue->base = (void*) 0x11100000;
glue->otg_board_data.dev = udev;
glue->musb_pdata.config = &mt8xx_musb_hdrc_config;
glue->musb_pdata.platform_ops = &mt8xx_ops;
glue->musb_pdata.board_data = &glue->otg_board_data;
glue->musb_pdata.mode = MUSB_PERIPHERAL;
musb_writeb(glue->base, MUSB_POWER, 0);
l1ints = musb_readl(glue->base, USB_L1INTS);
l1intm = musb_readl(glue->base, USB_L1INTM);
musb_writew(glue->base, MUSB_INTRRX, 0xffff);
musb_writew(glue->base, MUSB_INTRTX, 0xffff);
musb_writeb(glue->base, MUSB_INTRUSB, 0xff);
musb_writeb(glue->base, 0xb, 39);
glue->musb = musb_register(&glue->musb_pdata,
(struct device *)&glue->otg_board_data,
glue->base);
if (ret)
return ret;
return 0;
}
static int mt8xx_remove(struct udevice *udev)
{
return 0;
}
static const struct udevice_id mtk_musb_ids[] = {
{ .compatible = "mediatek,mtk-musb" },
{ }
};
#if 0
U_BOOT_DRIVER(usb_dev_generic_drv) = {
.id = UCLASS_USB_DEV_GENERIC,
.name = "usb_dev_generic_drv",
};
UCLASS_DRIVER(usb_dev_generic) = {
.id = UCLASS_USB_DEV_GENERIC,
.name = "usb_dev_generic",
};
#endif
U_BOOT_DRIVER(mtk_musb) = {
.name = "mtk-musb",
.id = UCLASS_USB_GADGET_GENERIC,
.of_match = mtk_musb_ids,
.ops = &mt8xx_ops,
.probe = mt8xx_probe,
.remove = mt8xx_remove,
.platdata_auto_alloc_size = sizeof(struct mt8xx_glue),
};