xref: /openbmc/qemu/hw/usb/imx-usb-phy.c (revision 3202b262)
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"
16*3202b262SGuenter 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,
230701a5efSGuenter Roeck     .fields = (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:
94*3202b262SGuenter Roeck         if (index < USBPHY_MAX) {
950701a5efSGuenter Roeck             value = s->usbphy[index];
96*3202b262SGuenter Roeck         } else {
97*3202b262SGuenter Roeck             qemu_log_mask(LOG_GUEST_ERROR,
98*3202b262SGuenter Roeck                           "%s: Read from non-existing USB PHY register 0x%"
99*3202b262SGuenter Roeck                           HWADDR_PRIx "\n",
100*3202b262SGuenter Roeck                           __func__, offset);
101*3202b262SGuenter Roeck             value = 0;
102*3202b262SGuenter 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:
180*3202b262SGuenter Roeck         /* Other registers are read-only or do not exist */
181*3202b262SGuenter Roeck         qemu_log_mask(LOG_GUEST_ERROR,
182*3202b262SGuenter Roeck                       "%s: Write to %s USB PHY register 0x%"
183*3202b262SGuenter Roeck                       HWADDR_PRIx "\n",
184*3202b262SGuenter Roeck                       __func__,
185*3202b262SGuenter Roeck                       index >= USBPHY_MAX ? "non-existing" : "read-only",
186*3202b262SGuenter 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 
2210701a5efSGuenter Roeck     dc->reset = 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