Ignore:
File:
1 edited

Legend:

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

    r2be2506a r57912af3  
    3737#define _DDF_DATA_IMPLANT
    3838
     39#define DEBUG_CM
     40
    3941#include <ddf/driver.h>
    4042#include <ddf/log.h>
     
    4648#include "uhh.h"
    4749#include "usbtll.h"
    48 #include "core_cm.h"
    49 #include "usbhost_cm.h"
     50#include "cm/core.h"
     51#include "cm/clock_control.h"
     52#include "cm/usbhost.h"
    5053
    5154#define NAME  "rootamdm37x"
     55
     56typedef 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
     67static 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
     74static 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
     114static 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 */
     179static 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}
    52221
    53222typedef struct {
     
    102271        .hw_resources = {
    103272            .resources = ehci_res,
    104             .count = sizeof(ehci_res)/sizeof(ehci_res[0]),
     273            .count = sizeof(ehci_res) / sizeof(ehci_res[0]),
    105274        }
    106275};
     
    118287        .interfaces[HW_RES_DEV_IFACE] = &fun_hw_res_ops
    119288};
    120 
    121 static 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  */
    162 static 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 }
    251289
    252290static bool rootamdm37x_add_fun(ddf_dev_t *dev, const char *name,
     
    263301        /* Add match id */
    264302        if (ddf_fun_add_match_id(fnode, str_match_id, 100) != EOK) {
     303                ddf_fun_destroy(fnode);
     304                return false;
     305        }
     306       
     307        /* Set provided operations to the device. */
     308        ddf_fun_data_implant(fnode, (void*)fun);
     309        ddf_fun_set_ops(fnode, &rootamdm37x_fun_ops);
     310       
     311        /* Register function. */
     312        if (ddf_fun_bind(fnode) != EOK) {
     313                ddf_msg(LVL_ERROR, "Failed binding function %s.", name);
    265314                // TODO This will try to free our data!
    266315                ddf_fun_destroy(fnode);
     
    268317        }
    269318       
    270         /* Set provided operations to the device. */
    271         ddf_fun_data_implant(fnode, (void*)fun);
    272         ddf_fun_set_ops(fnode, &rootamdm37x_fun_ops);
    273        
    274         /* Register function. */
    275         if (ddf_fun_bind(fnode) != EOK) {
    276                 ddf_msg(LVL_ERROR, "Failed binding function %s.", name);
    277                 ddf_fun_destroy(fnode);
    278                 return false;
    279         }
    280        
    281319        return true;
    282320}
     
    292330static int rootamdm37x_dev_add(ddf_dev_t *dev)
    293331{
    294         int ret = usb_clocks(true);
     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);
    295343        if (ret != EOK) {
    296344                ddf_msg(LVL_FATAL, "Failed to enable USB HC clocks!.\n");
     
    298346        }
    299347
    300         ret = usb_tll_init();
     348        ret = usb_tll_init(device);
    301349        if (ret != EOK) {
    302350                ddf_msg(LVL_FATAL, "Failed to init USB TLL!.\n");
    303                 usb_clocks(false);
     351                usb_clocks(device, false);
    304352                return ret;
    305353        }
     
    343391{
    344392        printf("%s: HelenOS AM/DM37x(OMAP37x) platform driver\n", NAME);
    345         ddf_log_init(NAME, LVL_ERROR);
     393        ddf_log_init(NAME);
    346394        return ddf_driver_main(&rootamdm37x_driver);
    347395}
Note: See TracChangeset for help on using the changeset viewer.