Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/infrastructure/rootamdm37x/rootamdm37x.c

    r57912af3 r2be2506a  
    3737#define _DDF_DATA_IMPLANT
    3838
    39 #define DEBUG_CM
    40 
    4139#include <ddf/driver.h>
    4240#include <ddf/log.h>
     
    4846#include "uhh.h"
    4947#include "usbtll.h"
    50 #include "cm/core.h"
    51 #include "cm/clock_control.h"
    52 #include "cm/usbhost.h"
     48#include "core_cm.h"
     49#include "usbhost_cm.h"
    5350
    5451#define NAME  "rootamdm37x"
    55 
    56 typedef struct {
    57         uhh_regs_t *uhh;
    58         tll_regs_t *tll;
    59         struct {
    60                 core_cm_regs_t *core;
    61                 clock_control_cm_regs_t *clocks;
    62                 usbhost_cm_regs_t *usbhost;
    63         } cm;
    64 } amdm37x_t;
    65 
    66 #ifdef DEBUG_CM
    67 static void log(volatile void *place, uint32_t val, volatile void* base, size_t size, void *data, bool write)
    68 {
    69         printf("PIO %s: %p(%p) %#"PRIx32"\n", write ? "WRITE" : "READ",
    70             (place - base) + data, place, val);
    71 }
    72 #endif
    73 
    74 static int amdm37x_hw_access_init(amdm37x_t *device)
    75 {
    76         assert(device);
    77         int ret = EOK;
    78 
    79         ret = pio_enable((void*)USBHOST_CM_BASE_ADDRESS, USBHOST_CM_SIZE,
    80             (void**)&device->cm.usbhost);
    81         if (ret != EOK)
    82                 return ret;
    83 
    84         ret = pio_enable((void*)CORE_CM_BASE_ADDRESS, CORE_CM_SIZE,
    85             (void**)&device->cm.core);
    86         if (ret != EOK)
    87                 return ret;
    88 
    89         ret = pio_enable((void*)CLOCK_CONTROL_CM_BASE_ADDRESS,
    90                     CLOCK_CONTROL_CM_SIZE, (void**)&device->cm.clocks);
    91         if (ret != EOK)
    92                 return ret;
    93 
    94         ret = pio_enable((void*)AMDM37x_USBTLL_BASE_ADDRESS,
    95             AMDM37x_USBTLL_SIZE, (void**)&device->tll);
    96         if (ret != EOK)
    97                 return ret;
    98 
    99         ret = pio_enable((void*)AMDM37x_UHH_BASE_ADDRESS,
    100             AMDM37x_UHH_SIZE, (void**)&device->uhh);
    101         if (ret != EOK)
    102                 return ret;
    103 
    104 #ifdef DEBUG_CM
    105         pio_trace_enable(device->tll, AMDM37x_USBTLL_SIZE, log, (void*)AMDM37x_USBTLL_BASE_ADDRESS);
    106         pio_trace_enable(device->cm.clocks, CLOCK_CONTROL_CM_SIZE, log, (void*)CLOCK_CONTROL_CM_BASE_ADDRESS);
    107         pio_trace_enable(device->cm.core, CORE_CM_SIZE, log, (void*)CORE_CM_BASE_ADDRESS);
    108         pio_trace_enable(device->cm.usbhost, USBHOST_CM_SIZE, log, (void*)USBHOST_CM_BASE_ADDRESS);
    109         pio_trace_enable(device->uhh, AMDM37x_UHH_SIZE, log, (void*)AMDM37x_UHH_BASE_ADDRESS);
    110 #endif
    111         return EOK;
    112 }
    113 
    114 static int usb_clocks(amdm37x_t *device, bool on)
    115 {
    116         /* Set DPLL3 to automatic */
    117         pio_change_32(&device->cm.clocks->autoidle_pll,
    118             CLOCK_CONTROL_CM_AUTOIDLE_PLL_AUTO_CORE_DPLL_AUTOMATIC,
    119             CLOCK_CONTROL_CM_AUTOIDLE_PLL_AUTO_CORE_DPLL_MASK, 5);
    120 
    121         /* Set DPLL4 to automatic */
    122         pio_change_32(&device->cm.clocks->autoidle_pll,
    123             CLOCK_CONTROL_CM_AUTOIDLE_PLL_AUTO_PERIPH_DPLL_AUTOMATIC,
    124             CLOCK_CONTROL_CM_AUTOIDLE_PLL_AUTO_PERIPH_DPLL_MASK, 5);
    125 
    126         /* Set DPLL5 to automatic */
    127         pio_change_32(&device->cm.clocks->autoidle2_pll,
    128             CLOCK_CONTROL_CM_AUTOIDLE2_PLL_AUTO_PERIPH2_DPLL_AUTOMATIC,
    129             CLOCK_CONTROL_CM_AUTOIDLE2_PLL_AUTO_PERIPH2_DPLL_MASK, 5);
    130 
    131 
    132 #ifdef DEBUG_CM
    133         printf("DPLL5 could be on: %"PRIx32" %"PRIx32".\n",
    134             pio_read_32((ioport32_t*)&device->cm.clocks->idlest_ckgen),
    135             pio_read_32((ioport32_t*)&device->cm.clocks->idlest2_ckgen));
    136 #endif
    137 
    138         if (on) {
    139                 /* Enable interface and function clock for USB TLL */
    140                 pio_set_32(&device->cm.core->fclken3,
    141                     CORE_CM_FCLKEN3_EN_USBTLL_FLAG, 5);
    142                 pio_set_32(&device->cm.core->iclken3,
    143                     CORE_CM_ICLKEN3_EN_USBTLL_FLAG, 5);
    144 
    145                 /* Enable interface and function clock for USB hosts */
    146                 pio_set_32(&device->cm.usbhost->fclken,
    147                     USBHOST_CM_FCLKEN_EN_USBHOST1_FLAG |
    148                     USBHOST_CM_FCLKEN_EN_USBHOST2_FLAG, 5);
    149                 pio_set_32(&device->cm.usbhost->iclken,
    150                     USBHOST_CM_ICLKEN_EN_USBHOST, 5);
    151 #ifdef DEBUG_CM
    152         printf("DPLL5 (and everything else) should be on: %"PRIx32" %"PRIx32".\n",
    153             pio_read_32((ioport32_t*)&device->cm.clocks->idlest_ckgen),
    154             pio_read_32((ioport32_t*)&device->cm.clocks->idlest2_ckgen));
    155 #endif
    156         } else {
    157                 /* Disable interface and function clock for USB hosts */
    158                 pio_clear_32(&device->cm.usbhost->iclken,
    159                     USBHOST_CM_ICLKEN_EN_USBHOST, 5);
    160                 pio_clear_32(&device->cm.usbhost->fclken,
    161                     USBHOST_CM_FCLKEN_EN_USBHOST1_FLAG |
    162                     USBHOST_CM_FCLKEN_EN_USBHOST2_FLAG, 5);
    163 
    164                 /* Disable interface and function clock for USB TLL */
    165                 pio_clear_32(&device->cm.core->iclken3,
    166                     CORE_CM_ICLKEN3_EN_USBTLL_FLAG, 5);
    167                 pio_clear_32(&device->cm.core->fclken3,
    168                     CORE_CM_FCLKEN3_EN_USBTLL_FLAG, 5);
    169         }
    170 
    171         return EOK;
    172 }
    173 
    174 /** Initialize USB TLL port connections.
    175  *
    176  * Different modes are on page 3312 of the Manual Figure 22-34.
    177  * Select mode than can operate in FS/LS.
    178  */
    179 static int usb_tll_init(amdm37x_t *device)
    180 {
    181 
    182         /* Reset USB TLL */
    183         pio_set_32(&device->tll->sysconfig, TLL_SYSCONFIG_SOFTRESET_FLAG, 5);
    184         ddf_msg(LVL_DEBUG2, "Waiting for USB TLL reset");
    185         while (!(pio_read_32(&device->tll->sysstatus) & TLL_SYSSTATUS_RESET_DONE_FLAG));
    186         ddf_msg(LVL_DEBUG, "USB TLL Reset done.");
    187 
    188         /* Setup idle mode (smart idle) */
    189         pio_change_32(&device->tll->sysconfig,
    190             TLL_SYSCONFIG_CLOCKACTIVITY_FLAG | TLL_SYSCONFIG_AUTOIDLE_FLAG |
    191             TLL_SYSCONFIG_SIDLE_MODE_SMART, TLL_SYSCONFIG_SIDLE_MODE_MASK, 5);
    192 
    193         /* Smart idle for UHH */
    194         pio_change_32(&device->uhh->sysconfig,
    195             UHH_SYSCONFIG_CLOCKACTIVITY_FLAG | UHH_SYSCONFIG_AUTOIDLE_FLAG |
    196             UHH_SYSCONFIG_SIDLE_MODE_SMART, UHH_SYSCONFIG_SIDLE_MODE_MASK, 5);
    197 
    198         /* Set all ports to go through TLL(UTMI)
    199          * Direct connection can only work in HS mode */
    200         pio_set_32(&device->uhh->hostconfig,
    201             UHH_HOSTCONFIG_P1_ULPI_BYPASS_FLAG |
    202             UHH_HOSTCONFIG_P2_ULPI_BYPASS_FLAG |
    203             UHH_HOSTCONFIG_P3_ULPI_BYPASS_FLAG, 5);
    204 
    205         /* What is this? */
    206         pio_set_32(&device->tll->shared_conf, TLL_SHARED_CONF_FCLK_IS_ON_FLAG, 5);
    207 
    208         for (unsigned i = 0; i < 3; ++i) {
    209                 /* Serial mode is the only one capable of FS/LS operation.
    210                  * Select FS/LS mode, no idea what the difference is
    211                  * one of bidirectional modes might be good choice
    212                  * 2 = 3pin bidi phy. */
    213                 pio_change_32(&device->tll->channel_conf[i],
    214                     TLL_CHANNEL_CONF_CHANMODE_UTMI_SERIAL_MODE |
    215                     TLL_CHANNEL_CONF_FSLSMODE_3PIN_BIDI_PHY,
    216                     TLL_CHANNEL_CONF_CHANMODE_MASK |
    217                     TLL_CHANNEL_CONF_FSLSMODE_MASK, 5);
    218         }
    219         return EOK;
    220 }
    22152
    22253typedef struct {
     
    271102        .hw_resources = {
    272103            .resources = ehci_res,
    273             .count = sizeof(ehci_res) / sizeof(ehci_res[0]),
     104            .count = sizeof(ehci_res)/sizeof(ehci_res[0]),
    274105        }
    275106};
     
    287118        .interfaces[HW_RES_DEV_IFACE] = &fun_hw_res_ops
    288119};
     120
     121static int usb_clocks(bool on)
     122{
     123        usbhost_cm_regs_t *usb_host_cm = NULL;
     124        core_cm_regs_t *l4_core_cm = NULL;
     125
     126        int ret = pio_enable((void*)USBHOST_CM_BASE_ADDRESS, USBHOST_CM_SIZE,
     127            (void**)&usb_host_cm);
     128        if (ret != EOK)
     129                return ret;
     130
     131        ret = pio_enable((void*)CORE_CM_BASE_ADDRESS, CORE_CM_SIZE,
     132            (void**)&l4_core_cm);
     133        if (ret != EOK)
     134                return ret;
     135
     136        assert(l4_core_cm);
     137        assert(usb_host_cm);
     138        if (on) {
     139                l4_core_cm->iclken3 |= CORE_CM_ICLKEN3_EN_USBTLL_FLAG;
     140                l4_core_cm->fclken3 |= CORE_CM_FCLKEN3_EN_USBTLL_FLAG;
     141                usb_host_cm->iclken |= USBHOST_CM_ICLKEN_EN_USBHOST;
     142                usb_host_cm->fclken |= USBHOST_CM_FCLKEN_EN_USBHOST1_FLAG;
     143                usb_host_cm->fclken |= USBHOST_CM_FCLKEN_EN_USBHOST2_FLAG;
     144        } else {
     145                usb_host_cm->fclken &= ~USBHOST_CM_FCLKEN_EN_USBHOST2_FLAG;
     146                usb_host_cm->fclken &= ~USBHOST_CM_FCLKEN_EN_USBHOST1_FLAG;
     147                usb_host_cm->iclken &= ~USBHOST_CM_ICLKEN_EN_USBHOST;
     148                l4_core_cm->fclken3 &= ~CORE_CM_FCLKEN3_EN_USBTLL_FLAG;
     149                l4_core_cm->iclken3 &= ~CORE_CM_ICLKEN3_EN_USBTLL_FLAG;
     150        }
     151
     152        //TODO Unmap those registers.
     153
     154        return ret;
     155}
     156
     157/** Initialize USB TLL port connections.
     158 *
     159 * Different modes are on page 3312 of the Manual Figure 22-34.
     160 * Select mode than can operate in FS/LS.
     161 */
     162static int usb_tll_init()
     163{
     164        tll_regs_t *usb_tll = NULL;
     165        uhh_regs_t *uhh_conf = NULL;
     166
     167        int ret = pio_enable((void*)AMDM37x_USBTLL_BASE_ADDRESS,
     168            AMDM37x_USBTLL_SIZE, (void**)&usb_tll);
     169        if (ret != EOK)
     170                return ret;
     171
     172        ret = pio_enable((void*)AMDM37x_UHH_BASE_ADDRESS,
     173            AMDM37x_UHH_SIZE, (void**)&uhh_conf);
     174        if (ret != EOK)
     175                return ret;
     176
     177        /* Reset USB TLL */
     178        usb_tll->sysconfig |= TLL_SYSCONFIG_SOFTRESET_FLAG;
     179        ddf_msg(LVL_DEBUG2, "Waiting for USB TLL reset");
     180        while (!(usb_tll->sysstatus & TLL_SYSSTATUS_RESET_DONE_FLAG));
     181        ddf_msg(LVL_DEBUG, "USB TLL Reset done.");
     182
     183        {
     184        /* Setup idle mode (smart idle) */
     185        uint32_t sysc = usb_tll->sysconfig;
     186        sysc |= TLL_SYSCONFIG_CLOCKACTIVITY_FLAG | TLL_SYSCONFIG_AUTOIDLE_FLAG;
     187        sysc = (sysc
     188            & ~(TLL_SYSCONFIG_SIDLE_MODE_MASK << TLL_SYSCONFIG_SIDLE_MODE_SHIFT)
     189            ) | (0x2 << TLL_SYSCONFIG_SIDLE_MODE_SHIFT);
     190        usb_tll->sysconfig = sysc;
     191        ddf_msg(LVL_DEBUG2, "Set TLL->sysconfig (%p) to %x:%x.",
     192            &usb_tll->sysconfig, usb_tll->sysconfig, sysc);
     193        }
     194
     195        {
     196        /* Smart idle for UHH */
     197        uint32_t sysc = uhh_conf->sysconfig;
     198        sysc |= UHH_SYSCONFIG_CLOCKACTIVITY_FLAG | UHH_SYSCONFIG_AUTOIDLE_FLAG;
     199        sysc = (sysc
     200            & ~(UHH_SYSCONFIG_SIDLE_MODE_MASK << UHH_SYSCONFIG_SIDLE_MODE_SHIFT)
     201            ) | (0x2 << UHH_SYSCONFIG_SIDLE_MODE_SHIFT);
     202        sysc = (sysc
     203            & ~(UHH_SYSCONFIG_MIDLE_MODE_MASK << UHH_SYSCONFIG_MIDLE_MODE_SHIFT)
     204            ) | (0x2 << UHH_SYSCONFIG_MIDLE_MODE_SHIFT);
     205        ddf_msg(LVL_DEBUG2, "Set UHH->sysconfig (%p) to %x.",
     206            &uhh_conf->sysconfig, uhh_conf->sysconfig);
     207        uhh_conf->sysconfig = sysc;
     208
     209        /* All ports are connected on BBxM */
     210        uhh_conf->hostconfig |= (UHH_HOSTCONFIG_P1_CONNECT_STATUS_FLAG
     211            | UHH_HOSTCONFIG_P2_CONNECT_STATUS_FLAG
     212            | UHH_HOSTCONFIG_P3_CONNECT_STATUS_FLAG);
     213
     214        /* Set all ports to go through TLL(UTMI)
     215         * Direct connection can only work in HS mode */
     216        uhh_conf->hostconfig |= (UHH_HOSTCONFIG_P1_ULPI_BYPASS_FLAG
     217            | UHH_HOSTCONFIG_P2_ULPI_BYPASS_FLAG
     218            | UHH_HOSTCONFIG_P3_ULPI_BYPASS_FLAG);
     219        ddf_msg(LVL_DEBUG2, "Set UHH->hostconfig (%p) to %x.",
     220            &uhh_conf->hostconfig, uhh_conf->hostconfig);
     221        }
     222
     223        usb_tll->shared_conf |= TLL_SHARED_CONF_FCLK_IS_ON_FLAG;
     224        ddf_msg(LVL_DEBUG2, "Set shared conf port (%p) to %x.",
     225            &usb_tll->shared_conf, usb_tll->shared_conf);
     226
     227        for (unsigned i = 0; i < 3; ++i) {
     228                uint32_t ch = usb_tll->channel_conf[i];
     229                /* Clear Channel mode and FSLS mode */
     230                ch &= ~(TLL_CHANNEL_CONF_CHANMODE_MASK
     231                    << TLL_CHANNEL_CONF_CHANMODE_SHIFT)
     232                    & ~(TLL_CHANNEL_CONF_FSLSMODE_MASK
     233                    << TLL_CHANNEL_CONF_FSLSMODE_SHIFT);
     234
     235                /* Serial mode is the only one capable of FS/LS operation. */
     236                ch |= (TLL_CHANNEL_CONF_CHANMODE_UTMI_SERIAL_MODE
     237                    << TLL_CHANNEL_CONF_CHANMODE_SHIFT);
     238
     239                /* Select FS/LS mode, no idea what the difference is
     240                 * one of bidirectional modes might be good choice
     241                 * 2 = 3pin bidi phy. */
     242                ch |= (2 << TLL_CHANNEL_CONF_FSLSMODE_SHIFT);
     243
     244                /* Write to register */
     245                ddf_msg(LVL_DEBUG2, "Setting port %u(%p) to %x.",
     246                    i, &usb_tll->channel_conf[i], ch);
     247                usb_tll->channel_conf[i] = ch;
     248        }
     249        return EOK;
     250}
    289251
    290252static bool rootamdm37x_add_fun(ddf_dev_t *dev, const char *name,
     
    301263        /* Add match id */
    302264        if (ddf_fun_add_match_id(fnode, str_match_id, 100) != EOK) {
     265                // TODO This will try to free our data!
    303266                ddf_fun_destroy(fnode);
    304267                return false;
     
    312275        if (ddf_fun_bind(fnode) != EOK) {
    313276                ddf_msg(LVL_ERROR, "Failed binding function %s.", name);
    314                 // TODO This will try to free our data!
    315277                ddf_fun_destroy(fnode);
    316278                return false;
     
    330292static int rootamdm37x_dev_add(ddf_dev_t *dev)
    331293{
    332         assert(dev);
    333         amdm37x_t *device = ddf_dev_data_alloc(dev, sizeof(amdm37x_t));
    334         if (!device)
    335                 return ENOMEM;
    336         int ret = amdm37x_hw_access_init(device);
    337         if (ret != EOK) {
    338                 ddf_msg(LVL_FATAL, "Failed to setup hw access!.\n");
    339                 return ret;
    340         }
    341 
    342         ret = usb_clocks(device, true);
     294        int ret = usb_clocks(true);
    343295        if (ret != EOK) {
    344296                ddf_msg(LVL_FATAL, "Failed to enable USB HC clocks!.\n");
     
    346298        }
    347299
    348         ret = usb_tll_init(device);
     300        ret = usb_tll_init();
    349301        if (ret != EOK) {
    350302                ddf_msg(LVL_FATAL, "Failed to init USB TLL!.\n");
    351                 usb_clocks(device, false);
     303                usb_clocks(false);
    352304                return ret;
    353305        }
     
    391343{
    392344        printf("%s: HelenOS AM/DM37x(OMAP37x) platform driver\n", NAME);
    393         ddf_log_init(NAME);
     345        ddf_log_init(NAME, LVL_ERROR);
    394346        return ddf_driver_main(&rootamdm37x_driver);
    395347}
Note: See TracChangeset for help on using the changeset viewer.