10701a5efSGuenter Roeck /*
20701a5efSGuenter Roeck * i.MX USB PHY
30701a5efSGuenter Roeck *
40701a5efSGuenter Roeck * Copyright (c) 2020 Guenter Roeck <linux@roeck-us.net>
50701a5efSGuenter Roeck *
60701a5efSGuenter Roeck * This work is licensed under the terms of the GNU GPL, version 2 or later.
70701a5efSGuenter Roeck * See the COPYING file in the top-level directory.
80701a5efSGuenter Roeck *
90701a5efSGuenter Roeck * We need to implement basic reset control in the PHY control register.
100701a5efSGuenter Roeck * For everything else, it is sufficient to set whatever is written.
110701a5efSGuenter Roeck */
120701a5efSGuenter Roeck
130701a5efSGuenter Roeck #include "qemu/osdep.h"
140701a5efSGuenter Roeck #include "hw/usb/imx-usb-phy.h"
150701a5efSGuenter Roeck #include "migration/vmstate.h"
163202b262SGuenter Roeck #include "qemu/log.h"
170701a5efSGuenter Roeck #include "qemu/module.h"
180701a5efSGuenter Roeck
190701a5efSGuenter Roeck static const VMStateDescription vmstate_imx_usbphy = {
200701a5efSGuenter Roeck .name = TYPE_IMX_USBPHY,
210701a5efSGuenter Roeck .version_id = 1,
220701a5efSGuenter Roeck .minimum_version_id = 1,
233abedf29SRichard Henderson .fields = (const VMStateField[]) {
240701a5efSGuenter Roeck VMSTATE_UINT32_ARRAY(usbphy, IMXUSBPHYState, USBPHY_MAX),
250701a5efSGuenter Roeck VMSTATE_END_OF_LIST()
260701a5efSGuenter Roeck },
270701a5efSGuenter Roeck };
280701a5efSGuenter Roeck
imx_usbphy_softreset(IMXUSBPHYState * s)290701a5efSGuenter Roeck static void imx_usbphy_softreset(IMXUSBPHYState *s)
300701a5efSGuenter Roeck {
310701a5efSGuenter Roeck s->usbphy[USBPHY_PWD] = 0x001e1c00;
320701a5efSGuenter Roeck s->usbphy[USBPHY_TX] = 0x10060607;
330701a5efSGuenter Roeck s->usbphy[USBPHY_RX] = 0x00000000;
340701a5efSGuenter Roeck s->usbphy[USBPHY_CTRL] = 0xc0200000;
350701a5efSGuenter Roeck }
360701a5efSGuenter Roeck
imx_usbphy_reset(DeviceState * dev)370701a5efSGuenter Roeck static void imx_usbphy_reset(DeviceState *dev)
380701a5efSGuenter Roeck {
390701a5efSGuenter Roeck IMXUSBPHYState *s = IMX_USBPHY(dev);
400701a5efSGuenter Roeck
410701a5efSGuenter Roeck s->usbphy[USBPHY_STATUS] = 0x00000000;
420701a5efSGuenter Roeck s->usbphy[USBPHY_DEBUG] = 0x7f180000;
430701a5efSGuenter Roeck s->usbphy[USBPHY_DEBUG0_STATUS] = 0x00000000;
440701a5efSGuenter Roeck s->usbphy[USBPHY_DEBUG1] = 0x00001000;
450701a5efSGuenter Roeck s->usbphy[USBPHY_VERSION] = 0x04020000;
460701a5efSGuenter Roeck
470701a5efSGuenter Roeck imx_usbphy_softreset(s);
480701a5efSGuenter Roeck }
490701a5efSGuenter Roeck
imx_usbphy_read(void * opaque,hwaddr offset,unsigned size)500701a5efSGuenter Roeck static uint64_t imx_usbphy_read(void *opaque, hwaddr offset, unsigned size)
510701a5efSGuenter Roeck {
520701a5efSGuenter Roeck IMXUSBPHYState *s = (IMXUSBPHYState *)opaque;
530701a5efSGuenter Roeck uint32_t index = offset >> 2;
540701a5efSGuenter Roeck uint32_t value;
550701a5efSGuenter Roeck
560701a5efSGuenter Roeck switch (index) {
570701a5efSGuenter Roeck case USBPHY_PWD_SET:
580701a5efSGuenter Roeck case USBPHY_TX_SET:
590701a5efSGuenter Roeck case USBPHY_RX_SET:
600701a5efSGuenter Roeck case USBPHY_CTRL_SET:
610701a5efSGuenter Roeck case USBPHY_DEBUG_SET:
620701a5efSGuenter Roeck case USBPHY_DEBUG1_SET:
630701a5efSGuenter Roeck /*
640701a5efSGuenter Roeck * All REG_NAME_SET register access are in fact targeting the
650701a5efSGuenter Roeck * REG_NAME register.
660701a5efSGuenter Roeck */
670701a5efSGuenter Roeck value = s->usbphy[index - 1];
680701a5efSGuenter Roeck break;
690701a5efSGuenter Roeck case USBPHY_PWD_CLR:
700701a5efSGuenter Roeck case USBPHY_TX_CLR:
710701a5efSGuenter Roeck case USBPHY_RX_CLR:
720701a5efSGuenter Roeck case USBPHY_CTRL_CLR:
730701a5efSGuenter Roeck case USBPHY_DEBUG_CLR:
740701a5efSGuenter Roeck case USBPHY_DEBUG1_CLR:
750701a5efSGuenter Roeck /*
760701a5efSGuenter Roeck * All REG_NAME_CLR register access are in fact targeting the
770701a5efSGuenter Roeck * REG_NAME register.
780701a5efSGuenter Roeck */
790701a5efSGuenter Roeck value = s->usbphy[index - 2];
800701a5efSGuenter Roeck break;
810701a5efSGuenter Roeck case USBPHY_PWD_TOG:
820701a5efSGuenter Roeck case USBPHY_TX_TOG:
830701a5efSGuenter Roeck case USBPHY_RX_TOG:
840701a5efSGuenter Roeck case USBPHY_CTRL_TOG:
850701a5efSGuenter Roeck case USBPHY_DEBUG_TOG:
860701a5efSGuenter Roeck case USBPHY_DEBUG1_TOG:
870701a5efSGuenter Roeck /*
880701a5efSGuenter Roeck * All REG_NAME_TOG register access are in fact targeting the
890701a5efSGuenter Roeck * REG_NAME register.
900701a5efSGuenter Roeck */
910701a5efSGuenter Roeck value = s->usbphy[index - 3];
920701a5efSGuenter Roeck break;
930701a5efSGuenter Roeck default:
943202b262SGuenter Roeck if (index < USBPHY_MAX) {
950701a5efSGuenter Roeck value = s->usbphy[index];
963202b262SGuenter Roeck } else {
973202b262SGuenter Roeck qemu_log_mask(LOG_GUEST_ERROR,
983202b262SGuenter Roeck "%s: Read from non-existing USB PHY register 0x%"
993202b262SGuenter Roeck HWADDR_PRIx "\n",
1003202b262SGuenter Roeck __func__, offset);
1013202b262SGuenter Roeck value = 0;
1023202b262SGuenter Roeck }
1030701a5efSGuenter Roeck break;
1040701a5efSGuenter Roeck }
1050701a5efSGuenter Roeck return (uint64_t)value;
1060701a5efSGuenter Roeck }
1070701a5efSGuenter Roeck
imx_usbphy_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)1080701a5efSGuenter Roeck static void imx_usbphy_write(void *opaque, hwaddr offset, uint64_t value,
1090701a5efSGuenter Roeck unsigned size)
1100701a5efSGuenter Roeck {
1110701a5efSGuenter Roeck IMXUSBPHYState *s = (IMXUSBPHYState *)opaque;
1120701a5efSGuenter Roeck uint32_t index = offset >> 2;
1130701a5efSGuenter Roeck
1140701a5efSGuenter Roeck switch (index) {
1150701a5efSGuenter Roeck case USBPHY_CTRL:
1160701a5efSGuenter Roeck s->usbphy[index] = value;
1170701a5efSGuenter Roeck if (value & USBPHY_CTRL_SFTRST) {
1180701a5efSGuenter Roeck imx_usbphy_softreset(s);
1190701a5efSGuenter Roeck }
1200701a5efSGuenter Roeck break;
1210701a5efSGuenter Roeck case USBPHY_PWD:
1220701a5efSGuenter Roeck case USBPHY_TX:
1230701a5efSGuenter Roeck case USBPHY_RX:
1240701a5efSGuenter Roeck case USBPHY_STATUS:
1250701a5efSGuenter Roeck case USBPHY_DEBUG:
1260701a5efSGuenter Roeck case USBPHY_DEBUG1:
1270701a5efSGuenter Roeck s->usbphy[index] = value;
1280701a5efSGuenter Roeck break;
1290701a5efSGuenter Roeck case USBPHY_CTRL_SET:
1300701a5efSGuenter Roeck s->usbphy[index - 1] |= value;
1310701a5efSGuenter Roeck if (value & USBPHY_CTRL_SFTRST) {
1320701a5efSGuenter Roeck imx_usbphy_softreset(s);
1330701a5efSGuenter Roeck }
1340701a5efSGuenter Roeck break;
1350701a5efSGuenter Roeck case USBPHY_PWD_SET:
1360701a5efSGuenter Roeck case USBPHY_TX_SET:
1370701a5efSGuenter Roeck case USBPHY_RX_SET:
1380701a5efSGuenter Roeck case USBPHY_DEBUG_SET:
1390701a5efSGuenter Roeck case USBPHY_DEBUG1_SET:
1400701a5efSGuenter Roeck /*
1410701a5efSGuenter Roeck * All REG_NAME_SET register access are in fact targeting the
1420701a5efSGuenter Roeck * REG_NAME register. So we change the value of the REG_NAME
1430701a5efSGuenter Roeck * register, setting bits passed in the value.
1440701a5efSGuenter Roeck */
1450701a5efSGuenter Roeck s->usbphy[index - 1] |= value;
1460701a5efSGuenter Roeck break;
1470701a5efSGuenter Roeck case USBPHY_PWD_CLR:
1480701a5efSGuenter Roeck case USBPHY_TX_CLR:
1490701a5efSGuenter Roeck case USBPHY_RX_CLR:
1500701a5efSGuenter Roeck case USBPHY_CTRL_CLR:
1510701a5efSGuenter Roeck case USBPHY_DEBUG_CLR:
1520701a5efSGuenter Roeck case USBPHY_DEBUG1_CLR:
1530701a5efSGuenter Roeck /*
1540701a5efSGuenter Roeck * All REG_NAME_CLR register access are in fact targeting the
1550701a5efSGuenter Roeck * REG_NAME register. So we change the value of the REG_NAME
1560701a5efSGuenter Roeck * register, unsetting bits passed in the value.
1570701a5efSGuenter Roeck */
1580701a5efSGuenter Roeck s->usbphy[index - 2] &= ~value;
1590701a5efSGuenter Roeck break;
1600701a5efSGuenter Roeck case USBPHY_CTRL_TOG:
1610701a5efSGuenter Roeck s->usbphy[index - 3] ^= value;
1620701a5efSGuenter Roeck if ((value & USBPHY_CTRL_SFTRST) &&
1630701a5efSGuenter Roeck (s->usbphy[index - 3] & USBPHY_CTRL_SFTRST)) {
1640701a5efSGuenter Roeck imx_usbphy_softreset(s);
1650701a5efSGuenter Roeck }
1660701a5efSGuenter Roeck break;
1670701a5efSGuenter Roeck case USBPHY_PWD_TOG:
1680701a5efSGuenter Roeck case USBPHY_TX_TOG:
1690701a5efSGuenter Roeck case USBPHY_RX_TOG:
1700701a5efSGuenter Roeck case USBPHY_DEBUG_TOG:
1710701a5efSGuenter Roeck case USBPHY_DEBUG1_TOG:
1720701a5efSGuenter Roeck /*
1730701a5efSGuenter Roeck * All REG_NAME_TOG register access are in fact targeting the
1740701a5efSGuenter Roeck * REG_NAME register. So we change the value of the REG_NAME
1750701a5efSGuenter Roeck * register, toggling bits passed in the value.
1760701a5efSGuenter Roeck */
1770701a5efSGuenter Roeck s->usbphy[index - 3] ^= value;
1780701a5efSGuenter Roeck break;
1790701a5efSGuenter Roeck default:
1803202b262SGuenter Roeck /* Other registers are read-only or do not exist */
1813202b262SGuenter Roeck qemu_log_mask(LOG_GUEST_ERROR,
1823202b262SGuenter Roeck "%s: Write to %s USB PHY register 0x%"
1833202b262SGuenter Roeck HWADDR_PRIx "\n",
1843202b262SGuenter Roeck __func__,
1853202b262SGuenter Roeck index >= USBPHY_MAX ? "non-existing" : "read-only",
1863202b262SGuenter Roeck offset);
1870701a5efSGuenter Roeck break;
1880701a5efSGuenter Roeck }
1890701a5efSGuenter Roeck }
1900701a5efSGuenter Roeck
1910701a5efSGuenter Roeck static const struct MemoryRegionOps imx_usbphy_ops = {
1920701a5efSGuenter Roeck .read = imx_usbphy_read,
1930701a5efSGuenter Roeck .write = imx_usbphy_write,
1940701a5efSGuenter Roeck .endianness = DEVICE_NATIVE_ENDIAN,
1950701a5efSGuenter Roeck .valid = {
1960701a5efSGuenter Roeck /*
1970701a5efSGuenter Roeck * Our device would not work correctly if the guest was doing
1980701a5efSGuenter Roeck * unaligned access. This might not be a limitation on the real
1990701a5efSGuenter Roeck * device but in practice there is no reason for a guest to access
2000701a5efSGuenter Roeck * this device unaligned.
2010701a5efSGuenter Roeck */
2020701a5efSGuenter Roeck .min_access_size = 4,
2030701a5efSGuenter Roeck .max_access_size = 4,
2040701a5efSGuenter Roeck .unaligned = false,
2050701a5efSGuenter Roeck },
2060701a5efSGuenter Roeck };
2070701a5efSGuenter Roeck
imx_usbphy_realize(DeviceState * dev,Error ** errp)2080701a5efSGuenter Roeck static void imx_usbphy_realize(DeviceState *dev, Error **errp)
2090701a5efSGuenter Roeck {
2100701a5efSGuenter Roeck IMXUSBPHYState *s = IMX_USBPHY(dev);
2110701a5efSGuenter Roeck
2120701a5efSGuenter Roeck memory_region_init_io(&s->iomem, OBJECT(s), &imx_usbphy_ops, s,
2130701a5efSGuenter Roeck "imx-usbphy", 0x1000);
2140701a5efSGuenter Roeck sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
2150701a5efSGuenter Roeck }
2160701a5efSGuenter Roeck
imx_usbphy_class_init(ObjectClass * klass,void * data)2170701a5efSGuenter Roeck static void imx_usbphy_class_init(ObjectClass *klass, void *data)
2180701a5efSGuenter Roeck {
2190701a5efSGuenter Roeck DeviceClass *dc = DEVICE_CLASS(klass);
2200701a5efSGuenter Roeck
221*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, imx_usbphy_reset);
2220701a5efSGuenter Roeck dc->vmsd = &vmstate_imx_usbphy;
2230701a5efSGuenter Roeck dc->desc = "i.MX USB PHY Module";
2240701a5efSGuenter Roeck dc->realize = imx_usbphy_realize;
2250701a5efSGuenter Roeck }
2260701a5efSGuenter Roeck
2270701a5efSGuenter Roeck static const TypeInfo imx_usbphy_info = {
2280701a5efSGuenter Roeck .name = TYPE_IMX_USBPHY,
2290701a5efSGuenter Roeck .parent = TYPE_SYS_BUS_DEVICE,
2300701a5efSGuenter Roeck .instance_size = sizeof(IMXUSBPHYState),
2310701a5efSGuenter Roeck .class_init = imx_usbphy_class_init,
2320701a5efSGuenter Roeck };
2330701a5efSGuenter Roeck
imx_usbphy_register_types(void)2340701a5efSGuenter Roeck static void imx_usbphy_register_types(void)
2350701a5efSGuenter Roeck {
2360701a5efSGuenter Roeck type_register_static(&imx_usbphy_info);
2370701a5efSGuenter Roeck }
2380701a5efSGuenter Roeck
2390701a5efSGuenter Roeck type_init(imx_usbphy_register_types)
240