summaryrefslogtreecommitdiffstats
path: root/utils/hwstub/stub/stmp/target.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/hwstub/stub/stmp/target.c')
-rw-r--r--utils/hwstub/stub/stmp/target.c205
1 files changed, 205 insertions, 0 deletions
diff --git a/utils/hwstub/stub/stmp/target.c b/utils/hwstub/stub/stmp/target.c
new file mode 100644
index 0000000000..60411f908e
--- /dev/null
+++ b/utils/hwstub/stub/stmp/target.c
@@ -0,0 +1,205 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2013 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "stddef.h"
+#include "target.h"
+#include "system.h"
+#include "logf.h"
+
+#define __REG_SET(reg) (*((volatile uint32_t *)(&reg + 1)))
+#define __REG_CLR(reg) (*((volatile uint32_t *)(&reg + 2)))
+#define __REG_TOG(reg) (*((volatile uint32_t *)(&reg + 3)))
+
+#define __BLOCK_SFTRST (1 << 31)
+#define __BLOCK_CLKGATE (1 << 30)
+
+#define __XTRACT(reg, field) ((reg & reg##__##field##_BM) >> reg##__##field##_BP)
+#define __XTRACT_EX(val, field) (((val) & field##_BM) >> field##_BP)
+#define __FIELD_SET(reg, field, val) reg = (reg & ~reg##__##field##_BM) | (val << reg##__##field##_BP)
+
+/**
+ *
+ * Global
+ *
+ */
+
+enum stmp_family_t
+{
+ UNKNOWN,
+ STMP3600,
+ STMP3700,
+ STMP3770,
+ STMP3780
+};
+
+enum stmp_family_t g_stmp_family = UNKNOWN;
+
+/**
+ *
+ * Clkctrl
+ *
+ */
+
+#define HW_CLKCTRL_BASE 0x80040000
+
+#define HW_CLKCTRL_PLLCTRL0 (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x0))
+#define HW_CLKCTRL_PLLCTRL0__BYPASS (1 << 17) /* STMP3600 only */
+#define HW_CLKCTRL_PLLCTRL0__POWER (1 << 16)
+#define HW_CLKCTRL_PLLCTRL0__EN_USB_CLKS (1 << 18)
+
+#define HW_CLKCTRL_PLLCTRL1 (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x10))
+#define HW_CLKCTRL_PLLCTRL1__LOCK (1 << 31)
+
+/* STMP3600 only */
+#define HW_CLKCTRL_CPUCLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x20))
+#define HW_CLKCTRL_CPUCLKCTRL__DIV_BP 0
+#define HW_CLKCTRL_CPUCLKCTRL__DIV_BM 0x3ff
+#define HW_CLKCTRL_CPUCLKCTRL__WAIT_PLL_LOCK (1 << 30)
+
+/* STMP3600 */
+#define HW_CLKCTRL_HBUSCLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x30))
+
+/* STMP3600 only */
+#define HW_CLKCTRL_XBUSCLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x40))
+#define HW_CLKCTRL_XBUSCLKCTRL__DIV_BP 0
+#define HW_CLKCTRL_XBUSCLKCTRL__DIV_BM 0x3ff
+
+/* STMP3600 only */
+#define HW_CLKCTRL_UTMICLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x70))
+#define HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK30M_GATE (1 << 30)
+#define HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK120M_GATE (1 << 31)
+
+/**
+ *
+ * Digctl
+ *
+ */
+
+/* Digital control */
+#define HW_DIGCTL_BASE 0x8001C000
+#define HW_DIGCTL_CTRL (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0))
+#define HW_DIGCTL_CTRL__USB_CLKGATE (1 << 2)
+
+#define HW_DIGCTL_MICROSECONDS (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0xC0))
+
+#define HW_DIGCTL_CHIPID (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0x310))
+#define HW_DIGCTL_CHIPID__PRODUCT_CODE_BP 16
+#define HW_DIGCTL_CHIPID__PRODUCT_CODE_BM 0xffff0000
+#define HW_DIGCTL_CHIPID__REVISION_BP 0
+#define HW_DIGCTL_CHIPID__REVISION_BM 0xff
+
+#define HZ 1000000
+
+/**
+ *
+ * USB PHY
+ *
+ */
+/* USB Phy */
+#define HW_USBPHY_BASE 0x8007C000
+#define HW_USBPHY_PWD (*(volatile uint32_t *)(HW_USBPHY_BASE + 0))
+
+#define HW_USBPHY_CTRL (*(volatile uint32_t *)(HW_USBPHY_BASE + 0x30))
+
+void target_init(void)
+{
+ /* detect family */
+ uint16_t product_code = __XTRACT(HW_DIGCTL_CHIPID, PRODUCT_CODE);
+ if(product_code >= 0x3600 && product_code < 0x3700)
+ {
+ logf("identified STMP3600 family\n");
+ g_stmp_family = STMP3600;
+ }
+ else if(product_code == 0x3700)
+ {
+ logf("identified STMP3700 family\n");
+ g_stmp_family = STMP3700;
+ }
+ else if(product_code == 0x37b0)
+ {
+ logf("identified STMP3770 family\n");
+ g_stmp_family = STMP3770;
+ }
+ else if(product_code == 0x3780)
+ {
+ logf("identified STMP3780 family\n");
+ g_stmp_family = STMP3780;
+ }
+ else
+ logf("cannot identify family: 0x%x\n", product_code);
+
+ if(g_stmp_family == STMP3600)
+ {
+ /* CPU clock is always derived from PLL, if we switch to PLL, cpu will
+ * run at 480 MHz unprepared ! That's bad so prepare to run at slow sleed
+ * (1.2MHz) for a safe transition */
+ HW_CLKCTRL_CPUCLKCTRL = HW_CLKCTRL_CPUCLKCTRL__WAIT_PLL_LOCK | 400;
+ /* We need to ensure that XBUS < HBUS but HBUS will be 1.2 MHz after the
+ * switch so lower XBUS too */
+ HW_CLKCTRL_XBUSCLKCTRL = 20;
+ /* Power PLL */
+ __REG_SET(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__POWER;
+ HW_CLKCTRL_PLLCTRL0 = (HW_CLKCTRL_PLLCTRL0 & ~0x3ff) | 480;
+ /* Wait lock */
+ while(!(HW_CLKCTRL_PLLCTRL1 & HW_CLKCTRL_PLLCTRL1__LOCK));
+ /* Switch to PLL source */
+ __REG_CLR(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__BYPASS;
+ /* Get back XBUS = 24 MHz and CPU = HBUS = 64MHz */
+ HW_CLKCTRL_CPUCLKCTRL = 7;
+ HW_CLKCTRL_HBUSCLKCTRL = 7;
+ HW_CLKCTRL_XBUSCLKCTRL = 1;
+ __REG_CLR(HW_CLKCTRL_UTMICLKCTRL) = HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK120M_GATE;
+ __REG_CLR(HW_CLKCTRL_UTMICLKCTRL) = HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK30M_GATE;
+ }
+ else
+ __REG_SET(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__POWER;
+ /* enable USB PHY PLL */
+ __REG_SET(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__EN_USB_CLKS;
+ /* power up USB PHY */
+ __REG_CLR(HW_USBPHY_CTRL) = __BLOCK_CLKGATE | __BLOCK_SFTRST;
+ HW_USBPHY_PWD = 0;
+ /* enable USB controller */
+ __REG_CLR(HW_DIGCTL_CTRL) = HW_DIGCTL_CTRL__USB_CLKGATE;
+}
+
+static struct usb_resp_info_stmp_t g_stmp;
+static struct usb_resp_info_target_t g_target =
+{
+ .id = HWSTUB_TARGET_STMP,
+ .name = "STMP3600 / STMP3700 / STMP3780 (i.MX233)"
+};
+
+int target_get_info(int info, void **buffer)
+{
+ if(info == HWSTUB_INFO_STMP)
+ {
+ g_stmp.chipid = __XTRACT(HW_DIGCTL_CHIPID, PRODUCT_CODE);
+ g_stmp.rev = __XTRACT(HW_DIGCTL_CHIPID, REVISION);
+ g_stmp.is_supported = g_stmp_family != 0;
+ *buffer = &g_stmp;
+ return sizeof(g_stmp);
+ }
+ else
+ return -1;
+}
+
+void target_exit(void)
+{
+}